SQL-инъекции, связанные с мультибайтовыми кодировками и addslashes

Недавно на milw0rm’е был опубликован эксплоит для популярного форумного движка  Simple  Machines  Forum  версии 1.1.4, являющейся довольно распространенной на просторах интернета. Уязвимость связана с реализацией SQL-инъекции, основанной на особенностях мультибайтовых кодировок, которые позволяют обойти экранирование опасных символов с помощью функции addslashes().

Итак, уязвимость возможна благодаря тому, что при установке SMF переменная $db_character_set не записываются в конфигурационный файл, если пользователь оставил кодировку соединения с базой данных по умолчанию (в SMF это UTF-8). При включенной опции register_globals злоумышленник может назначить этой переменной любое значение, состоящее из буквенно-цифровых символов. Таким образом, вместо стандартной кодировки можно назначить любую другую, включая определенные мультибайтовые кодировки, позволяющие обойти фильтрацию входящих данных посредством addslashes() на символ одинарной кавычки. К таким кодировкам относятся SJIS, BIG5 и GBK. В чем же заключается ошибка addslashes()? Дело в том, что addslashes() просто добавляет обратный слэш перед одинарными (0×27) и двойными кавычками (0×22), перед бэклсэшем (0×5c) и перед null байтом (0×00), причем эта функция не проверяет какой символ в итоге будет создан. Например, в кодировке GBK мультбайтовый символ 0xbf27 не является допустимым, однако 0xbf5c воспринимается как приемлемый. Точно так же и для BIG5: 0xa327 – неправильный символ, но после того, как addslashes() добавит слэш перед 0×27, у нас получится следующая последоавтельность байтов: 0xa35c27. 0xa35c является корректным мультибайтовым символом для кодировки BIG5, т.е. он будет рассматриваться как один символ, в то время как 0×27 станет самостоятельным и одинарная кавычка останется без экранирования.

Рассмотрим простой пример:

<?php
$_POST['username'] = chr(0xa3) .
                              chr(0x27) .
                              ' OR 1=1 /*';
$_POST['password'] = 'blah';

$username = addslashes($_POST['username']);
$password = addslashes($_POST['password']);

$sql = "SELECT *
          FROM    users
          WHERE  username = '$username'
          AND      password = '$password'";

$result = mysql_query($sql);

if (mysql_num_rows($result)) {
    /* авторизован */
} else {
    /* не авторизован */
}
?>

0xa327 после обработки функцией addslashes() превратится в 0xa35c27. Таким образом, в $username окажется:
переданное пользователем значение + мультибайтовый символ 0xa35c + кавычка (0×27) + SQL-выражение OR 1=1 /*, которое позволит авторизоваться без правильного пароля.

Несмотря на то, что UTF-8 относится к мультибайтовым кодировкам (т.е. один символ может занимть более одного байта), данной уязвимости эта кодировка не подвержена, так как этот вид атак возможен для любой кодировки, в которой мультибайтовым считается символ заканчивающийся на 0×5c. UTF-8 к таковым не относится в силу того, что в ней каждый последующий байт мультибайтового символа должен иметь значение больше 128 в десятичном представлении. 0×5c в десятичном виде равняется 92, что меньше 128.

Автор эксплоита указывает на то, что в SMF имеется множество SQL-инъекций, возможных благодаря неправильной обработке опасных символов функцией addslashes(). Похожая уязвимость была найдена в прошлом году в Wordpress. Однако уязвимы были лишь те блоги, где использовались мультибайтовые кодировки (например китайские сайты) и изменить ее удаленно атакующий не мог, чего не скажешь о недавно опубликованной уязвимости в SMF.

В целях безопасности рекомендуется использовать функцию mysql_real_escape_string() вместо addslashes() и mysql_escape_string(). Функция mysql_real_escape_string() учитывает кодировку текущего соединения с базой данных, поэтому ей необходимо передавать указатель соединения. Надеюсь теперь понятно какой смысл разработчики вкладывают в real в названии функции =)

6 comments:

  1. wi11son, 18. Июнь 2008, 17:25

    круто…

     
  2. Spm, 19. Июнь 2008, 7:21

    Еще такого бы…. Это все супер))

     
  3. Dimi4, 22. Декабрь 2008, 19:31

    Спасибо Разор, как раз в тему)

     
  4. ekim, 1. Февраль 2009, 2:12

    круто! отличный пример. хорошо хоть для utf-8 не применимо

     
  5. баблочёрт, 8. Ноябрь 2009, 23:56

    Мне интересно, на данный момент только SMF подвержен этой уязвимости?! Т.е я хочу сказать: в одном ли только SMF можно принудительно сменить кодировку?

     
  6. cawok, 11. Ноябрь 2009, 23:04

    фух у меня ютф. спасибо полезно

     

Write a comment: