Writeup-NewStarCTF2023
逆向大部分题都很简单,AK了week1,没什么好记录的,week2和week3有几道题需要记录一下.
week3和week4没怎么打,看着慢慢补充吧…
Reverse
EzDll
先看exe文件,可以看到使用encrypt()
函数对flag进行加密,并且从[4*i]
猜测是TEA系加密:
DLL动态链接库同样可以使用IDA进行分析,在题目提供的dll文件中我们可以找到encrypt()
加密函数:
可以看到这是一个魔改的XTEA加密,所以传递的第二个参数就是密钥,我们将其提取出来,然后尝试进行解密:
1 |
|
发现乱码,说明哪里有问题.
再看main函数和函数列表,发现有反调试的部分,例如这个异或判断,就要求必须是不在调试的时候运行,否则IsDebuggerPresent()
会返回非0值:
并且在函数列表发现了Tls相关的函数(别问我是怎么知道这东西的),并且我们知道其常常被用于反调试…
最终我们在一系列"callback"函数中找到了这个该死的对key进行修改的部分:
这里的数组就是key数组.
把这里的修改加上就出flag了:
1 |
|
结束…
eazy_enc
使用了一个函数指针数组来进行多次加密:
分别分析4个加密函数,最终决定对flag的每一个字符进行爆破,保持加密函数逻辑不变,对爆破的字符进行加密,最后检查是否匹配.
实际上后来发现上面的4个加密函数执行后,密文和明文并不是一一对应的(单射?),原因可能在于第四个加密中的*=52
这个操作会有溢出,导致回绕:
实际可能不止这一处,懒得分析了(数学不太行),总之就是要把每一个可行的字符都输出来,尝试肉眼进行匹配(flag长度并不长,并且接近是一段英语).
解密脚本:
1 |
|
flag简单地猜测即可得出.
Random_1
多余的话不说,main函数都能分析明白,关键就是找到这个伪随机的种子.
我们确定了程序的平台,编译环境,那么理论上我们只需要找到固定的随机数种子就能生成相同的伪随机数序列,进而实现解密,但是这个seed不好找…
由于题解在很久之后才写,所以这里主要记录一下之前做的时候的一些过程思路,实际思考过程并不是像这篇题解这样的.
实际上我们从导入表进行交叉引用,慢慢找就能找到关键函数.
尝试了动调获取seed失败,我们能够知道这个程序是有反调试手段的,那么从这个角度出发,我们如果能找到反调试的部分在哪里,也许就能顺藤摸瓜找到seed这个种子究竟在哪里设置的.
经过分析某个该死的函数的IDA图形化交叉引用视图,这里忘了是哪个了,当时应该就是从那个_srand()
函数出发的…
我们可以发现这个程序的反调试的手段在这个_Z1av
指向的函数中:
我没记错的话这个a()函数就是_Z1av
指向的函数(忘记了)
实际上就是从这里的这个函数进行依次调用的:
依次调用了这个函数指针数组中保存的一系列函数,我们跟进去看就是前图那两个_Z1av
和_Z1bv
,虽然不知道为什么起这么个名字.
实际上这里看到我们要找的关键函数在__init_array_start
中,这里就涉及到init_array段
了,其中的函数调用早于main()函数,所以我们一下子找不到这个函数,但是他们确确实实地运行了,同样的还有fini_array段
,其中的部分是在程序结束时执行的.
那么再往后看,第二个_Z1bv
指向的函数同样跟进去一看,就发现这个函数里有种子了(记得这个就是对应着_Z1bv
):
那么种子有了,其他部分的加密很简单,直接写脚本就好,一定要在同样的环境下跑—Ubuntu22下运行
解密脚本:
1 |
|
记得就是上面这个,应该没什么问题…
运行结果:
STL_1
不知道STL是什么先去学c++吧…
这个题就是要能够读懂程序,STL经过编译后,IDA分析出来的函数名很长,实际上关键的就是那一点:
熟悉c++的话这题代码分析起来没难度…
难点在于对加密过程进行逆向.
程序中先对字符串进行reverse,然后执行了若干位运算,重点是位运算.
最后的检查flag是否正确还有一部分位运算变换,并且是将4个字符(4字节)作为一个int进行解释,然后进行位操作的.
将一个int的32个位展开,逐步分析各个位操作,最终能整理出如何一点点的进行逆向,最终我们需要多步操作逐渐将这32个位分别进行还原,由于后来写的WP(其实是懒),逻辑直接放代码里了…
解密脚本:
1 |
|
运行结果:
ez_chal
久远了,就存着个解密代码了.是个魔改XTEA:
1 |
|
Let’s GO
GO逆向,有一个反调试:
这里的异或操作是在生成真正的iv
,用于后续的AES加密
.
调试可得是将位于0x3F56C0
的字符串NewStar!NewStar!
进行依次异或.(实际上这个字符串是AES的key)
接下来真正的main中,qword_436096
存储的就是密文,不过要根据这个十六进制字符串生成字节流才行.
不过这几行纯靠猜…
动调到ASE加密的函数这里,检查参数:
可以知道字符串NewStar!NewStar!
就是使用到的key.
再后面这里看到是CBC模式,并且前面发现的那个反调试控制的异或操作对应的数组就是iv:
(这么看来前面那个crypto_aes_NewCipher()
是初始化加密环境的函数)
现在为止已经分析清楚了,可以编写脚本了:
1 | from Crypto.Cipher import AES |
运行结果: