ret2libc对策 – ASLR
ASLR(Address Space Layout Randomization)
主要是地址随机化
现代Linux内核中默认开启
ret2libc成功的原因是,libc之类的读取地址是固定的
因此如果每次运行时,libc之类的地址随机,是一个比较好的方式
miao# echo 2 > /proc/sys/kernel/randomize_va_space miao# ldd stack6 | grep libc libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d94000) miao# ldd stack6 | grep libc libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7dd4000)
如上所示,每次运行地址都不同
ASLR绕过 - 方式1
ASLR中,并非所有地址都是随机的
PLT/GOT之类的地址是固定的,可以利用这一点
实际的内存映射大概是这样
红框中是固定地址,PLT和GOT在这里
GOT中存储ASLR随机化后的地址
因此出现了有名的的根据这些信息计算libc地址的方法
GOT leak
GOT中包含重要地址
- printf的外部地址
如果能够读取更新后的(printf@got.plt)这个值,那么就可能计算出libc.so的加载地址
GOT overwrite
因为GOT位于RW区域,因此可能覆写
- 使用某种漏洞将printf的GOT替换为另一个地址
默认情况下可以重写GOT的值。通过某种方式将其修改为其他函数的地址,当调用printf函数的时候会调用修改后的其他函数。这种方式叫做GOT overwrite。
NX+ASLR绕过1 – memory leak + ret2plt + GOT overwrite
假设存在栈溢出
通过ret2plt等方式,显示出printf@got的地址(write)
- 泄漏地址
- 攻击者可以通过泄漏的地址计算libc的基地址,加上偏移量计算出system的地址
通过ret2plt等方式,向printf@got读入system的地址(read)
- 下次调用printf的时候,会实际调用system
其他的泄漏
除GOT leak之外,其他能够泄漏libc地址的情况
- 通过(Stack/Heap)缓冲区溢出读取造成的泄漏
- 无序参考,负数索引,类型(主要是结构体)的混淆导致的泄漏
- 字符串末尾无终止字符造成的泄漏
- 格式化字符串问题
- Use After Free,Double Free
- 条件竞争等
通过泄漏想要获取的值
- stack区域上__libc_start_main的返回地址
- 指向bss区域中与libc相关的变量的指针(例如FILE *之类的)
- 指向堆管理区域(元数据)中的bin/fastbins的指针
- bin/fastbins无任何连接时适用
- 与libc相关的所有其他地址
其他的指针
GOT之外其他可写的函数指针
- C++ class的vtable
- 在C++中,class有method,在内部实现了一个函数指针表
- .fini_array(旧的.dtor区域)
- gcc编译具有
__attribute__((destructor))
的函数时,会在这里注册
- gcc编译具有
- 由atexit()注册的列表
- 明确指定析构函数时的函数指针
- 但是它与Thread Local Storage中奇怪的值XOR(PTR_MANGLE)之后进行注册