ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 28.04.2024
Просмотров: 87
Скачиваний: 0
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
-
Поиск
При написании самого первого издания этой книги я бесцельно путешествовал по интернету в поисках интересного контента, на примере которого можно было бы показать уязвимости, и забрел на web-страницу одной компании, предлагающей решения для создания корпоративных web-сайтов (рис. 5.1). На изображении некоторые части закрашены, чтобы не портить репутацию компании, хотя ошибка уже давно исправлена. URL компании я также не стану афишировать, будем считать, что это www.XXXXXXXX.com.
Рис. 5.1. Web-сайт компании, который я буду проверять
Итак, компания предлагает решения для создания корпоративных web-сайтов. Мне стало интересно, как работает их собственный web-сайт и насколько он защищен. Говорят, что web-сайт — это лицо компании, и если он выглядит ужасно, то и компания такая же. Я такого мнения не придерживаюсь, потому что очень часто за неказистыми web-сайтами прячутся очень хорошие решения и программы.
Первое, что я делаю, когда проверяю web-сайт на безопасность, — передаю мусор во всех параметрах, которые попадают мне на глаза, а дальнейшие мои действия уже зависят от ответной реакции. Среди этого мусора я обязательно указываю одинарную кавычку. Зачем? Читайте дальше и все поймете.
Под параметрами я понимаю:
-
все данные, вводимые в поля ввода. Если на web-сайте есть поле ввода, например поиска, то его данные, скорее всего, будут передаваться в качестве запроса базе данных. В это поле ввода необходимо попытаться передать какие-то данные и обязательно указать одинарную кавычку. Именно она является магическим символом в атаке "SQL-инъекция"; -
все параметры, передаваемые через строку URL. Параметры находятся в строке адреса после символа ? (вопросительного знака) и имеют вид имя=значение. Параметры разделяются между собой символом &.
Допустим, URL выглядит следующим образом: http://www.sitename.com/index.php?id=2&page=1
Здесь всего два параметра: id и page. Первому присваивается значение 2, а второму — 1. Через такие параметры сценарии могут передавать определенные данные между web-страницами или от пользователя к сценарию.
Сразу видно, что оба параметра, id и page, числовые. А что, если попытаться передать буквы или другие символы? Как на это отреагирует сценарий?
Пять минут мучений, а положительной реакции никакой. Нет, сценарий отвечает мне, но вполне корректно обрабатывает все значения, которые я ему посылаю.
Тогда я решил уже скачать демо-версию их программы и, развернув на своем web- сервере, посмотреть ее локально. При просмотре информации меня заинтересовала ссылка для печати. Наведя указатель на ссылку, я увидел в строке состояния не корректный адрес страницы, а текст javascript:;. Получается, что ссылка на страницу, которая должна загружаться, спрятана. Интересно, раз запрятали, значит, что- то там есть? А может, если запрятали, то расслабились и не проверили там параметры? Щелкнув по ссылке, я увидел просто окно для печати формы. Значит, первое отпадает. Посмотрим второе.
Чтобы проверить параметры, для начала нам необходимо узнать реальную ссылку на сценарий, который выполняется. Для этого выбираем Вид | Просмотр HTML- кода, чтобы в коде найти ссылку, раз уж она спрятана под javascript:;. Опачки, а исходный код не появился! Интересно. Если это ошибка браузера, то это одно, а если попытка разработчика защититься от просмотра исходного кода, то это абсолютно глупо. Чтобы все же увидеть код, я сохранил web-страницу на локальном диске (Файл | Сохранить как). Web-страница без проблем сохранилась, теперь можно приступать к изучению исходного кода. Код кнопки печати выглядит следующим образом:
"MM_openBrWindow('http://www.XXXXXXXXX.com/print.php?id=1',
'print', 'scrollbars=yes, width=600, height=400')" href="javascript:;">
Итак, ссылка на сценарий, который отвечает за отображения окна печати, выглядит следующим образом: http://www.XXXXXXXXXXX.com/print.php?id=1. Сценарию print.php передается один параметр id, которому присваивается значение 1. Имя классическое, значит, можно предположить, что и смысл его классический: по этому идентификатору сценарий определит, информацию о каком продукте необходимо подготовить к печати.
Попробуем в качестве параметра передать не 1, а цифру и апостроф. Тут сценарий сообщает нам об ошибке в SQL-запросе. Попробуем в строке URL указать следующий адрес: http://www.XXXXXXxXxXX.com/print.php?id=1 and 1=0.
Сценарий отобразил только web-страницу, на которой содержалась пара строк информации о компании и правообладателях. Видимо, эти строки отображаются для любого продукта и прошиты в самом сценарии, а не в базе данных.
Теперь попробуем указать следующий адрес:
http://www.XXXXXXXXXXXX.com/print.php?id=1 and 1=1
На этот раз web-страница отобразится корректно (рис. 5.2).
Явная проблема с проверкой параметров, и весь текст, помещаемый нами в параметр id, попадает в SQL-запрос, который выполняет сценарий. Разработчик явно расслабился — понадеялся на то, что хакер не увидит ссылки, и не проверил получаемый от пользователя параметр, а зря. Если я нашел, то другие тоже смогут найти.
Вот за что я люблю большие программы, так это за то, что тут больше вероятность, что найдется параметр, который не будет проверяться. Так случилось и в данном случае. На этом я закончил свое исследование, сообщив администраторам web- сайта о найденной ошибке. На следующий день ее исправили и уверили, что подобной ошибки нет в коммерческом продукте, который предлагает компания. Скачав этот продукт, я удостоверился, что это правда.
-
Ошибка
Итак, давайте рассмотрим атаку "SQL-инъекция" на примере. Я напишу небольшой сценарий (листинг 5.1), который будет содержать ошибку, и мы посмотрим, как злоумышленник сможет ею воспользоваться.
Листинг 5.1. PHP-сценарий с ошибкой
// Connect to MySQL
$connection = new PDO('mysql:host=127.0.0.1;dbname=testdb', 'testuser', 'password');
// execute sql
$username=$_GET['username'];
$sql = "SELECT * FROM phone WHERE lastname like '". $username . "'"; $query = $connection->prepare($sql); print($sql . "
");
$query->execute(); if ($query->errorInfo()[1]) { print_r($query->errorInfo());
}
echo "Search: $username";
// show result ?>
Firstname | Lastname | Phone |
---|---|---|
= $line['firstname'] ?> | = $line['lastname'] ?> | = $line['phone'] ?> |
Смысл сценария в том, чтобы отобразить поле для ввода имени пользователя. Введенное имя применяется для поиска в таблице базы данных phone. Для поиска используется следующий запрос:
SELECT *
FROM phone
WHERE lastname like '?'
На место вопросительного знака попадает значение, которое передается через поле ввода. На рис. 5.3 показаны результат работы сценария и итоговая таблица для случая, когда пользователь передал сценарию знак процента. Процент в данном случае соответствует совершенно любому количеству любых символов, то есть мы увидим все записи.
Для данного примера я использую таблицу phone, которую недавно создал, чтобы тестировать запросы, и она тут отлично подойдет. Структура таблицы:
CREATE TABLE 'phone' (
'phoneid' int(11) NOT NULL AUTO_INCREMENT,
'firstname' varchar(20) DEFAULT NULL,
'lastname' varchar(20) DEFAULT NULL,
'phone' varchar(100) DEFAULT NULL,
'cityid' int(11) DEFAULT NULL,
'm' int(11) DEFAULT NULL,
PRIMARY KEY ('phoneid'),
)
Итак, если указать имя пользователя, то сценарий получит соответствующую строку из базы данных и отобразит ее на web-странице. Если имя указано неверно, то результат будет пустым, то есть результирующая таблица будет пустой.
Главная проблема этого сценария в том, что он не проверяет параметр, который вводит пользователь, а пользователь может передать что угодно. Если пользователем является хакер, то он без проблем сможет взломать web-сервер, на котором работает этот сценарий.
Теперь самое интересное: что если в качестве имени пользователя передать одинарную кавычку? В результате SQL-запрос будет выглядеть следующим образом:
SELECT *
FROM phone
WHERE firstname='''
Имя posterName сравнивается с тремя одинарными кавычками, что неправильно. Запрос оказывается незавершенным, и в результате мы увидим ошибку (рис. 5.4).
Если мы добились ошибки в SQL-запросе, то существует вероятность того, что текущие настройки позволят нам получить доступ к чему-нибудь интересному. Давайте посмотрим, чего именно можно добиться. Но для начала необходимо узнать, сколько полей возвращает SQL-запрос. Да, в данном случае мы можем увидеть это в нашем сценарии, но в реальных условиях нам будет доступно только сообщение об ошибке, в котором нет необходимой информации.
А если передать теперь не просто одинарную кавычку, а следующий текст:
1' union all SELECT 1, GRANTEE, PRIVILEGE_TYPE, 1, 1, 1 FROM information schema.USER PRIVILEGES where 1='1
Этот текст превратится в запрос:
SELECT *
FROM phone
WHERE firstname='1'
union all
SELECT 1, GRANTEE, PRIVILEGE_TYPE, 1, 1, 1
FROM information schema.USER PRIVILEGES where 1=’1
г ® ® ® injection test X + 4- О A Not Secure phpbook/sql.php?username=%27 HI Apps В Work В Dev | ☆ a # * i В Other Bookmarks |
Injection test | |
User name: |' 11 Find | | |
Search: 'SELECT * FROM phone WHERE lastnamc like | |
Array ([0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds | |
to your MySQL server version for the right syntax to use near m" at line 1 ) Firstname Lastnamc | Phone |
Рис. 5.4. Результат передачи в качестве параметра одинарной кавычки
• ® ® injection test X +
f 4 С A Not Secure phpbook/sql.php?usemame=l9/o27+union+all+SELECT+1%2C+GRANTEEyo2C+PRIVILE...
Hi Apps EfJ Work Й Dev ЁВ Other Bookmarks
Injection test
Search: 1' union all SELECT 1. GRANTEE. PR1V1LEGE.TYPE. 1.1.1 FROM information.schcma USER PRIVILEGES where 1=1 SELECT • FROM phone WHERE lastnamc like T union all SELECT 1, GRANTEE. PRIVILEGE.TYPE, 1.1,1 FROM information_schcma.USER_PRIVILEGBS where l=rl'
Firstname Lastnamc Phone
'root'@'localho«' | SELECT | 1 |
'root@'localhost' | INSERT | 1 |
'root'@'localhost' | UPDATE | 1 |
'root'@'localhost' | DELETE | 1 |
'root'@'localhost' | CREATE | 1 |
'root'@'localhost' | DROP | 1 |
'root'@'localhost' | RELOAD | 1 |
'root'@'localhost' | SHUTDOWN | 1 |
'root'@'localhost' | PROCESS | 1 |
'root'@'localhost' | FILE | 1 |
'root'@'localhost' | REFERENCES | 1 |
'root'@'localhost' | INDEX | 1 |
'root'@'localhost' | ALTER | 1 |