Flask - это микрофреймворк для создания веб-приложений на языке Python. Он предоставляет минимальный набор инструментов для создания веб-приложений, но при этом оставляет достаточно свободы для выбора архитектуры и инструментов, которые будут использоваться в проекте. Flask позволяет создавать веб-приложения любой сложности, от простых сайтов до сложных веб-сервисов. Он имеет множество расширений, которые позволяют добавлять дополнительные функциональные возможности, такие как авторизация, обработка форм, работа с базами данных и многое другое. Одной из главных особенностей Flask является его простота и легковесность. Он не навязывает определенную архитектуру и не требует большого количества настроек, что делает его идеальным выбором для быстрого прототипирования и разработки небольших проектов. Кроме того, Flask имеет отличную документацию и активное сообщество разработчиков, что делает его очень доступным для изучения и использования. Отладка приложений на Flask может быть выполнена с помощью встроенного в Flask отладчика, который позволяет отслеживать ошибки и исключения в приложении. Для включения которого, необходимо установить параметр debug=True в объекте приложения Flask. Это позволит отображать подробную информацию об ошибках в браузере. Когда режим отладки включен, Flask будет выводить подробную информацию об ошибках и исключениях, что может помочь разработчику быстрее и легче находить и исправлять ошибки в приложении. Однако, включение режима отладки на продакшен-сервере может представлять угрозу безопасности, поэтому debug pin обычно используется только во время разработки и тестирования приложения. Данный пин может быть использован разработчиком для выполнения python комманд на сервере, и если забыть его отключить, а потом залить приложение в продакшен на сервер, мы получим уязвимость. Процесс отладки приложения на Flask может быть выполнен следующим образом: Включите режим отладки, установив параметр debug=True в объекте приложения Flask. Запустите приложение Flask. Откройте браузер и перейдите на страницу приложения. Если возникнет ошибка, Flask отобразит подробную информацию об ошибке в браузере. Используйте эту информацию для исправления ошибки в коде приложения. После исправления ошибки перезапустите приложение Flask и проверьте, что ошибка больше не возникает. Повторяйте этот процесс до тех пор, пока все ошибки не будут исправлены. Отличительной чертой приложений на Flask является возможность получения доступа к консоли отладки, что может быть опасно для безопасности приложения, если оно находится в открытом доступе. Также данные приложения с включенным режимом отладки обычно работают на 5000 порту. Консоль отладки в таких приложениях находится по следующему пути: http(s)://IP/console Давайте напишем свой простейший сервер на данном микрофреймворке. Разберем построчно данный код: from flask import * - импортируем все классы из библиотеки Flask. app = Flask(__name__) - создаем экземпляр класса Flask и передаем ему имя текущего модуля в качестве аргумента. Это нужно для того, чтобы Flask мог правильно определить путь к шаблонам и статическим файлам. @app.route('/') - декоратор, который связывает URL-адрес с функцией, которая будет обрабатывать запросы на этот адрес. В данном случае, мы связываем корневой URL-адрес с функцией hello_world(). def hello_world(): - определяем функцию hello_world(), которая будет обрабатывать запросы на корневой URL-адрес. return 'Hello, World!' - возвращаем строку "Hello, World!" в качестве ответа на запрос. app.run(debug=True) - Запускаем наше приложение в режиме отладки Этот код создает простейший сервер на Flask, который будет отвечать на запросы на корневой URL-адрес строкой "Hello, World!". Как выглядит запуск сервера из консоли:  Рендеринг нашей страницы:  При запуске нашего сервера также мы получили Debugger PIN, который нужен разработчику для входа в панель отладки. Злоумышленник, который зайдет на сайт и попробует войти в консоль столкнется с следующим сообщением:  Сложность получения данного пина злоумышленником заключается в том, что для его генерации нунжны некоторые значения, которые нельзя получить не имея доступа к целевой системе. В свою очередь разработчик(ну или любой другой человек), зная данный пин, может исполнять любые команды на python, которые после будут исполнены. Причем ограничения на ввод команд никаких нет, то есть вы можете хоть просто создавать переменные и выводить их, хоть импортировать другие модули для дальнейшей эксплуатации. В этом и кроется опасность, мы не можем запретить никому вводить какие-либо вводить команды. Защитой отладчика от других пользователей является только пин!  Давайте разберемся как генеруется PIN. Какие у него есть дефолтные значения, а после попробуем уже самостоятельно сгенерировать его. Далее будет рассматриваться исходный код werkzeug, ссылка на исходники: ссылка Первым делом происходит вызов функции get_pin_and_cookie_name.  В данной функции и происходит процесс генерации  имени куки и PIN'а. В процессе генерации ключа участвуют 2 набора байт: Публичный набор Эта информация существует только для того, чтобы сделать файл cookie уникальным на компьютере, а не в качестве функции безопасности. Приватный набор Эта информация предназначена для того, чтобы злоумышленнику было сложнее угадать эти значения. Маловероятно, что они будут содержаться где-либо на неаутентифицированной странице отладки, поэтому для того чтобы их узнать придется потрудится. Публичный набор состоит из: Username Modname `getattr(app, "name", type(app).name), `getattr(mod, "file", None),  Приватный набор состоит из: MAC адреса интерфейса в десятичной системе machine_id  Далее эти два набора байт проходят через цикл и хешируются алгоритмом sha1.  Сразу после этого цикла на основе результата хеширования генерируется имя куки, которое будет присваиваться пользователю после входа в консоль.  Важно заметить, что генерируется именно имя куки, а не значение. Ее имя будет постоянное, а с генерацией значения мы разберемся чуть позже. Строка, в которой происходит назначение имени куки:  Значения переменной h после хеширования, зеленым цветом выделено значение, которое берется как значение имени куки:  Далее идет заключающий цикл, где пину придается окончательный вид.  Результат цикла:  Имя текущего пользователя можно получить несколькими способами: Чтение файла /proc/self/cgroup Чтение файла /etc/passwd По дефолту стоит <flask.app>, скорее всего менять не придется  Стандартное значение содержащее значение Flask Путь до flask  Скрин на котором видны названные выше переменные:  Путь до приложения Flask можно получить ввестя любой некорректный шаблон или любые некорректные данные в функцию, после которого Flask выдаст вам ошибку, в ней и будет указан путь до flask.  При получении интерфейса могут возьникнуть небольшие проблеммы, если этих интерфейсов несколько. Тут стоит пропробовать все интерфейсты, которые имеют доступ к интернету. Поэтому если у вас не подходит deubg pin, то попробуйте сменить интерфейс. Список доступных интерйесов вы можете увидеть с помощью чтения файла /proc/net/dev. А вот MAC адрес интерфейста можно увидеть с помощью файла /sys/class/net/INT/address, где INT - любой интерфейс. Этот байт состоит из нескольких частей: Полное содержимое файла /etc/machine-id(если он есть, в ином случае /proc/sys/kernel/random/boot_id) Часть файла после последнего слеша /proc/self/cgroup Итого в конце герации цикла мы имеем следующие переменные:  Начало генерации куки идет еще с функции get_pin_and_cookie_name, которая в конечном результате возвращает нам значения имени куки, а также пин. Генерация имени куки.  Генерация значения куки. Генерация значения куки просходит в фалйе __init__.py  и состоит из хеша пина и времени в формате UNIX time.  PIN хешируется алгоритом sha1 в функции hash_pin, но стоит заметить, что хешируется не только PIN, а строка содержащая его: "<YOUR PIN> added salt".   Значение сгенерированное в данной функции: 2d97afcb1caf  После соединения всего воедино получаем следующее: Давайте представим, что код данной страницы выглядит чуть сложнее, чем в прошлом примере. Практически ничего не изменилось, но появилась уязвимость, позволяющая читать любые файлы, так как нет никакой фильтрации ввода: Запускаем наш сервер и видим, что в данный момент пином является следующее значение(633-204-910):  На данным момент наша задача представить, что мы являемся злоумышленником и попытаться получить доступ к удаленному отладчику для последующего получения доступа к системе. Теперь, имея доступ к чтению файлов на системе, мы сможем самостоятельно сгенерировать пин и получить доступ к отладчику. Для более удобной генерации пина, я написал небольшой скрипт, может кому-нибудь облегчит жизнь) ссылка:  В данный момент нам необходимо прочитать череду файлов, для получения нужных значений, используемых в процессе генерации. Еще раз приведу ниже значения, которые нам понадобяться: Публичный набор: Username Modname `getattr(app, "name", type(app).name), `getattr(mod, "file", None), Приватный набор: MAC machine_id Всего 6 значений, но некоторые из них имеют стандартные значения, или их очень легко получить, например: getattr(app, "__name__", type(app).__name__),  по умолчанию имеет значение Flask getattr(mod, "__file__", None),  путь до Flask, который мы может легко получить, вызвав любую ошибку, например: в функции чтения файлов вместо ожидаемого на вход файла введем директорию /. В результате получаем ошибку и еще одно значение(/home/user/.local/lib/python3.11/site-packages/flask/app.py), которое нам понадобится для дальнейшей генерации пина.  Modname тоже имеет стандартное значение: flask.app Для получения дальнейших значений будет необходим доступ к чтению файлов Тут в первую очередь стоит попробовать пользователя www-data, ну или же попробовать всех пользователей, которые есть в файле /etc/passwd. В данном случае в файле /etc/passwd есть только 3 пользователя, которые могут запустить данный сервер: Тут стоит обратить внимание на значение, которое мы получили в предыдущем этапе(/home/**user**/.local/lib/python3.11/site-packages/flask/app.py). В нем уже есть намек от имени какого пользователя запущен сервер. В этом и следующем этапе получение данных не такое простое, их нельзя получить из открытых источников, а так же они обычно всегда уникальные. Получение MAC'а делиться на 2 этапа: Получение имени сетевого интерфейса Получение MAC'а для данного интерфейса Получить имена всех сетевых интерфейсов можно прочитав файл /proc/net/dev На скрине ниже видно, что трафик идет только на интерфейсе wlan0, следовательно скорее всего он нам и нужен  Получить MAC для любого интерфеса можно прочитав файл /sys/class/net/INT/address, где INT - имя интерфейса  Последняя часть, необходимая для генерации пина это machine_id Его получение так же делится на 2 этапа: Прочитать файл /etc/machine_id Прочитать файл /proc/self/cgroup На самом деле нам нужно не все содержимое этих файлов(это было описано в части "Анализ исходного кода"), но для корректной работы моего скрипта требуется ввести полное содержимое файлов. Получение значений:  Теперь нам остется только подствить данные значения в скрипт и сгенерировать этот пин. Команда, которая сгенерирует данный пин по данным выше значениям: `python3 gen.py --appname Flask --path /home/user/.local/lib/python3.11/site-packages/flask/app.py --modname flask.app --username user --mac fc:44:82:9d:ba:02 --machine_id b643ebdac5ee44789d21e98a03ce4bb5 --cgroup 0::/user.slice/user-1000.slice/session-2.scope Результат:  Вуаля! Пин, который выдал сервер разработчику и наш сгенерированный пин одинаковые, а это значит, что теперь мы можем получить доступ к отладочной консоли и выполнить произвольный код! Как говорилось ранее, обычно консоль находится по адресу: http://127.0.0.1:5000/console и при входе в консоль нас встречает окошко с просьбой ввести PIN. После ввода которого мы и получим выполнение произвольного кода.  Исполним следующее выражение, где вместо CMD может быть любая команда: Команды на сервере успешно выполняются! А это значит, что мы из чтения файлов получили полноценный удаленный доступ к системе. При введении некорректного PIN'а, мы обычно получаем следующий ответ:  Но если попыток неправльного входа будет слишком много, то переменная exhausted изменяется на true:  Сообщение, которое вы увидите в браузере:  Даже если мы после попробуем ввести корректный пин, то нам выдаст ошибку:  Чтобы обойти это мы должны использовать ранее сгенерированную куку: Cookie: __wzdb0b4cd30605c88d2470b=1681556351|2d97afcb1caf. Также нужно изменить параметр &pin=... на &frm=0. После этого мы сможем успешно выполнить код.  В данной статье мы разобрали как можно с помощью уязвимости чтения файлов получить доступ к интерактивной консоли Python. Как итог: включение режима отладки в приложении Flask может открыть уязвимости, так как в этом режиме приложение будет выводить подробную информацию об ошибках, включая трассировку стека и значения переменных. Это может быть полезно для разработки и отладки приложения, но может также предоставить злоумышленникам ценную информацию о структуре приложения и его уязвимостях.  Злоумышленнику может получить доступ к интерактивной консоли Python и выполнить произвольный код в контексте приложения. Это может привести к компрометации данных пользователей, утечке конфиденциальной информации и другим серьезным последствиям. Поэтому рекомендуется отключать режим отладки в приложениях Flask на продакшен-серверах и использовать его только для разработки и отладки на локальной машине. На этом у меня все, если есть вопросы или предложения, то прошу не стесняться и писать мне в телеграм или на почту. telegram: https://t.me/SidneyJobChannel mail: SidneyJob13@gmail.com