Dedecms 最新版漏洞收集并复现学习

以下漏洞复现均处于最新版dedecms即V5.7 SP2(当然从18年开始就已经没有更新了,应该是没有人维护了)。下载可以直接在官网下载。

1. 前台任意用户密码修改

漏洞信息

无CVE, SSV-97074,提交时间:20180110

漏洞成因

在用户密码重置功能处,php存在弱类型比较,导致如果用户没有设置密保问题的情况下可以绕过验证密保问题,直接修改密码(管理员账户默认不设置密保问题)。值得注意的是修改的密码是member表中的密码,即使修改了管理员密码也是member表中的管理员密码,仍是无法进入管理

漏洞代码分析

php弱类型比较问题很常见,在不同类型比较时,如果使用的是==,php会将其中一个数据进行强制转换为另一个,比如’123a’就会被强制转换成123。这样就出现了弱类型比较问题,当然如果使用===判断比较就不会出现问题了。常见比较如下

dedecms的/member/resetpassword.php就是用来处理用户密码重置的问题,问题出在75行开始处理验证密保问题处。

可以看到,这段代码先是从数据库取出相关用户的密保问题及密保答案,在对用户输入做了一些处理后,进行了关键性的判断if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer) ,就在这里用了弱类型判断==

首先我们知道,如果没有设置密保的话safequestion从数据库取出默认为’0’,safeanswer为空。根据empty函数特性,’0’会被判断为空,会进入重新将$safequestion赋值为’’。而'0' != '' ,所以我们需要一个输入即不使empty为空,且弱类型等于’0’的字符串。'00'、'000'、'0.0'以上这些都是可以的。

接下来safeanswer既然本来就为空,那么不输入正好也就相等了。跟踪sn函数

跟踪newmail。

可见在sn函数中将send参数设置了’N’,其实就是生成了暂时密码并插入了数据库中,并进行跳转:

跳转链接就是修改密码的链接了。

复现

在找回密码处,点击通过安全问题取回。

填写信息并抓包,修改id和userid为想要重置密码的对象,再加上以上分析内容,发包即可得到修改密码url

进入该url,修改密码。

修复意见

改为强类型比较===

2. 前台文件上传漏洞

漏洞信息

CVE-2018-20129, 提交时间:20181221

漏洞成因

管理员用户前台可以绕过限制上传shell

漏洞代码分析

漏洞在于用户发布文章上传图片处。处理文件在/include/dialog/select_images_post.php

而上传文件存在全局过滤/include/uploadsafe.inc.php

可以看到名字中不得有上述字符,且限制了content-type。按道理说直接限制不得存在的字符,似乎没有问题了,可在发布文章文件上传的处理文件select_images_post.php中存在如下代码:

再次过滤了图片名,并且再次判断如上三种文件类型是否存在其中。这么一次过滤,直接粗暴的将一些特殊字符替换为空,那么我们就可以通过特殊字符绕过上面的全局文件名不能包含php字符的限制,比如文件名为1.jpg.p*hp

复现

登录并进入member/article_add.php发布文章,选择下面的富文本编辑器插入图片

选择好shell并上传抓包

向如上分析修改文件名与content-type,即可返回shell地址

修复意见

在最后拼接文件名时再判断一次。

3. DeDecms 任意用户登录

漏洞信息

漏洞编号:SSV-97087,提交时间:20180118

漏洞成因

dedecms的会员模块的身份认证使用的是客户端session,在Cookie中写入用户ID并且附上ID__ckMd5,用做签名。主页存在逻辑漏洞,导致可以返回指定uid的ID的Md5散列值。原理上可以伪造任意用户登录。

漏洞代码分析

在/member/index.php中会接收uid和action参数。uid为用户名,进入index.php后会验证Cookie中的用户ID与uid(用户名)并确定用户权限。

我们可以看到当uid存在值时就会进入我们现在的代码中,当cookie中的last_vid中不存在值为空时,就会将uid值赋予过去,$last_vid = $uid;,然后PutCookie。

那么这么说,我们控制了$uid就相当于可以返回任意值经过服务器处理的md5值。

而在接下来会验证用户是否登录。

现在我们来看看,dedecms会员认证系统是怎么实现的:/include/memberlogin.class.php

$this->M_ID等于Cookie中的DedUserID,我们继续看看GetCookie函数

它不但读了cookie还验证了md5值。

这样,由于index.php中我们可以控制返回一个输入值和这个输入值经过服务器处理后的md5值。那么如果我们伪造DedUserID和它对应的MD5就行了。

最后一个问题,因为我们上面是通过用户名伪造ID的,用户名为字符串而ID为整数,但好在在构造用户类中将M_ID intval了一下$this->M_ID = intval($this->M_ID); 那么这么说,如果我们想伪造ID为1的用户的Md5,我们只要在上面设置uid(用户名)为’000001’即可。

复现

现在我们的思路就是

  1. 先从member/index.php中获取伪造的DedeUserID和它对于的md5
  2. 使用它登录

访问member/index.php?uid=0000001并抓包(注意cookie中last_vid值应该为空)。

可以看到已经获取到了,拿去当做DeDeUserID

可以看到,登陆了admin用户。

修复意见

M_ID被intval后还要判断是否与未intval之前相同。

4. Dedecms V5.7后台的两处getshell

漏洞信息

CVE-2018-9175,提交时间:20180401

漏洞成因

后台写配置文件过滤不足导致写shell。

漏洞代码分析

第一个

在/dede/sys_verifies.php中的第152行处

可以看到,这里会将$refiles数组中的内容写入配置文件modifytmp.inc中。

dedecms对于输入是全局过滤的,在/common.inc.php中注册并过滤了外部提交的变量

上面的$refiles就是注册的外部变量,可见已经addlashes了而我们还是需要绕过fwrite($fp, '$files['.$i.'] = "'.$filename.'";'."\r\n"); 实现注入shell,首先需要注入就必须闭合双引号,在这里有个诡异的操作

$filename = substr($filename,3,strlen($filename)-3);

去掉了输入的前三个字符,这样就为我们写shell制造了机会,当我们输入\" 时经过addlashes会变成\\\",再去掉前三个字符就只剩下双引号实现闭合。

此时写入shell后只要再找一个包含modifytmp.inc文件的文件就好了,全局搜索一下可以发现就在本文件/dede/sys_verifies.php

第二个

同样是写配置文件,位于/dede/sys_cache_up.php

跟进WriteEnumsCache()

 

可以看到,直接从数据库中读取并写入php文件中,从数据库中取出后并没有经过过滤。

将shell写进数据库中https://172.16.180.130/dedecms/uploads/dede/stepselect_main.php?action=addenum_save&ename=123&egroup=;phpinfo();//&islogin=1

复现

因为包含是在同一个文件,所以直接输入dede/sys_verifies.php?action=getfiles&refiles[]=123&refiles[]=\%22;phpinfo();die();// 就可以。

修复意见

更改前面的过滤条件

5. 某cms v5.7 sp2 后台文件上传 getshell

漏洞信息

CVE-2019-8362,提交时间 20190216

漏洞成因

上传zip文件解压缩对于文件名过滤不周,导致getshell

漏洞代码分析

/dede/album_add.php 175行验证后缀

$fm->GetMatchFiles($tmpzipdir,"jpg|png|gif",$imgs);

进入函数:

可以确定preg_match("/\.(".$fileexp.")/i",$filename)只是判断了文件名中是否存在.jpg、.png、.gif中的一个,只要构造1.jpg.php就可以绕过。

复现

管理员用户上传压缩了1.jpg.php这个shell的zip文件再解压缩即可。这里

修复意见

加强过滤正则的书写。

同和上面,dedecms后台getshell真的很鸡肋。。。

发表评论

电子邮件地址不会被公开。 必填项已用*标注