[GWCTF 2019]re3
步骤
- 64位程序,无壳儿,直接用ida打开,首先是检索程序里的字符串
- 根据correct跳转去找到有关flag的函数,下面能看到ABC……*/,猜测程序里存在base64加密
- 这边没法f5,估计是jz的锅影响了ida的正常运行,先看一下上面的main函数
main()
输入的字符串长度为32位,利用mprotect函数将dword_400000处的0xF000长度地址修改成了可读可写可执行,sub_402219()里的数据进行了异或处理。 - 可以看到sub_402219()函数既作为数据参与异或,又作为函数来引用,而且这个函数打不开
我们猜测异或完后,这个函数才是真正的函数。所以先将sub_402219()里的数据还原看看,
直接在伪代码部分点sub_402219跳转不到它的数据段,得在汇编代码里找
找到后按D转换成data型
之后使用idc脚本还原数据,第一次接触idc脚本,简单记录一下
首先shif+f2调出脚本编辑器,然后就可以编辑idc脚本了,语法跟c有点相似,具体的语法看这篇文章和这篇文章
简单解释一下写法,首先定义一个局部变量addr,就是我们要修复数据的起始位置,i用来遍历,之后的for循环照抄main函数里的,最后就是PatchByte(addr+i,Byte(addr+i)^0x99)
这句。
首先看一下PatchByte的语法,这句话就是从addr开始,利用i遍历地址,将对应地址的值设置为byte_402219[addr+i]=byte_402219[addr+i]^0x99
点击run还原数据
还原后选择数据按c,选择force强制执行,将数据转换成代码
之后在代码开始的地方0x402219按p创建函数
现在回头再去看看我们的main函数
sub_402219()该函数能打开了,19行的的jumpout百度了一下,看雪上给的解释是
函数边界识别错误, 或者是
由于编译器某些原因会把某些代码分出来,不存放在连续区域,而是在其他位置,这些块有时ida能识别出来,被称为chunk,有些不能识别,此时就得自己手动设置。
如果是边界识别错误,那就alt+p,找到正确的末尾;
如果是后者,那就通过append_func_tail来将目标区域添加到本函数中,另外,得先undefine目标区域。
我去百度了这题的wp,发现不影响,我也就没有继续折腾它了。
-
继续看main(),之后调用了 sub_40207B()
sub_40207B(),它的参数unk_603170()直接在ida里看不到,后面动调看看
sub_40207B()里调用了sub_401CF9函数,它太长了,就不贴了,根据函数特征码,可以发现这是md5加密
n1book的p273有算法的特征码
这个函数主要将base64表进行了两次md5加密 -
之后是sub_402219()
sub_400A71()
首先它整体循环了4次,处理数据的时候用到了byte_4023A0
根据上方我贴的n1book里的图,可以发现这个是AES加密的s盒,所以这个函数的作用就是将unk_603170(base64表进行了两次md5加密后的结果)
传入作为了密钥
sub_40196E()里面有同样的特征码,应该是AES加密的步骤,所以它的作用是利用unk_603170(上一层传入的base64表进行了两次md5加密后的结果)
作为密钥对我们输入的数据进行了AES加密
经过9~11行的处理后得到了byte_6030a0里的数据,将byte_6030a0里的数据提取一下
byte_6030a0=BC0AADC0147C5ECCE0B140BC9C51D52B46B2B9434DE5324BAD7FB4B39CDB4B5B -
到这里理清楚了程序的逻辑
先是base64表进行了两次md5加密的结果传入了unk_603170
unk_603170,利用它对我们输入的数据进行了AES加密后得到了byte_6030a0
unk_603170可以通过动调或者在线md5加密平台得到或者自己写md5加密脚本跑一下 -
动调找unk_603170的值(主要是我利用工具网站两次md5加密后得不到正确的key,自己写的python被卡在编码的转换之间)
由于是elf文件,所以要用虚拟机动调,关于如何使用IDA动调ELF文件(使用虚拟机),详细的看这篇文章
前提是物理机和虚拟机能够互相ping通,ping不通的重置虚拟机网卡。
调了好久,终于给我弄出来了,unk_603170=CB8D493521B47A4CC1AE7E62229266CE
这边记录一下调试这题的坑
首先你看程序只要输入的字符串长度为32就能绕过这个exit(0),但是实际操作的时候发现不行,我的绕过做法是现在执行if判断前下个断点,然后在执行给unk_603170赋值前在下一个断点
设置好后先f9运行到第一个断点,之后ctrl+f7运行到第二个断点,之后单步f8到unk_603170完成赋值,去查看unk_603170即可。 -
最后用unk_603170给byte_6030a0解密即可,在线工具解密失败,贴一下其他师傅python2的exp,自己用python3被编码的转换卡死了
from Crypto.Cipher import AES
import codecs
aes = AES.new(decode_hex('CB8D493521B47A4CC1AE7E62229266CE')[0], AES.MODE_ECB)
print(aes.decrypt(decode_hex('BC0AADC0147C5ECCE0B140BC9C51D52B46B2B9434DE5324BAD7FB4B39CDB4B5B')[0]))
flag{924a9ab2163d390410d0a1f670}