这题出现在DDCTF的level8,题目给了两张图片和一段文字,稍后我会提供附件。
挑战:《Crack me if you can》
赛题背景:图片信息隐藏与数字水印技术一直是安全研究领域的热门话题之一,本挑战结合了图片内嵌、算法逆向等知识点,考察了挑战者的综合技术素养。
赛题描述:本题是一张图片,请试分析图片中隐藏的内嵌文件,逆向 Crack me 算法并得到 DDCTF-65f9 输入所对应的密钥。
评分标准:密钥正确则可进入下一题。
图片1:
图片2(名字crackme.png,关键附件,请从下文中下载原图):
附件下载:http://pan.baidu.com/s/1jIMaBum 密码:5cah
从图片到程序
首先由名字crackme,我们知道了这是一道re题,但他给了一张图片。
我们用010editor打开他。
emmm,标准的jpg文件头,果然png的后缀名是假的,jpg的文件结尾标志是FFD9,ctrl+F查找
发现后面附加了一段数据,把这段数据先单独存下来。
0x789c是zlib的压缩数据的头部标志,用python写脚本解压一下。
1 | import zlib |
输出了一段base64,由于数据过长,就不贴了。我把他base64解码后写到文件。
1 | import zlib |
再用010editor打开,发现我们熟悉的zip文件头PK被改成了KP(滑稽)
改过来以后得到压缩包dump.zip
。
然而解压需要密码。
结合题目提供的第一张图,这是一个除零错误。
试一试就知道了。
1 | 2/0 |
1 | Traceback (most recent call last): |
所以压缩密码是integer division or modulo by zero
。
成功得到crackme.exe
!!
IDA加OD动静态分析
OD里下GetDlgItemTextA
断点,来到获取输入的地址0x00**1EE4
,IDA也相应的来到0x00**1EE4
。
接下来在IDA中疯狂整理代码逻辑和变量名。这段辛酸过程省略,不想整理的话我上面的附件里也提供了我当时做题时整理好的idb文件,直接载入也行。
首先程序里有一段240bytes长的char * head,作为常量,结合输入的password(即mail)进行大量的运算,所得的值1和输入的uasename通过某种运算的到的值2相等。
整理一下逻辑。
username题目告诉我们了,因为用了strcat,所以key可以推出,key到IV3由于是正向计算,直接在OD中动态跟一下结果IV3也就出来了。又因为IV2和IV3是相等的关系,所以IV2也可以直接得到。head到hash是正向算法,hash也可以直接动态跟出来。
1 |
|
所以现在的关键是需要对IV12IV3这个算法求逆,由IV2和head推出IV1。然后再对hash2IV1这个函数求逆,由IV1和hash推出pwd。然后pwd直接encode_hex就能得到mail_mid。
分析IV12IV2
又是一段艰苦的逆向,最后发现就是一个稍微变化过的aes解码函数。。。
当然逆向这东西,事后看看都觉得简单,只有自己逆过才懂得艰辛。
用python写出加密和解密函数:
1 | head = '4E5332303137434D2D44444354462D006469646963687578696E672E636F6D00E3E22A86D2D569CBFF912D88ABD70088795A7C0A1A320972735C6E5C1033035C7E73C8AAACA6A16153378CE9F8E08C61B0FD53F4AACF5A86D99334DAC9A037861090A478BC360519EF0189F017E105912C5455E7869B0F615F083BBB96A80C3DDD94FDCB61A2F8D28EA37122994274B3434E26BBC5D529DA9ADD12610C751E5C0DB91FCF6C1BE71DE2B8963F7BFAE28CAF1526946AC00F4EF01D1D2FFC680373A928A37DC5334460278BD25F5C7130D34D8C69C6274C6688D7517BA72B3978D4CBAF95E70E9CD187291703D87566330B'.decode('hex') |
得到iv1:e3c8f0eb7ad23ff182c8d87383f44918
分析hash2IV1函数
又是一阵疯狂的逆向加整理。
如果你直接在ida里按f5的话,你会得到这样的代码:
1 | int __cdecl hash2IV1(char *hash, char *pwd, char *IV1) |
这种代码你想写逆算法根本是不可能的,我们要先对这段代码进行整理和改编。
由于用了一些不同数据长度的类型的转换,所以这里我用c语言来写。
1 | include <stdio.h> |
从这改编过的代码中,我们可以明显看出轮加密的痕迹,也就是Feistel网络结构。
那逆算法就好写了。
1 | include <stdio.h> |
从而得到pwd:93c65c807c3800b15f3600d449c64692
收尾
由格式知,我们的password(也就是mail)为DDCTF-93c65c807c3800b15f3600d449c64692@didichuxing.com
总结这道题,不说前面的非re部分,难点主要在于求这两个的逆函数上。对此应当对常见的加密算法模式有比较透彻的理解。
而且从头到尾彻彻底底的写了一遍AES加密算法和AES的解密算法还真TM赤鸡呢!