0x01 简介
P师傅很早在小密圈里面就提过这样的问题,刚好最近也遇到过一个类似的情况dedecms标签,所以就总结一下这类错误的用法。
strip_tags && preg_replace
$textMsg = trim(strip_tags(preg_replace('/]*>.*?\1>/s','',$message)));
这个代码的意图很简单——去掉所有的标签和内容。首先使用过滤掉标签、标签内容、标签属性,接着又使用去掉其余的html和php标记。
常规的输入方式如:,得到的结果是空,即全部都被过滤了。
但是如果攻击者输入之类,就会导致evil字符串逃逸,攻击者利用evil字符串再结合上下文说不定就能够造成漏洞。
0x02 漏洞实例
这个是出现在中,在/mail/class..php中的发送邮件的函数()中就存在这样的代码:
function MsgHTML($message, $basedir = '') {
$this->IsHTML(true);
$this->Body = $message;
$textMsg = trim(strip_tags(preg_replace('/]*>.*?\1>/s', '', $message)));
if (!empty($textMsg) && empty($this->AltBody)) {
$this->AltBody = html_entity_decode($textMsg);
}
if (empty($this->AltBody)) {
$this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "nn";
}
}
最终this->,而就会作为邮件的一部分发送出去。所以如果使用不当,我们利用这个小特点能够形成存储型XSS等等漏洞。
escapeshellarg && escapeshellcmd
- 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号
- 会对&#;|*?~^()[]{}$, x0A和 xFF进行转义,’和 “仅在不配对儿的时候被转义
需要注意的是和在win平台和linux平台的表现是不一样的。他们两者造成的漏洞也主要是在Linux平台下。接下来主要是说明在Linux平台下的情况
$msg = "123'456";
echo escapeshellarg($msg) // 结果是:'123'''456'
echo escapeshellcmd($msg) // 结果是: 123'456 当两者混合使用时,就会出现问题。代码如下:
$parameter1 = escapeshellarg($parameter)
$parameter2 = escapeshellcmd($parameter1)
system("curl ".$parameter2)
假设我们传入的$为172.17.0.2' -v -d a=1,那么经过之后变为'172.17.0.2''' -v -d a=1'。之后经过变为'172.17.0.2'\'' -v -d a=1',此时的存在后面得’不会被转义,所以后面的两个’’变为了空白字符。
那么最后实际的命令为curl 172.17.0.2 -v -d a=1',成功地逃逸了单引号。
这两个函数联合使用之后可以造成单引号逃逸,这样就很有可能会造成漏洞,利用的方式就需要看具体的应用场景了。
关于这个漏洞的详细实例可以参考
PHP ()+() 之殇
addslashes && basename
的主要用法是:
给出一个包含有指向一个文件的全路径的字符串,()函数返回基本的文件名。如果是在环境下,路径中的斜线(/)和反斜线()都可以用作目录分割符,在其他环境下是斜线(/)
以一个简单的例子来进行说明:
在 win平台下
$mypath1 = 'C:/Users/monkey/1.txt';
$name1 = basename($mypath1);
var_dump($name1); // 1.txt
$mypath2 = 'C:Usersmonkey2.txt';
$name2 = basename($mypath2);
var_dump($name2); // 2.txt
在Linux平台下
$mypath1 = 'C:/Users/monkey/1.txt';
$name1 = basename($mypath1);
var_dump($name1); // 1.txt
$mypath2 = 'C:Usersmonkey2.txt';
$name2 = basename($mypath2);
var_dump($name2); // C:Usersmonkey2.txt
需要说明的是
漏洞演示如下:
$filename = "123'456.png";
$filename = addslashes($filename);
var_dump($filename); //结果是 123'456.png
$filename = basename($filename);
var_dump($filename); // 结果是 '456.png
通过例子可以看到,成功地逃逸了反斜线,单引号也保留了。
如果存在如下的代码:
// 对输入进行转义
if ( get_magic_quotes_gpc()) {
$_GET = $_GET ? $this->addslashes_deep($_GET) : '';
$_POST = $_POST ? $this->addslashes_deep($_POST) : '';
$_COOKIE = $this->addslashes_deep($_COOKIE);
$_REQUEST = $this->addslashes_deep($_REQUEST);
}
$imagename = basename($_POST['image']);
$sql = "UPDATE table SET image = '".$imagename."'where id=1";
query($sql);
此时,如果我们输入的image的参数为123' and if(1.sleep(3),0)#,最后的的值为' and if(1.sleep(3),0)#,sql语句为 table SET image = '' or if(1.sleep(3),0)#'where id=1形成了一个盲注。
0x03 漏洞实例
在.3的版本中就存在一个这样的问题。
在admin/.php中存在如下的代码:
elseif ($rec == 'update') {
if (empty($_POST['title']))
$dou->dou_msg($_LANG['article_name'] . $_LANG['is_empty']);
// 上传图片生成
if ($_FILES['image']['name'] != "") {
// 获取图片文件名
$basename = basename($_POST['image']);
$file_name = substr($basename, 0, strrpos($basename, '.'));
$upfile = $img->upload_image('image', "$file_name"); // 上传的文件域
$file = $images_dir . $upfile;
$up_file = ", image='$file'";
}
// 格式化自定义参数
$_POST['defined'] = str_replace("rn", ',', $_POST['defined']);
$sql = "UPDATE " . $dou->table('article') . " SET cat_id = '$_POST[cat_id]', title = '$_POST[title]', defined = '$_POST[defined]' ,content = '$_POST[content]'" . $up_file . ", keywords = '$_POST[keywords]', description = '$_POST[description]' WHERE id = '$_POST[id]'";
$dou->query($sql);
$dou->create_admin_log($_LANG['article_edit'] . ': ' . $_POST['title']);
$dou->dou_msg($_LANG['article_edit_succes'], 'article.php');
}
可以看到使用了$ = ($_POST['image']);,之后$就传递到$dedecms标签,而SQL语句就直接使用了$。如果仅仅只使用()不存在问题。但是在此之前调用了过滤代码,过滤代码是:
function dou_magic_quotes() {
if (!@ get_magic_quotes_gpc()) {
$_GET = $_GET ? $this->addslashes_deep($_GET) : '';
$_POST = $_POST ? $this->addslashes_deep($_POST) : '';
$_COOKIE = $this->addslashes_deep($_COOKIE);
$_REQUEST = $this->addslashes_deep($_REQUEST);
}
}
所以我们通过合理地构造$_POST[‘image’]参数就能够进行的盲注了,具体漏洞的过程这里不进行详细地说明了。
explode && preg_replace
严格来说,这两个函数不算是过滤函数,但是这两个函数有时一起使用时说不定就会存在漏洞,而且这种漏洞尤其是会存在在文件上传的地方。()函数的用法相信大家都十分的熟悉。而()用法参照php手册上面的说明:
array ( $ , $ [, int $limit ] ),此函数返回由字符串组成的数组,每个元素都是 的一个子串,它们被字符串 作为边界点分割出来。
下面是一个使用的简单示例:
$pizza = "piece1 piece2 piece3 piece4 piece5 piece6";
$pieces = explode(" ", $pizza); // 得到数组array("piece1","piece2","piece3","piece4","piece5","piece6")
这两个函数造成的漏洞其实就是一个任意文件上传,由于()过滤了特殊字符,导致能够逃逸出php这种后缀,而()用以取文件名,最后取得的就是错误的文件后缀。
我们以中的后台文件上传漏洞为例进行说明。首先我们需要明确的是在中是禁止上传包含以下文件后缀的文件的。php|pl|cgi|asp|aspx|jsp|php3|shtm|shtml。但是由于和错误使用,使得可以上传任意文件。
在//.php中:
// 过滤非法字符
$imgfile_name = trim(preg_replace("#[ rnt*%\/?><|":]{1,}#", '', $imgfile_name));
// 校验文件类型
if(!preg_match("#.(".$cfg_imgtype.")#i", $imgfile_name))
{
ShowMsg("你所上传的图片类型不在许可列表,请更改系统对扩展名限定的配置!", "-1");
exit();
}
// 拼接文件名,得到上传文件的绝对路径
$filename_name = $cuserLogin->getUserID().'-'.dd2char(MyDate("ymdHis", $nowtme).mt_rand(100,999));
$filename = $mdir.'/'.$filename_name;
$fs = explode('.', $imgfile_name);
$filename = $filename.'.'.$fs[count($fs)-1];
$fullfilename = $cfg_basedir.$activepath."/".$filename;
// 上传文件
move_uploaded_file($imgfile, $fullfilename) or die("上传文件到 $fullfilename 失败!");
其中$ = trim(("#[ rnt*%\/?>
限时特惠:本站持续每日更新海量各大内部创业课程,一年会员仅需要98元,全站资源免费下载
点击查看详情
站长微信:Jiucxh