ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 28.04.2024
Просмотров: 96
Скачиваний: 0
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
.
Теперь можно вызывать этот сценарий и в параметре $cmd передавать команды, которые будут выполняться, например: http://localhost/cmd.php?cmd=ls -al. В итоге web-сервер выполнит команду ls -al и отобразит результат ее выполнения.
Итак, как вы можете искать уязвимости на web-сайте? Самый рабочий способ — во всех параметрах, которые вы видите в строке URL, в полях ввода и в файле cookies, попытаться указать символ одинарной кавычки. Например, если URL выглядит следующим образом: http://localhost/index.php?id=1&s=test, то можно попытаться указать: http://localhost/index.php?id=1'&s=test\
Если сценарий вернет ошибку, то это уже говорит о возможности реализовать атаку SQL-инъекции. Как мы уже знаем, по ошибке можно определить достаточно много полезной информации, в том числе и выполняемый сценарием запрос, имя таблицы и ее поля.
На профессиональных web-сайтах, которые обслуживают опытные администраторы и программисты, вы не увидите ошибок на странице. Все прекрасно понимают, что такие ошибки дают хакеру слишком много информации, поэтому, получая некорректные параметры, сценарий просто может прерывать свою работу, отображая пустую web-страницу или web-страницу, на которой находится только шапка web- сайта. Если вы увидели пустую web-страницу, то это абсолютно ни о чем не говорит. Возможно, там есть ошибка, а может быть, ее там и нет.
Чтобы убедиться в наличии возможности реализации ошибки, в качестве контрольного выстрела можно попытаться выполнить следующие два запроса:
http://localhost/mdex.php?id=1' and 1=1&s=test’ and 1=1 и http://localhost/index.php?id=1 and 1=1&s=test’ and 1=1.
В обоих случаях помимо кавычки мы передаем условие "and 1=1", которое возвращает положительный результат, а значит, SQL-запрос с нашей инъекцией должен положительно выполниться. Если после этого web-страница отобразится корректно, то это уже говорит о возможности удачной атаки и о правильном направлении. Если web-страница отобразится пустой, то ошибки, скорее всего, нет.
Обратите внимание, что в первом случае в параметре id мы передаем кавычку, а во втором — нет. Дело в том, что этот параметр явно числовой, а значит, в запросе он может быть окружен одинарной кавычкой, а может и нет. Необходимо проверить оба варианта.
Не зная ошибку и исходные коды, исследовать SQL-инъекцию может быть тяжело, потому что страница может не отобразиться просто потому, что тип какой-то колонки не совпадает или вы передали такое значение, которое потом привело в коде к ошибке. То есть инъекция прошла успешно, но приложение сгенерировало ошибку уже после выполнения запроса.
И хотя подобные случаи очень сложно анализировать без исходных кодов и без ошибок, не стоит думать, что если вы используете свой собственный закрытый код и не показываете ошибки, то сайт будет в безопасности. Да, это немного усложнит работу, но с помощью автоматизации хакер может написать скрипты, которые проверят большое количество различных вариантов. Существуют различные программы, которые уже ищут ошибки, и мы рассматривали некоторые в главе 2.
Во всех СУБД, которые я видел, если строковое поле сравнивается с переменной не с помощью знака равенства, а посредством like, то символы процента и подчеркивания принимают особый смысл. Чтобы понять его, давайте посмотрим на следующий SQL-запрос:
SELECT * FROM smf_polls WHERE posterName LIKE '$username'
Символ подчеркивания означает любой одиночный символ. Например, вы не знаете, как правильно написано имя Михаил на английском — Michael или Mikhail. В обоих случаях семь букв и имя начинается с букв Mi, а заканчивается на букву l. В этом случае символы, которые вы знаете точно, можно написать в тех позициях, которые есть, а неизвестные символы можно заменить подчеркиванием:
M i _ _ _ _ l
Пробелы в данном случае введены только для того, чтобы вы видели границы символов. В реальных условиях это не нужно. Если передать в качестве параметра эту строку, то в результате база данных вернет нам записи, в которых есть как Mikhail, так и Michael.
Символ процента заменяет последовательность из любых символов. Это значит, что проблему имени Михаил можно решить следующим образом:
M i % l
Результат будет тем же самым, и база данных вернет нам записи, в которых есть как Mikhail, так и Michael. Если в качестве параметра просто передать символ процента, то в результате мы получим абсолютно все записи таблицы.
Как эти символы могут использовать хакеры? Допустим, что у вас есть таблица users, в которой хранятся имена учетных записей всех пользователей web-сайта. Для входа на web-сайт пользователь вводит имя пользователя и пароль
, а ваш сценарий должен проверить, есть ли такой пользователь в таблице. Вероятная проверка может выглядеть следующим образом:
$sql = "SELECT * FROM user WHERE username like '". $_POST['username'] .
"' AND password like '". $_POST['password'] . "'";
$query = $connection->prepare($sql);
$query->execute();
if ($query->rowCount() > 0) {
echo "
} else {
echo "
}
В этом коде снова есть SQL-инъекция, но именно сейчас не об этом.
В данном случае подразумевается, что в переменной $_post [' username' ] находится имя проверяемого пользователя, а в переменной $_post[ 'password' ] — пароль. Если SQL-запрос возвращает хотя бы одну строку, то авторизацию считаем пройденной удачно, ведь раз такой пользователь есть в таблице, значит, все в порядке.
А если в качестве имени и пароля указать процент? В этом случае запрос вернет все записи, и сценарий посчитает нашу авторизацию корректной, хотя на самом деле она такой не является.
Чтобы авторизоваться под чужим именем, достаточно указать его имя пользователя (на web-сайтах и форумах имена зарегистрированных пользователей чаще всего не являются секретом), а в качестве пароля — процент. В результате запрос найдет нужную запись и разрешит нам вход. Хакеру достаточно только узнать имя администратора (чаще всего это admin или administrator), войти под его именем, и можно делать на web-сайте все, что душе угодно и от чужого имени.
Если символ процента запрещен, а подчеркивания — нет, то наша задача усложняется, но не сильно. Мы должны только подобрать длину пароля и указать соответствующее количество подчеркиваний. Подбор не отнимет очень много времени, нужно только указать сначала один символ подчеркивания, затем два, три и т. д., пока вход не завершится удачей. Количество проверок будет равно количеству символов в пароле. Чаще всего это количество не более 10 символов.
Дабы не столкнуться с такой проблемой, лучше вообще не использовать LIKE, но если по какой-то магической причине это необходимо, то после получения записей необходимо произвести еще одну проверку, как показано в листинге 5.2.
Листинг 5.2. Проверка корректности имени пользователя
$line = $query->fetch(PDO::FETCH_ASSOC); if ($query->rowCount() > 0 &&
$line[username] == $_POST['username'] &&
$line[password] == $_POST['password']) { echo "
} else {
echo "
}
В рассматриваемом случае после получения данных мы читаем строку из результирующего набора и проверяем, чтобы имя пользователя и пароль из этой строки были равны имени пользователя и паролю, переданным пользователем. Эта проверка происходит средствами PHP, и тут уже символы подчеркивания и процента не имеют никаких специальных значений, а значит, шутка хакера не пройдет.
Но даже в этом случае лучше все же не использовать like в запросах, а заменить его на знак равенства, как показано в листинге 5.3.
Листинг 5.3. Используем знак равенства
$sql = "SELECT * FROM user WHERE username = $_POST['username'] . "' AND password = $_POST['password'] . "'";
$query = $connection->prepare($sql);
$query->execute();
$line = $query->fetch(PDO::FETCH_ASSOC);
if ($line[username] == $_POST['username'] && $line[password] == $_POST['password']) { echo "
} else {
echo "
}
Связанный запрос выводит результат обращения к двум и более связанным таблицам. Если связь наводится после переменной, в которую мы внедряем код, то ее необходимо восстановить, прежде чем ставить комментарий.
Например, сценарий выполняет следующий SQL-запрос:
SELECT *
FROM tablel t1, table2 t2 WHERE posterName='$username'
AND t1.keyfield = t2.keyfield
Если в переменной $username будут просто одинарные кавычки и открытие комментария, то результат окажется нежелательным. Необходимо в переменной передавать и связь, например:
' AND t1.keyfield = t2.keyfield and ... /*
Если какая-то команда не выполняется, то это плюс администратору, который заблокировал доступ, или просто у вас нет прав на выполнение данной команды.
Чуть проще ситуация в тех случаях, когда используется связь таблиц через join:
SELECT *
FROM table1 t1 inner join table2 t2 on t1.keyfield = t2.keyfield WHERE posterName='$username'
Здесь мы внедряемся в SQL-запрос уже после того, как наведена любая связь.
Еще одна преграда, которую устанавливают администраторы и программисты перед хакерами: экранирование одинарных кавычек или их запрет. Раньше в PHP был параметр magic_quotes_gpc. Если этот параметр включен, то перед опасными символами, такими как одинарная кавычка, устанавливается слеш. С одной стороны, это хорошо, потому что если хакер в качестве параметра передаст кавычку, то она не будет иметь специализированного значения. То же самое программисты могут сделать на сервере и другими инструментами, просто заменяя одинарную кавычку на \' простой заменой.
Недостаток этого подхода в том, что он расслабляет администратора, который надеется, что хакер не сможет использовать SQL-инъекцию, но это не так. Данную защиту очень легко обойти практически в любой СУБД. Для начала посмотрим, как это можно сделать в MySQL. Допустим, вы хотите внедрить следующий SQL-запрос:
INSERT INTO table VALUES (1, 'admin')
Так как одинарная кавычка невозможна, этот запрос не может быть выполнен. Как же тогда передать текст, если нельзя использовать кавычку? Да очень просто — передать строку в виде кодов:
Теперь можно вызывать этот сценарий и в параметре $cmd передавать команды, которые будут выполняться, например: http://localhost/cmd.php?cmd=ls -al. В итоге web-сервер выполнит команду ls -al и отобразит результат ее выполнения.
-
Поиск уязвимости
Итак, как вы можете искать уязвимости на web-сайте? Самый рабочий способ — во всех параметрах, которые вы видите в строке URL, в полях ввода и в файле cookies, попытаться указать символ одинарной кавычки. Например, если URL выглядит следующим образом: http://localhost/index.php?id=1&s=test, то можно попытаться указать: http://localhost/index.php?id=1'&s=test\
Если сценарий вернет ошибку, то это уже говорит о возможности реализовать атаку SQL-инъекции. Как мы уже знаем, по ошибке можно определить достаточно много полезной информации, в том числе и выполняемый сценарием запрос, имя таблицы и ее поля.
На профессиональных web-сайтах, которые обслуживают опытные администраторы и программисты, вы не увидите ошибок на странице. Все прекрасно понимают, что такие ошибки дают хакеру слишком много информации, поэтому, получая некорректные параметры, сценарий просто может прерывать свою работу, отображая пустую web-страницу или web-страницу, на которой находится только шапка web- сайта. Если вы увидели пустую web-страницу, то это абсолютно ни о чем не говорит. Возможно, там есть ошибка, а может быть, ее там и нет.
Чтобы убедиться в наличии возможности реализации ошибки, в качестве контрольного выстрела можно попытаться выполнить следующие два запроса:
http://localhost/mdex.php?id=1' and 1=1&s=test’ and 1=1 и http://localhost/index.php?id=1 and 1=1&s=test’ and 1=1.
В обоих случаях помимо кавычки мы передаем условие "and 1=1", которое возвращает положительный результат, а значит, SQL-запрос с нашей инъекцией должен положительно выполниться. Если после этого web-страница отобразится корректно, то это уже говорит о возможности удачной атаки и о правильном направлении. Если web-страница отобразится пустой, то ошибки, скорее всего, нет.
Обратите внимание, что в первом случае в параметре id мы передаем кавычку, а во втором — нет. Дело в том, что этот параметр явно числовой, а значит, в запросе он может быть окружен одинарной кавычкой, а может и нет. Необходимо проверить оба варианта.
Не зная ошибку и исходные коды, исследовать SQL-инъекцию может быть тяжело, потому что страница может не отобразиться просто потому, что тип какой-то колонки не совпадает или вы передали такое значение, которое потом привело в коде к ошибке. То есть инъекция прошла успешно, но приложение сгенерировало ошибку уже после выполнения запроса.
И хотя подобные случаи очень сложно анализировать без исходных кодов и без ошибок, не стоит думать, что если вы используете свой собственный закрытый код и не показываете ошибки, то сайт будет в безопасности. Да, это немного усложнит работу, но с помощью автоматизации хакер может написать скрипты, которые проверят большое количество различных вариантов. Существуют различные программы, которые уже ищут ошибки, и мы рассматривали некоторые в главе 2.
-
Процент опасности
Во всех СУБД, которые я видел, если строковое поле сравнивается с переменной не с помощью знака равенства, а посредством like, то символы процента и подчеркивания принимают особый смысл. Чтобы понять его, давайте посмотрим на следующий SQL-запрос:
SELECT * FROM smf_polls WHERE posterName LIKE '$username'
Символ подчеркивания означает любой одиночный символ. Например, вы не знаете, как правильно написано имя Михаил на английском — Michael или Mikhail. В обоих случаях семь букв и имя начинается с букв Mi, а заканчивается на букву l. В этом случае символы, которые вы знаете точно, можно написать в тех позициях, которые есть, а неизвестные символы можно заменить подчеркиванием:
M i _ _ _ _ l
Пробелы в данном случае введены только для того, чтобы вы видели границы символов. В реальных условиях это не нужно. Если передать в качестве параметра эту строку, то в результате база данных вернет нам записи, в которых есть как Mikhail, так и Michael.
Символ процента заменяет последовательность из любых символов. Это значит, что проблему имени Михаил можно решить следующим образом:
M i % l
Результат будет тем же самым, и база данных вернет нам записи, в которых есть как Mikhail, так и Michael. Если в качестве параметра просто передать символ процента, то в результате мы получим абсолютно все записи таблицы.
Как эти символы могут использовать хакеры? Допустим, что у вас есть таблица users, в которой хранятся имена учетных записей всех пользователей web-сайта. Для входа на web-сайт пользователь вводит имя пользователя и пароль
, а ваш сценарий должен проверить, есть ли такой пользователь в таблице. Вероятная проверка может выглядеть следующим образом:
$sql = "SELECT * FROM user WHERE username like '". $_POST['username'] .
"' AND password like '". $_POST['password'] . "'";
$query = $connection->prepare($sql);
$query->execute();
if ($query->rowCount() > 0) {
echo "
Welcome
";} else {
echo "
Try again
";}
В этом коде снова есть SQL-инъекция, но именно сейчас не об этом.
В данном случае подразумевается, что в переменной $_post [' username' ] находится имя проверяемого пользователя, а в переменной $_post[ 'password' ] — пароль. Если SQL-запрос возвращает хотя бы одну строку, то авторизацию считаем пройденной удачно, ведь раз такой пользователь есть в таблице, значит, все в порядке.
А если в качестве имени и пароля указать процент? В этом случае запрос вернет все записи, и сценарий посчитает нашу авторизацию корректной, хотя на самом деле она такой не является.
Чтобы авторизоваться под чужим именем, достаточно указать его имя пользователя (на web-сайтах и форумах имена зарегистрированных пользователей чаще всего не являются секретом), а в качестве пароля — процент. В результате запрос найдет нужную запись и разрешит нам вход. Хакеру достаточно только узнать имя администратора (чаще всего это admin или administrator), войти под его именем, и можно делать на web-сайте все, что душе угодно и от чужого имени.
Если символ процента запрещен, а подчеркивания — нет, то наша задача усложняется, но не сильно. Мы должны только подобрать длину пароля и указать соответствующее количество подчеркиваний. Подбор не отнимет очень много времени, нужно только указать сначала один символ подчеркивания, затем два, три и т. д., пока вход не завершится удачей. Количество проверок будет равно количеству символов в пароле. Чаще всего это количество не более 10 символов.
Дабы не столкнуться с такой проблемой, лучше вообще не использовать LIKE, но если по какой-то магической причине это необходимо, то после получения записей необходимо произвести еще одну проверку, как показано в листинге 5.2.
Листинг 5.2. Проверка корректности имени пользователя
$line = $query->fetch(PDO::FETCH_ASSOC); if ($query->rowCount() > 0 &&
$line[username] == $_POST['username'] &&
$line[password] == $_POST['password']) { echo "
Welcome
";} else {
echo "
Try again
";}
В рассматриваемом случае после получения данных мы читаем строку из результирующего набора и проверяем, чтобы имя пользователя и пароль из этой строки были равны имени пользователя и паролю, переданным пользователем. Эта проверка происходит средствами PHP, и тут уже символы подчеркивания и процента не имеют никаких специальных значений, а значит, шутка хакера не пройдет.
Но даже в этом случае лучше все же не использовать like в запросах, а заменить его на знак равенства, как показано в листинге 5.3.
Листинг 5.3. Используем знак равенства
$sql = "SELECT * FROM user WHERE username = $_POST['username'] . "' AND password = $_POST['password'] . "'";
$query = $connection->prepare($sql);
$query->execute();
$line = $query->fetch(PDO::FETCH_ASSOC);
if ($line[username] == $_POST['username'] && $line[password] == $_POST['password']) { echo "
Welcome
";} else {
echo "
Try again
";}
-
Возможные проблемы
Связанный запрос выводит результат обращения к двум и более связанным таблицам. Если связь наводится после переменной, в которую мы внедряем код, то ее необходимо восстановить, прежде чем ставить комментарий.
Например, сценарий выполняет следующий SQL-запрос:
SELECT *
FROM tablel t1, table2 t2 WHERE posterName='$username'
AND t1.keyfield = t2.keyfield
Если в переменной $username будут просто одинарные кавычки и открытие комментария, то результат окажется нежелательным. Необходимо в переменной передавать и связь, например:
' AND t1.keyfield = t2.keyfield and ... /*
Если какая-то команда не выполняется, то это плюс администратору, который заблокировал доступ, или просто у вас нет прав на выполнение данной команды.
Чуть проще ситуация в тех случаях, когда используется связь таблиц через join:
SELECT *
FROM table1 t1 inner join table2 t2 on t1.keyfield = t2.keyfield WHERE posterName='$username'
Здесь мы внедряемся в SQL-запрос уже после того, как наведена любая связь.
Еще одна преграда, которую устанавливают администраторы и программисты перед хакерами: экранирование одинарных кавычек или их запрет. Раньше в PHP был параметр magic_quotes_gpc. Если этот параметр включен, то перед опасными символами, такими как одинарная кавычка, устанавливается слеш. С одной стороны, это хорошо, потому что если хакер в качестве параметра передаст кавычку, то она не будет иметь специализированного значения. То же самое программисты могут сделать на сервере и другими инструментами, просто заменяя одинарную кавычку на \' простой заменой.
Недостаток этого подхода в том, что он расслабляет администратора, который надеется, что хакер не сможет использовать SQL-инъекцию, но это не так. Данную защиту очень легко обойти практически в любой СУБД. Для начала посмотрим, как это можно сделать в MySQL. Допустим, вы хотите внедрить следующий SQL-запрос:
INSERT INTO table VALUES (1, 'admin')
Так как одинарная кавычка невозможна, этот запрос не может быть выполнен. Как же тогда передать текст, если нельзя использовать кавычку? Да очень просто — передать строку в виде кодов: