20242308 2026-2027-1 《网络与系统攻防技术》实验一实验报告
1.基础知识
1.汇编指令机器码:NOP(0x90)为空操作指令;JNE不为0跳转,JE等于0跳转;JMP无条件跳转;CMP用于比较两个操作数,影响标志寄存器。
2.反汇编:可将二进制可执行文件翻译为汇编代码,使用objdump、GDB工具完成,用来分析程序内部函数与指令。
3.栈缓冲区溢出原理:函数调用栈中,缓冲区在低地址,保存的返回地址在高地址。不安全函数gets不限制输入长度,超长输入可覆盖返回地址。函数ret执行时读取返回地址送入EIP,以此劫持程序执行流。
4.ELF可执行文件:Linux下可执行程序格式,可使用十六进制编辑器直接修改程序内机器码,改变程序执行逻辑。
5.Shellcode:可直接运行的机器指令,不包含空字节;NOP雪橇由大量0x90组成,只要命中任意一条NOP,CPU就会顺序执行到后续shellcode。
6.ASLR地址空间布局随机化:系统安全机制,随机改变栈、库加载地址;关闭后栈地址固定,便于shellcode注入调试。x86采用小端存储,多字节地址存放时低字节放在低地址。
2.实验内容
本次实践的对象是一个名为pwn1的linux可执行文件。
实践的目标是想办法运行这个代码片段,学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
3.注入一个自己制作的shellcode并运行这段shellcode。
3.实验过程
进入实验工作目录,准备目标程序。 切换到学号命名文件夹20242308,使用ls查看目录,确认目标文件pwn1存在。

任务一:手工修改ELF二进制文件,直接跳转到getShell。 复制pwn1得到pwn3,赋予可执行权限chmod a+x ./pwn3,使用十六进制编辑器修改pwn3内的机器指令,修改跳转逻辑,让程序执行流直接跳转到getShell函数。修改完成运行./pwn3,成功获取shell,执行ls验证shell可用,exit退出。

chmod赋予pwn3执行权限,运行pwn3成功弹出shell,执行ls查看目录文件。
任务二:GDB调试pwn1,验证缓冲区溢出,定位偏移。 执行gdb pwn1加载程序,输入r运行程序,输入超长字符串1111111122222222333333334444444455555555,程序回显输入内容。

GDB加载pwn1,执行r启动程序,输入超长字符串,程序回显输入。
继续在GDB中再次运行程序,输入另一组超长字符,程序触发SIGSEGV段错误,执行info r查看寄存器,观察EIP寄存器的值被输入字符覆盖,证明我们可控EIP寄存器,程序执行流可被劫持。

程序段错误,info r查看寄存器,EIP被覆盖为0x35353535,验证控制EIP成功。
再次调试,继续测试溢出,输入新的payload,程序再次触发段错误,EIP被覆盖为0x343333231,确认缓冲区到返回地址的偏移长度。

程序发生段错误,查看寄存器EIP被填充字符覆盖,确定溢出偏移。
使用perl命令构造二进制payload,填充对应偏移长度的字符,后面拼接getShell函数地址(按x86小端序),输出写入input文件;xxd查看input文件,校验payload十六进制内容。将payload输入pwn1程序,触发缓冲区溢出,覆盖foo函数返回地址,尝试劫持EIP跳转到getShell。

perl生成payload写入input,xxd查看payload的十六进制,管道输入payload到pwn1,程序段错误。
任务三:Shellcode注入实验。 尝试关闭ASLR地址随机化,执行sudo命令,出现sudo无法解析主机名报错。继续用perl生成payload,payload由NOP雪橇\x90 + 32位linux execve("/bin/sh") shellcode组成,写入input_shellcode文件。将payload输入pwn1,栈上布置shellcode,虽然ASLR未成功关闭,payload在程序内被输出,shellcode原始机器码在内存中展示。

sudo关闭ASLR报错,perl生成shellcode payload,输入pwn1,栈上输出shellcode机器码。
使用GDB反汇编foo函数,disassemble foo查看foo汇编代码,确认漏洞点gets@plt;在foo的ret返回地址0x080484ae设置断点,执行c继续运行,调试栈帧,观察ret指令前栈内存,验证payload在栈中的排布。

GDB反汇编foo,定位gets漏洞,在ret地址打断点,调试观察栈布局。
继续调试,切换root账户关闭ASLR,再次执行payload注入。关闭ASLR成功后,栈地址固定,重新构造payload,NOP雪橇+shellcode+目标跳转地址,输入程序。foo函数执行ret时,EIP跳转到栈上NOP区域,顺着NOP雪橇执行后面的shellcode,成功弹出/bin/sh交互shell,完成shellcode注入攻击。
4.问题及解决方案
- 问题1:修改二进制文件后程序无法运行,报权限错误或者无法识别ELF。
- 问题1解决方案:修改文件后确认文件权限,使用chmod +x赋予可执行权限;修改机器码时不能改动文件头部关键ELF元数据,仅修改代码段内指令。
- 问题2:缓冲区溢出后程序直接段错误,无法跳转到getShell。
- 问题2解决方案:重新精确计算缓冲区到返回地址的偏移;确认地址按x86小端序编排,核对函数地址,去除payload内空字节。
5.学习感悟、思考等
本次实验完整学习了栈溢出的两种攻击方式,手工修改二进制和栈溢出劫持控制流,让我直观理解程序底层机器码、栈帧工作机制。我认识到gets这类无长度限制函数存在巨大安全隐患,现代操作系统ASLR、NX等防护机制可以有效抵御传统shellcode注入攻击。攻防是博弈过程,攻击者利用程序漏洞篡改执行流,防御方通过编译选项、系统保护机制降低攻击面。实验过程中多次出现段错误,需要耐心调试偏移、地址字节序,培养了底层调试排错的思维。安全开发必须从源头规避不安全函数,在编码阶段限制输入长度,减少缓冲区溢出类漏洞。

浙公网安备 33010602011771号