首页
论坛
专栏
课程

看雪CTF 2018国庆题 WriteUp

impakho 2018-10-8 11:57 1445

叹息之墙

题目及题解文件打包:见附件 wall.zip

 

之前玩过几次看雪CTF,确实玩不动玩不动,题目好难啊。前几名是魔鬼吧,逆向分析能力惊人,很快就出flag了。

 

这次国庆只放出了一题,用来测试平台团队功能,为后面的团队赛做准备。

 

国庆假期出去玩了几天,回来看了一下这道题。花了一天半时间解出来,解法可能不是很优秀哈~

流程框图

这张图确实像一面墙,难怪叫“叹息之墙”。这也让我想起某次比赛的“给大佬递IDA”。 (╭・ω・)╭IDA

 

流程分析

每个函数内部大致情况就是,不断的二叉树判断条件,判断进入哪个代码段去执行,可以理解为很多个 if 和 elseif 。此函数中 [esi+301Ch] 存储的值为判断条件(我把它叫做 jump code ,然后该值对应进入的代码段首地址叫做 jump addr )。

 

分析主函数 main_func

使用搜索功能,找到一些关键代码段,进一步分析出代码段的功能,然后发现部分相同的代码段会重复出现在不同地址处,有些不会被调用到,估计是为了混淆代码。

 

下面列出已知代码段的 jump addr

entry 代码段:0x40bdc1
功能:主函数首先会进入的代码段

welcome 代码段:0x40bff3, 0x4513a6, 0x45bc28
功能:分别输出两条字符串,然后读取用户输入

format error 代码段:0x437db2, 0x43922e, 0x443c31, 0x45a2e4, 0x45bacb, 0x45bb3c
功能:输出“格式错误”

incorrect 代码段:0x44ec31, 0x45bbd5
功能:输出“输入错误”

correct 代码段:0x44f13d
功能:输出“输入正确”

ret 代码段:0x45104d
功能:返回,退出函数

虽然已知部分代码段的功能,但还是无法掌握整个函数的运行流程。

 

因此,我专门根据每个代码段里面,出现下一次 jump code 的位置规律,编写了一个用于生成函数内代码段调用顺序框图的脚本。详见文件打包内的生成脚本 flow_main_func.py

 

生成结果 flow_main_func.png (点此查看大图)

 

 

correct 代码段往前推导,根据条件判断标志,找到两处关键函数 0x44d1700x44c195

分析代码段 0x44d170

 

此处调用 calc_raw 函数,传递了4个32位参数,其实是2个64位数。

 

第一个64位数为 dword_49F57C ,第二个64位数来自 0x44c195 代码段里的累加结果(详情见下节)。

 

返回结果需要等于 dword_49F580 才能进入 correct 代码段,否则进入 incorrect 代码段。

 

通过动态调试,传入不同值,尝试了几十次的函数调用,根据返回传入值和结果的规律,得知了函数的功能。

 

然后编写出了爆破脚本,详见文件打包内的 cpu爆破脚本 calc_cpu.py 和 gpu爆破脚本 calc_gpu.py

分析代码段 0x44c195

 

dword_49FE40 处存储着用户输入的那几组整数,整数范围[0,351),然后分别去 dword_49F000 中取出对应数字进行累加,累加结果小于 0x900000000

 

累加结果在 0x44d170 代码段中,作为 calc_raw 函数的参数传入(第二个64位数)。

 

仔细发现 dword_49F000 里的351个32位数字其实是有规律的,可以挑选出9个特别的数字,这351个数字是这9个数字的倍数。

解法一

使用爆破脚本 calc_cpu.pycalc_gpu.py ,把 calc_raw 函数第二个64位数的可能值跑出来。

爆破得到的可能值:
0x55121c15, 0x154b3eba3, 0x25455bb31,
0x353f78abf, 0x453995a4d, 0x5533b29db,
0x652dcf969, 0x7527ec8f7, 0x852209885

然后再根据代码段 0x44c195 的功能,编写脚本 getflag_normal.py 解方程并排除无效项,得到序列号。

分析主函数 calc_raw

使用脚本生成代码段调用顺序框图。详见文件打包内的生成脚本 flow_calc_raw.py

 

生成结果 flow_calc_raw.png

 

 

使用上面相同的倒序推导方法,结合动态调试,得到函数内部进行运算的原理。

 

编写出计算脚本 calc_raw.py

解法二

根据“351个数字是其中9个数字的倍数”规律,把数字划分为9组,进行迭代组合,计算累加结果。

 

将累加结果代入到 calc_raw.py 里计算,判断结果是否等于 dword_49F580 (进入 correct 代码段的条件)。

 

将以上解法二过程编写成脚本 getflag_raw.py ,运行脚本得到序列号。

正确的序列号

序列号:17x27x60x97x133x161x243x292x309X



[防守篇]2018看雪.TSRC CTF 挑战赛(团队赛)11月1日征题开启!

上传的附件:
最新回复 (2)
新月之铭 2018-10-15 23:26
2

0

写的很好的
tiaotiao 2018-10-24 19:21
3

0

不错,感谢分享
返回