从0学代码审计——DedeCMS-5.5.7-sp2
0x01 前言
继续审计和复现框架漏洞了,DedeCMS框架在我之前打鹏城杯的时候遇到过,于是找了个比较老的版本,审计一下漏洞,也算是熟悉一下该CMS的基本结构。
0x02 漏洞审计
织梦CMS貌似是基于文件的访问形式,没有像极致CMS那样的路由定义,所以在功能对标实现代码上还是比较轻松的,织梦CMS的基本目录如下

直接开始分析漏洞
cookie伪造导致任意前台用户登录
涉及到前台登录,我们就看一下登录的相关代码,在/member/index_do.php文件中

首先会判断验证码是否正确,登录的用户名是否合法,密码是否存在。然后调用 CheckUser 方法检查账号

首先会在数据库查询该用户的相关信息,然后验证密码是否正确,都没问题的话,调用 PutLoginInfo 方法设置登录信息,然后返回1表示登录成功。

在这个函数里,先判断距离上一次登录是否超过两个小时,增加积分,然后更新数据库的登录时间,最后将uid写进cookie里,那这个uid表示的是什么,实际上就是数据表中前面的主键


这里设置了两个cookie,一个是uid,另一个将uid和 $cfg_cookie_encode 全局变量拼接,然后取md5加密的前十六位。其实就是uid与uid加密后的字符串,后续肯定会在这方面做验证。

在 getcookie 方法中确实做了验证。这么做就是为了验证登录状态,攻击者可以去修改cookie中的uid,但是在这个方法中做了验证,在不知道源码的情况下,我们无法得到该uid的加密字符串,自然就过不了验证。
漏洞点在 member/index.php文件中的 124到165行,也就是实现会员空间主页的代码

当 $last_vid为空的时候,会走到else分支里

将 uid 赋值为 last_vid,然后下发cookie,以及它的加密值,如果这个 uid 我们可控,我们就能够得到任意用户的uid加密值,就可以任意用户登录了。

这个uid可控,就是用户名。那么检查登录状态的代码在哪里呢
在 menberlogin.class.php 文件的构造方法里,当时很疑惑,为什么访问index.php会实例化 memberlogin 这个类,找了一会才知道,在index.php前面包含了 config.php 文件,而在这个配置文件中

实例化了 memberlogin 类,然后调用 IsLogin 方法判断用户是否登录。

在该类的构造方法中,获取名为 DedeUserID 的cookie,然后再数据库中查询是否存在相关信息。这个M_ID做了绝对值处理,所以在注册用户的时候可以注册为01,001,0001等等。
我们已经注册了一个0001的用户,然后访问它的空间

下发了last_vid=0001以及对应的ckMd5的cookie,再将这两个值赋值给 DedeUserID 以及对应的ckMd5,刷新就可以成功登录到admin账户了。

前台任意用户密码修改
关键代码在 member\resetpassword.php 文件的75行到95行

这里验证用户提交的问题和回答是否正确,然后会调用 sn 方法,这里是通过弱比较判断,可以绕过。一般没有做安全问题验证的用户,数据库里safequestion字段都是默认为0。用户将 $safequestion 传入0正好可以满足条件,但是不能直接传0,因为 empty 函数处理,所以我们可以传入浮点数的0(也就是0.0)如果做了安全验证,数据表中该字段是有值的,并且为int类型,那这个方法就行不通了。

之后就是进入到 sn 方法里,

会调用到 newmail 方法,注意这里的 $send为 N

然后返回一个密码修改链接,就可以修改密码了。
这里选择安全问题找回密码

这时候会返回一个密码修改链接,注意这里的&是&的编码格式,访问的时候改回来就好了

然后就可以任意密码修改。
前台任意文件上传
需要登录前台管理员,在内容中心的发表文章的上传图片功能点存在任意文件上传漏洞

具体实现代码在 include\dialog\select_images_post.php 文件中

这里获取文件名,它是通过正则来检测上传的是否是图片,并没有对文件的后缀名截取进行检测,此处可以通过上传图片马来绕过,

,这里修改一下后缀名为p%hp,不然前端有检测,传不上去。根据上图代码可知,会规范我们的文件名,然后重命令。php后缀会保留,然而jpg则会被修改。根据这个路径访问我们上传的php文件

能够成功getshell。
0x03 结语
一旦登录到了后台,就可以对源码进行修改了,所以说后台的审计的漏洞真的算漏洞吗?可能开发者就是要对后台管理员设置这么大的权限。

所以后台涉及到的相关漏洞就不再分析了。