实践九 软件安全攻防--缓冲区溢出和shellcode
20212806 2021-2022-2 《网络攻防实践》实践九报告
1.实践内容
1.1shellcode原理
Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得尤为重要。
1.2缓冲区溢出的危害
所谓缓冲区可以更抽象地理解为一段可读写的内存区域,缓冲区攻击的最终目的就是希望系统能执行这块可读写内存中已经被蓄意设定好的恶意代码。按照冯·诺依曼存储程序原理,程序代码是作为二进制数据存储在内存的,同样程序的数据也在内存中,因此直接从内存的二进制形式上是无法区分哪些是数据哪些是代码的,这也为缓冲区溢出攻击提供了可能。
危害有以下两点:
- 程序崩溃,导致拒绝服务
- 跳转并且执行一段恶意代码
2.实践过程
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
2.1.直接修改程序机器指令,改变程序执行流程
①知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具
②学习目标:理解可执行文件与机器指令
③进阶:掌握ELF文件格式,掌握动态技术
- 下载目标文件pwn1到Desktop目录,执行
unzip
命令进行解压,然后使用objdump -d 20212806pwn1|more
命令进行反汇编,并利用管道进行分页显示。
- 现需要修改main函数中call指令的地址,使其跳转到getShell函数,具体操作如下,将'D7'改成'C3'即可
- 修改后将两次运行结果做对比,发现第pwn1程序调用的是foo函数,而20212806pwn1程序调用的则是getShell函数,则修改成功
2.2.通过构造输入参数,造成BOF攻击,改变程序执行流
①知识要求:堆栈结构,返回地址
②学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
③进阶:掌握ELF文件格式,掌握动态技术
- 构造字符串,进行缓冲区溢出攻击。确认输入字符串哪几个字符会覆盖到返回地址
- 通过查看EIP的值发现5678这四个数最终会覆盖到堆栈上的返回地址,所以只需把这四个字符替换为getShell的内存地址即可:
- 构造输入字符串
通过之前的反汇编可知替换为\x7d\x84\x04\x08
即可修改返回地址,调用getShell函数。由于我们没法通过键盘输入\x7d\x84\x04\x08
这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a
表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。
用16进制查看指令xxd查看input文件的内容是否如预期。
然后将input的输入,通过管道符'|',作为20212806pwn1的输入。
2.3.注入Shellcode并执行
- 设置堆栈为可执行状态
- 关闭地址随机化,并查看地址随机化的状态
- 构造要注入的字符串地址,并开始注入攻击
- 再开另外一个终端,使用
ps -ef | grep 20212806pwn3
找到对应的进程号为2132:
- 根据20212806pwn3的进程号使用gdb对其进行调试,通过设置断点,来查看注入字符串的内存地址。根据ESP的值查看当前栈顶的值为
0x01020304
,所以确定新内存地址的值应该为0xffffd4dc+0x00000004=0xffffd4e0
- 构造shellcode,将修改后的字符串地址作为20212806pwn3的输入,执行成功。得到shell,如下图所示:
3.学习中遇到的问题及解决
- 问题1:在安装gdb调试器时,出现以下错误:
- 问题1解决方案:因为sources.list文件是只读的,所以需要先用
sudo chmod a+w /etc/apt/sources.list
命令修改一下权限,再使用sudo apt-get update、sudo apt-get install gdb
,命令更新一下源即可,执行完后可查看gdb版本:
安装成功 - 问题2:在执行
sudo apt-get install prelink
命令时,出现package无法定位的情况 - 问题2解决方案:执行以下步骤,更换源:
①打开sources.list文件
sudo vim /etc/apt/sources.list
②在文件中添加以下内容
deb 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
deb http://old.kali.org/kali moto main non-free contrib
③保存退出,再进行更新
sudo apt-get update
4.实践总结
本周学习了有关缓冲区溢出的相关知识和shellcode原理,学会了怎样去观察堆栈的变化,怎样去计算相关的地址。并学会了一些汇编语法,如掌握了NOP, JNE, JE, JMP, CMP汇编指令的机器码;还能正确修改机器指令改变程序执行流程。同时能正确构造payload进行bof攻击。总之还需要多实践,这样才能掌握好网络攻防的相关技能。