Yesterday

День 34. Race Conditions

Условия гонки - Узнайте о состояниях гонки и о том, как они влияют на безопасность веб-приложений.

1. Введение

Допустим, нам поручено протестировать безопасность веб-приложения для онлайн-покупок. Возникает множество вопросов. Можно ли использовать одну и ту же подарочную карту на 10 долларов для оплаты товара стоимостью 100 долларов? Можно ли применить одну и ту же скидку к корзине покупок несколько раз? Ответ: возможно ! Если система подвержена уязвимости типа «гонка состояний», мы можем сделать всё это и многое другое.

В этом разделе рассматривается уязвимость, связанная с состоянием гонки. Состояние гонки — это ситуация в компьютерных программах, когда время событий влияет на поведение и результат программы. Обычно это происходит, когда к переменной обращаются и изменяют её несколько потоков. Из-за отсутствия надлежащих механизмов блокировки и синхронизации между различными потоками злоумышленник может злоупотребить системой и применить скидку несколько раз или совершить денежные транзакции, превышающие его баланс.

Цели обучения

После прохождения этого раздела вы узнаете следующее:

  • Уязвимость к условиям гонки
  • Использование Burp Suite Repeater для эксплуатации состояний гонки

В процессе обучения вы также узнаете о:

  • Потоки и многопоточность
  • Диаграммы состояний

Предварительные условия обучения

Для успешного прохождения этого курса рекомендуется ознакомиться с протоколом HTTP , веб-приложениями и Burp Suite . Для восполнения пробелов в знаниях рекомендуется пройти следующие курсы и модули.

2. Многопоточность

В этом задании мы кратко рассмотрим следующие термины:

  • Программа
  • Процесс
  • Нить
  • Многопоточность

Программы

Программа это набор инструкций для выполнения определенной задачи. Для достижения желаемого результата необходимо выполнить программу. Без выполнения она ничего не сделает и останется набором статических инструкций.

Представьте это как рецепт; вы только что скачали новый рецепт кофе, в котором используются различные травы, такие как кардамон и корица. Вот инструкция:

1. Combine brewed coffee, cardamom, cinnamon, and cloves (if using) in a saucepan.
2. Heat the mixture over low heat for 5 minutes, stirring occasionally. Do not boil.
3. Strain the coffee into your mug.
4. Add milk if desired, and sweeten to taste with honey or sugar.

Если кто-либо не выполнит вышеуказанные инструкции, кофе подаваться не будет!

Сравните это с нашим минимальным сервером Flask (Python) «Hello, World!». Приведенный ниже код указывает, что приложение будет прослушивать порт 8080 и отвечать минимальной приветственной HTML-страницей, содержащей «Hello, World!». Однако, прежде чем ожидать получения каких-либо приветственных страниц, необходимо выполнить эти инструкции (программу).

Обратите внимание, что приведенный ниже код Flask предназначен только для демонстрационных целей. Мы не предоставили среду для его запуска, поскольку это выходит за рамки данной темы.

# Import the Flask class from the flask module
from flask import Flask

# Create an instance of the Flask class representing the application
app = Flask(__name__)

# Define a route for the root URL ('/')
@app.route('/')
def hello_world():
    # This function will be executed when the root URL is accessed
    # It returns a string containing HTML code for a simple web page
    return '<html><head><title>Greeting</title></head><body><h1>Hello, World!</h1></body></html>'

# This checks if the script is being run directly (as the main program)
# and not being imported as a module
if __name__ == '__main__':
    # Run the Flask application
    # The host='0.0.0.0' allows the server to be accessible from any IP address
    # The port=8080 specifies the port number on which the server will listen
    app.run(host='0.0.0.0', port=8080)

Процессы

Однажды днем ​​вы решаете попробовать новый рецепт кофе, который скачали из интернета. Вы начинаете выполнять рецепт шаг за шагом. Вы находитесь в процессе приготовления этого кофе. Во время «выполнения» «инструкций» вас может прервать срочный звонок. Или вы можете заняться другой «работой», ожидая, пока нагреется вода. Перерывы и ожидание, как правило, неизбежны. Выполнение инструкций рецепта для приготовления кофе похоже на выполнение инструкций программы.

