Некоторые уязвимости web ресурсов, использующих SQL


В заметке рассматривается уязвимость SQL, связанная с проникновением в тело запроса.

Суть уязвимости

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

Генерируемый запрос к базе даных вынужден иметь в себе логин также пароль, введенные пользователем. По этим полям БД должна найти соответствующую запись в таблице.  После отделки запроса, БД выдает найденную информацию о пользователе, которую PHP скрипт оформляет в виде HTML также отдаёт пользователю.

Расcмотрим достаточно типичный фрагмент PHP скрипта, использующий SQL запрос для доступа к базе данных:

<?php
$result = mysql_db_query("database","select * from userTable where login = '$userLogin' and password = '$userPassword' ");
while($row = mysql_fetch_array($result)) {
    echo $row["fullname"];
   
echo $row["email"];
    echo $row["password"];

}
mysql_free_result($result);
?>

Как наблюдаем, логин также пароль, введенные пользователем содержатся в переменных $userLogin также $userPassword. Содержимое этих переменных встявляется в запрос для отфильтровки информации именно об этом пользователе. Фильтр задается с помощью опции where команды select SQL. В данном случае, запрос выглядит таким образом: select * from userTable where login = '$userLogin' and password = '$userPassword' где userTable - имя таблицы, содержащей нужную информацию. Если переменые логина также пароля содержат значения vanya также vasya соответственно, то запрос, отсылаемый БД, примет такой вид: select * from userTable where login = 'vanya' and password = 'vasya'. Понятно, что ежели в базе данных находится в отсутствии запись, в которой логин равен vanya однако пароль - vasya, вплоть до запрос никак не пришлет ни одной строчки из БД, также скрипт ничего никак не выдаст. Таким образом, приведенная система обеспечивает доступ к информации только пользователя, обладающего безошибочным паролем также логином.

Казалось бы, такая система никак не содержит изъянов. На самом занятии, это никак не так. Логика программиcтов, создававших приведенный выше пример, подразумевает, что введенные пользователем логин также пароль, будут содержаться внутри одинарных кавычек, которые жестко забиты в теле запроса. Однако, посмотрим, что произойдет, ежели самолично пароль, введенный пользоваетелм содержит кавычку. Пусть он владеет значение vas'ya, в то время запрос примет вид: select * from userTable where login = 'vanya' and password = 'vas'ya'. При исполнении такого запроса, непременно возникнет ошибка, поскольку кавычка из пароля, закрыла открывающую кавычку из запроса, также конец пароля ya' остался "висеть" вне условного выражения.

А ежели вставить в качестве пароля  такую строку: ' or 1=1 ' , то запрос станет таким: : select * from userTable where login = 'vanya' and password = '' or 1=1 '' также никак не станет иметь синтаксических ошибок. Зато логическое выражение станет тождественно верным, также в возражение на этот запрос, SQL выдаст всю базу данных пользователей 8-).

Таким образом, используя символ апострофа, мы можем прникнуть в тело SQL запроса также сделать так, что бы  проверяемое условие было истинным. Если нас интересует конкретный пользователь vanya, то для получения информации о нем, разрешено воспользоваться такой строкой пароля: ' or login = 'vanya. При этом запрос станет таким: select * from userTable where login = 'vanya' and password = '' or login = 'vanya' . Как вы понимаете, в результате мы получим информацию именно о vanya.

Описанная уязвимость сервисов, основаных на SQL, никак не ограничивается несанкционированным получением информации. Поскольку в таких системах используется, как правило, MySQL, то имеется возможность никак не только модифицировать условное выражение в команде select, но также выйти за пределы этой  команды, также выполнить другую команду БД. Поскольку в MySQL допускается несколько команд в одном запросе, разделенных ; , то мы можем выполнить любую из этих команд, введя в поле пароля следующий код: ' ; <командаSQL> в каком месте в качестве <командаSQL> разрешено указать любую допустимую команду. Так например такой код: ' ; drop table 'userTable просто напросто уничтожит таблицу userTable из базы данных.

Практическое использование уязвимости

Несмотря на простоту, практическое использование ошибок SQL запросов очень затруднительно.

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

    Рассмотренная уязвимость присуща всем SQL запросам, независимо от скрипта либо программы, откуда они вызываются. Все же мы будем рассматривать системы, основанные на PHP. Это связано с тем, что поток ошибок PHP как положение (по умолчанию) направляется конечному пользователю. В то пора как Perl либо Exe приложения обычно никак не информируют пользователя о характере ошибок.

    Определение факта использования SQL в системе.

    При исследовании конкретной системы, нужно в первую очередь выяснить использует ли она SQL.
    Этот факт разрешено выявить или косвеными путями (просмотрев имена используемых файлов, ссылки на используемые средства также т.д.), или непосредственно - заставив SQL проявить себя. Если мы рабоатем с PHP, то существует только один средство определить однозначно использование SQL - это вызвать погрешность его выполнения. Если при выполнении запроса проистекает ошибка, также однако PHP скрипте явно погрешности никак не выпонения никак не обрабатываются, то сообщение об погрешности PHP выдаст непосредственно на страницу пользователя.
    Как вызвать погрешность выполнения SQL запроса зависит от конкретного утройства рассматриваемой системы. В большинстве случаев погрешность разрешено вызвать введя в систему некорректные данные.

    Выявление факта наличия уязвимости. Выяснение реакции скрипта на ошибки.

    Наиболее бесхитростный средство выявления наличия уязвимости, однако заодно также факта использования SQL, является последующий: В всяком поле, которое предположительно участвует в формировании SQL запроса (например поле Login либо Password), вводим знак одинарной кавычки. Остальные поля заполняем любыми корректными данными (либо оставляем пустыми, ежели это допускается системой). Отослав данные формы, смотрим на реакцию системы. Если в результате PHP скрипт выдает нам погрешность SQL, то можем себя поздравить: в системе используется SQL также скрипт никак не фильтрует одинарную кавычку. То кушать система содержит уязвимость.
    Ошибка SQL запроса станет в таком случае выглядеть на страничке примерно так:

    Форма ввода данных:


    Как результат-ошибка SQL запроса:


    Если кода погрешности SQL на странице нет, то это может означать следующее:
    1)Система содержит уязвимость, но скрипт PHP обрабатывает ошибки. В таком случае систему разрешено взломать, но придется действовать "наощупь", поскольку мы никак не будем знать в какое время синтаксис SQL станет корректным, однако в какое время нет.
    2)Скрипт фильтрует кавычку также потому погрешности никак не возникает. В таком случае система никак не содержит уязвимости.
    3)Система общий никак не использует SQL.
    В пары последних случаях понятно, что дальнейшее исследование SQL никак не владеет смысла.

    Определение имен полей в таблице.

    Для того, что бы получить информацию из базы данных с конкретными данными, мы должны определить значения некоторых полей в запросе (например задать логин пользователя). Все же для этого нужно знать имя соответствующих полей. Напрямую узнать данные имена возможности нет. Поэтому тут придется искать данные имена методом перебора. Данных имена могут совпадать с именами полей в форме, отсылаемой на сервер,а могут также никак не совпадать. Благое занятие, что имена полей как положение стандартны также вариантов написания их никак не так немало. Так, например, имя поля для имени пользователя скорее всего станет login либо user либо nick. Схоже для пароля: password либо pwd либо pass.
    Для определения существования определенного поля, предлагается бесхитростный метод: Пусть мы хотим проверить существует ли поле pwd в таблице. Введем в всяком поле формы такую строку ' pwd='. Если поле pwd существует в таблице, то SQL корректно обработает запрос, ежели бла бла такого поля нет, то снова возникнет погрешность выполнения SQL. Таким образом подставляя разные значения имен полей также исследуя результат отделки запроса, мы можем выяснить какие поля существуют в таблице, однако какие нет.

    Определение имен существующих таблиц.

    Аналогично методике нахождения имен полей в таблицах, разрешено искать также имена существующих таблиц в базе данных. Пусть мы хотим выяснить существует ли в базе таблица adminList. Для этого введем в нектором поле формы такую строку ';select * from adminList. Если в результате погрешности SQL никак не начинается, значит таблица adminList существует. Для корректности этого теста, необходимо вводить данную строку в то поле, которое фигурирует завершительным в SQL запросе. Это необходимо для того, что бы никак не вызывалась погрешность синтаксиса из-за оставшегося "хвоста" исходного запроса, какой станет присутствовать позже select * from adminList. Отметим, что ежели вид для запроса владеет пара поля Login также Password, то скорее всего именно поле пароля станет фигурировать в запросе последним.

    P.S.

    Используя данную уязвимость, был взломан сайт http://www.bigmir.net (точнее его фотогаллерея также чат). Мы собщили об уязвимости владельцам сайта. Дыра была пофиксина. Но вот сейчас мы еще однажды проверил регистрационную форму чата. Плюс обнаружил все ту бла бла уязвимость 8-).