Краткое содержание
углубленный анализ CVE-2023–24329
Описание
CVE: CVE-2023–24329.
Описание. Проблема в компоненте urllib.parse
Python до версии 3.11.4 позволяет злоумышленникам обходить методы внесения в черный список, предоставляя URL-адрес, который начинается с пробелов.
Поставщик: Фонд программного обеспечения Python
Версия: => 3.11.3
Предыстория
Python — самый популярный язык программирования в мире. Эксплойт CVE-2023–24329 довольно прост, но его влияние очень велико.
важно, поскольку библиотека urllib.parse
используется во многих веб-приложениях для предотвращения атак с использованием черных списков, таких как
инъекция и загрузка файлов. Когда эта библиотека сломана, злоумышленники могут манипулировать входными данными и обходить фильтры.
ошибка затрагивает любую версию до 3.11.4
, я использую версию python3 3.11.3
, которая является последней версией перед патчем
Воспроизведение уязвимости
urllib.parse
разбивает строки URL-адреса (унифицированный указатель ресурсов) на такие компоненты, как схема (файл, FTP, HTTP, HTTP).
который используется в URL-адресе, поэтому при анализе URL-адреса с URL-адресом example.com
[1] в обычном случае функция urlparse
определяет схему предоставленного URL-адреса и используется для предотвращения LFI (файла).
[2] если пользователь добавит пробел в функцию, он сосредоточится на обнаружении схемы, которая рассматривает схему URL-адреса с пробелом, как показано ниже.
Демонстрация сценария эксплуатации
Я создал простое веб-приложение, чтобы продемонстрировать использование этой CVE в случае, если библиотека используется для предотвращения LFI (локального файла).
Включение) с использованием библиотеки Flask, которую легко можно установить с помощью pip3 install flask
с помощью urllib
с двумя файлами app.py
и
index.html
- app.py
from flask import Flask, render_template, request import urllib.request import urllib.error app = Flask(__name__) def safeURLOpener(inputLink): block_schemes = ["file", "gopher", "expect", "php", "dict", "ftp", "glob", "data"] block_host = ["instagram.com", "youtube.com", "tiktok.com"] input_scheme = urllib.parse.urlparse(inputLink).scheme input_hostname = urllib.parse.urlparse(inputLink).hostname if input_scheme in block_schemes: return "Input scheme is forbidden" if input_hostname in block_host: return "Input hostname is forbidden" try: target = urllib.request.urlopen(inputLink) content = target.read().decode('utf-8') return content except urllib.error.URLError as e: return "Error opening URL: " + str(e) @app.route('/', methods=['GET', 'POST']) def index(): content = "" error = None if request.method == 'POST': domain = request.form.get('domain') if domain: content = safeURLOpener(domain) return render_template('index.html', content=content, error=error) if name == '__main__': app.run(debug=True)
- Индекс.html
<!DOCTYPE html> <html> <head> <title>Domain Content Viewer</title> </head> <body> <h1>Domain Content Viewer</h1> <form method="post"> <label for="domain">Enter a domain:</label> <input type="text" name="domain" id="domain" value="{{ request.form['domain'] }}"> <button type="submit">Submit</button> </form> {% if content %} <h2>Content:</h2> <pre>{{ content }}</pre> {% endif %} {% if error %} <h2>Error:</h2> <p>{{ error }}</p> {% endif %} </body> </html>
запустите приложение, используя python3
который по умолчанию работает на 127.0.0.1:5000
в случае отправки общей полезной нагрузки LFI file:c:\WINDOWS\win.ini
на базе Windows
приложение вернуло код Input schema is forbidden
, поскольку схема file
заблокирована черным списком
После добавления пробела в URL-адрес черный список приложений не смог обнаружить URL-адрес schema
и вызвал обход
черный список
Настройка среды отладки
уязвимая библиотека: https://github.com/python/cpython/tree/3.11/Lib/urllib
from urllib.parse import urlparse url_to_parse = " https://www.vicarius.io/" output = urlparse(url_to_parse) print(output)
затем добавьте точку останова в строку, которая использует функцию для запуска уязвимой функции.
запустите отладчик, нажав кнопку отладчика на панели инструментов
После запуска отладчика и входа в него, чтобы позволить IDE перейти к исходному коду установленной версии Python в
машине, значением по умолчанию в Windows является C:\Users\yosef\AppData\Local\Programs\Python\Python39\Lib\urllib
.
Похоже, что он вызывает функцию urlparse
, которая существует в файле parse.py
.
urlparse
Функция urlparse
сначала разбивает предоставленный аргумент на две части
scheme
и
URl
установил пустую строку (схема='') по умолчанию и заданную
URL-адрес. Затем функция приступает к анализу аргумента
передав его в функцию _coerce_args
_coerce_args
_coerce_args
функция проверяет, является ли данный аргумент строкой
вернуть noop
, а если нет, то выдать ошибку Cannot nix str and non-str arguments
затем urlparse
вызовите urlspilt
, чтобы передать заданный URL-адрес в scheme
, netloc
(сетевое расположение), url
, query
и fragment
.
urlsplilt
urlsplilt
есть все важные работы, в которых используются
UNSAFE_URL_BYTES_TO_REMOVE
переменная, как показано ниже, для удаления '\t', '\r', '\n'
предотвращения инъекции
Первопричина
for c in url[:i]
, который проверяет наличие символов в первой части URL-адреса перед двоеточием (схема файла), используя url.find(':')
для
все символы, если c
среди допустимых символов, существующих в переменной scheme_chars
, как показано ниже:
если символы c существовали в scheme_chars
, код продолжит работу и сохранит его как компонент scheme
, а также основную причину этого CVE, когда код не может получить schema
, обработка кода без получения схемы, как показано в трассировке стека ниже:
а затем проверяет наличие netloc
, который начинается с номера строки 380
в коде, проверяющего часть перед //
, и проверяет, есть ли []
не существует в формате URL-адреса IPv6, возникает ошибка Invalid IPv6 URL
, затем проверяется наличие фрагментов (разделы, обозначенные #
)
а затем запрос и передать функцию netloc
в _checknetloc()
и для _checknetloc(netloc)
Функция _checknetloc()
обрабатывает сетевое местоположение, сначала проверяя, состоит ли оно из символов ASCII или нет. Затем он приступает к замене таких символов, как «@», «:», «#» и «?». и нормализует полученную строку. После этого функция проверяет, существуют ли эти символы; если они это сделают, выдается ошибка
а затем сохраняет переменную parseResult
, которая отображается под изображением кода, обработанного без получения
Компоненты schema
и netloc
и сохраните URL-адрес в path
.
Изменение патчей
модификация библиотеки заключалась в добавлении
test_attributes_bad_scheme
функция, которая проверяет, циклически перебирая диапазон возможных недопустимых значений.
схемы сценариев, включая ".", "+", "-", "0", "http&"
и не-ascii, чтобы предотвратить обход с использованием пробела, как в предыдущем случае.
эксплуатация
смягчение последствий
Обновите Python до последней версии 3.11.4
Последние мысли
углубившись в исходный код библиотеки Python urllib
и отладив библиотеку, мы посмотрим, могут ли быть простые ошибки
оказать существенное влияние, поскольку мы видим, что простая планка может обойти любой черный список
Ссылка:
Присоединяйтесь к vsociety: https://vsociety.io/
Проверьте наш дискорд: https://discord.gg/sHJtMteYHQ