程序退出调用链的利用--exit_hook
字数 1219 2025-08-22 12:22:24

exit_hook利用技术详解

1. 基本概念

exit_hook是一种在glibc 2.34版本之前存在的利用技术,通过劫持程序退出时的调用链来获取控制权。这种技术特别适用于存在任意地址写漏洞的场景。

2. 技术原理

2.1 调用链分析

exit_hook技术主要利用以下调用链:

__run_exit_handlers -> _dl_fini

这个调用链可以通过两种方式触发:

  1. 通过libc_start_main进入
  2. 程序显式调用了exit函数

2.2 _dl_fini函数分析

_dl_fini函数是动态链接器的一部分,负责在程序退出时清理动态加载的共享库。关键代码片段如下:

#ifdef SHARED
int do_audit = 0;
again:
#endif
for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns) {
    /* Protect against concurrent loads and unloads. */
    __rtld_lock_lock_recursive (GL(dl_load_lock));
    unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
    /* No need to do anything for empty namespaces or those used for auditing DSOs. */
    if (nloaded == 0
#ifdef SHARED
        || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
#endif
       )
    __rtld_lock_unlock_recursive (GL(dl_load_lock));
}

其中关键的并发保护机制:

__rtld_lock_lock_recursive (GL(dl_load_lock));
__rtld_lock_unlock_recursive (GL(dl_load_lock));

2.3 _rtld_global结构体

_rtld_global结构体是glibc中RTLD(动态链接器运行时)管理全局状态和信息的关键组件。exit_hook的利用点就位于这个结构体的特定偏移处。

3. 不同版本libc的偏移

不同版本的glibc中exit_hook的偏移位置:

  • libc-2.23:

    • exit_hook = libc_base + 0x5f0040 + 3848
    • exit_hook = libc_base + 0x5f0040 + 3856
  • libc-2.27:

    • exit_hook = libc_base + 0x619060 + 3840
    • exit_hook = libc_base + 0x619060 + 3848

4. 利用条件

  1. 知道libc版本
  2. 存在任意地址写漏洞
  3. 程序会调用exit或通过libc_start_main退出

5. 例题分析

5.1 ezheap例题

程序分析:

  1. 包含一个猜数字程序(sub_4012B6)
  2. srand种子是当前时间
  3. 提供size输入,size为有符号整数(重要)
  4. 提供八字节地址任意写功能

利用思路:

  1. 通过输入size为-1将地址映射到libc附近,泄露地址
  2. 修改exit_hook函数为one_gadget
  3. 触发exit调用获取shell

EXP关键代码:

# 获取堆地址
rl("input size you want to malloc\n")
sl(str(-10))
heap_addr=int(mx.recv(14),16)+ 0x100000ff0

# 计算exit_hook地址
exit_hook=heap_addr+ 0x619f60+8

# 写入one_gadget
s(p64(exit_hook))
s(p64(ogg))

5.2 hctf2018_the_end例题

程序特点:

  1. 提供了libc
  2. 任意地址写四个字节

利用流程:

  1. 泄露libc地址
  2. 计算exit_hook地址
  3. 分四次写入one_gadget地址

EXP关键代码:

# 计算目标地址
target_addr=libc_addr+3848+0x5f0040

# 分四次写入one_gadget
for i in range (4):
    s(p64(target_addr))
    sleep(0.5)
    s(p8(ogg&0xff))
    target_addr+=1
    ogg=ogg>>8

6. 总结与建议

  1. 在攻击低版本libc时,exit_hook是一个有效的替代IO_FILE利用的技术
  2. 需要精确计算目标libc版本的偏移
  3. 任意地址写漏洞是前提条件
  4. 相比IO_FILE利用,exit_hook通常更简单直接

7. 防御措施

  1. 升级到glibc 2.34或更高版本
  2. 对用户输入进行严格校验,防止任意地址写
  3. 使用现代防护机制如ASLR、FORTIFY_SOURCE等

8. 参考文献

  1. glibc源码分析
  2. 相关CTF题目writeup
  3. 动态链接器内部机制文档
exit_ hook利用技术详解 1. 基本概念 exit_ hook是一种在glibc 2.34版本之前存在的利用技术,通过劫持程序退出时的调用链来获取控制权。这种技术特别适用于存在任意地址写漏洞的场景。 2. 技术原理 2.1 调用链分析 exit_ hook技术主要利用以下调用链: 这个调用链可以通过两种方式触发: 通过libc_ start_ main进入 程序显式调用了exit函数 2.2 _ dl_ fini函数分析 _ dl_ fini函数是动态链接器的一部分,负责在程序退出时清理动态加载的共享库。关键代码片段如下: 其中关键的并发保护机制: 2.3 _ rtld_ global结构体 _ rtld_ global结构体是glibc中RTLD(动态链接器运行时)管理全局状态和信息的关键组件。exit_ hook的利用点就位于这个结构体的特定偏移处。 3. 不同版本libc的偏移 不同版本的glibc中exit_ hook的偏移位置: libc-2.23 : exit_ hook = libc_ base + 0x5f0040 + 3848 exit_ hook = libc_ base + 0x5f0040 + 3856 libc-2.27 : exit_ hook = libc_ base + 0x619060 + 3840 exit_ hook = libc_ base + 0x619060 + 3848 4. 利用条件 知道libc版本 存在任意地址写漏洞 程序会调用exit或通过libc_ start_ main退出 5. 例题分析 5.1 ezheap例题 程序分析 : 包含一个猜数字程序(sub_ 4012B6) srand种子是当前时间 提供size输入,size为有符号整数(重要) 提供八字节地址任意写功能 利用思路 : 通过输入size为-1将地址映射到libc附近,泄露地址 修改exit_ hook函数为one_ gadget 触发exit调用获取shell EXP关键代码 : 5.2 hctf2018_ the_ end例题 程序特点 : 提供了libc 任意地址写四个字节 利用流程 : 泄露libc地址 计算exit_ hook地址 分四次写入one_ gadget地址 EXP关键代码 : 6. 总结与建议 在攻击低版本libc时,exit_ hook是一个有效的替代IO_ FILE利用的技术 需要精确计算目标libc版本的偏移 任意地址写漏洞是前提条件 相比IO_ FILE利用,exit_ hook通常更简单直接 7. 防御措施 升级到glibc 2.34或更高版本 对用户输入进行严格校验,防止任意地址写 使用现代防护机制如ASLR、FORTIFY_ SOURCE等 8. 参考文献 glibc源码分析 相关CTF题目writeup 动态链接器内部机制文档