看雪.腾讯TSRC 2017 CTF 秋季赛 第三题点评及解析思路
看雪CTF快讯:
第三题攻破人数突破100啦!
导语
周一快乐~
经过一个周末的奋战,第三题攻破人数破百,第三题作者上升至第二位。
第三题过后,攻击方的排名如下:ccfer依然居于首位,风间仁、爱琴海紧随其后。风间仁曾是上一届看雪CTF 的冠军,不知此次能够继续捍卫自己的冠军宝座呢?让我们拭目以待!
革命尚未成功,同志仍需努力!
接下来让我们一起来看看关于第三题的点评、出题思路和解析。
看雪评委 netwind 点评
作者用常见的反调试手段对程序进行了一定的保护,然后通过一个迷宫算法来实现程序的验证流程。本来是一个很有趣的题目,但是作者的算法有多处疏漏导致了破解方法也是五花八门。
第三题作者简介
littlewisp,从同事那里接触看雪论坛以来,对破解产生了浓厚的兴趣,陆续接触了加壳脱壳,驱动,rootkit等。后来的研发转向安全方向,长期从事外壳,虚拟机等软件保护产品的开发,在国内没有混淆的虚拟机保护的加密方案简直就是裸奔。
第三题设计思路
简单迷宫:
从头走到尾即可,q上z下p左l右
将路径字符串采用morse码编码,将morse码采用base64编码两次,得到第一部分结果;
将morse码采用sm3算法Hash,得到的部分作为第二部分结果。
破解思路:
过掉一些简单的反调试、单步跟踪,找到迷宫的数据,很容易找到走迷宫字符串,在根据对输入序列号的处理算法得到输入字符串。
下面选取攻击者ccfer的解析过程
因为exe有重定位表,为了方便读者阅读分析代码,先用pe编辑工具把exe的重定位表地址rv清0
程序中有很多检测,但检测到异常后,都会调用一个共同入口0042E086来处理,因此只要在0042E086处改一个字节ret直接返回就可以了。
ida打开exe,从GetDlgItemTextA的参考入手找到读取输入的地方,并对后面的流程做个注释:
.text:00435061 push 401h ; cchMax
.text:00435066 lea eax, [ebp+String]
.text:0043506C push eax ; lpString
.text:0043506D push 3E9h ; nIDDlgItem
.text:00435072 mov ecx, [ebp+hDlg]
.text:00435075 push ecx ; hDlg
.text:00435076 call ds:GetDlgItemTextA //读取输入
...
.text:004350A6 lea eax, [ebp+var_C30]
.text:004350AC push eax
.text:004350AD push 400h
.text:004350B2 lea ecx, [ebp+String]
.text:004350B8 push ecx
.text:004350B9 call sub_42D267 //对输入做第一层base64解码
...
.text:004350DE lea eax, [ebp+var_1038]
.text:004350E4 push eax
.text:004350E5 push 400h
.text:004350EA lea ecx, [ebp+var_C30]
.text:004350F0 push ecx
.text:004350F1 call sub_42D267 //对输入做第二层base64解码
.text:004350F6 add esp, 0Ch
.text:004350F9 push 400h
.text:004350FE lea eax, [ebp+var_1440]
.text:00435104 push eax
.text:00435105 lea ecx, [ebp+var_1038]
.text:0043510B push ecx
.text:0043510C call sub_42D96A //摩尔斯电码解码,空格分隔,4个字符转成一个小写字母
.text:00435111 add esp, 0Ch
.text:00435114 mov [ebp+var_144C], 3
.text:0043511E lea eax, [ebp+var_1474]
.text:00435124 push eax
.text:00435125 mov ecx, [ebp+var_144C]
.text:0043512B push ecx
.text:0043512C lea edx, [ebp+var_1038]
.text:00435132 push edx
.text:00435133 call sub_42DA78 //计算前3个字符的hash
.text:00435138 add esp, 0Ch
.text:0043513B mov [ebp+var_1888], 0
.text:00435145 jmp short loc_435156
.text:00435147 loc_435147:
.text:00435147 mov eax, [ebp+var_1888]
.text:0043514D add eax, 1
.text:00435150 mov [ebp+var_1888], eax
.text:00435156 loc_435156:
.text:00435156 cmp [ebp+var_1888], 20h
.text:0043515D jge short loc_43518B
.text:0043515F mov eax, [ebp+var_1888]
.text:00435165 movzx ecx, [ebp+eax+var_1474]
.text:0043516D push ecx
.text:0043516E push offset a02x ; "%02x"
.text:00435173 mov edx, [ebp+var_1888]
.text:00435179 lea eax, [ebp+edx*2+var_187C]
.text:00435180 push eax
.text:00435181 call sub_42DF05 //hash结果转成16进制字符串
.text:00435186 add esp, 0Ch
.text:00435189 jmp short loc_435147
.text:0043518B loc_43518B:
...
.text:004351C0 sub esi, eax
.text:004351C2 push esi
.text:004351C3 lea eax, [ebp+var_187C]
.text:004351C9 push eax
.text:004351CA call sub_42DB27 //hash串和输入的后64个字符比较
.text:004351CF add esp, 0Ch
.text:004351D2 test eax, eax
.text:004351D4 jnz short loc_435214
.text:004351D6 call sub_42D0B4
.text:004351DB lea eax, [ebp+var_1440]
.text:004351E1 push eax
.text:004351E2 push offset unk_49B000 //迷宫数据
.text:004351E7 call sub_42D9AB //根据输入做迷宫寻路
.text:004351EC add esp, 8
.text:004351EF movzx ecx, al
.text:004351F2 cmp ecx, 1
.text:004351F5 jnz short loc_435214
.text:004351F7 mov esi, esp
.text:004351F9 push 0 ; uType
.text:004351FB push offset Caption ; "CrackMe"
.text:00435200 push offset Text ; "ok"
.text:00435205 push 0 ; hWnd
.text:00435207 call ds:MessageBoxA
.text:0043520D cmp esi, esp
摩尔斯电码解码4个字符一组,空格是分隔符,空格前加'/'转义表示空格本身,每4个字符查表0049B2A0处的数据表,按顺序对应a~z:
.-**
-...
-.-.
-..*
.***
..-.
--.*
....
..**
.---
-.-*
.-..
--**
-.**
---*
.--.
--.-
.-.*
...*
-***
..-*
...-
.--*
-..-
-.--
--..
大小是10*10的迷宫数据49B000,要求从左上角走到右上角,0是可走点,1是障碍,x是个暗桩导致死锁:
0 1 1 1 1 1 1 1 1 0
0 0 1 1 1 1 1 0 0 0
1 0 0 0 0 0 1 0 1 1
1 1 1 1 1 0 1 0 x 1
1 0 0 0 1 0 1 0 0 1
1 0 1 0 0 0 1 0 1 1
1 0 1 1 1 1 1 0 0 1
1 0 0 0 0 1 1 1 0 0
1 1 1 1 0 0 0 0 1 0
1 1 1 1 1 1 1 0 0 0
迷宫走法是:
z 下
l 右
q 上
p 左
所以解题流程就清楚了:把迷宫路线用zlqp四个字符表示出来(注意末尾带个空格表示结束):
zlzllllzzzppqppzzzlllzlllzllqqpqpqqqqqllq
然后转成摩尔斯编码:
--.. .-.. --.. .-.. .-.. .-.. .-.. --.. --.. --.. .--. .--. --.- .--. .--. --.. --.. --.. .-.. .-.. .-.. --.. .-.. .-.. .-.. --.. .-.. .-.. --.- --.- .--. --.- .--. --.- --.- --.- --.- --.- .-.. .-.. --.-/
做两层base64:
TFMwdUxpQXVMUzR1SUMwdExpNGdMaTB1TGlBdUxTNHVJQzR0TGk0Z0xpMHVMaUF0TFM0dUlDMHRMaTRnTFMwdUxpQXVMUzB1SUM0dExTNGdMUzB1TFNBdUxTMHVJQzR0TFM0Z0xTMHVMaUF0TFM0dUlDMHRMaTRnTGkwdUxpQXVMUzR1SUM0dExpNGdMUzB1TGlBdUxTNHVJQzR0TGk0Z0xpMHVMaUF0TFM0dUlDNHRMaTRnTGkwdUxpQXRMUzR0SUMwdExpMGdMaTB0TGlBdExTNHRJQzR0TFM0Z0xTMHVMU0F0TFM0dElDMHRMaTBnTFMwdUxTQXRMUzR0SUM0dExpNGdMaTB1TGlBdExTNHRMeUE
后面加上hash得到答案:
TFMwdUxpQXVMUzR1SUMwdExpNGdMaTB1TGlBdUxTNHVJQzR0TGk0Z0xpMHVMaUF0TFM0dUlDMHRMaTRnTFMwdUxpQXVMUzB1SUM0dExTNGdMUzB1TFNBdUxTMHVJQzR0TFM0Z0xTMHVMaUF0TFM0dUlDMHRMaTRnTGkwdUxpQXVMUzR1SUM0dExpNGdMUzB1TGlBdUxTNHVJQzR0TGk0Z0xpMHVMaUF0TFM0dUlDNHRMaTRnTGkwdUxpQXRMUzR0SUMwdExpMGdMaTB0TGlBdExTNHRJQzR0TFM0Z0xTMHVMU0F0TFM0dElDMHRMaTBnTFMwdUxTQXRMUzR0SUM0dExpNGdMaTB1TGlBdExTNHRMeUEb92a72497b685c31013347a7276f371f8cf91085ab8322009bfed2df41d94f94
实际情况是,题目中迷宫判断有bug,遇到空格就会结束,判为成功,所以利用空格可以构造出无数的解来,甚至自己不加空格,程序都会自动从内存中一直向后找到一个空格为止。
温馨提示
每道题结束过后都会看到很多盆友的精彩解题分析过程,因为公众号内容的限制,每次题目过后我们将选出一篇与大家分享。解题方式多种多样,各位参赛选手的脑洞也种类繁多,想要看到更多解题分析的小伙伴们可以前往看雪论坛【CrackMe】版块查看哦!
热门推荐| 看雪CTF