写在前面:最近特忙,不太可能每题都有空参加,能做一题是一题了,文章争取写清楚,论坛有些文字乱码我也不知道怎么办。
下载地址:https://ctf.pediy.com/attach-download-86.htm
一、侦查:无壳 Microsoft Visual C/C++(6.0)[libc],有明确提示成功和失败信息。
二、出坑:OD加载,查找字符,定位到:“You get it!”
地址 反汇编 文本字符串
00401000 PUSH ctf2017_.0041B06C \n Crackme for CTF2017 @Pediy.\n
0040102F PUSH ctf2017_.0041B05C You get it!\n
0040103F PUSH ctf2017_.0041B038 Bad register-code, keep trying.\n
00401053 PUSH ctf2017_.0041B0AC Coded by Fpc.\n\n
00401060 PUSH ctf2017_.0041B090 Please input your code:
00401072 PUSH ctf2017_.0041B08C %s
00401000 /$ 68 6CB04100 PUSH ctf2017_.0041B06C ; \n Crackme for CTF2017 @Pediy.\n
00401005 |. E8 382D0100 CALL ctf2017_.00413D42
0040100A |. 83C4 04 ADD ESP,0x4
0040100D |. C705 34B04100>MOV DWORD PTR DS:[0x41B034],0x2 ; 2
00401017 |. E8 34000000 CALL ctf2017_.00401050 ; input
0040101C |. E8 6F000000 CALL ctf2017_.00401090 ; check1
00401021 |. E8 BA000000 CALL ctf2017_.004010E0 ; check2
00401026 |. A1 34B04100 MOV EAX,DWORD PTR DS:[0x41B034] ; 0
0040102B |. 85C0 TEST EAX,EAX
0040102D |. 75 10 JNZ Xctf2017_.0040103F
0040102F |. 68 5CB04100 PUSH ctf2017_.0041B05C ; You get it!\n
00401034 |. E8 092D0100 CALL ctf2017_.00413D42
00401039 |. 83C4 04 ADD ESP,0x4
0040103C |. 33C0 XOR EAX,EAX
0040103E |. C3 RETN
0040103F |> 68 38B04100 PUSH ctf2017_.0041B038 ; Bad register-code, keep trying.\n
00401044 |. E8 F92C0100 CALL ctf2017_.00413D42
00401049 |. 83C4 04 ADD ESP,0x4
0040104C |. 33C0 XOR EAX,EAX
0040104E \. C3 RETN
0040104F 90 NOP
00401050 /$ 83EC 0C SUB ESP,0xC
00401053 |. 68 ACB04100 PUSH ctf2017_.0041B0AC ; Coded by Fpc.\n\n
00401058 |. E8 E52C0100 CALL ctf2017_.00413D42
0040105D |. 83C4 04 ADD ESP,0x4
00401060 |. 68 90B04100 PUSH ctf2017_.0041B090 ; Please input your code:
00401065 |. E8 D82C0100 CALL ctf2017_.00413D42
0040106A |. 83C4 04 ADD ESP,0x4
0040106D |. 8D4424 00 LEA EAX,DWORD PTR SS:[ESP]
00401071 |. 50 PUSH EAX
00401072 |. 68 8CB04100 PUSH ctf2017_.0041B08C ; %s
00401077 |. E8 F72C0100 CALL ctf2017_.00413D73
0040107C |. 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+0x8]
00401080 |. 83C4 14 ADD ESP,0x14
00401083 \. C3 RETN
简单跟踪几步发现 401090、4010E0 为显性算法比较,分析 401090、4010E0:
void sub_401090()
{
int l32; // [esp+4h] [ebp-8h]
int h32; // [esp+8h] [ebp-4h]
if ( h32 && l32 && h32 != l32 && 5 * (h32 - l32) + h32 == 0x8F503A42 && 0xD * (h32 - l32) + l32 == 0xEF503A42 )
--dword_41B034;
}
void sub_4010E0()
{
int l32; // [esp+4h] [ebp-8h]
int h32; // [esp+8h] [ebp-4h]
if ( h32 && l32 && h32 != l32 && 0x11 * (h32 - l32) + h32 == 0xF3A94883 && 7 * (h32 - l32) + l32 == 0x33A94883 )
--dword_41B034;
}
把输入每4个字符ASCII作为十六进制赋值计算,假设为a,b则:
⑴:0x5 * ( a - b ) + a == 0x8F503A42
⑵:0xD * ( a - b ) + b == 0xEF503A42
⑶:0x11 * ( a - b ) + a == 0xF3A94883
⑷:0x7 * ( a - b ) + b == 0x33A94883
考虑该显性算法未随机打乱数值,低位特征依然继承到计算结果,因此先尝试求解低位,再逐个往高位求解,避免穷举范围过大:
def solve_false():
start_time = time.clock()
for a1 in range(0x30,0x7b):
for b1 in range(0x30,0x7b):
if (0x5 * (a1 - b1) + a1) & 0xff == 0x42:
if (0xd * (a1 - b1) + b1) & 0xff == 0x42:
if (0x11 *(a1 - b1) + a1) & 0xff == 0x83:
if (0x7 * (a1 - b1) + b1) & 0xff == 0x83:
print ("found sn a1 : %x" % a1)
print ("found sn b1 : %x" % b1)
print ('use time: %.3f second' % (time.clock()-start_time))
return
迅速识别该方程组无合法答案,无疑是作者埋的坑,立即寻找其他途径。
三、溢出:测试不同输入长度,发现当输入15个字符时就已经可以覆盖CALL 00401050的返回地址,将断点设在401083观察:
比如输入:123456781111AAA
0018FF3C 34333231
0018FF40 38373635
0018FF44 31313131
0018FF48 00414141 ctf2017_.00414141
esp:
0018FF48 00414141 ctf2017_.00414141
返回地址覆盖为:0x414141“AAA”,因此作者设置了此处溢出可以根据输入字符转移流程,达到隐蔽算法目的。这里我们可以测试(复制到验证界面):
123456781111/@
可以显示成功,但因比赛规则要求防守方和攻击方都得遵守合法字符的要求,因此出现特殊字符不被认可,我们继续分析。
四、破解:上文已经做好了一切破解的准备,因合法字符要求,现在我们寻找0x413030-0x417a7a之间的可疑过程或函数入口,删除OD模块分析:
很快就看到了0x413131这个位置很可疑,花指令一大堆,此处无银三百两嘛,对应溢出字符“11A”,现在我们输入“Just0for0fun11A”(为避免啰嗦,直接用正确注册码阐述
):
a:0x7473754A "Just"
b:0x726F6630 "0for"
c:0x6E756630 "0fun"
取消前文所有断点,在0x413131位置设置新断点,回车断下,忽略花指令,仅摘录算法相关代码:
00413131 83C4 F0 ADD ESP,-0x10
00413150 33C0 XOR EAX,EAX ; EAX清零
00413184 A3 34B04100 MOV DWORD PTR DS:[0x41B034],EAX ; 全局变量[0x41B034]清零
004131BA 58 POP EAX ; EAX=输入的1-4位,例如7473754A"Just",记为a
004131EB 8BC8 MOV ECX,EAX ; ECX=EAX
0041321F 58 POP EAX ; EAX=输入的5-8位,例如726F6630"0for",记为b
00413254 8BD8 MOV EBX,EAX ; EBX=EAX
00413289 58 POP EAX ; EAX=输入的第9-12位,例如6E756630 "0fun",记为c
004132B5 8BD0 MOV EDX,EAX ; EDX=EAX
004132AD 8BD0 MOV EDX,EAX ; EDX=EAX
004132E2 8BC1 MOV EAX,ECX ; EAX=ECX
00413316 2BC3 SUB EAX,EBX ; EAX=EAX-EBX=a-b
00413349 C1E0 02 SHL EAX,0x2 ; EAX=EAX*4=4*(a-b)
00413380 03C1 ADD EAX,ECX ; EAX=EAX+ECX=4*(a-b)+a
004133B5 03C2 ADD EAX,EDX ; EAX=EAX+EDX=4*(a-b)+a+c
004133E9 2D E217F9EA SUB EAX,0xEAF917E2 ; EAX=EAX-0xEAF917E2=4*(a-b)+a0xEAF917E2==0……⑴
00413455 03C1 ADD EAX,ECX ; EAX=ECX=a
00413489 2BC3 SUB EAX,EBX ; EAX=EAX-EBX=a-b
004134BF 8BD8 MOV EBX,EAX ; EBX=EAX
004134F3 D1E0 SHL EAX,1 ; EAX=EAX*2=2*(a-b)
00413525 03C3 ADD EAX,EBX ; EAX=EAX+EBX=3*(a-b)
00413559 03C1 ADD EAX,ECX ; EAX=EAX+ECX=3*(a-b)+a
0041358F 8BC8 MOV ECX,EAX ; ECX=EAX
004135C3 03C2 ADD EAX,EDX ; EAX=EAX+EDX=3*(a-b)+a+c
004135F7 2D C808F5E8 SUB EAX,0xE8F508C8 ; EAX=EAX-0xE8F508C8=3*(a-b)+a0xE8F508C8==0……⑵
00413665 8BC1 MOV EAX,ECX ; EAX=ECX=3*(a-b)+a
0041365D 8BC1 MOV EAX,ECX ; EAX=ECX
004136A7 2BC2 SUB EAX,EDX ; EAX=EAX-EDX=3*(a-b)c
004136D8 2D 683C0A0C SUB EAX,0xC0A3C68 ; EAX=EAX-0xC0A3C68=3*(a-b)c-0xC0A3C68==0……⑶
00413747 58 POP EAX ; EAX=0x413131
00413777 35 01810000 XOR EAX,0x8101 ; EAX=EAX^0x8101=0x41B030
004137A9 8BF8 MOV EDI,EAX ; EDI=EAX
004137E2 33C0 XOR EAX,EAX ; EAX=0
00413817 AB STOS DWORD PTR ES:[EDI]
0041385C 58 POP EAX ; EAX=0x413835
0041388E 50 PUSH EAX ; ctf2017_.00413835
004138BA 8BF8 MOV EDI,EAX ; ctf2017_.00413835
004138B2 8BF8 MOV EDI,EAX ; ctf2017_.00413835
004138E6 68 6909004E PUSH 0x4E000969
0041391F 58 POP EAX ; EAX=x4E000969
00413950 33C2 XOR EAX,EDX ; EAX=EAX^EDX=20756F59
00413983 AB STOS DWORD PTR ES:[EDI]
004139B5 35 3E0A0100 XOR EAX,0x10A3E ; EAX=EAX^0x10A3E=20746567
004139EB AB STOS DWORD PTR ES:[EDI]
00413A1C 33C3 XOR EAX,EBX ; EAX=EAX^EBX=22706A7D
00413A4D 35 141E5122 XOR EAX,0x22511E14 ; EAX=EAX^0x22511E14=00217469
00413A82 AB STOS DWORD PTR ES:[EDI]
00413AB6 35 2D646100 XOR EAX,0x61642D ; EAX=EAX^0x61642D=00401044
00413B83 3305 34B04100 XOR EAX,DWORD PTR DS:[0x41B034] ; EAX=EAX^0=0x401044
00413BBB ^\FFE0 JMP EAX ; JMP 0x401044 飞向光明顶
esp:
0018FF48 00413835 ASCII "You get it!"
这里得到了三组方程:
⑴:4*(a-b)+a0xEAF917E2==0
⑵:3*(a-b)+a0xE8F508C8==0
⑶:3*(a-b)c-0xC0A3C68==0
三个未知数,三组方程可以求解了,化简、笔算也可以,如果图省事那就:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ctf.pediy.com TSRC 2017CTF crackme 2 keygen
# python 3.6.0 64bit
# written by 爱琴海
# 2017/10/26
from sympy import *
def Main():
a=Symbol('a')
b=Symbol('b')
c=Symbol('c')
print (solve([4*(a-b)+a0xEAF917E2,3*(a-b)+a0xE8F508C8,3*(a-b)c-0xC0A3C68],[a,b,c]))
if __name__=="__main__":
Main()
解出:{a: 1953723722, b: 1919903280, c: 1853187632} 转十六进制:{a: 0x7473754A, b: 0x726F6630, c: 0x6E756630} 得到答案:“Just0for0fun11A”
五、总结:作者通过显性算法坑、溢出隐藏算法流程、花指令干扰分析、加密成功出口等手段对抗破解,有意思。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界