-
-
[原创]KCTF 2024 第九题 第一次接触 WriteUp
-
发表于: 2024-9-4 00:01 1921
-
使用ida打开程序, 分析main函数的逻辑为:
首先输入的长度是3的倍数, 而且只包含小写字母与0到9
之后把输入分为等长的三段分别用不同的函数判断, 函数需要返回非0
再之后对输入进行了个md5的校验
第一个函数为
先转小写再确保前8个字符是hellocat; 因为之前确保了输入是小写所以这里的to_lower可以无视
第二个函数为
先将输入逆转, 再计算各个字符与'0'的差值和, 即将逆转后输入作为数字的各位数加在一起确保等于13
之后3*输入数字等于150633606, 即逆转后输入等于50211202
逆转前的输入为20211205
第三个函数为
sub_458232
经分析,逻辑为将输入解析为两个字符表示的44坐标, 第一个字符为a-d
,第二个字符为1-4
;
初始存在一个全0的44数组, 将输入坐标位置设置为1, 然后检查同行,同列,以及斜向方向上是否存在1(即已设置)
如果坐标解析错误或存在则返回0, 不存在就返回1
回来仔细观察verify3_45C500
的逻辑发现无论如何也不能满足dword_531E9C == 0x10000039
dword_531E9C初始为0, 要满足条件需要其最低位为1,唯一将最低位设置为1的语句用的是=
而非^=
,会清除之前的0x10000000
而且需要sub_458232
返回0才置位也很奇怪
观察gpart3与dword_531E9C的位置发现:
gpart3_531E94的大小为8字节, 如果part3为9字节则part3的最后一个字符会覆盖dword_531E9C的最低位从而可能满足条件
假设溢出的字符值就是0x39
即字符9, 则sub_458232的判断需要返回1
之前的比较保证坐标的第一个字符需要从小到大,则需要分别为a,b,c,d
再回头看前两个函数输入为9字节的情况;
第一段只比较前8字节所以为hellocat?
第二段parseint
允许前缀0所以为202112050
第三段为a?b?c?d?9
写python脚本爆破:
output_45548D((
int
)&unk_50AE70, v4);
j__memset(input, 0, 0x12Cu);
input_45591F(
"%[^\n]"
, (
char
)input);
length = j__strlen(input);
if
( !(length % 3) && length )
{
for
( i = 0; i < length; ++i )
{
if
( (input[i] <
'a'
|| input[i] >
'z'
) && (input[i] <
'0'
|| input[i] >
'9'
) )
goto
LABEL_3;
// output_45548D((int)"WRONG!\n", v5); return 0
}
Count = length / 3;
part1 = (
char
*)j__malloc(__CFADD__(length / 3, 1) ? -1 : length / 3 + 1);
part2 = (
char
*)j__malloc(__CFADD__(Count, 1) ? -1 : Count + 1);
part3 = (
char
*)j__malloc(__CFADD__(Count, 1) ? -1 : Count + 1);
j__memset(part1, 0, length / 3 + 1);
j__memset(part2, 0, length / 3 + 1);
j__memset(part3, 0, length / 3 + 1);
j__strncpy(part1, input, length / 3);
j__strncpy(part2, &input[Count], Count);
j__strncpy(part3, &input[2 * Count], Count);
if
( verify1_456BCB(part1) && verify2_4578CD(part2) && verify3_456E78(part3) )
{
Str1 = (
char
*)md5_4579F4(input);
if
( !j__strcmp(Str1,
"40d511825ecbc207eb6ef9a7b1c6e34b"
) )
output_45548D((
int
)
"Success~\n"
, v5);
...
}
...
}
output_45548D((
int
)&unk_50AE70, v4);
j__memset(input, 0, 0x12Cu);
input_45591F(
"%[^\n]"
, (
char
)input);
length = j__strlen(input);
if
( !(length % 3) && length )
{
for
( i = 0; i < length; ++i )
{
if
( (input[i] <
'a'
|| input[i] >
'z'
) && (input[i] <
'0'
|| input[i] >
'9'
) )
goto
LABEL_3;
// output_45548D((int)"WRONG!\n", v5); return 0
}
Count = length / 3;
part1 = (
char
*)j__malloc(__CFADD__(length / 3, 1) ? -1 : length / 3 + 1);
part2 = (
char
*)j__malloc(__CFADD__(Count, 1) ? -1 : Count + 1);
part3 = (
char
*)j__malloc(__CFADD__(Count, 1) ? -1 : Count + 1);
j__memset(part1, 0, length / 3 + 1);
j__memset(part2, 0, length / 3 + 1);
j__memset(part3, 0, length / 3 + 1);
j__strncpy(part1, input, length / 3);
j__strncpy(part2, &input[Count], Count);
j__strncpy(part3, &input[2 * Count], Count);
if
( verify1_456BCB(part1) && verify2_4578CD(part2) && verify3_456E78(part3) )
{
Str1 = (
char
*)md5_4579F4(input);
if
( !j__strcmp(Str1,
"40d511825ecbc207eb6ef9a7b1c6e34b"
) )
output_45548D((
int
)
"Success~\n"
, v5);
...
}
...
}
BOOL
__cdecl verify1_45C360(
char
*part1)
{
__CheckForDebuggerJustMyCode(&unk_535028);
to_lower_455816(part1);
return
j__strncmp(part1,
"hellocat"
, 8u) == 0;
}
BOOL
__cdecl verify1_45C360(
char
*part1)
{
__CheckForDebuggerJustMyCode(&unk_535028);
to_lower_455816(part1);
return
j__strncmp(part1,
"hellocat"
, 8u) == 0;
}
BOOL
__cdecl verify2_45C400(
char
*part2)
{
size_t
i;
// [esp+D4h] [ebp-14h]
int
v3;
// [esp+E0h] [ebp-8h]
__CheckForDebuggerJustMyCode(&unk_535028);
reverse(part2);
v3 = 0;
for
( i = 0; i < j__strlen(part2); ++i )
v3 = v3 + part2[i] -
'0'
;
return
v3 == num13_531004 && num3_531008 * parseint(part2) == 150633606;
}
BOOL
__cdecl verify2_45C400(
char
*part2)
{
size_t
i;
// [esp+D4h] [ebp-14h]
int
v3;
// [esp+E0h] [ebp-8h]
__CheckForDebuggerJustMyCode(&unk_535028);
reverse(part2);
v3 = 0;
for
( i = 0; i < j__strlen(part2); ++i )
v3 = v3 + part2[i] -
'0'
;
return
v3 == num13_531004 && num3_531008 * parseint(part2) == 150633606;
}
BOOL
__cdecl verify3_45C500(
char
*part3)
{
__CheckForDebuggerJustMyCode(&unk_535028);
j__strcpy(&gpart3_531E94, part3);
if
( j__strlen(&gpart3_531E94) < 8 )
return
0;
dword_531E9C |= 0x10000000u;
if
( gpart3_531E94 >= *(&gpart3_531E94 + 2) )
dword_531E9C |= 0x88u;
if
( *(&gpart3_531E94 + 2) >= *(&gpart3_531E94 + 4) )
dword_531E9C |= 0x90u;
if
( *(&gpart3_531E94 + 4) >= *(&gpart3_531E94 + 6) )
dword_531E9C |= 0xA0u;
if
( !sub_458232((
int
)&gpart3_531E94) )
dword_531E9C = 1;
if
( !sub_458232((
int
)&gpart3_2) )
dword_531E9C ^= 8u;
if
( !sub_458232((
int
)&gpart3_4) )
dword_531E9C ^= 0x10u;
if
( !sub_458232((
int
)&gpart3_6) )
dword_531E9C ^= 0x20u;
return
dword_531E9C == 0x10000039;
}
BOOL
__cdecl verify3_45C500(
char
*part3)
{
__CheckForDebuggerJustMyCode(&unk_535028);
j__strcpy(&gpart3_531E94, part3);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)