Процесс — это программа , находящаяся в процессе выполнения. В некоторых источниках можно встретить термин «задание» . Оба термина обозначают одно и то же, хотя термин «процесс» вытеснил термин «задание». В отличие от программы, которая является статической, процесс — это динамическая сущность. Он обладает несколькими ключевыми аспектами, в частности:

  • Программа : исполняемый код, относящийся к процессу.
  • Память : временное хранилище данных.
  • Состояние : Процесс обычно переходит между различными состояниями. После того, как он находится в состоянии «Новый», то есть только что создан, он переходит в состояние «Готов», то есть готов к выполнению после получения процессорного времени. Как только процессор выделит для него время, он переходит в состояние «Выполняется». Кроме того, он может находиться в состоянии «Ожидание», ожидая завершения операций ввода-вывода или событий. После завершения он переходит в состояние «Завершено».

Если вы запустите приведенный выше код Flask, будет создан процесс, который будет прослушивать входящие соединения на порту 8080. Другими словами, большую часть времени он будет находиться в состоянии ожидания (Waiting). Получив HTTP- GET /запрос, он переключится в состояние готовности (Ready), ожидая своей очереди на выполнение в соответствии с планированием ЦП . После перехода в состояние выполнения (Running) он отправит HTML-страницу клиенту и вернется в состояние ожидания (Waiting).

С точки зрения сервера, приложение обслуживает клиентов последовательно, то есть запросы клиентов обрабатываются по одному. (Обратите внимание, что Flask по умолчанию многопоточный, начиная с версии 1.0. Мы использовали аргумент --without-threadsдля принудительного запуска в однопоточном режиме.)

Обратите внимание, что приведенная ниже команда Flask носит исключительно демонстрационный характер.

Терминал

$ flask run --without-threads --host=0.0.0.0
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://192.168.0.104:5000
Press CTRL+C to quit
127.0.0.1 - - [16/Apr/2024 23:34:46] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [16/Apr/2024 23:34:48] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [16/Apr/2024 23:35:11] "GET / HTTP/1.1" 200 -

Нити

В заключение еще одна кофейная аналогия! Рассмотрим случай с профессиональной эспрессо-машиной в кофейне. Допустим, у нее два портафильтра. В начале рабочего дня бариста включает эспрессо-машину, и всякий раз, когда клиент заказывает эспрессо, для приготовления порции используется один портафильтр. Заказывает ли эспрессо другой клиент? Нет проблем, на помощь приходит второй портафильтр! Разогретая эспрессо-машина — это процесс; каждому новому заказу назначается свой портафильтр; это аналогия для всей дискуссии.

Поток — это легковесная единица выполнения. Он разделяет с процессом различные части памяти и инструкции.

Во многих случаях нам приходится многократно повторять один и тот же процесс. Представьте себе веб-сервер, обслуживающий тысячи пользователей одной и той же страницей (или персонализированной страницей). Мы можем использовать один из двух основных подходов:

  • Последовательный режим: запущен один процесс, который последовательно обслуживает пользователей одного за другим. Новые пользователи добавляются в очередь.
  • Параллельный режим: работает один процесс; он создает поток для обслуживания каждого нового пользователя. Новые пользователи добавляются в очередь только после достижения максимального количества запущенных потоков.

Предыдущее приложение может работать в четырех потоках с использованием Gunicorn. Gunicorn, также называемый «Зеленым Единорогом», — это HTTP- сервер WSGI на Python . WSGI расшифровывается как Web Server Gateway Interface (интерфейс шлюза веб-сервера), который соединяет веб-серверы и веб-приложения на Python. В частности, Gunicorn может запускать несколько рабочих процессов для одновременной обработки входящих запросов. Запуская приложение gunicornс --workers=4опцией, мы указываем, что нам нужны четыре рабочих процесса, готовых обрабатывать запросы клиентов; кроме того, --threads=2указывает, что каждый рабочий процесс может запускать два потока.

Обратите внимание, что приведенная ниже команда Gunicorn предназначена только для демонстрационных целей. Мы не предоставили среду для ее запуска, поскольку это выходит за рамки данной темы.

Терминал

gunicorn --workers=4 --threads=2 -b 0.0.0.0:8080 app:app
[2024-04-16 23:35:59 +0300] [507149] [INFO] Starting gunicorn 21.2.0
[2024-04-16 23:35:59 +0300] [507149] [INFO] Listening at: http://0.0.0.0:8080 (507149)
[2024-04-16 23:35:59 +0300] [507149] [INFO] Using worker: gthread
[2024-04-16 23:35:59 +0300] [507150] [INFO] Booting worker with pid: 507150
[2024-04-16 23:35:59 +0300] [507151] [INFO] Booting worker with pid: 507151
[2024-04-16 23:35:59 +0300] [507152] [INFO] Booting worker with pid: 507152
[2024-04-16 23:35:59 +0300] [507153] [INFO] Booting worker with pid: 507153

Стоит отметить следующее:

  • Запустить более одной копии этого процесса невозможно, поскольку он привязывается к TCP- порту 8080. К TCP- или UDP- порту может быть привязан только один процесс.
  • Процесс можно настроить с любым количеством потоков, и HTTP- запросы, поступающие на порт 8080, будут отправляться различным потокам.

Вопрос: Вы скачали инструкцию по изготовлению журавлика оригами. Как бы выглядела эта инструкция с точки зрения компьютерной графики?

Ответ: Program

Вопрос: Как называется состояние, в котором процесс ожидает события ввода-вывода?

Ответ: Waiting

3. Условия гонки

Аналогия с реальным миром

Представьте следующую ситуацию. Вы звоните в ресторан, чтобы забронировать столик для важного делового обеда. Вы знакомы с рестораном и его обстановкой. Один конкретный столик, номер 17, — ваш предпочтительный выбор, поскольку из него открывается хороший вид и он находится в относительно уединенном месте. Вы звоните, чтобы забронировать столик № 17; администратор подтверждает, что он свободен, так как на нем нет метки «Забронировано». В то же время другой клиент разговаривает с другим администратором и бронирует тот же столик.

Кто на самом деле забронировал столик? Это уже вопрос расовой принадлежности. (что? эм скорее это проблема перевода... ну или нет))

Почему это произошло? Эта неприятная ситуация возникла из-за того, что бронированием занимались несколько хостесс; кроме того, хостесс потребовалось несколько минут, чтобы достать бирку «Забронировано» и положить её на стол после обновления ежедневной книги бронирований. У другого клиента есть как минимум минута, чтобы забронировать зарезервированный столик.

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

Пример А

Рассмотрим следующий сценарий:

  • На банковском счете 100 долларов.
  • Два потока пытаются одновременно вывести деньги.
  • Первый поток проверяет баланс (видит 100 долларов) и снимает 45 долларов.
  • Перед тем как поток 1 обновит баланс , поток 2 также проверит баланс (ошибочно увидит 100 долларов) и выведет 35 долларов.

Мы не можем быть на 100% уверены, какой поток первым обновит остаток средств; однако предположим, что это будет Поток 1. Поток 1 установит остаток средств на уровне 55 долларов. После этого Поток 2 может установить остаток средств на уровне 65 долларов, если это не будет обработано должным образом. (Поток 2 рассчитал, что после снятия средств на счете должно остаться 65 долларов, поскольку на момент проверки Потоком 2 баланс составлял 100 долларов.) Другими словами, пользователь совершил два снятия средств, но остаток на счете был списан только за второе, потому что так решил Поток 2!

Пример Б

Рассмотрим другой сценарий:

  • На банковском счету 75 долларов.
  • Два потока пытаются одновременно вывести деньги.
  • Первый поток проверяет баланс (видит 75 долларов) и снимает 50 долларов.
  • Перед тем как поток 1 обновит баланс , поток 2 проверит баланс (ошибочно увидит 75 долларов) и выведет 50 долларов.

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

Примеры A и B демонстрируют уязвимость, связанную с преобразованием данных о времени проверки в данные о времени использования (TOCTOU).

Пример кода

Рассмотрим следующий код на Python с двумя потоками, имитирующими завершение задачи с шагом в 10%.

import threading

x = 0  # Shared variable

def increase_by_10():
    global x
    for i in range(1, 11):
        x += 1
        print(f"Thread {threading.current_thread().name}: {i}0% complete, x = {x}")

# Create two threads
thread1 = threading.Thread(target=increase_by_10, name="Thread-1")
thread2 = threading.Thread(target=increase_by_10, name="Thread-2")

# Start the threads
thread1.start()
thread2.start()

# Wait for both threads to finish
thread1.join()
thread2.join()

print("Both threads have finished completely.")

Эти два потока запускаются одновременно; они ничего не делают, кроме вывода значения на экран. Следовательно, можно было бы ожидать, что они завершатся одновременно, или, по крайней мере, результат будет согласованным. Однако в приведенной выше программе нет гарантии, какой поток завершится первым и как скоро это произойдет. Ниже приведен результат первого выполнения:

Терминал

python t3_race_to_100.py
...
Thread Thread-1: 40% complete, x = 10
Thread Thread-2: 70% complete, x = 11
Thread Thread-1: 50% complete, x = 12
Thread Thread-2: 80% complete, x = 13
Thread Thread-1: 60% complete, x = 14
Thread Thread-1: 70% complete, x = 16
Thread Thread-2: 90% complete, x = 15
Thread Thread-2: 100% complete, x = 17
Thread Thread-1: 80% complete, x = 18
Thread Thread-1: 90% complete, x = 19
Thread Thread-1: 100% complete, x = 20
Both threads have finished completely.

Ниже представлен второй результат выполнения:

Терминал

python t3_race_to_100.py 
...
Thread Thread-1: 70% complete, x = 10
Thread Thread-2: 40% complete, x = 11
Thread Thread-1: 80% complete, x = 12
Thread Thread-2: 50% complete, x = 13
Thread Thread-1: 90% complete, x = 14
Thread Thread-2: 60% complete, x = 15
Thread Thread-1: 100% complete, x = 16
Thread Thread-2: 70% complete, x = 17
Thread Thread-2: 80% complete, x = 18
Thread Thread-2: 90% complete, x = 19
Thread Thread-2: 100% complete, x = 20
Both threads have finished completely.

Многократный запуск этой программы приведет к различным результатам. В первой попытке поток Thread-2 достиг 100 первым; однако во второй попытке поток Thread-2 достиг 100 вторым. Мы не можем контролировать результат. Если безопасность нашего приложения зависит от того, завершится ли один поток раньше другого, то нам необходимо внедрить механизмы для обеспечения надлежащей защиты. Рассмотрим следующие два примера, чтобы лучше понять серьезность ошибок, возникающих, когда мы полагаемся на случай.

На платформе AttackBox вы можете сохранить приведенный выше код Python и запустить его несколько раз, чтобы понаблюдать за результатом. Например, если вы сохранили его как race.py, вы можете запустить скрипт с помощью python race.pyкоманды.

Причины

Как мы видели в предыдущей программе, два потока изменяли одну и ту же переменную. Всякий раз, когда потоку предоставлялось процессорное время, он стремился увеличить значение xна 1. В результате эти два потока «соревновались» в увеличении одной и той же переменной. Эта программа демонстрирует простой пример, происходящий на одном хосте.

В целом, распространенной причиной состояний гонки являются совместно используемые ресурсы. Например, когда несколько потоков одновременно обращаются к одним и тем же общим данным и изменяют их. Примерами совместно используемых данных являются запись в базе данных и структура данных в оперативной памяти. Существует множество более тонких причин, но мы упомянем три наиболее распространенных:

  • Параллельное выполнение : Веб-серверы могут выполнять несколько запросов параллельно для обработки одновременных взаимодействий с пользователями. Если эти запросы обращаются к общим ресурсам или состояниям приложения и изменяют их без надлежащей синхронизации, это может привести к состояниям гонки и непредсказуемому поведению.
  • Операции с базой данных : Параллельные операции с базой данных, такие как последовательности чтения-изменения-записи, могут приводить к состояниям гонки. Например, попытка двух пользователей одновременно обновить одну и ту же запись может привести к несогласованности данных или конфликтам. Решение заключается в обеспечении надлежащих механизмов блокировки и изоляции транзакций.
  • Сторонние библиотеки и сервисы : В настоящее время веб-приложения часто интегрируются со сторонними библиотеками, API и другими сервисами. Если эти внешние компоненты не предназначены для надлежащей обработки одновременного доступа, при одновременном взаимодействии нескольких запросов или операций могут возникать состояния гонки.

Вопрос: Гарантирует ли представленный скрипт на Python, какой поток первым достигнет 100% выполнения? (Да/Нет)

Ответ: Nay


Вопрос: Как называется поток, который первым достиг 100% при втором выполнении скрипта на Python?

Ответ: Thread-1

4. Архитектура веб-приложения

Давайте рассмотрим архитектуру веб-приложений, чтобы объяснить, как могут возникать состояния гонки.

Клиент-серверная модель

Веб-приложения работают по клиент-серверной модели:

  • Клиент : Клиентом является программа или приложение, инициирующее запрос на предоставление услуги. Например, когда мы просматриваем веб-страницу, наш веб-браузер запрашивает веб-страницу (файл) у веб-сервера.
  • Сервер : Сервер — это программа или система, которая предоставляет эти услуги в ответ на входящие запросы. Например, веб-сервер отвечает на входящий HTTP- GET запрос и отправляет HTML-страницу (или файл) запрашивающему веб-браузеру (клиенту).

В общем случае, клиент-серверная модель работает по сети. Клиент отправляет свой запрос по сети, а сервер получает его и обрабатывает, прежде чем отправить обратно необходимый ресурс.

Типичное веб-приложение

Веб-приложение имеет многоуровневую архитектуру. Такая архитектура разделяет логику приложения на разные слои или уровни. Наиболее распространенная архитектура использует три уровня:

  • Уровень представления : В веб-приложениях этот уровень состоит из веб-браузера на стороне клиента. Веб-браузер отображает код HTML, CSS и JavaScript.
  • Уровень приложения : Этот уровень содержит бизнес-логику и функциональность веб-приложения. Он получает запросы от клиентов, обрабатывает их и взаимодействует с уровнем данных. Он реализован с использованием серверных языков программирования, таких как Node.js и PHP , а также многих других.
  • Уровень данных : Этот уровень отвечает за хранение и обработку данных приложения. Типичные операции с базой данных включают создание, обновление, удаление и поиск существующих записей. Обычно это достигается с помощью системы управления базами данных (СУБД); примерами СУБД являются MySQL и PostgreSQL.

Штаты

Прежде чем углубляться в тему, рассмотрим несколько примеров из области бизнес-логики. Рассмотрим следующие примеры:

  • Проверка и осуществление денежных переводов.
  • Проверка промокодов и применение скидок.

Проверка и осуществление денежных переводов

Рассмотрим пример перевода денег другу или на другой свой счет. Программа будет работать следующим образом:

  1. Пользователь нажимает кнопку «Подтвердить перевод».
  2. Приложение запрашивает данные из базы данных, чтобы подтвердить, что баланс счета покрывает сумму перевода.
  3. База данных отвечает на запрос.
    1. Если сумма находится в пределах лимитов счета, приложение выполняет транзакцию.
    2. Если сумма превышает лимит счета, приложение выдает сообщение об ошибке.

В идеальном случае приведенный выше код приводит к двум состояниям программы:

  • Сумма не отправлена
  • Отправленная сумма

Проверка промокодов и применение скидок.

Рассмотрим пример применения купона на скидку. Пользователь заходит в корзину и добавляет купон, чтобы получить скидку. Последовательность действий может выглядеть примерно так:

  1. Пользователь вводит промокод
  2. Приложение запрашивает данные из базы данных, чтобы определить, действителен ли промокод и существуют ли какие-либо ограничения.
  3. База данных отвечает, указывая на достоверность и ограничения.
    1. Скидка применяется, если код действителен и нет ограничений на его применение для данного пользователя.
    2. Если код недействителен или существуют ограничения на его применение для данного пользователя, отображается сообщение об ошибке.

Приведённый выше код приводит к нескольким состояниям программы:

  • Купон не применен
  • Купон применен

Два штата? Подумайте ещё раз.

Продолжим анализ применения купона на скидку. В идеале мы ожидаем два состояния: «Купон не применен» и «Купон применен» . Однако это слишком упрощенно для описания реальных сложных сценариев. Мы можем добавить промежуточное состояние: «Проверка применимости купона» .

В зависимости от способа разработки приложения можно ожидать больше состояний. Например, проверка применимости купона может включать два состояния: проверка действительности купона и проверка ограничений купона . Купон может быть действителен, но существующие ограничения не позволяют его использовать. Аналогично, применение купона может быть разделено на два состояния, одно из которых — перерасчет общей суммы .

Почему это важно для условий гонки?

На приведенной выше диаграмме состояний видно, что мы проходим через несколько состояний, прежде чем купон будет помечен как примененный. Давайте изобразим состояния на временной оси, как показано ниже.

Между моментом попытки добавления купона и моментом, когда купон помечается как примененный и его нельзя применить повторно, существует временной промежуток. Пока купон не помечен как примененный, скорее всего, никакие механизмы контроля не препятствуют его многократному использованию. В течение этого временного промежутка мы можем использовать его несколько раз.

Аналогичная ситуация наблюдается и при рассмотрении состояний программы, осуществляющей денежный перевод. Хотя в идеале должно быть два состояния, с учетом бизнес-логики мы можем легко обновить диаграмму, включив в нее три состояния. Причина в том, что мы ожидаем некоторого времени, затрачиваемого на проверку баланса счета и лимитов; хотя это время может быть небольшим, оно не равно нулю. Если мы копнем глубже, мы сможем обнаружить больше «скрытых» состояний.

Однако, даже если веб-приложение уязвимо, нам все равно предстоит преодолеть одну проблему: временные рамки. Даже в уязвимых приложениях это «окно возможностей» относительно короткое; поэтому для его использования необходимо, чтобы наши запросы достигали сервера одновременно. На практике мы стремимся к тому, чтобы наши повторные запросы достигали сервера с интервалом всего в миллисекунды.

Как нам добиться того, чтобы дублирующиеся запросы достигали сервера в течение этого короткого промежутка времени? Нам нужен такой инструмент, как Burp Suite .

Вопрос: Сколько состояний содержала исходная схема состояний «проверка и осуществление денежных переводов»?

Ответ: 2

Вопрос: Сколько состояний содержала обновленная схема состояний «проверка и осуществление денежных переводов»?

Ответ: 3

Вопрос: Сколько состояний содержала итоговая диаграмма состояний «проверка кодов купонов и применение скидок»?

Ответ: 5

5. Использование условий гонки

Нажмите кнопку «Запустить машину» справа, чтобы запустить подключенную виртуальную машину . Нажмите кнопку «Запустить AttackBox» вверху, чтобы запустить AttackBox. В AttackBox перейдите по адресу http://MACHINE_IP:8080.

Это учетные данные двух пользователей:

  • Пользователь1:07799991337
  • Пароль:pass1234

И

  • Пользователь2:07113371111
  • Пароль:pass1234

Это веб-приложение принадлежит мобильному оператору и позволяет переводить средства на счет телефона. В этой демонстрации мы проверим, подвержена ли система уязвимости типа «гонка», и попытаемся использовать её, переведя больше средств, чем у нас есть на счету.

Для начала нам нужно изучить, как целевое веб-приложение получает HTTP-запросы и как оно на них отвечает. Используя Burp Suite Proxy , нажмите «Открыть браузер» на вкладке «Перехват» . (Если вы получите сообщение об ошибке, связанное с включением песочницы браузера, вам необходимо вручную изменить настройки. В этом случае нажмите «Настройки» в правом верхнем углу окна Burp Suite, выберите браузер Burp в разделе «Инструменты» и установите флажок « Разрешить браузеру Burp работать без песочницы» .) Используя встроенный браузер, мы можем просмотреть целевой сайт и изучить, как он обрабатывает наши HTTP-запросы, в частности, сами HTTP- запросы и соответствующие ответы. На вкладке « История HTTP» регистрируется каждый HTTP- запрос и соответствующий ответ.POST

Войдите в любой из аккаунтов и нажмите кнопку «Оплата и пополнение» . Давайте совершим перевод средств: нажмите кнопку «Перевод» и введите номер мобильного телефона другого аккаунта, а также сумму, которую хотите перевести. Вы можете попробовать перевести сумму, превышающую ваш текущий баланс, и небольшую сумму, например, 1 доллар, чтобы посмотреть, как система отреагирует в каждом случае.

Burp Suite : Repeater

На изображении ниже мы видим:

  1. ЗапросPOST
  2. В подробностях указан целевой номер телефона и сумма перевода в размере 1,5 доллара.
  3. Из полученного ответа можно сделать вывод, что транзакция прошла успешно.

Теперь, когда мы рассмотрели, как система реагирует на действительные и недействительные запросы, давайте посмотрим, сможем ли мы использовать состояние гонки. Щелкните правой кнопкой мыши по POSTзапросу, который хотите скопировать, и выберите «Отправить в повторитель» .

На вкладке «Повторитель» , как показано на пронумерованных скриншотах ниже:

  1. Щелкните +значок рядом с вкладкой «Полученные запросы» и выберите «Создать группу вкладок».
  2. Присвойте группе имя и укажите вкладку запроса, который вы только что отправили импортеру, прежде чем нажать кнопку «Создать».
  3. Щелкните правой кнопкой мыши на вкладке запроса и выберите «Дублировать вкладку» (если эта опция недоступна в вашей версии, вы можете вместо этого несколько раз нажать CTRL + R ).
  4. Для начала мы повторим это 20 раз.
  5. Рядом с кнопкой «Отправить» стрелка, указывающая вниз, откроет меню, позволяющее выбрать способ отправки дублирующихся запросов.

Далее мы воспользуемся уязвимостью целевого приложения, отправив дублированный запрос. Используя встроенные параметры Burp Suite Repeater, стрелка раскрывающегося списка предлагает следующие варианты:

  • Отправка группы последовательно ( одно соединение )
  • Отправка группы последовательно ( отдельные соединения )
  • Отправка группы параллельно

Последовательная отправка группы запросов

При последовательной отправке группы предоставляются два варианта:

  • Отправка группы последовательно ( одно соединение )
  • Отправка группы последовательно ( отдельные соединения )

Отправка группы сообщений последовательно по одному соединению.

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

Отправка групповых сообщений последовательно по отдельным соединениям.

Как следует из названия, эта опция устанавливает TCP-соединение, отправляет запрос от группы и закрывает TCP-соединение, после чего процесс повторяется для последующего запроса.

Мы протестировали этот вариант атаки на веб-приложение. На скриншоте ниже показаны 21 TCP-соединение для различных POST-запросов в отправленной нами группе.

  • Первая группа (обозначена цифрой 1) включает пять успешных запросов. Мы смогли подтвердить их успешность, проверив соответствующие ответы. Кроме того, мы заметили, что каждый запрос занимал около 3 секунд, как показано на графике (обозначен цифрой 3).
  • Вторая группа (обозначенная цифрой 2) показывает шестнадцать отклоненных запросов. Длительность составила около четырех миллисекунд. Интересно также проверить относительное время начала.

На скриншоте ниже показано всё TCP-соединение для запроса. Мы можем подтвердить, что POSTзапрос был отправлен одним пакетом.

Отправка группы запросов параллельно

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

  • В столбце «Относительное начало» мы видим, что все 21 пакет были отправлены в течение окна в 0,5 миллисекунды (обозначено цифрой 1).
  • Все 21 запрос были успешно выполнены; в результате был успешно осуществлен перевод средств. Выполнение каждого запроса заняло около 3,2 секунды (обозначено цифрой 2).

Внимательно изучив скриншот выше, мы видим, что каждый запрос приводил к отправке 12 пакетов; однако в предыдущей попытке (последовательная отправка) каждый запрос требовал всего 10 пакетов. Почему это произошло?

Согласно документации по отправке групповых HTTP-запросов , при параллельной отправке Repeater использует различные методы для синхронизации поступления запросов к целевому объекту, то есть для обеспечения их поступления в течение короткого промежутка времени. Метод синхронизации зависит от используемого HTTP-протокола:

  • В случае HTTP/2+, ретранслятор пытается отправить всю группу в одном пакете. Другими словами, один TCP- пакет будет содержать несколько запросов.
  • В случае HTTP/1, Repeater прибегает к синхронизации по последнему байту. Этот приём достигается за счёт удержания последнего байта из каждого запроса. Только после отправки всех пакетов без последнего байта отправляется последний байт всех запросов. На скриншоте ниже показан наш POSTзапрос, отправленный в двух пакетах.

Делаем 100 баксов!

Чтобы получить рейскондитион ( гонку вооружений) с 1 аккаунта отправим 1 доллар на другой

Перехватываем

Отправляем в репитор

Создаем группу

Копируем запросы 100 раз ( но перед этим меняем сумму отправки на 2 доллара)

Получаем в группу 100 запросов по 2 доллара

Отправляем запросы одним коннектом

У нас стало на 2 доллара меньше

авторизуемся под другим пользователем и видим 11 баксов

значит все гуд, возравщаемся и пробуем отправить 100 запросов не в одном коннекте, а в нескольких.

Проверяем от куда списывалось )

а на аккаунте куда отправили видим 79$

но нам же нужна 100$

теперь попробуем работать с числами побольше, переливая деньги туда и сюда.

