其他
看雪·众安 2021 KCTF 秋季赛 | 第七题设计思路及解析
看雪·众安 2021 KCTF秋季赛的第七题《声名远扬》已于今天中午12点截止答题!
经统计,本题围观人数多达1179人,共计20支战队成功破解。
恭喜金左手用时4002秒拿下“一血”,接下来和我一起来看看该赛题的设计思路和相关解析吧~
出题团队简介
赛题设计思路
在win64中,代码段寄存器0x23和0x33所对应的GDT表项中CPU的模式分别为32位与64位。
具体原理参考链接:https://bbs.pediy.com/thread-221236.htm
设计思路:
1、exe程序编译为32位程序,把核心判断代码放入64位代码中。
2、加密用base64改了一下编码表,编码表特别好找,单步跟就能看到。
3、校验flag的流程是线性的,没有反调试,加了一丢丢的垃圾指令(可能你们都注意不到)。只要找到onclick函数,一路单步就可以看到输出的结果。
4、把关键字符串隐藏起来,运行时解密出来。比如:"正确","错误",flag编码后的字符串。隐藏字符串算法是异或。
流程如下:
1、把输入的flag进行base64编码;
2、把编码结果丢到64位代码中对比,接收对比结果;
3、把对比结果输出。
破解思路:
1、找到64位代码中flag加密后的数据。
2、找到base64编码表。
3、通过base64算法还原flag。
赛题解析
本赛题解析由看雪论坛sunfishi给出:
考察C++逆向。
int __cdecl base64Maps(int a1)
{
int *v1; // eax
char v3[8]; // [esp+4h] [ebp-68h] BYREF
int v4; // [esp+Ch] [ebp-60h]
_BYTE base64[65]; // [esp+10h] [ebp-5Ch] BYREF
unsigned int v6[2]; // [esp+51h] [ebp-1Bh] BYREF
int v7; // [esp+68h] [ebp-4h]
v4 = 0;
sub_26D5D0((char *)v6 + 3, 8u);
qmemcpy(base64, "prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!", sizeof(base64));
v1 = (int *)__FrameHandler3::TryBlockMap::TryBlockMap(
(__FrameHandler3::TryBlockMap *)v3,
(const struct _s_FuncInfo *)base64,
(unsigned int)v6);
sub_26EA90((char *)v6 + 3, *v1, v1[1]);
v7 = 0;
sub_26EAD0((void *)a1, (int)v6 + 3);
v4 |= 1u;
v7 = -1;
sub_26EA70();
return a1;
}
下面进行验证。 动态调试得到编码串:
import base64
baseMaps = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
newMaps = "prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!"
cipherText = "EHsnG0bjGT44BqIhETj!"
cipherText = cipherText.translate(cipherText.maketrans(newMaps, baseMaps))
print(base64.b64decode(cipherText.encode('utf-8')).decode())
解得lovectf{mas0n},验证成功。 进入下一步。 经过调试分析确定总体逻辑如下图:
__int64 __fastcall sub_145AC(char *a1, __int64 a2)
{
unsigned int v4; // edx
char v5; // al
__int64 v6; // rcx
int v7; // edx
char v8; // al
char *v9; // rcx
__int64 v10; // rax
unsigned int v11; // edx
char v12; // al
__int64 v13; // rcx
char v14; // cl
__int64 v15; // r8
int *v16; // rax
char v17; // al
__int64 v18; // rcx
char v19; // cl
__int64 v20; // r8
int *v21; // rax
int v23; // [rsp+4h] [rbp-3Ch] BYREF
char v24; // [rsp+8h] [rbp-38h]
__int16 v25; // [rsp+9h] [rbp-37h]
char v26; // [rsp+Bh] [rbp-35h]
unsigned int v27; // [rsp+Ch] [rbp-34h]
char v28[48]; // [rsp+10h] [rbp-30h] BYREF
v27 = 44;
v4 = 0;
*(__m128i *)v28 = _mm_load_si128((const __m128i *)&xmmword_14408);
*(__m128i *)&v28[32] = _mm_load_si128((const __m128i *)&xmmword_143F8);
*(__m128i *)&v28[16] = _mm_load_si128(xmmword_14418);
do
{
v5 = v4 - 52;
v6 = v4++;
v28[v6] ^= v5;
}
while ( v4 < v27 ); // 还原base64编码串
v28[v27] = 0;
v7 = 0;
v8 = *a1;
if ( *a1 )
{
v9 = a1;
do
{
if ( v8 != v9[v28 - a1] ) // strcmp
break;
++v9;
++v7;
v8 = *v9;
}
while ( *v9 );
}
v10 = v7;
v11 = 0;
v24 = -48;
if ( a1[v10] == v28[v10] ) // bingo
{
v23 = 0x78063019; // 正确
v25 = 0;
v26 = 0;
do
{
v12 = v11 - 52;
v13 = v11++;
*((_BYTE *)&v23 + v13) ^= v12;
}
while ( v11 < 4 );
v24 = 0;
v14 = v23;
if ( (_BYTE)v23 )
{
v15 = a2 - (_QWORD)&v23;
v16 = &v23;
do
{
*((_BYTE *)v16 + v15) = v14;
v16 = (int *)((char *)v16 + 1);
v14 = *(_BYTE *)v16;
}
while ( *(_BYTE *)v16 );
}
}
else
{
v23 = 0x3C002078; // 错误
v25 = 0;
v26 = 0;
do
{
v17 = v11 - 52;
v18 = v11++;
*((_BYTE *)&v23 + v18) ^= v17;
}
while ( v11 < 4 );
v24 = 0;
v19 = v23;
if ( (_BYTE)v23 )
{
v20 = a2 - (_QWORD)&v23;
v21 = &v23;
do
{
*((_BYTE *)v21 + v20) = v19;
v21 = (int *)((char *)v21 + 1);
v19 = *(_BYTE *)v21;
}
while ( *(_BYTE *)v21 );
}
}
return 0i64;
}
简单异或还原明文验证猜想。
"""
v23 = 0x78063019;
v25 = 0;
v26 = 0;
do
{
v12 = v11 - 52;
v13 = v11++;
*((_BYTE *)&v23 + v13) ^= v12;
}
while ( v11 < 4 );
"""
v11 = 0
v23 = bytearray(int.to_bytes(0x78063019, length=4, byteorder="little"))
while 1:
v12 = v11 - 52
v13 = v11
v11 += 1
v23[v13] ^= v12 & 0xff
if v11 >= 4:
break
print(v23.decode('gbk'))
# 正确
最终解题脚本如下:
import base64
"""
v27 = 44;
v4 = 0;
*(__m128i *)v28 = _mm_load_si128((const __m128i *)&xmmword_15408);
*(__m128i *)&v28[32] = _mm_load_si128((const __m128i *)&xmmword_153F8);
*(__m128i *)&v28[16] = _mm_load_si128(xmmword_15418);
do
{
v5 = v4 - 52;
v6 = v4++;
v28[v6] ^= v5;
}
while ( v4 < v27 );
v28[v27] = 0;
"""
xmmArr = [0x0B3E38188BB9CBA9DBAFFB697ABA2948B, 0x0BFDBD9AAD6D4BCA1878490B0B5AE858C, 0x0F8D6D7A7BAB89480B78A94B9AE]
v27 = 44
v28 = b''
for xmm in xmmArr:
v28 += int.to_bytes(xmm, length=16, byteorder="little")
v28 = bytearray(v28)
v4 = 0
while 1:
v5 = v4 - 52
v6 = v4
v4 += 1
v28[v6] ^= v5 & 0xff
if v4 >= v27:
break
v28[v27] = 0
print(v28)
cipherText = v28.decode()
baseMaps = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
newMaps = "prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!"
cipherText = cipherText.translate(cipherText.maketrans(newMaps, baseMaps))
print(base64.b64decode(cipherText.encode('utf-8')).decode())
往期解析
1、看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析
2、看雪·众安 2021 KCTF 秋季赛 | 第三题设计思路及解析
3、看雪·众安 2021 KCTF 秋季赛 | 第四题设计思路及解析
4、看雪·众安 2021 KCTF 秋季赛 | 第五题设计思路及解析
5、看雪·众安 2021 KCTF 秋季赛 | 第六题设计思路及解析
第八题《群狼环伺》正在火热进行中,
👆还在等什么,快来参赛吧!球分享
球点赞
球在看