从0学代码审计——DedeCMS-5.5.7-sp2
0x01 前言
继续审计和复现框架漏洞了,DedeCMS框架在我之前打鹏城杯的时候遇到过,于是找了个比较老的版本,审计一下漏洞,也算是熟悉一下该CMS的基本结构。
0x02 漏洞审计
织梦CMS貌似是基于文件的访问形式,没有像极致CMS那样的路由定义,所以在功能对标实现代码上还是比较轻松的,织梦CMS的基本目录如下
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/1.png)
直接开始分析漏洞
cookie伪造导致任意前台用户登录
涉及到前台登录,我们就看一下登录的相关代码,在/member/index_do.php文件中
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/2.png)
首先会判断验证码是否正确,登录的用户名是否合法,密码是否存在。然后调用 CheckUser 方法检查账号
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/3.png)
首先会在数据库查询该用户的相关信息,然后验证密码是否正确,都没问题的话,调用 PutLoginInfo 方法设置登录信息,然后返回1表示登录成功。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/4.png)
在这个函数里,先判断距离上一次登录是否超过两个小时,增加积分,然后更新数据库的登录时间,最后将uid写进cookie里,那这个uid表示的是什么,实际上就是数据表中前面的主键
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/5.png)
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/6.png)
这里设置了两个cookie,一个是uid,另一个将uid和 $cfg_cookie_encode 全局变量拼接,然后取md5加密的前十六位。其实就是uid与uid加密后的字符串,后续肯定会在这方面做验证。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/7.png)
在 getcookie 方法中确实做了验证。这么做就是为了验证登录状态,攻击者可以去修改cookie中的uid,但是在这个方法中做了验证,在不知道源码的情况下,我们无法得到该uid的加密字符串,自然就过不了验证。
漏洞点在 member/index.php文件中的 124到165行,也就是实现会员空间主页的代码
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/8.png)
当 $last_vid为空的时候,会走到else分支里
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/9.png)
将 uid 赋值为 last_vid,然后下发cookie,以及它的加密值,如果这个 uid 我们可控,我们就能够得到任意用户的uid加密值,就可以任意用户登录了。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/10.png)
这个uid可控,就是用户名。那么检查登录状态的代码在哪里呢
在 menberlogin.class.php 文件的构造方法里,当时很疑惑,为什么访问index.php会实例化 memberlogin 这个类,找了一会才知道,在index.php前面包含了 config.php 文件,而在这个配置文件中
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/11.png)
实例化了 memberlogin 类,然后调用 IsLogin 方法判断用户是否登录。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/12.png)
在该类的构造方法中,获取名为 DedeUserID 的cookie,然后再数据库中查询是否存在相关信息。这个M_ID做了绝对值处理,所以在注册用户的时候可以注册为01,001,0001等等。
我们已经注册了一个0001的用户,然后访问它的空间
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/13.png)
下发了last_vid=0001以及对应的ckMd5的cookie,再将这两个值赋值给 DedeUserID 以及对应的ckMd5,刷新就可以成功登录到admin账户了。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/14.png)
前台任意用户密码修改
关键代码在 member\resetpassword.php 文件的75行到95行
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/15.png)
这里验证用户提交的问题和回答是否正确,然后会调用 sn 方法,这里是通过弱比较判断,可以绕过。一般没有做安全问题验证的用户,数据库里safequestion字段都是默认为0。用户将 $safequestion 传入0正好可以满足条件,但是不能直接传0,因为 empty 函数处理,所以我们可以传入浮点数的0(也就是0.0)如果做了安全验证,数据表中该字段是有值的,并且为int类型,那这个方法就行不通了。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/16.png)
之后就是进入到 sn 方法里,
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/17.png)
会调用到 newmail 方法,注意这里的 $send为 N
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/18.png)
然后返回一个密码修改链接,就可以修改密码了。
这里选择安全问题找回密码
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/19.png)
这时候会返回一个密码修改链接,注意这里的&是&的编码格式,访问的时候改回来就好了
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/20.png)
然后就可以任意密码修改。
前台任意文件上传
需要登录前台管理员,在内容中心的发表文章的上传图片功能点存在任意文件上传漏洞
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/22.png)
具体实现代码在 include\dialog\select_images_post.php 文件中
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/23.png)
这里获取文件名,它是通过正则来检测上传的是否是图片,并没有对文件的后缀名截取进行检测,此处可以通过上传图片马来绕过,
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/24.png)
,这里修改一下后缀名为p%hp,不然前端有检测,传不上去。根据上图代码可知,会规范我们的文件名,然后重命令。php后缀会保留,然而jpg则会被修改。根据这个路径访问我们上传的php文件
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/25.png)
能够成功getshell。
0x03 结语
一旦登录到了后台,就可以对源码进行修改了,所以说后台的审计的漏洞真的算漏洞吗?可能开发者就是要对后台管理员设置这么大的权限。
![](/2023/12/11/%E4%BB%8E0%E5%AD%A6%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E2%80%94%E2%80%94DedeCMS-5-5-7-sp2/21.png)
所以后台涉及到的相关漏洞就不再分析了。