看雪·深信服 2021 KCTF 春季赛 | 第六题设计思路及解析

发布者:Editor
发布于:2021-05-21 17:40



本题我们跟随主人公飞停一起,寻找宝剑。本题耗时2天,吸引了超过2千人围观,最终11支战队夺旗成功!恭喜!



出题团队简介


崇文路大专是一个隶属于重庆邮电大学信息安全协会的CTF战队,其主要目标是培养对信息安全感兴趣的学弟学妹们,带着新入门的成员一起参加比赛,致力于夺得各大比赛签到题一血。同时也是重庆邮电大学信息安全协会旗下的0xFA战队的附属战队,0xFA战队曾多次进入XCTF线下总决赛、安洵杯线下总决赛、国赛总决赛。



专家点评


比赛第六题是一个有趣的42*42棋盘游戏,使用了自己开发的混淆器进行混淆处理。选手需要编写代码去除混淆拿到核心算法代码再进行逆向。题目难度中等偏上,需要考验选手的逆向和编写脚本的能力。



赛题设计思路


题目设计了一个巧妙的数学问题,既考察了各位选手的代码审计能力,又对信息收集能力与编程解题能力有一定的要求。

 

首先程序会问36乘49等于多少,这是对题目算法内容的一种暗示:36×49=42×42。

 

接着程序会读取输入,输入不允许出现0-9、A-Z、"+-*/%="以外的其他字符。

 

然后程序会检查输入的长度是否为84,如果满足则把输入的字符两两一组以四十二进制的方式解析成42个整数,存放在数组里,其中这42个整数必须是按照严格递增的顺序被输入。

 

接下来,用一个42×42的二维数组来抽象一个42×42个格子的棋盘,然后将该二维数组一维化,将输入的整数数组中的每个整数当作下标,将对应下标的元素设置为true(两位的四十二进制刚好不会超过棋盘的大小)。

 

若某数组元素为true,则代表棋盘中该元素对应的格子里放了一颗棋子,反之则没有放任何东西。

 

接下来检查,是否每一行、每一列均只有一颗棋子(即:同一行/列中不能有多颗棋子,因为只可以放42颗棋子,所以刚好可以每行每列放一个)。

 

我规定某两颗棋子的连线称作它们的相对偏移线段(比如:第一行第一列的棋子和第二行第二列的棋子的相对偏移线段是一条长度为根号二、斜率为负一的线段),若两条相对偏移线段的长度和斜率均相等,则称它们相等。

 

后面的代码是检验是否任意两颗棋子之间的相对偏移线段均不相等(注:相对偏移线段没有“方向”这个概念,也就是说,“棋子A与棋子B的相对偏移线段”和“棋子B与棋子A的相对偏移线段”视作同一条相对偏移线段)。

 

若检验通过,则判断输入的开头14个字符是否与指定的字符串相等,换句话说我指定了棋盘上前7颗棋子的位置(按从左到右、从上到下的顺序)。

 

若检验全通过,则输出成功,否则输出错误。

 

程序采用Release x64模式编译,所用编译器为Visual Studio 2019可选安装的LLVM - clang-cl(版本为10.0),设置了生成调试信息:否、优化:已禁用、启用内部函数:否、优选大小或速度:均不,编译环境为Windows10 2004。

 

由于题目要求不允许使用第三方壳或VM,我认为ollvm或许会被认定为第三方,因此没有采用ollvm方式编译,题目难度稍有降低。


原创混淆器


本次比赛出题使用了我自己开发的“COP”混淆器,COP可以打开并解析一个PE文件,针对32/64位分别进行处理。

 

COP要求所给文件必须具有.text段、.reloc段,且不含有花指令。

 

COP使用Capstone解析出程序文件的所有汇编指令,将指令进行混淆,并且随机打乱,膨胀后的指令无法塞进原.text段,因此将多余的部分放入新的.cop段中。

 

顺序被完全打乱的指令需要用某种方式连接它们,让它们顺序执行,我将非跳转指令用“call+pop+add/xor+push+ret”的方式连接,将跳转指令进行了不同程度的变形。

 

此外,COP还将程序所有基于相对偏移的指令进行了修复,通过重定位表将所有基于绝对地址的命令进行了修复,对64位程序的基于rip寻址的指令进行了修复。

 

