作者:小华 QQ:56111981
转自作者blog:http://xiaohuar.blogchina.com
文章已发表于黑客X档案12期 转载请注明
DISCUZ论坛以其漂亮的界面,完备的功能受到很多站长青睐,在PHP论坛中占有很大市场,从各方面都有可以和动网论坛相媲美。2.0虽然属于老版本,但还是有一大部分用户正在使用。自从9月DISCUZ爆了一个漏洞以来,随后又相继出来了几个漏洞,但这些漏洞要么影响很少,要么利用起来很困难。我写过一个DISCUZ利用程序,经常有人问我如何利用,我无法回答。为此,我读了一下DISCUZ源代码,发现它的上传存在问题,经过测试,在WIN2000下和Red Hat下都存在该问题,不过部分UNIX系统不受影响。文章是写如何发现上传漏洞,给大家和程序作者一点思路,其中源程序请去网上下载免费版。
一 漏洞分析
我首先说DISCUZ2或者更高版本的一个BUG。它的include/common.php存在物理路径泄露漏洞。require $discuz_root../config.php;
require $discuz_root../include/global.php;
require $discuz_root../include/global.php;
require $discuz_root../include/db_.$database..php;
这段代码中$discuz_root默认是等于”.”的,就是当前目录的意思,如果在PHP.ini中没有设置INCLUDE选项,那系统就会报告无法找到config.php,因为系统认为common.php是被其他文件包含的,而包含它的文件是在INCLUDE目录上层,所以代码是这样写的,但是系统不可能阻止我们直接访问common.php。所以,如果我们在浏览器提交(我的机子为例)
http://localhost/discuz/include/common.php
就会泄露物理路径。 好,切入正题,开始分析上传漏洞如何形成以及如何利用。
DISCUZ论坛的上传函数是include/post.php下面的attach_upload。我一步一步解释程序的执行过程,涉及关键代码处我会详细说明。
global $discuz_root, $attachsave, $attach, $attach_name, $attach_size, $attach_fname, $attachdir, $maxattachsize, $attachextensions;
//获得全局变量
if(!function_exists(is_uploaded_file)) {
if(!is_uploaded_file($attach)) {
return false;
}
} elseif(!($attach != none && $attach && trim($attach_name))) {
return false;
}
//以上判断$attach变量是不是一个上传文件,不是函数结束,我们上传的肯定是个文件
$attach_name = daddslashes($attach_name);
if($attachextensions && @!eregi(substr(strrchr($attach_name, .), 1), $attachextensions)) {
showmessage(post_attachment_ext_notallowed);
}
//关键代码,判断扩展名是否符合要求,默认安装时$attachextentsions为空,那么这个IF语句就跳过去了,这是我们所希望的。但是一般有点安全意识的网站都会设置一下,这个问题少后详细讨论。
if(!$attach_size || ($maxattachsize && $attach_size > $maxattachsize)) {
showmessage(post_attachment_toobig);
}
//判断文件大小,构造一下这句对我们没有效果,跳过不管
$filename = $attach_name;
$extension = strtolower(substr(strrchr($filename, .), 1));
if($attachsave) {
switch($attachsave) {
case 1: $attach_subdir = forumid_.$GLOBALS[fid]; break;
case 2: $attach_subdir = ext_.$extension; break;
case 3: $attach_subdir = month_.date(ym); break;
case 4: $attach_subdir = day_.date(ymd); break;
}
if(!is_dir($discuz_root../.$attachdir./.$attach_subdir)) {
mkdir($discuz_root../.$attachdir./.$attach_subdir, 0777);
}
$attach_fname = $attach_subdir./;
} else {
$attach_fname = ;
}
//如何保存,默认是放在论坛attachments目录下,不过有的论坛根据论坛ID号分类,或者日期分类,根据具体论坛而定,不过对我们影响不大
$filename = substr($filename, 0, strlen($filename) – strlen($extension) – 1);
if(preg_match(“/[x7f-xff]+/s”, $filename)) {
$filename = str_replace(/, , base64_encode(substr($filename, 0, 20)));
}
//过滤非ASCII字符
if(in_array($extension, array(php, php3, jsp, asp, cgi, pl))) {
$extension = _.$extension;
}
//关键代码,判断扩展名是不是非法,以防有人恶意上传WEBSHELL。不过我们构造条件要饶过这条语句
$attach_fname .= random(4).”_$filename.$extension”;
$attach_saved = false;
$source = stripslashes($discuz_root../.$attachdir./.$attach_fname);
//生成路径
剩下代码是上传文件的就省略了,因为要是能执行到这里,和文件任何属性都已无关,所以我也就不解释了(解释好累,呵呵)。
好我们开始反向追踪$source变量,可以看到它是三个变量组成:$discuz_root是定义好的,$attachdir也是定义好的,唯一能控制的是$attach_fname变量。好,再追踪$attach_fname变量,由4个随机字符串,一个下划线和两个变量组成,
$attach_fname .= random(4).”_$filename.$extension”;
废话少说,我把这个式子展开,用最原始的变量(我们可以构造的变量)替换,就变成了如下格式(别和我说没学过代数),随机串用abcd表示。
$extension=strtolower(substr(strrchr($attach_name, .), 1));
$filename=substr($attach_name, 0, strlen($attach_name) – strlen($extension) – 1);
$attach_fname=”abcd_$filename.$extentsion”;
其中$attach_name是我们提交的,我们按正常思维提交一个图片文件,得到如下结果。
$attach_name=”test.jpg”
$extension=”jpg”
$filename=”test”
$attach_fname=”abcd_test.jpg”
看到结果是如何生成的了吧?我们按非正常思维就要得到SHELL了,看如何利用漏洞。
二 漏洞变换利用
通过上面的分析,大家已经知道程序如何运行。我直接给出一个得到WEBSHELL的方法,并分析是如何跳过程序检查的,其他的利用方法大家可以仁者见仁,智者见智。
我们把$attach
回味起来却有久久不会退去的余香。