[ON] Достижение выполнения кода при контроле над текстом комментария в Python-скрипте

Обсуждение новостей, соответствующих тематике форума

Модератор: Модераторы разделов

Аватара пользователя
rssbot
Бот
Сообщения: 6001
ОС: gnu/linux

[ON] Достижение выполнения кода при контроле над текстом комментария в Python-скрипте

Сообщение rssbot »

Один из участников соревнования 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 расчётом на то, что в парсере могут оставаться ещё какие-то похожие ошибки и участники смогут их выявить.


Успешно справившийся с заданием участник не стал искать новые уязвимости в парсере, которые бы позволили разбить строку на части, а воспользовался особенностью выполнения в 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-секции области комментария, размещаемой в самом конце.
Изображение
Изображение




Источник: https://www.opennet.ru/opennews/art.shtml?num=63669
(opennet.ru, основная лента)
Последний раз редактировалось rssbot 04.08.2025 21:21, всего редактировалось 3 раза.
Причина: Updated upstream
Спасибо сказали:
Аватара пользователя
Janik
Сообщения: 860
Статус: Оператор вычислительных машин
ОС: Debian

Re: [ON] Достижение выполнения кода при контроле над текстом комментария в Python-скрипте

Сообщение Janik »

Красивый метод! Никаких переполнений буферов!
Кто ищет, тот всегда найдет!
Опыт - это когда все получается с первого раза.
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 3086
ОС: Gentoo

Re: [ON] Достижение выполнения кода при контроле над текстом комментария в Python-скрипте

Сообщение ormorph »

Всё что я об этом думаю.
Spoiler

Shell

import os
content = b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xc4~\x04[\xfd \xde\x1b)\x00\x00\x00$\x00\x00\x00\x0b\x00\x00\x00__main__.py\x01$\x00\xdb\xffprint("\xd0\xa4\xd0\xb8\xd0\xb3\xd0\xbd\xd1\x8f \xd0\xb2\xd1\x81\xd1\x91 \xd1\x8d\xd1\x82\xd0\xbe!") \nPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\xc4~\x04[\xfd \xde\x1b)\x00\x00\x00$\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x17\x00\x00\x00__main__.pyPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x009\x00\x00\x00i\x00\x00\x00\x00\x00\n'
head = b"""#!/usr/bin/env python3
printf('Hello World')
content = \"\"\"
# """
end = b'\nprint(Opa!)\n\"\"\"'
buf = head + content + end
with open('new.py', 'bw') as fd:
fd.write(buf)
fd.close()

os.system('python3 new.py')
и не скрыть.
Спасибо сказали: