这是一个 64 位 ELF 文件,在 Linux 中打开了一下没什么提示,随便输入几个字符提示 wrong,还是用 ida 打开它吧,打开之后直接看到主函数
其中有一个 for 循环进行了很多轮异或运算,而这个 sub_402219 函数正是参与运算的值,而且在后面它又作为函数单独出现,但是它又打不开,在汇编代码中可以找到这个函数的地址,发现这里有一大堆数据,所以我们需要把这一段数据给还原
我们选中 402219 的地址段,按 D 将其转化为数据,然后再通过 idc 脚本将其还原,脚本如下
然后选择数据之后按 C 分析数据,点击 force 强制执行,再将其转化为函数就可以了,这样之后我们的 sub_402219 函数就正常了,就可以正常打开了
在打开之前我们先用 findcrypt 看一下有哪些加密
有 md5 和 AES 两种加密,我们再看看 sub_402219 函数
# sub_402219 函数
1 | __int64 __fastcall sub_402219(__int64 a1) |
可以看到三个关键函数,第一个函数应用了刚刚在主函数中可以看到的 & unk_603170 这一组数据,但我们不知道,可以在后面的调试中获取
在进行三轮加密之后,与 byte_6030A0 数组进行对比,byte_6030A0 数组的数据如下
1 | 0xBC, 0x0A, 0xAD, 0xC0, 0x14, 0x7C, 0x5E, 0xCC, 0xE0, 0xB1, |
而这段加密是 AES 加密(小声 bb:我还没有学),不过通过刚才的 findcrypt 可以分析出来这里是 AES 加密,第一个函数就是生成轮密钥,而且那个未知数组是初始密钥,第二个和第三个函数分别是对输入字符串的前后 16 位进行 AES 加密
# sub_40207B 函数
1 | unsigned __int64 __fastcall sub_40207B(__int64 a1) |
在这个函数中,sub_401CF9 函数将 base64 表传入,并进行了加密
可以识别出这是 MD5 加密,在加密之后,被储存在 v2 中,之后又在 14 行进行了一次 MD5 加密后储存在 a1,也就是我们要找到的 & unk_603170 数组中
# 总体思路
在第一个函数中将 base64 表进行了两次 MD5 加密,然后以其作为第二个函数中的 AES 加密的初始密钥,在进行 AES 加密,加密后的结果已经储存在 byte_6030A0 数组中且是可见的,而密钥是可以通过调试获取的,但因为这道题它是一个 ELF 文件,在 windows 是无法调试的,所以只能通过 Linux 进行远程调试,获取数据之后,用脚本进行 AES 解密就可以得到 flag
# 远程调试
我用的 Linux 系统是 kali,第一次调试,先要把 linux_server 文件放到 kali 里面,然后再直接把文件放到 kali 的桌面上,然后复制一下它的文件位置,然后我们在桌面打开 kali 的终端,并且打开 Linux_server64 文件,之后回到 windows 的 ida 中,选择 debugger 为 remote Linux debugger,之后输入文件在 kali 中位置和虚拟机的 ip 即可开始调试了
这里有一个点要注意,就是我们如果在函数的开始部分就下断点,然后通过输入一个 32 长度的字符串的话,是无法绕过 if 的判断的,还是会退出程序,所以我们就在又在 if 判断的前后分别下一个断点,在运行到 if 之前的断点的时候再 ctrl+F7 跳过到下一个断点,通过这个方式来绕过,绕过之后再单步调试到 & unk_603170 所在函数,然后再进入汇编代码段获取数据就可以获取到它的数据了
# 脚本
在知道了密钥之后和最终密文之后,就是通过脚本进行 AES 解密获取明文 flag 了,我还不会 AES 所以就参照了大佬的脚本,不过不知道为什么我运行不了这个脚本,不过有的别的脚本可以运行,这里我就把两个脚本都放在这吧
1 | from Crypto.Cipher import AES |
1 | from Crypto.Cipher import AES |
注意一下第二个脚本得到的数据还要十六进制转 ASCII 一下
最后得到 flag {924a9ab2163d390410d0a1f670}
题目来源:BUUCTF 在线评测 (buuoj.cn)——re3