代码审计-Emlog CMS
0x01 前言
这次我选择的是个人博客CMS。
0x02 环境
lamp+emlog cms 6.0.0
安装的时候将直接访问/install.php,傻瓜操作即可。他不会主动创建数据库,所以要先准备一个数据库。
0x03 代码审计
首先粗略的看一下网站结构
查阅资料得知Emlog是一个MVC的设计模式。admin文件夹中是管理员后台/函数功能/后台模板。content文件夹中是备份数据/缓存数据/插件/模板文件。include文件夹为系统的控制器。
因此主要分析 admin 和 include 下的文件
/admin/comment.php-SQL注入
这个漏洞依旧是通过查找参数的方式找到的,最简单的使用正则匹配GET、POST等关键字,查看参数是否代入了sql语句。
代入的语句参数是否过滤。
我使用了seay进行查找
然后一个一个排查。
经过排查后,发现一个比较特殊的参数
为什么说它特殊呢,因为这个文件里的所有变量都做了intval()处理,即取整操作。唯独参数ip未做处理。
继续向下跟进
变量$ip被作为参数传递到了函数delCommentByIp(),我们继续使用搜索函数功能查找该函数。
跟进到此函数
这句:
验证:
由于这个文件处在admin/文件夹下,而该目录下存在权限判断,所以只有管理员才能执行。这也就是说这个漏洞比较鸡肋了,但是漏洞确实是存在的。
构造请求:
?action=delbyip&ip=127.0.0.1' and (extractvalue(1,concat(0x7e,(select user()),0x7e))) --+&token=32dbbe25d8a01e6b2eb40aa763a87fc7
admin/plugin.php-文件上传
同样使用灰盒审计思路,结合功能猜想可能存在的漏洞,
admin/plugin.php页面存在上传的功能
由于该网站开发的时候是可扩展性的,所以也就支持扩展插件的安装,而安装的插件必然是php文件,所以导致了getshell存在的可能。
我们跟进代码plugin.php
首先调用LoginAuth类的checkToken()方法进行权限判定
然后检测参数pluzip是否为空,如果发生错误等级为4(编译时解析错误 4),则调用函数emDirect(),此函数为一个页面跳转函数。跳转页面对应提示信息。
如果上传变量非zipfile 或 error大于等于1 或 临时存储路径文件名tmp_name为空,则提示上传失败。
继续跟进 这里对$zipfile['name']属性传递到了getFileSuffix()函数中。我们继续追踪这个函数。
pathinfo()函数返回文件的信息, PATHINFO_EXTENSION 返回文件后缀名
然后strtolower()函数返回小写的结果。
最后与'zip' 进行比对。不符合则跳转到?error_f=1
继续向下跟进
到emUnZip()函数,查看此函数
在解压的过程中会对压缩包里的文件名称进行判断,如果你压缩包名称为test则压缩包里必须存在test.php文件,否则会进行报错。需要注意的是这边有对zip文件名做判断,zip文件名必须以tpl_开头。所以使用tpl_文件名作为zip压缩包名即可。
验证:
将一句话木马以zip格式进行压缩
然后在插件上传处上传插件
访问路径/src/content/plugins/tpl_xor/tpl_xor.php
数据库备份getshell
通过数据库getshell我所知道的有这几种方法、
一是通过select '马子' into outfile '路径' 的方法,但是条件是:当前用户对web目录有写文件的权限;单引号可以使用;知道绝对路径;未配置 secure-file-priv,如果为linux服务器且管理员默认未配置 secure-file-priv 则路径为/var/lib/mysql-files/ 。
二是通过general_log,将日志写入特定目录下,但是这也是有条件的:当前用户对web目录要有写的权限;可以使用单引号;知道绝对路径;可以执行多行sql语句。
先尝试第一种方法:
备份sql语句,在其基础插入一句话木马。
但是由于 secure-file-priv 默认存在,所以GG
但是这样可以成功
但是毫无卵用。
继续尝试第二种方法
设置了 general_log 和 general_log_file 之后所有SQL记录都会写入指定的文件,所以可以通过这种方法将php语句写到log中。
为什么报错了呢,根据报错信息显示,general_log_file是无法写到/var/www/html下的。这是为啥呢?因为linux默认的 general_log_file 位置是/var/lib/mysql/ubuntu.log
这就扯犊子了 两种方法都失败,但是真的没办法了吗,也不一定,我只说了linux平台的MySQL,但是对于windows的lamp来说,以phpstudy举例,它的log就在www目录下: /phpStudy/PHPTutorial/WWW/emlog 。所以这玩意儿只有在windows才有用。
admin/link.php-存储型XSS
这个漏洞依然是从功能-参数找到的,除非只给我代码,要不然我不会单纯的代码审计,所以我肯定会结合功能去灰盒测试,link.php对应的是友链功能,其包含四个参数。
这些参数分别对应着这四个参数
我们跟进一下处理过程。
首先这里是没有进行html字符转义或者过滤的。addslashes()函数用于防御SQL注入还行,但是对于XSS来说并没什么用。
下面的正则判断下变量是否存在http/ftp关键字,没有就加上,所以我们不需要特意构造关键字。
addLink()函数接收了四个变量作为参数。调用了函数addLink。
跟进函数addLink()
首先对参数$taxis进行或处理,规定只存30000条数据,且首序号不能为负数。
然后未过滤直接进行插入数据。
然后跟进输出情况。
当action为空时,也就是点击友链功能未执行其他操作时。
$Link_Model变量,也就是Link_Model类的getLinks()方法会被调用。
我们继续跟进getLinks()方法。
首先进行sql查询,将表_link中的数据全部查出并升序排列。
然后将结果返回变量res
最后使用while循环将mysql_fetch_array的sitename变量进行htmlspecialchars()函数过滤并写入数组row
变量description同样做了htmlClean()函数处理。
然而变量siteurl并未进行过滤直接代入数组,最后返回函数处理后的数据。
继续跟进输出,程序静态调用View类的output()方法,将数据输出。
可见依然没有过滤。直接输出,这就构成了存储型的XSS。
验证:
write_log.php-存储型XSS
这玩意儿其实不是白盒出来的,由于编辑文章主体功能包含支持html代码功能,所以可以输入html代码,而本cms为了支持HTML代码功能,就没有对其默认编辑器Kindeditor的输入输出进行过滤,这就导致了存储型的XSS
验证:
flashXSS
Emlog使用了 uploadify.swf 的方式上传文件,这种XSS方式前面关于XSS的文章也有提到过,原因是flash的漏洞导致的,flash反正都快淘汰了,也不去分析了。文件路径 /include/lib/js/uploadify/uploadify.swf
admin/data.php-任意文件删除
灰盒测试的时候看到敏感功能就得看看有没有风险
这个功能在/data.php中
看一下代码
删除功能是无限制的,也就是说可以删除任意文件。
验证:
0x04 漏洞修复
SQL注入:
对于sql注入的修复一向都是过滤,由于这边是字符型,所以只要过滤单引号即可。这里使addslashes()函数处理即可
修改前:
修改后:
再试一下有没有sql注入
漏洞已修复
文件上传:
这个属于该博客的扩展功能,照理来说被上传shell也属于正常,如果实在要防止,只能采取两种方法:1、只信任商店中的插件,关闭上传功能,但是这样对于cms的可扩展性有所损失。2、对上传文件进行内容过滤,由于php过于灵活,强如D盾也没办法做到百分百必杀。所以我就不献丑了。
存储型XSS:
都是老生常谈的东西了,过滤!这里为什么用 htmlspecialchars() 函数就可以呢,因为这里没有html标签无法执行script语句的,包括事件也是无法执行的,因为事件也是需要html标签包裹才可以执行的。如果代码是这样的:
可见它的输出由input标签包裹,且 htmlspecialchars() 函数默认是没有过滤单引号的,所以可以构成了形成XSS的两个条件,一是存在html标签,二是单引号未被正确过滤。
那上面这怎么搞呢,使用 json_encode()函数 过滤后, 里边的代码就不会被当成js执行了。
修改前:
修改后:
漏洞修复
Kindeditor 编辑器引起的XSS
这个由于是编辑器的功能,也不能说算漏洞,但是确实可以造成影响,也可以选择过滤,但我不会。
数据库备份GETSHELL
这个应该不算漏洞了,属于无法避免的,所以这类cms在被获取后台管理权限时,百分百失陷。
任意文件删除
由于此功能是为了删除sql备份文件,所以不应该删除其他后缀的文件,限制后缀即可,我这里使用了一个正则进行处理。
修改前:
修改后:
已修复
0x05 结语
3