GOT overwrite对策 – Full-RELRO
GOT可以重写会产生问题
- Full-RELRO使其只读
- 这里整个section被设置为只读属性(只能在二进制启动时初始化写入),Full-RELRO (RELocation Read-Only)
- 编译选项:
gcc -Wl,-z,relro,-z,now
NX+ASLR+Full-RELRO绕过1 –ret2dl_runtime_resolve
- AVtokyo2014上inaz2公开的一项技术
- http://www.slideshare.net/inaz2/rop-illmatic-exploring-universal-rop-on-glibc-x8664-ja
- 利用dl_runtime_resolve和DT_DEBUG在libc中动态查找地址
- dl_runtime_resolve是PLT用于动态解析外部函数地址的函数
- 如果提供类似system()的数据,就能够得到system()的地址
- 详细参考inaz2的博客
- 通过ROP stager + Return-to-dl-resolve + DT_DEBUG read绕过 ASLR+DEP+RELRO
- x64环境下通过ROP stager + Return-to-dl-resolve + DT_DEBUG read尝试绕过ASLR+DEP+RELRO
NX+ASLR+Full-RELRO绕过2 – _IO_jump_t overwrite
当bss中有stdin/stdout等时有效
- 瞄准全局变量FILE*指针
http://outflux.net/blog/archives/2011/12/22/abusing-the-file-structure/
FILE函数指针指向处有一个函数表
覆盖函数表,当调用例如_IO_file_close()时会调用shellcode或者ROP
即使全局变量中没有fd,libc.so中总会有一个bss
其他的 – libc/ld specific ptr
- libc.so或者ld.so的bss中,有一些有趣的函数指针
- libc_bss+0x08(x86)/0x10(x64):_dl_runtime_resolve@got.plt
- libc_bss+0x30(x86)/0x38(x64):__tls_get_addr@got.plt
- ld_bss+0x838(x86)/0xf68(x64):_dl_rtld_lock_recursive
- ld_bss+0x83c(x86)/0xf70(x64):_dl_rtld_unlock_recursive
- (以上数据为Ubuntu 14.04 latest中的偏移)
- 还与一个函数指针表(指针的指针)
- (x86) libc.so正上方mapped+0x914处的匿名函数指针表
- (x64) ld.so正下方mapped+0x6f0处的匿名函数指针表
- 从
__GI___call_tls_dtors
调用的函数表 - (以上数据为Ubuntu 14.04 latest中的偏移)
- Ubuntu16.04中许多已经受到保护,但仍有部分可用
- 如果覆盖这些,exit()时将会自动调用
- 更改为shellcode地址,将会被执行
- 可以覆盖任意内存,但不能直接控制EIP/RIP的困难情况
- 尝试利用之前的地址强行控制EIP/RIP
- 之后从DROP开始的stack pivot可以做任何事情
- 实际应用这种情况不多
library地址相关
- 即使在ASLR下,x86的library地址也是很低的熵
- 具体来说,只有256种模式(8比特)
- 可以通过brute force来集中正确的libc_base
- mmap, vdso, pie时的.text也是同样程度的熵
- x64种,熵足够高(28比特),暴力方式几乎不可能
- 具体来说,只有256种模式(8比特)
- x86/x64种,library与某些区域的相对距离是固定的
- library A与library B
- library A与mapped
- library A与0x21000以上size的malloc地址
- library A与经过PIE的.text
- 泄露相关地址后,就能够计算出其他地址
- offset需要预先在相同版本ASLR环境下确认
- 需要注意的是,heap,vdso,stack之间的距离不是固定值