Уязвимости из OWASP Top 10. A1: 2017 – Injections (Часть 1)

Описание уязвимостей — это одно, а вот попробовать найти уязвимость и поработать с ней — совсем другое дело. Именно для этих целей создаются и развиваются специальные приложения, в которых намеренно оставлены уязвимости. Если набрать в поисковой системе запрос «Purposely vulnerable app», вы найдете ни один десяток ссылок.

В этом цикле мы начнем разбирать уязвимости из OWASP Top 10, и в качестве полигона я буду использовать такое намеренно уязвимое приложение. В моем случае это будет OWASP Mutillidae II. Это не то, чтобы самый лучший вариант, но в нем уязвимости структурированы именно так, как нужно для образовательных целей.

gy88_v2lyykqa97h4g7wiidkscc.jpeg

Дайте вашу руку

Итак, первая уязвимость — это инъекции. В OWASP Mutillidae II представлено несколько вариантов, и начнем мы с самого простого «SQLi extract Data» > «User Info (SQL)».
Перед нами обычное окно аутентификации — то, с чем вы взаимодействуете ежедневно:

djidao0plhyiy3ggkt-n4nynpou.png

У нас нет ни логина, ни пароля — ничего. Ну что ж, давайте зарегистрируемся на этом сайте. Я создам пользователя с именем belowzero273 и паролем 123:

ovo1t_znww9_0eze3drmif02re0.png

Отлично! Мы создали учетную запись, торжественная надпись »1 rows inserted» как бы намекает, что добавлена некая строка, судя по всему в таблицу, потому что большое количество учетных записей проще всего хранить в СУБД.

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

http://127.0.0.1/mutillidae/index.php?page=user-info.php&username=belowzero273&password=123&user-info-php-submit-button=View+Account+Details

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

username=belowzero273&password=123

на

username=belowzero273&password=12345

Пароль, конечно же, теперь неверный, и мы получили соответствующую ошибку: и это плохо. Плохо, потому что с помощью THC-Hydra, про которую я рассказывал тут, мы можем подобрать этот пароль, подставляя его в эту строку без всякой формы. Но это долго и не всегда может привести к положительному результату в приемлемые сроки.

У нас нет столько времени, поэтому попробуем кое-что другое. Добавим к нашему неправильному паролю знак апострофа:

username=belowzero273&password=123

на

username=belowzero273&password=12345'

Теперь мы получили полноценную ошибку:

pmo2yslv9bi7vl2sbtnoacthg70.png

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

Теперь мы видим, что на самом деле, когда мы нажимаем кнопку «Отправить» в фоне выполняется следующий запрос:

SELECT * FROM accounts WHERE username='belowzero273' AND password='12345'

Апострофами выделяются стринговые переменные. Наше веб-приложение не фильтрует данные, которые вводит пользователь, и своим дополнительным апострофом мы нарушили запрос. Теперь, когда мы знаем, как выглядит этот запрос в фоне, нужно придумать, как изменить его, чтобы получить нужную нам информацию из базы данных.

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

Давайте еще немного поколдуем над этим запросом:

SELECT * FROM accounts WHERE (username='belowzero273' AND password='12345') OR 1=’1

Мы добавили условие, которое выполняется всегда: 1=1. И запрос будет выполнен в двух случаях: или мы угадали комбинацию логина и пароля, или 1=1. То есть всегда будет выполняться.

Получается, что в качестве пароля можно указать следующее:

' or 1='1

Апостроф в конце строки уже не нужен, логика веб-приложения поставит его за нас. Бум! И мы получили выборку из базы со всеми аккаунтами:

1pkmvkhanj4xew-pmfcwf10d8ey.png

Круто, теперь у нас есть логины и пароли всех, кто зарегистрирован в этом приложении. И даже хуже, пароли тут лежат в открытом виде.

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

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

admin' or 1='1

То есть мы ищем запись в базе, где логин admin, а пароль — любой.

Пароль не найден!

Пароли не всегда хранятся в открытом виде, но не значит, что аутентификация делается безопасно. Посмотрим второй пример в OWASP Mutillidae II «SQLi Bypass Authentication» > «Login».

Аутентификацию можно обойти, если сформировать соответствующий запрос. Совсем недавно мы создали учетную запись belowzero273, а теперь давайте в качестве логина укажем:

' or ('a' = 'a' and username='belowzero273') -- 

Здесь мы проверяем заведомо правильное условие — а=а, а логин — belowzero273, а также отсекаем часть запроса с помощью »–».

Жмем Enter и успешно входим в систему при том, что свой пароль мы нигде не указали.

Так просто?

Иногда клиенты спрашивают, неужели так просто можно обойти аутентификацию на нашем сайте? Обычно я отвечаю вопросом на вопрос: «А вы уверены, что этого уже не произошло?». Инъекции не случайно находятся в топе рейтинга OWASP, так как эти уязвимости, как правило, имеют катастрофические последствия в случае реализации.

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

Прочитать блог автора статьи можно по этой ссылке.

© Habrahabr.ru