1. 漏洞简介
1.1 序列化、反序列化
序列化是将复杂的数据结构(如对象及其字段)转换为“更扁平”格式的过程,该格式可以作为连续的字节流发送和接收。序列化数据使以下操作变得更加简单:
- 将复杂数据写入进程间内存、文件或数据库
- 发送复杂数据,例如,通过网络、应用程序的不同组件之间或在 API 调用中发送
至关重要的是,在序列化对象时,其状态也会持久化。换句话说,将保留对象的属性及其分配的值。
反序列化
是将此字节流还原到原始对象的全功能副本的过程,其状态与序列化时的状态完全相同。然后,网站的逻辑可以与此反序列化对象进行交互,就像与任何其他对象一样。
1.2 反序列化漏洞产生原因
通常会出现不安全的反序列化,因为通常不了解反序列化用户可控制数据的危险性。理想情况下,用户输入根本不应反序列化。
许多网站认为安全是因为:
- 对反序列化的数据实施了某种形式的额外检查,这种方法通常无效。
原因:几乎不可能实施验证或清理来解释每种可能性,应该在反序列化后检查数据,但此时很可能已经无法防止攻击。
- 反序列化的对象通常被认为是可信的。特别是在使用具有二进制序列化格式的语言时,开发人员可能会认为用户无法有效地读取或操作数据,这种方法无效。
原因:尽管可能需要更多工作,但攻击者利用二进制序列化对象与利用基于字符串的格式一样。
由于现代网站中存在的依赖项数量众多,基于反序列化的攻击也是可能的。
- 典型的站点可能实现许多不同的库,每个库都有自己的依赖项。这创建了一个难以安全管理的大量类和方法池。
- 攻击者可以创建这些类中的任何一个的实例,因此很难预测可以对恶意数据调用哪些方法。
- 攻击者能够将一长串意外的方法调用链接在一起,将数据传递到与初始源完全无关的接收器中,则尤其如此。
因此,几乎不可能预测恶意数据的流动并堵塞每个潜在的漏洞。简而言之,可以说不可能安全地反序列化不受信任的输入。
1.3 漏洞危害
- 为大量增加的攻击面提供了一个入口点。
- 允许攻击者以有害的方式重用现有应用程序代码,从而导致许多其他漏洞,通常是远程执行代码。
- 即使在无法远程执行代码的情况下,不安全的反序列化也可能导致权限提升、任意文件访问和拒绝服务攻击。
2. 反序列化漏洞的预防
一般来说,除非绝对必要,否则应避免用户输入的反序列化。在许多情况下,它可能启用的高严重性漏洞利用以及防范这些漏洞的难度超过了好处。
如果确实需要反序列化来自不受信任源的数据,请合并可靠的措施以确保数据未被篡改。例如,您可以实现数字签名来检查数据的完整性。但是,请记住,在开始反序列化过程之前,必须进行任何检查。否则,它们就没有多大用处了。
如果可能,应完全避免使用通用反序列化功能。来自这些方法的序列化数据包含原始对象的所有属性,包括可能包含敏感信息的私有字段。相反,您可以创建自己的特定于类的序列化方法,以便至少可以控制公开哪些字段。
最后,请记住,该漏洞是用户输入的反序列化,而不是随后处理数据的小工具链的存在。不要依赖尝试消除您在测试期间识别的小工具链。尝试将它们全部插入是不切实际的,因为几乎肯定存在于您的网站上的跨库依赖项网络。在任何时候,公开记录的内存损坏漏洞也是一个因素,这意味着您的应用程序无论如何都可能容易受到攻击。
3. 反序列化漏洞的利用
3.1 如何识别不安全的反序列化
白盒测试还是黑盒测试在审核期间,查看传递到网站中的所有数据,并尝试识别看起来像序列化数据的任何内容。
Burp 可以自动标记任何似乎包含序列化对象的 HTTP 消息。
3.1.1 PHP 序列化格式
PHP使用一种大部分人类可读的字符串格式,字母表示数据类型,数字表示每个条目的长度。例如,考虑具有以下属性的对象:
User
序列化时,此对象可能如下所示:
这可以解释如下:
O:4:"User""User"
- 具有 4 个字符的类名的对象
2
- 对象有 2 个属性
s:4:"name""name"
- 第一个属性的键是 4 个字符的字符串
s:6:"carlos""carlos"
- 第一个属性的值是 6 个字符的字符串
s:10:"isLoggedIn""isLoggedIn"
- 第二个属性的键是 10 个字符的字符串
b:1true
- 第二个属性的值是布尔值
PHP 序列化的本机方法是
serialize()
和unserialize()
。如果有源代码访问权限,则应首先查找代码中任何位置的unserialize()
并进一步调查。3.1.2 Java 序列化格式
某些语言(如 Java)使用二进制序列化格式。这更难阅读,但如果您知道如何识别一些迹象,您仍然可以识别序列化的数据。例如,序列化的 Java 对象始终以相同的字节开头,这些字节的编码方式与十六进制中的
ac ed
和 Base64 中的rO0
编码相同。java.io.Serializable
实现接口的任何类都可以进行序列化和反序列化。如果具有源代码访问权限,请记下使用readObject()
该方法的任何代码,该方法用于从InputStream
中读取和反序列化数据。3.2 操作序列化对象
利用某些反序列化漏洞就像更改序列化对象中的属性一样简单。当对象状态持久化时,您可以研究序列化数据以识别和编辑感兴趣的属性值。然后,您可以通过网站的反序列化过程将恶意对象传递到网站中。这是基本反序列化攻击的第一步。
从广义上讲,在操作序列化对象时可以采用两种方法。
- 可以直接以字节流形式编辑对象,
- 可以使用相应的语言编写一个短脚本来创建和序列化新对象。
使用二进制序列化格式时,后一种方法通常更容易。
3.2.1 修改对象属性
篡改数据时,只要攻击者保留有效的序列化对象,反序列化过程就会创建一个具有修改后属性值的服务器端对象。
举个简单的例子,考虑一个网站,它使用序列化对象
User
在 Cookie 中存储有关用户会话的数据。如果攻击者在 HTTP 请求中发现此序列化对象,他们可能会对其进行解码以查找以下字节流:该属性是一个明显的关注点。攻击者只需将属性
isAdmin
的布尔值更改为1
(true),重新编码对象,然后使用此修改后的值覆盖其当前 Cookie。孤立地看,这没有任何影响。但是,假设网站使用此cookie来检查当前用户是否有权访问某些管理功能:此易受攻击的代码将基于 Cookie 中的
isAdmin
数据(包括攻击者修改的属性)实例化User
对象。在任何时候都不会检查序列化对象的真实性。然后,此数据将传递到条件语句中,在这种情况下,将允许轻松的权限提升。这种简单的场景在平时并不常见。但是,以这种方式编辑属性值演示了访问不安全的反序列化暴露的大量攻击面的第一步。
3.2.2 修改数据类型
我们已经了解了如何修改序列化对象中的属性值,但也有可能提供意外的数据类型。
因为在比较不同的数据类型时,其松散的比较运算符 (
==
) 的行为,基于 PHP 的逻辑特别容易受到这种操作的影响。例如,如果在整数和字符串之间执行松散比较,PHP 将尝试将字符串转换为整数,这意味着5 == "5"
计算结果为true
。通常,这也适用于以数字开头的任何字母数字字符串。在这种情况下,PHP 将根据初始数字有效地将整个字符串转换为整数值。字符串的其余部分将被完全忽略。因此,
5 == "5
在实践中被视为5 == 5
当比较一个字符串整数时,这变得更加奇怪:
0
为什么?因为字符串中没有数字,即 0 个数字。PHP 将整个字符串视为整数
0
。考虑这样一种情况,其中松散的比较运算符与反序列化对象中的用户可控制数据结合使用。这可能会导致危险的业务逻辑漏洞。
假设攻击者修改了 password 属性,使其包含整数
0
而不是预期的字符串。只要存储的密码不以数字开头,条件将始终返回true
,从而启用身份验证绕过。请注意,这之所以成为可能,是因为反序列化保留了数据类型。如果代码直接从请求中获取密码,则0
将转换为字符串,条件的计算结果将为false
。请注意,在修改任何序列化对象格式的数据类型时,请务必记住也要更新序列化数据中的任何类型标签和长度指示器。否则,序列化对象将被损坏,并且不会被反序列化。
直接使用二进制格式时,可以使用 Burp 的 Hackvertor 扩展,该扩展可以将序列化数据修改为字符串,它将自动更新二进制数据,并相应地调整偏移量。
3.3 使用应用程序功能
网站的功能还可能对反序列化对象中的数据执行危险操作。可以使用不安全的反序列化来传入意外数据,并利用相关功能造成损害。
例如,作为网站的“删除用户”功能的一部分,通过访问属性中的文件路径
$user->image_location
来删除用户的个人资料图片。如果$user
是从序列化对象创建的,则攻击者可以通过将image_location
设置为任意文件路径然后传入已修改对象来利用此漏洞。删除他们自己的用户帐户也会删除此任意文件。此示例依赖于攻击者通过用户可访问的功能手动调用危险方法。但是,当您创建将数据自动传递到危险方法中的漏洞利用时,不安全的反序列化变得更加有趣。这是通过使用“魔术方法”来实现的。
3.3.1 魔术方法
PHP中最常见的例子之一是
__construct()
,每当类的对象被实例化时就会调用它,类似于Python的__init__
。通常,像这样的构造函数魔术方法包含用于初始化实例属性的代码。但是,开发人员可以自定义魔术方法以执行他们想要的任何代码。魔术方法被广泛使用,本身并不代表漏洞。但是,当它们执行的代码处理攻击者可控制的数据(例如,来自反序列化对象的数据)时,它们可能会变得危险。攻击者可以利用此漏洞,在满足相应条件时自动调用反序列化数据上的方法。
最重要的是,在这种情况下,某些语言具有在反序列化过程中自动调用的神奇方法。例如,PHP 的
unserialize()
方法查找并调用对象的__wakeup()
魔术方法。在Java反序列化中,这同样适用于
ObjectInputStream.readObject()
方法,该方法用于从初始字节流中读取数据,并且本质上类似于“重新初始化”序列化对象的构造函数。但是,Serializable
类也可以声明自己的readObject()
方法,如下所示:完全以这种方式声明的
readObject()
方法充当在反序列化期间调用的魔术方法。这允许类更紧密地控制其自身字段的反序列化。您应该密切关注包含这些类型的魔术方法的任何类。它们允许您在对象完全反序列化之前将数据从序列化对象传递到网站的代码中。这是创建更高级漏洞利用的起点。
3.4 注入任意对象
有时可以通过简单地编辑网站提供的对象来利用不安全的反序列化。但是,注入任意对象类型可以开辟更多的可能性。
在面向对象的编程中,可用于对象的方法由其类确定。因此,如果攻击者可以操纵作为序列化数据传入的哪类对象,则他们可能会影响在反序列化之后甚至在反序列化期间执行的代码。
反序列化方法通常不检查它们正在反序列化的内容。这意味着可以传入网站可用的任何可序列化类的对象,并且该对象将被反序列化。这有效地允许攻击者创建任意类的实例。此对象不属于预期类的事实并不重要。意外的对象类型可能会导致应用程序逻辑中出现异常,但到那时恶意对象将已实例化。
如果有权访问源代码,可以检查它们中是否有任何一个对可控数据执行危险操作。然后,攻击者可以传入此类的序列化对象。包含这些反序列化魔术方法的类也可用于启动更复杂的攻击,涉及一长串方法调用,称为“小工具链”。
3.5 小工具链
“小工具”是应用程序中存在的代码片段,可帮助攻击者实现特定目标。
单个小工具不能直接对用户输入执行任何有害操作。但是,攻击者的目标可能只是调用一个方法,该方法会将其输入传递到另一个小工具中。通过以这种方式将多个小工具链接在一起,攻击者可能会将其输入传递到危险的“接收器小工具”中,从而造成最大的损害。
重要的是要了解,与某些其他类型的漏洞利用不同,小工具链不是攻击者构建的链式方法的有效载荷。网站上已经存在所有代码。攻击者唯一控制的是传递到小工具链中的数据。这通常使用在反序列化期间调用的魔术方法(有时称为“启动小工具”)来完成。
在平时,许多不安全的反序列化漏洞只能通过使用小工具链来利用。这有时可以是一个简单的一步或两步链,但构建高严重性攻击可能需要更详细的对象实例化和方法调用序列。因此,能够构建小工具链是成功利用不安全的反序列化的关键方面之一。
3.5.1 使用预构建的小工具链
有几种工具可以提供一系列预先发现的链,这些链已在其他网站上成功利用。即使您无权访问源代码,也可以使用这些工具以相对较少的工作量识别和利用不安全的反序列化漏洞。由于广泛使用包含可利用的小工具链的库,因此使此方法成为可能。
例如,如果Java的Apache Commons Collections库中的小工具链可以在一个网站上被利用,那么利用该库的任何其他网站也可以使用同一链进行利用。
- ysoserial
Java反序列化的一个工具是“ysoserial”。这使您可以为您认为目标应用程序正在使用的库选择一个提供的小工具链,然后传入要执行的命令。然后,它基于所选链创建适当的序列化对象。这仍然涉及一定的试验和错误,但它比手动构建自己的小工具链的劳动密集程度要低得多。
请注意,并非所有 yserial 中的小工具链都允许运行任意代码。相反,它们可能用于其他目的。例如,可以使用以下方法帮助您在几乎任何服务器上快速检测不安全的反序列化:
- 该
URLDNS
链会触发对提供的 URL 的 DNS 查找。
最重要的是,它不依赖于使用特定易受攻击库的目标应用程序,并且可以在任何已知的Java版本中工作。这使其成为用于检测目的的最通用的小工具链。如果您在流量中发现序列化对象,则可以尝试使用此小工具链生成一个对象,该对象触发与服务器的 DNS 交互。如果是这样,则可以确定在目标上发生了反序列化。
JRMPClient
是另一个可用于初始检测的通用链。它会导致服务器尝试与提供的 IP 地址建立 TCP 连接。
请注意,您需要提供原始 IP 地址而不是主机名。此链可能在所有出站流量都经过防火墙保护的环境中有用,包括 DNS 查找。您可以尝试使用两个不同的 IP 地址生成有效负载:一个是本地地址,另一个是防火墙的外部地址。如果应用程序立即响应具有本地地址的有效负载,但对于具有外部地址的有效负载挂起,从而导致响应延迟,则表明小工具链工作正常,因为服务器尝试连接到防火墙地址。在这种情况下,响应中的细微时间差可以帮助您检测服务器上是否发生反序列化,即使在盲例中也是如此。
- PHP 通用小工具链
大多数经常遭受不安全的反序列化漏洞的语言都具有等效的概念证明工具。例如,对于基于 PHP 的站点,您可以使用“PHP 通用小工具链”(PHPGGC)。
重要的是要注意,该漏洞是用户可控制数据的反序列化,而不仅仅是网站代码或其任何库中存在小工具链。小工具链只是一旦注入有害数据即可操纵其流的一种手段。这也适用于依赖于不受信任的数据反序列化的各种内存损坏漏洞。换句话说,一个网站可能仍然容易受到攻击,即使它确实以某种方式设法插入了每个可能的小工具链。
3.5.2 使用有文档记录的小工具链
可能并不总是有专用工具可用于利用目标应用程序使用的框架中的已知小工具链。在这种情况下,总是值得在线查看,看看是否有任何记录在案的漏洞可以手动适应。调整代码可能需要对语言和框架有一些基本的了解,有时您可能需要自己序列化对象,但这种方法仍然比从头开始构建漏洞利用要少得多。
3.5.3 创建您自己的漏洞利用
当现成的小工具链和记录在案的漏洞利用不成功时,您将需要创建自己的漏洞利用程序。
要成功构建自己的小工具链,您几乎肯定需要访问源代码。第一步是研究此源代码,以确定包含反序列化期间调用的魔术方法的类。评估此魔术方法执行的代码,以查看它是否直接使用用户可控制的属性执行任何危险操作。为了以防万一,这总是值得检查的。
如果魔术方法本身不可利用,它可以作为小工具链的“启动小工具”。研究启动小工具调用的任何方法。这些是否会对您控制的数据造成危险?如果没有,请仔细查看它们随后调用的每个方法,依此类推。
重复此过程,跟踪您有权访问的值,直到您到达死胡同或识别出可控数据传递到其中的危险接收器小工具。
确定如何在应用程序代码中成功构造小工具链后,下一步是创建包含有效负载的序列化对象。这只是一个在源代码中研究类声明并创建具有利用所需的适当值的有效序列化对象的案例。正如我们在前面的实验中看到的那样,在使用基于字符串的序列化格式时,这相对简单。
使用二进制格式(例如在构造 Java 反序列化攻击时)可能特别麻烦。对现有对象进行细微更改时,您可能习惯于直接使用字节。但是,当进行更重要的更改(例如传入一个全新的对象)时,这很快就会变得不切实际。用目标语言编写自己的代码通常要简单得多,以便自己生成和序列化数据。
在创建自己的小工具链时,请留意利用此额外攻击面触发次要漏洞的机会。
3.6 PHAR 反序列化
到目前为止,我们主要研究的是利用反序列化漏洞,其中网站显式反序列化用户输入。但是,在 PHP 中,即使没有明显使用反序列化
unserialize()
,有时也可以利用反序列化。PHP 提供了几个 URL 样式的包装器,您可以在访问文件路径时使用这些包装器来处理不同的协议。其中之一是
phar://
包装器,它提供了用于访问PHP归档(.phar
)文件的流接口。PHP 文档显示
PHAR
清单文件包含序列化的元数据。至关重要的是,如果对phar://
流执行任何文件系统操作,则此元数据将隐式反序列化。这意味着 phar://
流可能成为利用不安全的反序列化的向量,前提是您可以将此流传递到文件系统方法中。在明显危险的文件系统方法(如
include()
或fopen()
)的情况下,网站可能已经实施了对策,以减少它们被恶意使用的可能性。但是,诸如file_exists()
之类的方法并不是那么明显危险,因此可能没有得到很好的保护。此技术还要求您以某种方式将
PHAR
上载到服务器。例如,一种方法是使用图像上传功能。如果您能够创建一个多语言文件PHAR
,并伪装成一个简单的JPG
,您有时可以绕过网站的验证检查。如果您可以强制网站从phar://
流中加载此“JPG
”,则通过PHAR
元数据注入的任何有害数据都将被反序列化。由于 PHP 读取流时不检查文件扩展名,因此文件使用图像扩展名无关紧要。只要网站支持对象的类,就可以以这种方式调用
__wakeup()
和__destruct()
魔术方法,从而允许您使用此技术潜在地启动小工具链。3.7 利用内存损坏的反序列化
即使不使用小工具链,仍然有可能利用不安全的反序列化。如果所有其他方法都失败了,则通常存在公开记录的内存损坏漏洞,这些漏洞可以通过不安全的反序列化来利用。这些通常会导致远程执行代码。
反序列化方法(如PHP的
unserialize()
)很少针对此类攻击进行强化,并暴露了大量的攻击面。这本身并不总是被视为漏洞,因为这些方法首先不是为了处理用户可控制的输入。参考文章
本文章仅提供学习使用,有任何问题,欢迎您在底部评论区留言,一起交流~
- Author:KoGe
- URL:https://www.shipangshuo.xyz/article/deserialization
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts