Практически каждый Python-разработчик хотя бы раз использовал pickle. Этот модуль встроен в стандартную библиотеку, работает буквально в две строки и умеет сохранять практически любые объекты Python без дополнительной настройки.
Именно поэтому pickle часто используют для хранения состояния приложения, передачи объектов между процессами, кэширования, работы с ML-моделями и внутренних сервисов.
Но у такого удобства есть обратная сторона. В отличие от JSON, pickle восстанавливает не просто данные, а полноценные объекты Python. Если приложение десериализует данные, которыми управляет атакующий, это может закончиться выполнением произвольного кода на сервере. Не случайно небезопасная десериализация уже много лет входит в число наиболее опасных ошибок безопасности веб-приложений.
В этой статье разберем, почему так происходит, как устроен механизм Pickle, по каким признакам пентестер может обнаружить подобную проблему и что нужно делать разработчикам, чтобы не превратить сериализацию в точку входа для злоумышленника.
В конце статьи можно перейти к практическому заданию из бесплатного курса «Профессия Белый Хакер» и проверить, как небезопасная десериализация работает в учебном приложении.
Программа не может сохранить объект Python в файл или передать его по сети "как есть". Для этого объект сначала преобразуют в последовательность байтов. Этот процесс называется сериализацией.
Обратная операция — восстановление объекта из сохраненных данных — называется десериализацией. Именно она представляет основной интерес с точки зрения безопасности.
Сериализация используется практически в любом приложении:
Для большинства подобных задач применяют универсальные форматы вроде JSON, XML или YAML. Однако они умеют хранить только простые структуры данных. Если необходимо сохранить полноценный объект Python со всеми его свойствами, разработчики часто выбирают Pickle.
Почему Pickle отличается от JSONНа первый взгляд JSON и Pickle решают одну задачу — позволяют сохранить данные. Однако работают они по-разному.
После десериализации JSON приложение получает только стандартные структуры данных: словари, списки, строки, числа и логические значения. При этом никакие функции не вызываются.
Pickle предназначен для восстановления объектов Python. Чтобы воссоздать объект, интерпретатор читает сериализованный поток и выполняет действия, необходимые для его реконструкции: создает объекты, восстанавливает их состояние и при необходимости вызывает связанные механизмы восстановления.
Именно поэтому десериализация Pickle принципиально отличается от обычного разбора JSON. Она не ограничивается чтением данных, а участвует в восстановлении объектов. Если приложение передает в pickle.loads() данные, которыми управляет атакующий, механизм восстановления может быть использован для выполнения произвольного кода.
По этой причине разработчики Python рекомендуют никогда не десериализовать с помощью Pickle данные из недоверенных источников.
Метод __reduce__: механизм, который делает возможным RCEГлавную роль в большинстве атак играет специальный метод __reduce__.
Большинство разработчиков никогда его не используют напрямую. Тем не менее именно он определяет, каким образом объект должен быть восстановлен после десериализации.
Если очень упростить процесс, то __reduce__ отвечает на вопрос:
"Как заново создать именно этот объект?"
Вместо готового объекта метод возвращает описание действий, которые необходимо выполнить.
Например:
В обычных приложениях это абсолютно легальный механизм.
Однако проблема появляется тогда, когда описание объекта формирует атакующий.
В вашем учебном материале приведен классический пример: метод __reduce__ возвращает вызов системной функции с заданными аргументами. Во время десериализации эта функция автоматически выполняется.
Именно поэтому говорят, что Pickle способен выполнять код при десериализации.
На самом деле код не "спрятан" внутри файла.
Он вызывается самим механизмом восстановления объекта.
Почему это считается удаленным выполнением кодаПредставим, что приложение получает сериализованный объект через HTTP-запрос и без дополнительной проверки передает его в pickle.loads():
obj = pickle.loads(request.data)
Если содержимое запроса контролирует атакующий, он может подменить сериализованный объект собственным. Во время десериализации приложение самостоятельно выполнит действия, необходимые для его восстановления, что при определенных условиях приведет к выполнению произвольного кода на сервере.
Именно поэтому небезопасная десериализация входит в число наиболее опасных ошибок безопасности веб-приложений и может приводить к удаленному выполнению кода.
Почему Base64 ничего не меняетВо многих приложениях сериализованные данные дополнительно кодируют в Base64.
Например:
gASVOAAAAAAAAACM...
Из-за этого создается впечатление, что данные стали безопаснее. На деле всё не так.
Base64 — всего лишь способ представить бинарные данные в текстовом виде. Он не шифрует содержимое. После декодирования приложение получает тот же самый поток байтов Pickle и передает его в pickle.loads(). Для атакующего это практически ничего не меняет.
Где чаще всего встречается PickleМногие считают, что Pickle используют только начинающие разработчики.
На практике это не так.
Он широко применяется внутри доверенной инфраструктуры, где риск считается приемлемым.
Например:
Сам по себе Pickle не является уязвимостью.
Проблема начинается только тогда, когда поток сериализованных данных оказывается под контролем пользователя.
Именно этот момент обычно становится отправной точкой во время аудита безопасности.
Как пентестер обнаруживает небезопасную десериализациюНа практике никто не начинает поиск уязвимости с чтения исходного кода класса Exploit. Обычно всё происходит наоборот: сначала исследователь замечает подозрительные признаки, а уже потом пытается понять, используется ли в приложении Pickle.
Первый источник информации — сам код приложения.
Во время аудита стоит обращать внимание на вызовы:
pickle.loads(...)
pickle.load(...)
Если аргумент этих функций полностью или частично формируется пользователем, это уже повод разобраться, откуда именно поступают данные.
Но далеко не всегда исходный код доступен.
Во время внешнего тестирования приходится искать косвенные признаки.
Например, приложение может получать длинную строку в параметре запроса, cookie или теле POST-запроса. Иногда она выглядит как случайный набор символов, но после декодирования Base64 оказывается сериализованным объектом Pickle.
Поэтому опытный пентестер всегда задает себе несколько вопросов:
Именно цепочка «получение пользовательских данных → pickle.loads()» представляет наибольший интерес.
Какие признаки выдают использование PickleВ реальном приложении редко встречается комментарий вроде:
«Здесь находится опасная десериализация».
Чаще приходится собирать картину по косвенным признакам.
Вот несколько вещей, которые обычно привлекают внимание во время аудита:
Сам по себе ни один из этих признаков не означает наличие уязвимости.
Например, сохранение модели машинного обучения в файл Pickle — совершенно нормальная практика.
Опасность появляется только тогда, когда содержимое сериализованного объекта начинает контролировать пользователь.
Именно поэтому задача пентестера состоит не в поиске Pickle как такового, а в поиске места, где недоверенные данные попадают в десериализацию.
Почему фильтрация редко помогаетИногда разработчики понимают риск и пытаются защититься с помощью различных проверок.
Например:
К сожалению, подобные меры редко дают надежную защиту.
Причина проста.
Проблема заключается не в конкретной строке внутри сериализованных данных.
Опасен сам механизм восстановления объекта.
Если приложение доверяет данным настолько, что передает их в pickle.loads(), оно автоматически соглашается выполнить все инструкции, необходимые для реконструкции объекта.
Поэтому фильтрация превращается в бесконечную гонку между разработчиком и атакующим.
Именно по этой причине официальная рекомендация Python остается неизменной уже много лет: не десериализуйте с помощью Pickle данные из недоверенных источников. В предоставленном материале эта мысль также сформулирована однозначно: если атакующий контролирует данные, попадающие в Pickle, он может добиться выполнения произвольного кода.
Большинство подобных уязвимостей появляется вовсе не в публичных API.
Наоборот.
Обычно разработчики уверены, что определенный компонент используется только внутри доверенной инфраструктуры.
Например:
Со временем инфраструктура меняется.
Появляются новые интеграции.
Добавляется импорт пользовательских файлов.
Появляется возможность загрузить резервную копию или конфигурацию.
Именно в этот момент граница доверия может незаметно измениться.
Код при этом остается прежним.
В результате функция, которая раньше работала только с доверенными данными, начинает принимать объекты от пользователя.
Так и возникает классическая уязвимость небезопасной десериализации.
Как защищатьсяГлавное правило очень простое.
Не используйте Pickle для данных, происхождение которых невозможно полностью контролировать.
Если необходимо обмениваться информацией между клиентом и сервером, лучше выбрать формат, который описывает только данные, а не процесс восстановления объектов.
Чаще всего подходят:
Если отказаться от Pickle невозможно, стоит соблюдать несколько правил.
Во-первых, сериализованные данные должны поступать только из доверенного источника.
Во-вторых, полезно проверять их целостность с помощью цифровой подписи или HMAC. Это не делает Pickle безопасным сам по себе, но позволяет обнаружить попытку подмены данных.
В-третьих, необходимо четко понимать границы доверия. Даже если сегодня сериализованные объекты создаются исключительно вашим приложением, через год архитектура может измениться. Именно такие изменения нередко становятся причиной появления уязвимостей.
Что стоит запомнить перед практикойТеперь вернемся к тому, с чего начали.
Pickle сам по себе не является уязвимостью.
Это удобный механизм сериализации объектов Python, который отлично подходит для работы внутри доверенной среды.
Проблемы начинаются тогда, когда приложение начинает доверять данным, поступающим извне.
Именно поэтому во время анализа кода стоит обращать внимание не только на наличие модуля pickle, но и на происхождение данных, передаваемых в pickle.loads().
Перед выполнением практического задания полезно проверить, что вы можете ответить на несколько вопросов:
Если на все эти вопросы есть ответы, значит, у вас уже есть всё необходимое, чтобы приступить к поиску уязвимости в учебном приложении. Скорее всего, искать придется не «магический эксплойт», а место, где нарушена граница доверия между пользователем и механизмом десериализации. Именно это и является ключевой идеей большинства задач на небезопасную десериализацию.
Проверьте знания на практикеТеория помогает понять, как устроена небезопасная десериализация, но по-настоящему разобраться в теме можно только на практике.
Для этого подойдет задача «Элитный сомелье»*, доступная студентам бесплатного курса «Профессия Белый Хакер».
По сюжету ваш знакомый сомелье Володя устроился работать в модный ресторан и заодно запустил собственный сайт о вине. Теперь он рассуждает о «нотках дуба» и «послевкусии чернослива», но совсем забыл о безопасности своего приложения.
Известно, что сайт использует сериализацию с помощью Pickle. Ваша задача — исследовать приложение, добиться выполнения произвольных команд и получить флаг, расположенный в корне файловой системы.
Эта задача позволяет на практике увидеть, как небезопасная десериализация превращается в полноценную уязвимость, определить, где нарушена граница доверия, и применить знания, полученные в этой статье, в условиях, максимально приближенных к реальному пентесту.
Разбирайте решения на открытых вебинарахONE TASK — это не только самостоятельная практика, но и регулярные открытые разборы. Примерно раз в месяц студенты бесплатного курса «Профессия Белый Хакер» получают возможность разобрать накопившиеся задачи вместе с экспертом.
Обычно участники сначала пробуют решить задачи самостоятельно, а затем приходят на вебинар, где разбирается ход атаки: как анализировать условие, искать зацепки, проверять гипотезы и не тратить время на ложные направления.
Формат полезен тем, что показывает не просто готовое решение, а мышление действующего специалиста.
Следите за анонсами открытых вебинаров, регистрируйтесь на бесплатный курс «Профессия Белый Хакер» и используйте ONE TASK как регулярную практику для роста в пентесте.
*Чтобы открыть практическое задание «Элитный сомелье», нужно зарегистрироваться на бесплатном курсе «Профессия Белый Хакер». После регистрации задание станет доступно в личном кабинете.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | rPickle 0.11.0 | 0 | 5 | 10-07-2026 |
| 2 | pysae-ai-tools 0.1.1501 | 0 | 5 | 10-07-2026 |
| 3 | PHP Type Juggling: как нестрогое сравнение превращается в обход аутентификации | 0 | 8.1 | 22-07-2026 |
| 4 | doover 1.10.5 | 0 | 5 | 20-07-2026 |
| 5 | python-pkcs11 0.9.5 | 0 | 5 | 10-07-2026 |
| 6 | pydoover 1.10.5 | 0 | 5 | 20-07-2026 |
| 7 | doover 1.10.4 | 0 | 5 | 20-07-2026 |
| 8 | «Купер»: сколько стоит пикник на свежем воздухе | 5 | 3 | 02-07-2026 |
| 9 | Зачем нужен закон об устойчивости Рунета. И что может измениться для обычных пользователей | 0 | 0 | 12-02-2019 |