Краткое содержание

углубленный анализ 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.

Изменение патчей

ссылка: https://github.com/python/cpython/pull/99421/commits/a284d69de1d1a42714576d4a9562145a94e62127

модификация библиотеки заключалась в добавлении

test_attributes_bad_scheme функция, которая проверяет, циклически перебирая диапазон возможных недопустимых значений.

схемы сценариев, включая ".", "+", "-", "0", "http&" и не-ascii, чтобы предотвратить обход с использованием пробела, как в предыдущем случае.

эксплуатация

смягчение последствий

Обновите Python до последней версии 3.11.4

Последние мысли

углубившись в исходный код библиотеки Python urllib и отладив библиотеку, мы посмотрим, могут ли быть простые ошибки

оказать существенное влияние, поскольку мы видим, что простая планка может обойти любой черный список

Ссылка:



Присоединяйтесь к vsociety: https://vsociety.io/

Проверьте наш дискорд: https://discord.gg/sHJtMteYHQ