本项目为dede自研系统,其中所有功能点都由dede自开发,访问对应PHP文件即可找到对应功能点。
大部分文件都包含了/dede/config.php,该文件中检测了用户的登录状态,且对于XSS进行了过滤。
通过搜索 fwrite() 函数,发现这里存在可疑写入点,而我们知道得知dede的路由可以通过直接访问
我们可以看到这里代码70行的变量 $configstr 是经过序列化的 $faqs 变量传入的,那么这里的 $faqs
这个数组是怎么传入的。
直接访问该文件发现如下功能点,而这里的验证码设置功能处正是传入参数的地方。
这里抓包我们可以清楚的看到此处参数可控的地方。
但在代码的第60行是存在过滤的,这里当你 question 参数传入单引号时会被正则替换为双引号没办法
进行闭合,而 quswer 参数则并没有任何限制,反而帮我们删除了反斜杠,所以这里 answer 参数处就存在绕过。
搜索 read() 函数,发现在危险函数中存在参数可控的地方,我们进入 select_images.php 文件。
在测试功能点模块管理时,发现一处可以操作数据库的地方,我们点击修改。
其实我们可以直接在删除程序处输入我们想要执行的SQL语句进行测试
这里传入了两个参数 action 以及 hash。
这里通过uninstall执行该处分支,然后通过上面传入的hash参数值来定位文件, GetFileLists() 获取
跟进 GetFileLists() 函数。
在该函数中首先包含了 modulescache.php 文件,并通过 $hash 返回xml文件内容。
modulescache.php 文件内容。
找到该xml,查看该xml内容,该文件内容中就是相应模块的配置信息。
回到上面代码的的第425行,又执行了 uninstallok 分支。该分支就是卸载模块的分支,这里最重
要的是通过 GetSystemFile() 获取文件内容,这里传入了另一个参数 delsql ,跟进该函数
通过 GetHashFile() 函数获取文件内容。
这里的delsql内容中正是删除程序处的文件的base64内容
最后在代码518行执行SQL语句,所以我们可以通过Mysql日志文件来getshell,而这里需要网站的绝对
路径,由于存在目录遍历,所以可以轻松获取绝对路径。
最后访问cyw.php,获取到phpinfo信息。
同样的方法,在搜索危险函数 fwrite() 时发现在 article_string_mix.php 中存在可以控制写入内容
的地方。
在 article_string_mix.php 中 $allsource 写入的内容是可控的,但在代码29-34行中存在危险函数
过滤,但在过滤函数中过滤不严格导致绕过,实现代码执行。
通过 preg_replace() 绕过危险函数过滤,造成代码执行。
写入downmix.data.php
访问dede/article_template_rand.php文件,执行phpinfo()。
这里依旧是同样的功能点,所以大家看到这里其实也可以发现,在dedecms中使用 fwrite() 函数写入
配置文件的操作是很多的,在该系统中我们只需要观察两点即可,一写入的位置为可解析的php文件,
二写入的内容我们是可控的即可。
在函数 ReWriteConfig() 中,我们可以发现代码的第38行和第42行都是用了 fwrite() 函数,向上回
溯发现该处的值是从代码31行的 sysconfig 表中拿到的,我们去看看该表中的内容。
存储了网站的配置信息,上面的代码中可以看到type为 number 时会将 varname 字段
的值以及value字段的值写入配置文件,如果类型不为type时,这里会存在一个小小的过滤,这里的单引
号会被替换为空。
1.我们可以直接在type=number类型的字段中直接插入我们要执行的代码
2.通过\反斜杠来转义原本的单引号,然后使我们的代码逃逸出来
在 dopost 参数为 save 时,我们可以发现这里接收了post传入的参数,并且将传入的内容写入到了
sysconfig 表中。在代码74行中执行了上面分析的 ReWriteConfig() 函数。
我们访问/dede/sys_info.php文件,发现该处功能点确实是配置系统参数处,所以我们直接在
type=number参数处插入我们的代码。
第二种方法可以通过\反斜杠转义原有的单引号,使我们的代码逃逸出来。
这样的话也可以造成代码执行,只不过方法不同。
在测试系统功能点的时候,发现一处可以操作数据库的地方,下面的功能可以执行SQL语句。
漏洞分析:
这里执行到query分支,108-111行这里存在过滤,这里过滤了drop关键字,116行执行我们SQL语句。
set global general_log = on;
set global general_log_file = 'D:/phpstudy_pro/WWW/www.dedecms12.com/uploads/shell.php';
该处具有前端限制,上传 .jpg 后缀文件,结合brup抓包,发现处理上传功能的文件为dede/archives_do.php
入口文件通过 config.php 会实现权限认证和一些外部参数过滤注册
我们这里上传文件会带有$_FILES参数,上面通过全局分析得知会触发uploadsafe.inc.php的过滤
在经过过滤后,通过AdminUpload()实现最终文件上传
include/helpers/upload.helper.php
最终实现文件上传的AdminUpload()来自upload.helper.php,传入AdminUpload()的$ftype固定为imagelit,则一定会进入对应的检测判断,在检测判断代码中,$sparr定义了一个MIME Type白名单,若上传文件的MIME Type不在白名单中直接退出,MIME Type可控。
梳理一下,该功能点,系统只做了两个限制,MIMI Type为图片类型,可控。但MIME Type为图片类型时会通过getimagesize()检测,这里也可绕过,看是否可以利用保证Content-Type为图片类型,构造图片的文件头,绕过文件上传的限制,并且会返回上传文件名和路径。
进入添加文档,该功能可以发布文章,而且具有文件上传的功能。
测试发现还是黑盒好测一点,在dedecms后台还是存在很多xss的,本次是在黑盒测试后,在回头审计代码的问题,其实这样白盒审计意义不大,在全局分析中发现并没有对外部数据做xss全局过滤,另外注意到dedecms具有视图类负责显示输出,封装了很多输出的功能,在平时白盒审计xss漏洞需要注意echo,innerHTML这类输出到前端的关键词,但在dedecms中还需要注意视图类封装的输出函数
qrcode.php及加载的文件都没有做xss过滤,通过common.inc.php会注册全局变量
$id只能为整数类型,$type类型可控
加载模板qrcode.htm,利用视图类格式化输出$id,$type的值,$type可控,这里就存在xss漏洞
可以看到这里的触发点$dtp->SetVar('type',$type);,然而在seay这种代码扫描工具中是不会在意这些点的,同样有些框架对sql操作也做了很好的封装,如果只是依靠seay的结果来做代码审计,可能会忽略掉很多关键点
eay似乎没有 url 重定向漏洞的扫描,不过该漏洞审计也比较简单,主要关注能重定向的一些关键词,再看重定向地址是否可控
plus/download.php
对$link做了base64解码
程序中有一个很奇怪的限制,in_array($linkinfo['host'], $allowed),然而download.php中却没有$linkinfo这个参数dedecms后台也有一些url重定向漏洞,这里就不多关注这个洞了
在用户密码重置功能处,php存在弱类型比较,导致如果用户没有设置密保问题的情况下可以绕过验证密保问题,直接修改密码(管理员账户默认不设置密保问题)。值得注意的是修改的密码是member表中的密码,即使修改了管理员密码也是member表中的管理员密码,仍是无法进入管理。
php弱类型比较问题很常见,在不同类型比较时,如果使用的是==,php会将其中一个数据进行强制转换为另一个,比如'123a'就会被强制转换成123。这样就出现了弱类型比较问题,当然如果使用===判断比较就不会出现问题了。常见比较如下
'' == 0 == false '123' == 123 //'123'强制转换为123
'abc' == 0 //intval('abc')==0
'123a' == 123 //intval('123a')==123
'0x01' == 1 //被识别为十六进制
'0e123456789' == '0e987654321' //被识别为科学计数法
[false] == [0] == [NULL] == ['']
NULL == false == 0
true == 1
dedecms的/member/resetpassword.php就是用来处理用户密码重置的问题,问题出在75行开始处理验证密保问题处。
这段代码先是从数据库取出相关用户的密保问题及密保答案,在对用户输入做了一些处理后,进行了关键性的判断if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer) ,就在这里用了弱类型判断==。首先我们知道,如果没有设置密保的话safequestion从数据库取出默认为'0',safeanswer为空。根据empty函数特性,'0'会被判断为空,会进入重新将$safequestion赋值为''。而'0' != '' ,所
跟踪sn函数
跟踪newmail。
可见在sn函数中将send参数设置了'N',其实就是生成了暂时密码并插入了数据库中,并进行跳转:
在找回密码处,点击通过安全问题取回。
dedecms的会员模块的身份认证使用的是客户端session,在Cookie中写入用户ID并且附上
ID__ckMd5
漏洞代码分析
在/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就行了。
REF:
https://www.freebuf.com/articles/web/281747.html
https://blog.szfszf.top/article/25/
https://github.com/SukaraLin/php_code_audit_project/blob/master/dedecms/dedecms%20v5.7%20sp2%20%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1.md