-
-
[原创]看雪.TSRC 2017CTF秋季赛-第二题分析
-
发表于: 2017-10-27 22:46 3146
-
这个方程式无解的。
再看一下代码。发现在在4010E0函数下面一堆二进制数。
这样又面临另外二个问题,前面的12位可以是任意字符,题目出现无数个解这样的状况,而且0x10对应的字符也无法输入。先不管这些,用编辑器构造一个看看,构造如下key "111111111111/@" ,果然提示成功。如下图:
看起来成功了,去提交,结果没通过。看题目要求指导输入的必须是字符数字组合。
再次对上面的那段IDA无法分析的代码怀疑。先搜索下"You got it! \n",是否在这段代码中存在,没搜到。再搜索下面几个可疑的特征:
41B034 其如果为0则获得正确key
41102F 如果函数返回值为这个数值,则获得正确的key
无一例外,都没搜到。
但是如果我们把上面的溢出返回值构造到这段看起来加密的代码中,是否可行呢?而真正的校验是在这段代码中。先看一下这段代码的起始位置:
(x-y)*4 + x + z = 0xEAF917E2
(x-y)*3 + x + z = 0xE8F508C8
(x-y)*3 + x - z = 0xC0A3C68h
x=7473754A
y=726F6630
z=6E756630
调整下顺序, 对应key=“Just0for0fun11A”
.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp) .text:00401000 _main proc near ; CODE XREF: start+AFp .text:00401000 push offset aCrackmeForCtf2 ; "\n Crackme for CTF2017 @Pediy.\n" .text:00401005 call sub_413D42 .text:0040100A add esp, 4 .text:0040100D mov dword_41B034, 2 .text:00401017 call sub_401050 .text:0040101C call sub_401090 .text:00401021 call sub_4010E0 .text:00401026 mov eax, dword_41B034 .text:0040102B test eax, eax .text:0040102D jnz short loc_40103F .text:0040102F push offset aYouGetIt ; "You get it!\n" .text:00401034 call sub_413D42 .text:00401039 add esp, 4 .text:0040103C xor eax, eax .text:0040103E retn .text:0040103F ; --------------------------------------------------------------------------- .text:0040103F .text:0040103F loc_40103F: ; CODE XREF: _main+2Dj .text:0040103F push offset aBadRegisterCod ; "Bad register-code, keep trying.\n" .text:00401044 call sub_413D42 .text:00401049 add esp, 4 .text:0040104C xor eax, eax .text:0040104E retn .text:0040104E _main endp
从上面看变量41B034为0,则走“You get it!\n”分支。而变量41B034初始值为2,可以判断函数401050 401090 4010E0 是对key进行校验和处理的。跟进。
int *sub_401050() { int v1; // [sp+0h] [bp-Ch]@1 sub_413D42(aCodedByFpc_, v1); sub_413D42(aPleaseInputYou, v1); scanf(aS, &v1); return &v1; } void sub_401090() { int v0; // [sp+4h] [bp-8h]@0 int v1; // [sp+8h] [bp-4h]@0 if ( v1 && v0 && v1 != v0 && 5 * (v1 - v0) + v1 == 0x8F503A42 && 13 * (v1 - v0) + v0 == 0xEF503A42 ) --dword_41B034; } void sub_4010E0() { int v0; // [sp+4h] [bp-8h]@0 int v1; // [sp+8h] [bp-4h]@0 if ( v1 && v0 && v1 != v0 && 17 * (v1 - v0) + v1 == 0x8F503A42&& 7 * (v1 - v0) + v0 == 0x33A94883 ) --dword_41B034; }
可以看出401090和4010E0 是对key进行校验的。看起来是一个二元一次方程的题。
int *sub_401050() { int v1; // [sp+0h] [bp-Ch]@1 sub_413D42(aCodedByFpc_, v1); sub_413D42(aPleaseInputYou, v1); scanf(aS, &v1); return &v1; } void sub_401090() { int v0; // [sp+4h] [bp-8h]@0 int v1; // [sp+8h] [bp-4h]@0 if ( v1 && v0 && v1 != v0 && 5 * (v1 - v0) + v1 == 0x8F503A42 && 13 * (v1 - v0) + v0 == 0xEF503A42 ) --dword_41B034; } void sub_4010E0() { int v0; // [sp+4h] [bp-8h]@0 int v1; // [sp+8h] [bp-4h]@0 if ( v1 && v0 && v1 != v0 && 17 * (v1 - v0) + v1 == 0x8F503A42&& 7 * (v1 - v0) + v0 == 0x33A94883 ) --dword_41B034; }
可以看出401090和4010E0 是对key进行校验的。看起来是一个二元一次方程的题。
- 5 * (v1 - v0) + v1 = 0x8F503A42
- 13 * (v1 - v0) + v0 = 0xEF503A42
- 17 * (v1 - v0) + v1 = 0xF3A94883
- 7 * (v1 - v0) + v0 = 0x33A94883
这个方程式无解的。
再看一下代码。发现在在4010E0函数下面一堆二进制数。
.text:0040112B db 5 dup(90h) .text:00401130 dd 4800h dup(0) .text:00413130 ; --------------------------------------------------------------------------- .text:00413130 retn .text:00413130 ; --------------------------------------------------------------------------- .text:00413131 db 83h, 0C4h, 0F0h .text:00413134 dd 20712A70h, 0F1C75F2h, 28741C71h, 2E0671DDh, 870F574h .text:00413134 dd 74F17169h, 0DC167002h, 0EA74C033h, 0DC261275h, 0F471E771h .text:00413134 dd 6903740Fh, 0EB75EB70h, 0FDF7069h, 22712C70h, 0B8261F7Dh .text:00413134 dd 2B741E71h, 3E067169h, 870F57Ch, 7CF17169h, 0DC197002h .text:00413134 dd 41B034A3h, 75E77400h, 0E571DC12h, 7CDCF271h, 0E9706903h
难道是SMC吗。看下是否有TLS,发现没有。先从输入开始跟进吧,看看函数401050到底干了啥。发现scanf函数竟然是单独实现的不是系统函数。
int scanf(const char *a1, ...) { va_list va; // [sp+8h] [bp+8h]@1 va_start(va, a1); return _input(&stru_41B0D0, (int)a1, (int)va); }
跟进发现有很多看似系统函数却都是单独实现,比如read getc等函数。在这些函数中没发现什么问题。
.text:0040112B db 5 dup(90h) .text:00401130 dd 4800h dup(0) .text:00413130 ; --------------------------------------------------------------------------- .text:00413130 retn .text:00413130 ; --------------------------------------------------------------------------- .text:00413131 db 83h, 0C4h, 0F0h .text:00413134 dd 20712A70h, 0F1C75F2h, 28741C71h, 2E0671DDh, 870F574h .text:00413134 dd 74F17169h, 0DC167002h, 0EA74C033h, 0DC261275h, 0F471E771h .text:00413134 dd 6903740Fh, 0EB75EB70h, 0FDF7069h, 22712C70h, 0B8261F7Dh .text:00413134 dd 2B741E71h, 3E067169h, 870F57Ch, 7CF17169h, 0DC197002h .text:00413134 dd 41B034A3h, 75E77400h, 0E571DC12h, 7CDCF271h, 0E9706903h
难道是SMC吗。看下是否有TLS,发现没有。先从输入开始跟进吧,看看函数401050到底干了啥。发现scanf函数竟然是单独实现的不是系统函数。
int scanf(const char *a1, ...) { va_list va; // [sp+8h] [bp+8h]@1 va_start(va, a1); return _input(&stru_41B0D0, (int)a1, (int)va); }
跟进发现有很多看似系统函数却都是单独实现,比如read getc等函数。在这些函数中没发现什么问题。
int scanf(const char *a1, ...) { va_list va; // [sp+8h] [bp+8h]@1 va_start(va, a1); return _input(&stru_41B0D0, (int)a1, (int)va); }
跟进发现有很多看似系统函数却都是单独实现,比如read getc等函数。在这些函数中没发现什么问题。
函数read:将结尾回车的0D0A改成了0A0A。
函数read:将结尾回车的0D0A改成了0A0A。
函数read:将结尾回车的0D0A改成了0A0A。
函数_whiteout:如果起始字符是空格则直接过滤掉。
函数_whiteout:如果起始字符是空格则直接过滤掉。
函数_input:key中间有空格则直接将后面的字符截断。
函数_input:key中间有空格则直接将后面的字符截断。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
他的文章
- 看雪CTF 2019总决赛 第六题 三道八佛 IDA脱壳脚本 5671
- [原创]看雪CTF2019Q3第四题WP 5936
- [原创]看雪CTF2019Q3 第二题WP 6764
- [2019看雪CTF晋级赛Q3第九题WP 12495
- [原创]看雪CTF2019晋级赛Q2第三题 5023
看原图
赞赏
雪币:
留言: