一、实验目的
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段
二、实验内容与实验要求
三个实践内容如下:
1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
3.注入一个自己制作的shellcode并运行这段shellcode。
要求:
1.掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
2.掌握反汇编与十六进制编程器
3.能正确修改机器指令改变程序执行流程
4.能正确构造payload进行bof攻击
三、实验环境
VMware Workstation Pro+kali
四、实验过程与分析
1.直接修改程序机器指令,改变程序执行流程
下载目标文件pwn1,反汇编,并将给出的pwn文件复制到虚拟机桌面,复制两份,分别为pwn20232407、pwn20232407_1。
其中main中的第四行“call 8048491”表示这条指令将调用位于地址8048491处的foo函数,其对应机器指令为“e8 d7ffffff”,e8即跳转之意,按照正常流程此时EIP的值应该是下条指令的地址,即80484ba,但由于e8这条跳转指令,CPU就会转而执行“EIP+d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba+d7ffffff=80484ba-0x29,正好是8048491这个值,所以将会执行8048491位置的foo函数。
由此跳转,那我们想让它调用getShell,只要修改“d7ffffff”为getShell-80484ba对应的补码就行,由上图可知getshell地址804847d,计算47d-4ba为c3ffffff。
所以我们的实验思路是修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。
vi进入pwn20232407_1,在乱码界面按Esc键,然后输入:%!xxd将显示模式切换为16进制模式。
再反汇编看一下,call指令是否正确调用getShell
运行下改后的代码,会得到shell提示符#
2.通过构造输入参数,造成BOF攻击,改变程序执行流
确认输入字符串哪几个字符会覆盖到返回地址
如果输入字符串1111111122222222333333334444444412345678,那 1234 那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。那只要把这四个字符替换为 getShell 的内存地址,输给pwn1,pwn1就会运行getShell。
确认用什么值来覆盖返回地址
getShell的内存地址,通过反汇编时可以看到,即0804847d。
接下来要确认下字节序,简单说是输入11111111222222223333333344444444\x08\x04\x84\x7d,还是输入11111111222222223333333344444444\x7d\x84\x04\x08。
构造输入字符串
最后将input的输入,通过管道符“|”,作为pwn20232407的输入
3.注入Shellcode并执行
准备一段Shellcode
\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\
准备工作
构造要注入的payload
Linux下有两种基本构造攻击buf的方法:
retaddr+nop+shellcode
nop+shellcode+retaddr。
因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
我们这个buf够放这个shellcode了
结构为:nops+shellcode+retaddr。
nop一为是了填充,二是作为“着陆区/滑行区”。
我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
再开另外一个终端,用gdb来调试pwn20232407这个进程。
shellcode的地址为0xffffcf9c+4=0xffffcfa0,进行更改
重新开始
问题及解决方案
问题1:下载不了execstack
解决方法:许多用户报告在较新的 Debian 发行版中找不到 execstack(包曾在 prelink 源里)。Reddit+1
直接从 Ubuntu 存档下载旧的 .deb 安装(快速)
安装运行时依赖(如未安装)
sudo apt update
sudo apt install -y wget ca-certificates libelf1 libselinux1
下载旧版 execstack .deb(从 Ubuntu 存档)
wget -O /tmp/execstack.deb
"https://archive.ubuntu.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20130503-1.1_amd64.deb"
安装
sudo dpkg -i /tmp/execstack.deb
问题2:gdb输入c命令后卡住
解决方法:在运行pwn的原始终端窗口按回车键,这样程序才能继续执行,gdb才能进行后续分析,否则会一直处于等待状态。
学习感悟
本次逆向与 Bof 基础实验,让我对程序执行流程和漏洞利用有了直观认知。从手工修改机器指令改变函数调用,到构造输入触发 Bof 漏洞,再到注入 Shellcode,每一步都需结合汇编、堆栈结构等知识。调试时,确定返回地址、处理字节序、解决堆栈覆盖问题,让我明白理论与实践的差距 —— 看似简单的步骤,实际操作中需反复验证地址、调整 Payload 结构。实验也让我重视安全防御:关闭地址随机化、设置堆栈可执行等操作,反向揭示了真实环境中防御机制的重要性。未来需进一步研究 64 位系统防护与 ROP 等进阶技术,深化对二进制安全攻防的理解。