IO_File 与 ld.so 利用总结
[1] IO_File
[2] ld.so
[2-1] _rtld_global._dl_ns._ns_loaded
[2-1-1] 原理
程序在调用exit()
退出时,会调用(待调试)
,而我们可以通过修改 _rtld_global._dl_ns._ns_loaded.l_next->l_next->l_next
[2-1-2] 找偏移量
恢复调试符号请看Pwn - Heap Exploit Summary 的 patchelf 部分
恢复调试符号以后,在 pwndbg 中输入1
2
3
4
5
6
7
8
9
10
11# 找 &(_rtld_global._dl_ns._ns_loaded.l_next->l_next->l_next)
# 与 &(_rtld_global) 之间的偏移量
pwndbg> distance &_rtld_global &(_rtld_global._dl_ns._ns_loaded->l_next->l_next->l_next)
0x7f992b424040->0x7f992b3f3018 is -0x31028 bytes (-0x6205 words)
# 找 _rtld_global 的真实地址
pwndbg> p &_rtld_global
$1 = (struct rtld_global *) 0x7f8bb8255040 <_rtld_global>
# 若本次运行的 libc_base 为 0x7f8bb803a000
# 则 offset = 0x7f8bb8255040 - 0x7f8bb803a000 = 0x21b040
# 这个 offset 会在下面的 python 代码中用到
1 | # 计算 _rtld_global._dl_ns._ns_loaded.l_next->l_next->l_next 的真实地址 |
largebin attack 以后,观察 _rtld_global,应该有这样一条链1
2
3
4
5
6
7
8
9
10
11
12
13
14_rtld_global._dl_ns._ns_loaded = 0x7f... head_node
|
| (*_ns_loaded) + 0x18
v
_rtld_global._dl_ns._ns_loaded.l_next = 0x7f... node_1
|
| (*(xx.l_next)) + 0x18
v
..._ns_loaded.l_next->l_next = 0x7f... node_2
|
| (*(xx->l_next)) + 0x18
v
...l_next->l_next->l_next = 0x55...(堆地址) node_3
# 链上正好四个 node
[2-1-3] 构造 fake chunk
我们假设:1
2
3
4
5
6 |-----------|-----------|
fake_rtld_global -> | perv_size | size |
|-----------|-----------|
| user_data |
| . . . |
|-----------|-----------|
1 | # 我看的 wp 大多数都在构造 fake chunk 时用到了 libc + 一个偏移量, |
最后构造的 chunk 应该如下
1 | pwndbg> tele 0x5644419bbcd0 40 |
[2-2] _rtld_global.exit_hook
libc: 2.23 / 2.27 (其他版本未记录)
[2-2-1] exit_hook 调用链
exit —> run_exit_handlers —> _dl_fini —> rtld_lock_lock_recursive / __rtld_lock_unlock_recursive
[2-2-2] POC
1 | gdb 中输入 |
libc2.23 中:
exit_hook_addr = libc_base+0x5f0040+3848
exit_hook_addr = libc_base+0x5f0040+3856
在libc-2.27中
exit_hook_addr = libc_base+0x619060+3840
exit_hook_addr = libc_base+0x619060+3848