видим жирный минус -

Вопрос: Чтобы получить флаг, вам нужно иметь на одном из аккаунтов более 100 долларов на счету. Какой флаг вы получили?

Ответ: THM{PHONE-RACE}

6. Выявление и смягчение последствий

Обнаружение

Выявление состояний гонки с точки зрения владельца бизнеса может быть сложной задачей. Если несколько пользователей активировали одну и ту же подарочную карту несколько раз, это, скорее всего, останется незамеченным, если не проверять журналы на наличие определенных действий. Учитывая, что состояния гонки могут использоваться для эксплуатации даже более скрытых уязвимостей, очевидно, что нам нужна помощь специалистов по тестированию на проникновение и охотников за уязвимостями, чтобы попытаться обнаружить такие уязвимости и сообщить о своих находках.

Специалисты по тестированию на проникновение должны понимать, как система ведет себя в нормальных условиях при применении ограничений. К таким ограничениям относятся: однократное использование, однократное голосование, однократная оценка, ограничение баланса и ограничение до одного раза в 5 минут, и другие. Следующим шагом будет попытка обойти это ограничение путем использования состояний гонки. Выявление различных состояний системы может помочь сделать обоснованные предположения о временных окнах, в которых можно использовать состояние гонки. Такие инструменты, как Burp Suite Repeater, могут стать отличной отправной точкой.

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

Мы перечислим несколько методов смягчения последствий.

  • Механизмы синхронизации : Современные языки программирования предоставляют механизмы синхронизации, такие как блокировки. Блокировку может получить только один поток одновременно, что предотвращает доступ других потоков к общему ресурсу до тех пор, пока блокировка не будет освобождена.
  • Атомарные операции : Атомарные операции представляют собой неделимые исполнительные блоки — набор инструкций, сгруппированных вместе и выполняемых без прерывания. Такой подход гарантирует завершение операции без прерывания другим потоком.
  • Транзакции базы данных : Транзакции объединяют несколько операций с базой данных в один блок. Следовательно, все операции в рамках транзакции либо завершаются успешно, либо завершаются с ошибкой. Такой подход обеспечивает согласованность данных и предотвращает состояния гонки, возникающие при одновременном изменении базы данных несколькими процессами.

7. Соревнования по веб-приложениям

Теперь задача такая:

В этой комнате были представлены состояния гонки и различные ситуации, приводящие к таким уязвимостям. Сложность системы и географическое распространение могут приводить к разнообразным непредвиденным ситуациям, включая уязвимости, связанные с состояниями гонки. Для обнаружения и использования таких состояний крайне важно сначала понаблюдать за поведением системы в нормальных условиях, а затем попытаться выяснить, как она ведет себя при попытке использовать уязвимость по времени. Имеющиеся в настоящее время инструменты предоставляют множество методов для экспериментов.

Испытание

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

Нажмите кнопку «Запустить машину» справа, чтобы запустить подключенную виртуальную машину . Нажмите кнопку «Запустить AttackBox» вверху, чтобы запустить AttackBox, если вы еще этого не сделали. В AttackBox перейдите по адресу http://MACHINE_IP:5000.

Это учетные данные трех пользователей:

Имя: Рассер Конд

  • Имя пользователя:4621
  • Пароль:blueApple

Имя: Заводни Став

  • Имя пользователя:6282
  • Пароль:whiteHorse

Имя: Warunki Wyscigu

  • Имя пользователя:9317
  • Пароль:greenOrange

у каждого пользователя по 100$

Если мы аввторизуемся видим кнопочки для отправки денег пользователям

Это веб-приложение принадлежит банку и позволяет клиентам переводить деньги онлайн. Для этого необходимо иметь на одном из счетов более 1000 долларов .

Перехватываем через бурп

Создаем группу и 100 запросов

видим что прошло только 4-5 запросов

возможно ещё плюсуется комиссии, стамив еще меньше баланса для отправки, отправляем уже Zavodni Stav

Авторизуеся под Стаф

Вопрос: Какой флаг вы получили после того, как баланс счета превысил 1000 долларов?

Ответ: THM{BANK-RED-FLAG}


Основная группа обучения ИБ
Lab-группу с полезным софтом / книгами / аудио.
Чат для обсуждений, задавай свои вопросы.
P.S. С вами был @Fnay_Offensive
До новой встречи, user_name!