点击蓝字
关注我们
始于理论,源于实践,终于实战
老付话安全,每天一点点
激情永无限,进步看得见
严正声明
本号所写文章方法和工具只用于学习和交流,严禁使用文章所述内容中的方法未经许可的情况下对生产系统进行方法验证实施,发生一切问题由相关个人承担法律责任,其与本号无关。
特此声明!!!
如何识别不安全的反序列化
PHP 序列化格式
PHP序列化是一种将PHP变量转换为字符串的过程,这样它们就可以存储或传输,并且可以在稍后的时间点还原回原始变量。
PHP序列化格式有一些关键点:
NULL:被序列化为N;
布尔值:被序列化为b:0;或b:1;,其中0代表false,1代表true。
整数: 被序列化为i:123;,其中123是整数值。
双精度浮点数: 被序列化为d:123.45;,其中123.45是浮点数值。
字符串:被序列化为s:5:"hello";,其中5是字符串的长度,"hello"是字符串值。
数组: 数组的序列化稍微复杂一些,它们被表示为一系列键值对。例如,一个简单的数组可能被序列化为a:2:{i:0;s:3:"one";i:1;s:3:"two";}。
对象:对象的序列化包括对象的类名和属性。例如,一个对象可能被序列化为
O:8:"stdClass":2:{s:3:"foo";s:3:"bar";s:3:"baz";i:123;}。
1、O:8:"stdClass":类名称为 8 个字符 “stdClass” 的对象
2、2 :对象有 2 个属性
3、s:3:"foo":第一个属性的键是 3 个字符的字符串 “foo”
4、s:3:"bar":第一个属性的值是 3 个字符的字符串 “bar”
5、s:3:"baz":第二个属性的键是 3 个字符的字符串 “baz”
6、i:123:第二个属性的值是整数123
PHP 序列化的方法是 serialize() 和 unserialize()。如果源代码有访问权限,可以在代码中的任意位置查找 unserialize(),识别序列化。
Java 序列化格式
在Java中,要使一个类可以被序列化,需要使用java.io.Serializable 接口进行标识。当一个对象被序列化时,它的类定义、字段值以及其他必要的信息都会被编码到字节流中。
Java使用二进制序列化格式,很难阅读;但是序列化的 Java 对象始终以相同的字节开头,如十六进制编码的 ac, Base64 编码的 rO0,通过这些可以识别出序列化踪迹。使用接口 java.io.Serializable 的类都可以被序列化和反序列化。如有源代码访问权限,可以使用 readObject() 方法的任何代码,可从 InputStream 读取反序列化数据。
操作序列化对象
利用反序列化漏洞就像更改序列化对象中的属性一样简单,由于对象状态是持久的,因此可以研究序列化数据以识别和编辑感兴趣的属性值。然后,通过其反序列化过程将恶意对象传递到网站中。这是基本反序列化漏洞利用的第一步。在操作序列化对象时,可以采用两种方法:可以直接以字节流形式编辑对象,也可以用相应的语言编写一个简短的脚本来自己创建和序列化新对象。在处理二进制序列化格式时,后一种方法通常更容易。
1、修改对象属性
在篡改数据的情况下,如果攻击者能够保留一个有效的序列化对象,那么在反序列化的过程中,服务器端将会创建一个其属性值已经被修改的对象。这种情况通常发生在攻击者截获了序列化对象的字节流,并对其进行了修改,然后将修改后的字节流发送给服务器进行反序列化。
由于Java的反序列化机制在将字节流转换为对象时,不会对字节流的内容进行严格的验证,因此如果攻击者能够构造出一个合法的序列化字节流,即使其中的属性值已经被篡改,服务器端仍然会将其反序列化为一个对象,并且这个对象的属性值就是攻击者所设定的值。
例如:
一个网站使用序列化的 User 对象在 Cookie 中存储有关用户会话的数据。如果攻击者在 HTTP 请求中发现了这个序列化对象,他们可能会对其进行解码以找到以下字节流:
O:4:"User":2:{s:8:"username";s:6:"car";s:7:"isAdmin";b:0;}
攻击者只需将属性的布尔值更改为 1 (true),重新编码对象,并使用此修改后的值覆盖其当前 Cookie。网站使用此 cookie 来检查当前用户是否有权访问某些管理功能,将允许轻松进行权限提升。
2、修改数据类型
先了解一下PHP的类型转换,在 PHP 中,当进行比较操作时,如果一个字符串以数字开头,PHP 会尝试将整个字符串转换为整数值。这种转换是自动进行的,称为类型转换。
转换规则:
以数字开头的字符串:如果字符串以数字开头,PHP 会提取开头的数字部分并将其转换为整数。字符串的其余部分将被忽略。例如,字符串 "5 of something" 会被转换为整数 5。
非数字开头的字符串:如果字符串不以数字开头,PHP 会将其转换为整数 0。例如,字符串 "something 5" 会被转换为整数 0。
在比较操作中,PHP 会根据上述规则进行类型转换,然后再进行比较。例如,表达式 5 == "5 of something" 会被解释为 5 == 5,结果为 true。
PHP 的松散比较运算符(==)在比较不同数据类型时,会尝试将它们转换为相同的类型,然后再进行比较。这种行为在某些情况下可能会导致意外的结果,特别是在处理用户输入或反序列化数据时。如果在整数和字符串之间进行松散的比较,PHP 将尝试将字符串转换为整数,这意味着 5 == “5” 的计算结果为 true。
但在 PHP 8 及更高版本中,0 == “Example string” 比较的计算结果为 false,因为字符串在比较过程中不再隐式转换为 0。
魔术方法
攻击者通过用户可访问的功能手动调用危险方法,当您创建将数据自动传递到危险方法的漏洞时,不安全的反序列化变得更加有趣。这是通过使用 “magic methods” 实现的。魔术方法是面向对象编程中的一种特殊方法,它们不需要显式调用,而是会在特定的事件或情境下自动触发。这种机制在不同的编程语言中有不同的实现方式,但其核心思想是相同的,即通过定义一些特殊的方法来响应特定的操作或事件。在Python中,魔术方法通常以双下划线开头和结尾,例如__init__()、__str__()等。这些方法在特定的操作(如对象初始化、字符串转换等)发生时会被自动调用。魔术方法是各种语言中面向对象编程的常见功能。它们有时通过在方法名称前加上前缀或用双下划线括起来来表示。PHP 中最常见的示例之一是 __construct(),每当实例化类的对象时都会调用它,类似于 Python 的 __init__。
在处理反序列化数据时,如果这些数据是由攻击者控制的,那么在反序列化过程中自动调用的魔术方法可能会被执行,从而引发潜在的安全风险。例如,在PHP中,如果一个反序列化的对象包含有恶意构造的数据,那么在反序列化过程中,可能会自动调用对象的__wakeup()方法。如果这个方法中包含了对这些恶意数据的操作,那么攻击者就有可能通过精心构造的数据来执行任意代码,从而达到攻击的目的。
在 Java 反序列化中, ObjectInputStream.readObject()方法用于从初始字节流中读取数据,类似于用于“重新初始化”序列化对象的构造函数。
Serializable 类也可以声明自己的 readObject() 方法,充当在反序列化期间调用的魔术方法。这允许 class 更紧密地控制其自身字段的反序列化。
常见的PHP魔术方法
1、对象的初始化和销毁:
__construct():这个方法在创建对象时自动调用,通常用于初始化对象的属性或者执行一些必要的操作。例如,在创建一个数据库连接对象时,可以在构造方法中建立数据库连接。
__destruct():在对象被销毁时自动调用,通常用于执行清理操作或释放资源。例如,当一个文件处理对象不再需要时,可以在析构方法中关闭文件句柄。
2、 属性的动态访问和设置
__get() 和 __set():这两个方法用于读取和设置对象的属性,当尝试访问或设置一个不存在或私有的属性时,会自动调用这两个方法。这可以用于实现属性的访问控制,或者在访问属性时执行额外的操作,如数据验证或日志记录。
3、方法的动态调用
__call() 和 __callStatic():这两个方法用于捕获对象或类上不存在的方法调用。这可以用于实现方法的重载,或者在调用不存在的方法时执行默认操作。
4. 对象的字符串表示
__toString():这个方法在将对象转换为字符串时自动调用,通常用于调试或日志记录。例如,可以定义一个__toString()方法,使其返回对象的关键属性值,以便在打印对象时得到有意义的信息。
5. 序列化和反序列化
__sleep() 和 __wakeup():这两个方法在对象被序列化和反序列化时分别自动调用。可以用于在序列化之前清理资源,或者在反序列化之后重新初始化资源。
6. 克隆对象
__clone():当对象被克隆时自动调用,可以用于在克隆对象时执行额外的操作,如复制对象的资源。
7、对象作为函数调用
当需要将一个对象作为函数调用时,__invoke()方法会被自动调用。这个方法可以用来实现对象的函数调用语义,比如在事件驱动编程中,将对象作为事件处理器来调用等。
还有其他语言的魔术方法:
1、Python中的魔术方法
__init__():对象初始化时调用。
__str__():定义对象的字符串表示。
__add__():定义加法运算符的行为。
2、C++中的魔术方法
operator+:重载加法运算符。
operator=:重载赋值运算符。
3、Ruby中的魔术方法,method_missing 和 respond_to? 提供了类似魔术方法的功能,允许动态处理方法调用。
注入任意对象
虽然可以通过简单地编辑网站提供的对象来利用不安全的反序列化,但是,注入任意对象类型可以带来更多可能性。在面向对象的编程中,对象可用的方法由其类确定。因此,如果攻击者可以操纵作为序列化数据传入的对象类,他们就可以影响在反序列化之后甚至反序列化期间执行的代码。反序列化方法通常不检查它们正在反序列化的内容。这意味着您可以传入网站可用的任何可序列化类的对象,并且该对象将被反序列化。这就允许攻击者创建任意类的实例。
小工具链:
小工具(Gadget)是指存在于应用程序中的代码片段,小工具通常是一些现有的、合法的代码,但当它们被恶意利用时,可以组合成危险的攻击链。单个小工具不得直接对用户输入执行任何有害操作,但攻击者可以通过巧妙地链接多个小工具来达到其目的。每个小工具可能只执行一个看似无害的操作,但当这些操作被串联起来时,它们可以共同完成复杂的攻击行为。小工具链不是攻击者构建的链式方法的有效载荷。攻击者唯一控制的是传递到 Gadget 链中的数据。这通常是在反序列化期间调用的魔术方法完成的,有时称为“kick-off gadget”。
使用预先构建的小工具链
在无法访问源代码的情况下,识别和利用不安全的反序列化漏洞,可以借助一些预先发现的链的工具:
1. ysoserial
ysoserial 是一个用于生成反序列化攻击payload的工具。它支持多种语言和框架,包括Java、.NET、PHP等。ysoserial内置了许多已知的小工具链,这些链可以在不同的环境中被利用。您可以使用ysoserial生成payload,并将其发送到目标网站,以测试是否存在反序列化漏洞。还有其他快速检测不安全反序列化方法:URLDNS 链会触发对提供的 URL 的 DNS 查找。JRMPClient 是另一个可用于初始检测的通用链。它会导致服务器尝试与提供的 IP 地址建立 TCP 连接。
2. Gadget Inspector
Gadget Inspector 是一个用于分析Java类文件的工具。它可以自动查找类文件中的小工具链,并生成相应的payload。Gadget Inspector还支持自定义小工具链,您可以根据自己的需求添加新的小工具链。
3. JNDI注入工具
JNDI注入工具是一种专门用于测试Java应用程序中JNDI注入漏洞的工具。它可以生成各种类型的payload,并将其发送到目标网站。JNDI注入工具还支持多种协议,包括LDAP、RMI等。
4. Serialize Killer
Serialize Killer 是一个用于测试Java应用程序中反序列化漏洞的工具。它可以生成各种类型的payload,并将其发送到目标网站。Serialize Killer还支持多种协议,包括LDAP、RMI等。
注意:漏洞是用户可控数据的反序列化,而不仅仅是网站代码或其任何库中存在小工具链。小工具链只是一种在有害数据注入后操纵其流动的手段。这也适用于依赖于不受信任数据反序列化的各种内存损坏漏洞。换句话说,即使网站以某种方式设法插入了所有可能的小工具链,它也可能仍然容易受到攻击。
构建自己的漏洞利用程序
要成功构建自己的 Gadget 链,您几乎肯定需要源代码访问权限。第一步是研究此源代码,以识别包含反序列化期间调用的 magic 方法的类。评估此 magic 方法执行的代码,以查看它是否直接对用户可控属性执行任何危险操作。
如果魔术方法本身无法利用,它可以作为小工具链的“启动小工具”。研究 kick off 小工具调用的任何方法。这些是否对您控制的数据造成了危险?如果没有,请仔细查看它们随后调用的每个方法,依此类推。
一旦你弄清楚了如何在应用程序代码中成功构建一个小工具链,下一步就是创建一个包含有效负载的序列化对象。这只是研究源代码中的类声明并创建一个有效的序列化对象(具有您的漏洞利用所需的适当值)的情况。
PHAR 反序列化
前面我们主要研究了利用反序列化漏洞,其中网站显式反序列化用户输入。然而,在 PHP 中,即使没有明显使用 unserialize() 方法,有时也可以利用反序列化。
PHP 提供了几个 URL 样式的包装器,可用于在访问文件路径时处理不同的协议。其中一个是 phar:// 包装器,它提供用于访问 PHP 存档 (.phar) 文件的流接口。
PHP 文档显示 PHAR 清单文件包含序列化元数据。如果您在 phar:// 流上执行任何文件系统操作,则此元数据将被隐式反序列化。这意味着 phar:// 流可能成为利用不安全反序列化的向量,但前提是您可以将此流传递到文件系统方法中。
PHAR反序列化是指利用PHAR文件中的反序列化功能进行攻击的一种技术。PHAR文件是一种PHP归档文件,可以包含PHP代码和其他资源。PHAR文件中的反序列化功能可以将序列化的数据转换为PHP对象,但如果反序列化的数据被恶意篡改,可能会导致代码注入等安全问题。
PHAR反序列化攻击的条件:
-
攻击者能够控制PHAR文件的内容。
-
目标系统会加载并反序列化PHAR文件中的数据。
-
反序列化后的PHP对象会被目标系统执行或使用。
PHAR反序列化攻击技术要求以某种方式将 PHAR 上传到服务器。例如,一种方法是使用图像上传功能。如果能够创建一个多语言文件,其中 PHAR 伪装成简单的 JPG,有时可以绕过网站的验证检查。如果可以强制网站从 phar:// 流加载此多语言 “JPG”,则可以通过 PHAR 元数据注入的任何有害数据都将被反序列化。由于 PHP 读取流时不检查文件扩展名,因此文件是否使用图像扩展名并不重要。
END
老付
欢迎扫码
关注我们
网络安全
原文始发于微信公众号(老付话安全):利用不安全的反序列化漏洞
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论