Python-script-ում մեկնաբանության տեքստի վերահսկմամբ կոդի կատարումը ձեռք բերելը

Один из участников соревнования UIUCTF 2025, подробно разобрал, как ему удалось выполнить задание, требующее добиться исполнения своего кода на сервере, имея лишь возможность изменения содержимого текста комментария в коде.

Участники могли отправить сетевой запрос к Python-скрипту, который создавал новый Python-скрипт cо случайными именем, добавлял поступившие от пользователя данные в текст комментария, вырезав символы «\n» и «\r», и запускал этот скрипт командой «python3 имя.py». Контролируя только содержимое комментария участник должен был извлечь строку из файла «/home/ctfuser/flag». Скрипт создавался следующим кодом: comment = input(«> «).replace(«\n», «»).replace(«\r», «») code = f»»»print(«hello world!») # This is a comment. Here’s another: # {comment} print(«Thanks for playing!»)»»»

Вместо «{comment}» подставлялись данные, поступившие от участника, и в итоге запускался следующий код: print(«hello world!») # This is a comment. Here’s another: # Данные, поступившие от участника соревнования print(«Thanks for playing!»)

Задание было сформировано по мотивам уязвимости в парсере CPython, который обрабатывал символ с нулевым кодом, как окончание строки (уязвимость, например, можно было использовать для скрытия вредоносных действий в тексте комментария). Проблема была устранена в выпусках CPython 3.12.0 и 3.11.4. В применяемом в конкурсе обработчике вырезались только символы «\n» и «\r», но при использовании уязвимой версии СPython участник мог использовать символ «\0» как разделитель. Тем не менее этот трюк не сработал так как в конкурсе использовалась уже исправленная версия CPython c расчётом, что в парсере могут оставаться ещё какие-то похожие ошибки и участники смогут их выявить.

Успешно справившийся с заданием участник не стал искать новые уязвимости в парсере, которые бы позволили разбить строку на чаcти, а воспользовался особенностью выполнения в Python файлов по типу их содержимого. Например, вместо исходного кода в файл с расширением «.py» можно поместить прокэшированный байткод, сохраняемый в файлах с расширением «.pyc», и подобный файл будет выполнен. В рассматриваемом конкурсе участник мог контролировать только содержимое в середине файла, поэтому не мог добавить свой заголовок для искажения MIME-типа.

Задачу удалось решить, воспользовавшись тем, что Python начиная с ветки 2.6 может исполнять содержимое ZIP-архивов для поставки Python-пакетов в сжатом виде. Как и в случае с кэшем байткода наличие zip-архива определяется по содержимому, а не по расширению файла, т.е. в «файл.py» можно поместить zip-архив и при запуске командой «python файл.py» он будет обработан, как сжатый Python-пакет. При этом ZIP-архивы в Python индексируются не по заголовку в начале файла, а по секции EOCD (End of Central Directory Record) в конце файла. При наличии в архиве файла «__main__.py», этот файл запускается автоматически при прямом запуске архива командой «python архив».

Конкурсная задача была решена генерацией подобного ZIP-архива и подстановкой его в текст комментария. Для сохранения корректности структуры файла в условиях наличия в конце исходного файла вызова ‘print(«Thanks for playing!»)’, было использовано наличие в EOCD-секции области комментария, размещаемой в самом конце.

Python-script-ում մեկնաբանության տեքստի վերահսկմամբ կոդի կատարումը ձեռք բերելը
Python-script-ում մեկնաբանության տեքստի վերահսկմամբ կոդի կատարումը ձեռք բերելը


Ընտանիք: opennet.ru
Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster