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() просто добавляет обратный слэш перед одинарными (0x27) и двойными кавычками (0x22), перед бэклсэшем (0x5c) и перед null байтом (0x00), причем эта функция не проверяет какой символ в итоге будет создан. Например, в кодировке GBK мультбайтовый символ 0xbf27 не является допустимым, однако 0xbf5c воспринимается как приемлемый. Точно так же и для BIG5: 0xa327 — неправильный символ, но после того, как addslashes() добавит слэш перед 0x27, у нас получится следующая последоавтельность байтов: 0xa35c27. 0xa35c является корректным мультибайтовым символом для кодировки BIG5, т.е. он будет рассматриваться как один символ, в то время как 0x27 станет самостоятельным и одинарная кавычка останется без экранирования.

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

<?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 + кавычка (0x27) + SQL-выражение OR 1=1 /*, которое позволит авторизоваться без правильного пароля.

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

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

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


8 комментариев

  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

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

     
  7. m4h, 28. декабря 2011, 20:06

    Для тех кто привык читать по английски — похожая статья.
    http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

     
  8.  

    […] предполагалось, что там нужно будет задействовать уязвимость, основанную на мультибайтовых кодировках, но тот, кто редактировал запрос, просто забыл […]

     

Write a comment: