-
-
[原创]MTCTF-PSA-Writeup
-
发表于: 2021-7-5 02:33 13013
-
PSA这道题当时归到PWN类型下,到比赛截止是2sol。但其实这道题主要问题还是在它的逆向部分。有点后悔当时没有早点看这道题,比赛结束后半个小时把这题解出来了,美团CTF差一道题没进决赛,不然将来美团实习转正的时候说不定还能吹吹这个经历
IDA打开看到给了一个很像是登录的逻辑判断 :
如果用户名和密码对了就给你进到栈溢出函数vuln():
进入到先前的函数,可以看到题目进行了很多大数库操作,包括执行了bn_mod_exp之类的函数,基本上就可以判定是RSA,下面的代码我略修改过,所以基本上容易看清
那么接下的核心问题是确定公钥N和e:
注意到这里的e是用十六进制去存储的,也就是{0x01, 0x00, 0x01},即65537。N是小端序存储的,即0xdbea...
回到核心判断逻辑:
以用户名为例,读入用户名后经过public_block_operation的一轮RSA加密,结果存放在v11中,然后v11首先去除掉首部的空字节,然后以Qword形式存放到s中,说穿了就是截取加密后密文的前8个字节,然后去和'root'作比较,这里可以用GDB简单调试验证下:
我输入的username是'aaa\n',跟进来在strcmp之前rsi的值与RSA加密结果的前几位一致
下面那个password处理和这个同理,只不过加了一个简单异或,就不再赘述。
那么问题的核心就在于找到一个明文字符串,用公钥加密后的前几个字节必须是root。那么直接用\x00填充构建一个8字节的密文'root\x00\x00\x00\x00',然后反推明文,这个就是解RSA或模方程的问题了,不难,此题公钥N可以容易地被分解,password部分是同理的。
最后是栈溢出部分,题目还给了一个backdoor,里面是system('/bin/sh'),只要覆盖返回地址为backdoor地址就行了,但是我记得这题开了随机地址+覆盖字节数限制,只有一定的概率能覆盖成功。exp如下即可进入栈溢出函数:
栈溢出以后getshell,当时的老图贴上来
int
vuln()
{
__int64 buf;
/
/
[rsp
+
0h
] [rbp
-
10h
]
__int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
buf
=
0LL
;
v2
=
0LL
;
printf(
"You can set message: "
,
0LL
,
0LL
);
read(
0
, &buf,
0x1AuLL
);
return
printf(
"OK, recv!"
, &buf);
}
int
vuln()
{
__int64 buf;
/
/
[rsp
+
0h
] [rbp
-
10h
]
__int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
buf
=
0LL
;
v2
=
0LL
;
printf(
"You can set message: "
,
0LL
,
0LL
);
read(
0
, &buf,
0x1AuLL
);
return
printf(
"OK, recv!"
, &buf);
}
signed __int64 __fastcall public_block_operation(__int64 a1, unsigned
int
*
a2, __int64 a3, unsigned
int
a4, _DWORD
*
a5)
{
_DWORD
*
v6;
/
/
[rsp
+
8h
] [rbp
-
468h
]
char v7;
/
/
[rsp
+
30h
] [rbp
-
440h
]
char m;
/
/
[rsp
+
140h
] [rbp
-
330h
]
char e;
/
/
[rsp
+
250h
] [rbp
-
220h
]
char c;
/
/
[rsp
+
360h
] [rbp
-
110h
]
unsigned
int
edigits;
/
/
[rsp
+
468h
] [rbp
-
8h
]
unsigned
int
ndigits;
/
/
[rsp
+
46Ch
] [rbp
-
4h
]
v6
=
a5;
bn_decode((__int64)&m,
65u
, a3, a4);
bn_decode((__int64)&v7,
0x41u
, (__int64)(v6
+
1
),
256
);
bn_decode((__int64)&e,
0x41u
, (__int64)(v6
+
65
),
256
);
ndigits
=
bn_digits((__int64)&v7,
65
);
edigits
=
bn_digits((__int64)&e,
65
);
if
( (signed
int
)bn_cmp((__int64)&m, (__int64)&v7, ndigits) >
=
0
)
return
4097LL
;
bn_mod_exp((__int64)&c, (__int64)&m, (__int64)&e, edigits, (__int64)&v7, ndigits);
*
a2
=
(unsigned
int
)(
*
v6
+
7
) >>
3
;
bn_encode(a1,
*
a2, (__int64)&c, ndigits);
memset(&c,
0
,
0x104uLL
);
memset(&m,
0
,
0x104uLL
);
return
0LL
;
}
signed __int64 __fastcall public_block_operation(__int64 a1, unsigned
int
*
a2, __int64 a3, unsigned
int
a4, _DWORD
*
a5)
{
_DWORD
*
v6;
/
/
[rsp
+
8h
] [rbp
-
468h
]
char v7;
/
/
[rsp
+
30h
] [rbp
-
440h
]
char m;
/
/
[rsp
+
140h
] [rbp
-
330h
]
char e;
/
/
[rsp
+
250h
] [rbp
-
220h
]
char c;
/
/
[rsp
+
360h
] [rbp
-
110h
]
unsigned
int
edigits;
/
/
[rsp
+
468h
] [rbp
-
8h
]
unsigned
int
ndigits;
/
/
[rsp
+
46Ch
] [rbp
-
4h
]
v6
=
a5;
bn_decode((__int64)&m,
65u
, a3, a4);
bn_decode((__int64)&v7,
0x41u
, (__int64)(v6
+
1
),
256
);
bn_decode((__int64)&e,
0x41u
, (__int64)(v6
+
65
),
256
);
ndigits
=
bn_digits((__int64)&v7,
65
);
edigits
=
bn_digits((__int64)&e,
65
);
if
( (signed
int
)bn_cmp((__int64)&m, (__int64)&v7, ndigits) >
=
0
)
return
4097LL
;
bn_mod_exp((__int64)&c, (__int64)&m, (__int64)&e, edigits, (__int64)&v7, ndigits);
*
a2
=
(unsigned
int
)(
*
v6
+
7
) >>
3
;
bn_encode(a1,
*
a2, (__int64)&c, ndigits);
memset(&c,
0
,
0x104uLL
);
memset(&m,
0
,
0x104uLL
);
return
0LL
;
}
puts(
"Login\nPlease input your name:"
);
v13
=
read(
0
, buf,
0x100uLL
);
public_block_operation((__int64)v11, (unsigned
int
*
)&v10, (__int64)buf, v13, &pk);
for
( i
=
0
; i <
=
255
&& !v11[i];
+
+
i )
;
v0
=
&v11[i];
v1
=
v0[
1
];
*
(_QWORD
*
)s2
=
*
v0;
v9
=
v1;
puts(
"Please input your password:"
);
memset(buf,
0
,
0x100uLL
);
v13
=
read(
0
, buf,
0x100uLL
);
public_block_operation((__int64)v11, (unsigned
int
*
)&v10, (__int64)buf, v13, &pk);
for
( i
=
0
; i <
=
255
&& !v11[i];
+
+
i )
;
v2
=
&v11[i];
v3
=
v2[
1
];
*
(_QWORD
*
)s
=
*
v2;
v7
=
v3;
if
( strcmp(
"root"
, s2) )
goto LABEL_22;
if
( strlen(s) !
=
6
)
goto LABEL_22;
i
=
0
;
while
( i <
=
5
)
{
v4
=
i
+
+
;
asc_2040A3[v4] ^
=
0x11u
;
}
if
( !strcmp(asc_2040A3, s) )
{
puts(
"Welcome back, administrator. "
);
result
=
vuln();
}
puts(
"Login\nPlease input your name:"
);
v13
=
read(
0
, buf,
0x100uLL
);
public_block_operation((__int64)v11, (unsigned
int
*
)&v10, (__int64)buf, v13, &pk);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)