XCTF-攻防世界CTF平台-Reverse逆向类——54echo-server
Posted 大灬白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XCTF-攻防世界CTF平台-Reverse逆向类——54echo-server相关的知识,希望对你有一定的参考价值。
下载附件,查看信息:
是Linux下的32位ELF文件,运行程序:
发现是一个输入字符串,将字符串中的每个字符转换成对应的ASCII码输出的程序
用IDA打开,先查看字符串窗口:
有一些用到的字符串:
“Echo Server 0.3 ALPHA”这个在我们上面运行程序的时候见过了:
就是在main函数中,提示我们输入字符串之前
但是“F1@g_”和“You are very close! Now patch me~”却提示在程序中没有使用到:
"%02X"和"NULL"字符串就是在我们点击上面的&loc_80487C1+ 3函数跳转到的sub_804875D函数中,但是感觉这里的跳转是有点奇怪的:
sub_804875D函数的作用跟我们前面运行程序看到一样,就是将字符串中的每个字符转换成对应的ASCII码输出
第一个花指令混淆080487C1:
但是这样我们并不能直到如何获得flag,所以这个跳转肯定不会这么简单,查看&loc_80487C1+ 3函数的汇编代码:
显示的是一堆的乱码,报“endp ; sp-analysis failed”的错:SP是堆栈指针,IDA是通过retn指令来识别函数的结束的,一般是程序代码有一些干扰代码,让IDA的反汇编分析出现错误,结果它分析后发现调用栈不平衡,因此就提示sp analysis failed;也可能是因为编译器优化,结果IDA无法正确识别一个函数体的结尾部分。
将&loc_80487C1+ 3函数的汇编代码都右键转换成未定义的数据:
我们可以看到main函数中直接调用的是&loc_80487C1+ 3函数,所以loc_80487C1-loc_80487C3的汇编代码是不会影响到实际程序运行的时候的跳转,但是它是被识别成数据还是代码却可以影响到IDA之类的反汇编工具的识别。
右键.text:080487C4转换成代码,将.text:080487C4后未定义的数据重新识别成代码:
我们可以看到现在的才是真正的汇编代码loc_80487C4,
这时候,main函数中的汇编代码已经重新识别为直接跳转到loc_80487C4了:
刚开始反汇编窗口中的main函数还是&loc_80487C1+ 3:
后来我关了IDA重新打开,它就已经变成了loc_80487C4了:
至于上面loc_80487C1-loc_80487C3的汇编代码,因为IDA把它识别为sub_804875D函数的结尾处,它其实是涉及到sub_804875D函数的sp堆栈平衡:
其实这里的.text:080487C1 E8就是插入的花指令,用来混淆IDA反编译识别代码,在.text:080487C2右键转换为代码:
.text:080487C2的C9被识别成了代码leave;.text:080487C3的C3被识别成了代码retn;
我们再把E8改为90(会被识别为nop,不执行任何操作继续执行下一行代码),选中.text:080487C1 E8,选中IDA左上角的编辑->修补程序§,选中单字节修改方式或者双字节修改方式或者修改汇编都行:
修改之后:
再把修补程序应用到输入文件,才能够把修改保存到原文件:
第二个花指令混淆080487F3:
接着我们继续分析loc_80487C4下面的代码:
我们开始只是将.text:080487C4下面的部分未定义的数据成功转换成了汇编代码,但是下面的loc_80487F3后的未定义数据依旧无法自动识别为汇编代码。
我们可以看到代码运行到了.text:080487F3 EB FF的时候,它会跳转到loc_80487F3+1,也就是.text:080487F3 EB是没有意义的,所以这里的EB和上面的一样:都是用来干扰IDA反汇编的花指令,实际上0xEB常常被用来当作花指令。
右键.text:080487F3 EB FF,将他们转换成未定义的数据从而将他们分开:
之后我们照样把0xEB改成0x90:
右键.text:080487F4这行,从这开始转化为代码:
下面的数据也被识别成了正确的汇编代码,且出现了开始我们看到的字符串“You are very close! Now patch me~”,
但是字符串’F1@g_'依旧没有出现:
第三个花指令混淆08048816:
出现标红的汇编代码:
.text:08048816 E9 46 31 40 67 jmp near ptr 6F44B961h;
.text:08048859 E8 C7 04 24 01 call near ptr 9288D25h;
其实是IDA自动识别异常的代码,将它转换成未定义的数据:
发现.text:08048816处的数据刚好就是字符串’F1@gA’,原来它之前被IDA识别为了代码:
这里还要注意一个问题,上面的跳转:
.text:08048812 33 C0 xor eax, eax; Logical Exclusive OR
.text:08048814 74 07 jz short loc_804881C+1; Jump if Zero (ZF=1)
xor eax, eax将ZF置1之后jz跳转必然成立,程序每次都会跳转到loc_804881C+1,但是下面的代码IDA自动识别为从loc_804881C开始的,这里也是有问题的:
.text:0804881C 00
其实是表示字符串’F1@gA’的结尾‘\\0’,这里IDA把它识别成了从loc_804881C开始的代码,我们点击.text:0804881C转换成未定义,然后把花指令0xE9改成0x90、字符串’F1@gA’和结尾‘\\0’合成一个字符串:
然后点击.text:0804881D转换为代码:
这样IDA就会从.text:0804881D开始识别代码,下面的代码都变成了正确的可读性更好的汇编代码,下面的_strncmp函数比较[esp+4]上的"F1@gA"和[esp]上的我们输入的字符串(上面read函数读取存放在栈中),相等的话就会输出"You are very close! Now patch me~"。
运行程序,输入"F1@gA":
的确输出了"You are very close! Now patch me~",但是程序还在运行,而且这句话提示我们离flag很近了,现在还需要修补程序。也就是程序运行后面还有代码会输出flag。
第四个花指令混淆08048859:
那我们接着看输出"You are very close! Now patch me~"之后的程序:
接着就由一个判断跳转:
.text:08048848 A1 88 A0 04 08 mov eax, ds:dword_804A088
.text:0804884D 85 C0 test eax, eax; Logical Compare
.text:0804884F 74 15 jz short loc_8048866; Jump if Zero (ZF=1)
根据数据段的全局常量dword_804A088的值,当它为1时test eax, eax将ZF置0,jz short loc_8048866不成立;当它为0时test eax, eax将ZF置1,jz short loc_8048866成立。
而我们查看dword_804A088交叉引用,发现它除了这里只被使用了一次:
就是在main函数中将它的值设为1:
所以此时test eax, eax将ZF置0,jz short loc_8048866跳转永远都不会不成立,我们开始运行程序的时候看到这个时候程序就跳转到一直运行的位置。
我们接着看loc_8048851后面的代码:
.text:08048851 loc_8048851:
.text:08048851 ; CODE XREF: .text:08048857↓j
.text:08048851 66 B8 EB 05 mov ax, 5EBh
.text:08048855 31 C0 xor eax, eax; Logical Exclusive OR
.text:08048857 74 F9 jz short near ptr loc_8048851+1;
这三行代码构成了一个死循环:
mov ax, 5EBh后ax=5EBh,之后xor eax, eax结果eax=0置ZF=1,最后jz short near ptr loc_8048851+1跳转到loc_8048852,一直重复这个过程。
就是开始我们在运行程序输入正确的字符串后"F1@gA"看到的程序一直在运行。
这里也有一句标红IDA识别异常的代码:
.text:08048859 E8 C7 04 24 01 call near ptr 9288D25h;
我们觉得:
.text:08048859 E8
可能也是插入的花指令,影响了IDA的识别,把0xE8改为0x90:
可以看到这部分的代码也恢复了正常
修改程序跳转逻辑
接下来我们需要修改程序跳转逻辑:
.text:08048848 A1 88 A0 04 08 mov eax, ds:dword_804A088
.text:0804884D 85 C0 test eax, eax; Logical Compare
.text:0804884F 74 15 jz short loc_8048866; Jump if Zero (ZF=1)
有两种方法:
(1)把dword_804A088的值修改成0;
(2)把JZ条件跳转改为JMP直接跳转。
方法1:
我们先尝试方法1:
之后运行程序,输入‘F1@gA’:
得到flag:F8C60EB40BF66919A77C4BD88D45DEF4
方法2:
接着试一下方法2,直接修改汇编把jz修改为jmp或者把75改为EB:
之后运行程序,输入‘F1@gA’:
得到flag:F8C60EB40BF66919A77C4BD88D45DEF4
题外话:
其实我们直接修改了花指令080487C1、080487F3、08048816、08048859之后,就可以被IDA识别成伪函数sub_80487C4:
这时候我们就能比较清晰的看到程序的逻辑:比较输入的字符串s的5个字节和常量‘F1@gA’,相等就输出"You are very close! Now patch me~",然后计算一个md5值调用sub_804875D输出;否则调用sub_804875D把输入的字符串s按ASCII码值输出。
以上是关于XCTF-攻防世界CTF平台-Reverse逆向类——54echo-server的主要内容,如果未能解决你的问题,请参考以下文章
XCTF-攻防世界CTF平台-Reverse逆向类——53easyCpp
XCTF-攻防世界CTF平台-Reverse逆向类——65reverse-box
XCTF-攻防世界CTF平台-Reverse逆向类——59mfc逆向-200
XCTF-攻防世界CTF平台-Reverse逆向类——52handcrafted-pyc