ret2plt链的问题点
- 如果想要使用的函数不在PLT中,则无法构成链
- ret2libc
绕过NX2 - ret2libc
想要使用的函数不在PLT时,应该怎么办?
- 源代码中未使用的函数,在二进制程序中不会有PLT入口
- 也就是说,我们无法通过PLT代理到函数地址
- 即使没有PLT入口,但如果内存地址正确,也可以直接调用函数(至少libc中的函数可以这样)
- 如果能够知道system函数的地址,那么就能够调用它
怎样才能知道地址?
首先,了解下ASLR
miao# echo 0 > /proc/sys/kernel/randomize_va_space miao# ldd heap | grep libc.so libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7dda000) miao# ldd heap | grep libc.so libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7dda000) miao# echo 2 > /proc/sys/kernel/randomize_va_space miao# ldd heap | grep libc.so libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d45000) miao# ldd heap | grep libc.so libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d8e000) miao#
在ASLR关闭的情况下,无论运行多少次,读取到的目标地址都是不变的(这里练习环境关闭了ASLR)
对于不同的环境和二进制文件,该地址可能不同,但大体上相似(0xf7XXXXXX这种)
但是,32位机器上的结果和在64位机器上运行32位程序的结果不同
- 32位机器,0xb7XXXXXX
- 64位机器运行32位程序,0xf7XXXXXX
- 这是因为64位机器中内核区域的映射地址不是0xc0000000~(大概)
libc.so中的偏移地址,在文件中和内存中都是固定的
- libc.so的文件内容以完全相同的方式映射到内存
- 也就是说,我们只需要加上基地址
因此
- 使用objdump预先检查函数的偏移量
- 例如,system()的偏移是0x40190,如果对方的libc与自己的libc一致,那么内存中的地址就是0xf7e21000 + 0x40190
- 但是,如果环境不同,可能会有轻微的区别
检查libc中的函数地址
# ldd heap
(首先检查正在使用的libc路径)objdump -d /lib/i386-linux-gnu/libc.so.6 | grep "system"
(检查这个libc)
检查libc中特定字符串的地址
strings -tx /lib/i386-linux-gnu/libc.so.6 | grep "/bin/sh"
预先检查得到了system()和”/bin/sh”的地址,将他们加载到stack中
- “/bin/sh”类似的字符串也在libc.so中
如果环境不同,可能会有偏差
- 但是,即使环境不同,加载目标地址也只会以0x1000的增量变化
- 您可以以0x1000为增量进行暴力枚举
- 0xf7e61190, 0xf7e62190, 0xf7e63190, …
那么,问题来了
- 对方环境必须要是特定的libc
- 需要提前调查各种偏移地址
- 这考察了侦察能力
- 需要识别对方环境具体事什么版本的libc
- 对方环境必须要是特定的libc
目前为止的技术总结
技术 | 推荐练习的问题 |
---|---|
nop-sled | CodeGate 2013 - pwn100 |
brute force | CodeGate 2013 - pwn100 |
ret2esp | CSAW CTF 2012 - pwn300 - 4842 |
stager | Hack.lu CTF 2012 - pwn300 - braincpy |
ret2plt | Plaid CTF 2013 - pwn200 - ropasaurusrex |
ret2pop | Plaid CTF 2013 - pwn200 - ropasaurusrex |
ret2libc | Plaid CTF 2013 - pwn200 - ropasaurusrex |