COP自行维护了一个独立的重定位表,混淆后仍可以开启地址随机化。

 

为了提高混淆强度,对64位程序还将清空其.pdata段的内容。

 

COP还支持嵌套混淆(简称套娃),进一步提高混淆强度。

 

用户可以选择保留.reloc段或者去除,去除以后会进一步提高混淆强度,但不支持继续嵌套混淆,且会关闭地址随机化。

 

我使用COP将编译出的程序进行了2次混淆,得到最终附件,考察了各位选手编写脚本的能力。


解题思路


拿到的附件使用IDA打开,发现有非常多的重复的代码,且动态调试的时候有效指令出现的频率极低,因此可以考虑使用脚本对文件进行初步处理。

 


先拿到call后面的pop rax的地址,提取xor的第二个操作数,即可计算出下一条指令的位置。

 

计算相对偏移,将第一个push rax改成jmp到下一条指令。

 

这里比较方便的是使用IDAPython编写脚本,因为IDA提供了很多有用的API。

 

如此操作完以后,可以发现还嵌套了一层混淆。



这里可以采用的方法很多,我采用的顺序遍历+特征匹配的方式定位被jmp连起来的代码碎块,若一系列遍历下去发现指令与模式匹配,则认为它是一个混淆指令块,取pop rax的地址和add的第二个操作数(内层是add,外层是xor),计算下一条指令的位置,并把匹配的指令序列的第一个指令改成jmp,可以把代码还原成由jmp连接起来的零碎指令。



再用IDA打开去混淆后的程序,从字符串的交叉引用定位主函数。



 

但是可以看到可能因为我的去混淆代码写得不是很好,IDA的F5插件仍然无能为力,这里可以考虑使用Capstone或者IDA自带的API修一下代码,或许能提高反编译的质量和准确率。

 

在去混淆到这种程度后,一个好办法是动静结合,再根据F5的部分残破的语句,可以大致还原整个算法(因为没有开编译器优化,因此可读性比较强)。

 

拿到算法后,可以选择写代码跑出结果,也可以上网进行信息收集。

 

我们不难得知,前人已经对该问题进行过研究了,人们把它叫做科斯塔斯阵列(Costas Arrays)。

 

参考链接:http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.137.8983&rep=rep1&type=pdf

 

已经有许多高效的算法被前人发明,我们通过模仿与借鉴这些代码就能求出最终的结果。

 

最后,将求出的结果转化成42个整数,以四十二进制的方式转换后即是最终flag。



赛题解析


本赛题解析由看雪论坛 KuCha128 给出:


图片

具体解析可点击此链接:https://bbs.pediy.com/thread-267658.htm 查看


往期解析


1. 看雪·深信服 2021 KCTF 春季赛 | 第二题设计思路及解析

2. 看雪·深信服 2021 KCTF 春季赛 | 第三题设计思路及解析

3. 看雪·深信服 2021 KCTF 春季赛 | 第四题设计思路及解析

4. 看雪·深信服 2021 KCTF 春季赛 | 第五题设计思路及解析




主办方


看雪CTF(简称KCTF)是圈内知名度最高的技术竞技之一,从原CrackMe攻防大赛中发展而来,采取线上PK的方式,规则设置严格周全,题目涵盖Windows、Android、iOS、Pwn、智能设备、Web等众多领域。


看雪CTF比赛历史悠久、影响广泛。自2007年以来,看雪已经举办十多个比赛,与包括金山、360、腾讯、阿里等在内的各大公司共同合作举办赛事。比赛吸引了国内一大批安全人士的广泛关注,历年来CTF中人才辈出,汇聚了来自国内众多安全人才,高手对决,精彩异常,成为安全圈的一次比赛盛宴,突出了看雪论坛复合型人才多的优势,成为企业挑选人才的重要途径,在社会安全事业发展中产生了巨大的影响力。


合作伙伴


图片


深信服科技股份有限公司成立于2000年,是一家专注于企业级安全、云计算及基础架构的产品和服务供应商,致力于让用户的IT更简单、更安全、更有价值。目前深信服在全球设有50余个分支机构,员工规模超过7000名。



图片

比赛火热进行中!立即挑战!



图片

公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com


声明:该文观点仅代表作者本人,转载请注明来自看雪