前提条件
当题目中开启了nx保护
题目中所给的文件没有system函数和/bin/sh
程序中有输入输出函数
当满足这些条件时我们就可以考虑ret2libc
解题思路
首先,需要找到libc文件中的system函数地址和/bin/sh字符串的地址
其次,构造ROP链,让程序去执行
system(/bin/sh)
由于所给的文件中没有system和binsh,因此要在libc库中找到对应的真实地址
寻找真实地址需要下面的公式
1 | 函数的真实地址 = 基地址 + 偏移地址 |
因此就产生了一个问题:如何找到偏移量
got表和plt表
got表(global offset table)用于储存外部函数的在内存中的确切地址,也就是所需要的基地址,找到了system和binsh的got表地址再找到偏移量就能调用system(/bin/sh)
了
plt表(procedure link table)存放函数的入口地址,ida反编译出来的函数地址就是plt地址,用plt表可以执行程序中有的函数
找到真实地址和基地址后就可以计算出偏移地址,就能找到对应的libc版本
实例分析
BUUCTF在线评测 (buuoj.cn) ciscn_2019_c_1
开启了nx保护
拖入ida中没发现system函数
shift+f12也没看见binsh
程序中有puts() gets()
这两个输入输出函数
因此可以考虑ret2libc
程序分析
main函数
发现上来先输入1
才能让程序跳出循环继续执行
encrypt函数
就是输入一个字符串s然后给s各种加密最后再输出加密后的s
泄露libc版本
1 | main=0x400b28 |
先设置rdi寄存器储存puts函数的got表地址
再通过plt表调用puts函数,输出的是puts的got表地址
再让他回到main函数,这样就可以让程序重新走一遍再一次构造ROP
1 | puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0')) |
接受puts的got表地址然后再输出出来
输出出来的地址可通过:libc database search (blukat.me)查询libc版本(不推荐,因为经常能找出一大堆版本,不知道是不是我打开方式有问题)
这里我们直接用LibcSearcher库来找libc版本
1 | libc=LibcSearcher('puts',puts_addr) |
找到对应版本后算出偏移量再找到system和binsh的地址
调用system
之后再次构造rop链
1 | r.sendlineafter('choice!\n','1') |
调用system需要栈对齐,要填充ret
完整exp
1 | from pwn import* |
会发现有两个libc版本对应,挨个试,发现第二个可以
这题本地怎么都跑不通,连接远端服务器后就行,我估计是ubuntu版本太低了