OFCMS 1.1.3
0x00 前言
看 版本 看 控制器 看 过滤器
https://forum.butian.net/share/1229
从补天看到的java 代码审计文章,跟着学习复现。
0x01 环境搭建
1.1 cms下载地址
https://gitee.com/oufu/ofcms/tree/V1.1.3/
1.2 idea部署项目
https://blog.youkuaiyun.com/Alexz__/article/details/116229266
https://forum.butian.net/share/1229
https://blog.youkuaiyun.com/Alexz__/article/details/116272080?spm=1001.2014.3001.5502
感谢两位师傅的笔记
1.3 服务启动成功
1.4 程序自动安装(失败)
爆出语法错误
1.5 尝试手动部署 (成功)
1.5.1 创建库导入.sql文件
首先在MySQL中创建空的ofcms数据库,然后将 ofcms-V1.1.3/doc/sql/ofcms-v1.1.3.sql文件导入到自己创建的数据库中
1.5.2 修改数据库配置文件并改名
将数据库配置文件ofcms-V1.1.3/ofcms-admin/src/main/resources/dev/conf/db-config.properties文件名修改为db.properties,然后修改文件中的数据库配置信息
1.5.3 重新启动项目
重新启动项目
1.5.4 访问后台
,访问程序后台地址:
http://localhost:8080/ofcms_admin_war/admin/index.html
默认账号和密码:admin/123456
0x02 漏洞挖掘
拿到框架 先看
- pom.xml的依赖 dependency
- ofcms-V1.1.3\ofcms-admin\src\main\webapp\WEB-INF\web.xml 过滤器 filter
- 全局搜索关键字 配合 网页 功能点灰盒 审计
2.1 sql注入
2.1.1 漏洞位置
后台->系统设置->代码生成->增加 可以输入sql语句
2.1.2 定位代码
对应控制器处理方法为
com.ofsoft.cms.admin.controller.system.SystemGenerateController类的create()方法
2.1.3 分析传参处理
在create方法中 先用getPara()方法 获取用户的输入sql的值
该方法位于 com.jfinal.core.Crontroller类中
getPara方法 就是使用request.getParameter(name)来获取http协议提交过来的数据 返回string类型的数据
这里并没有对用户输入的内容进行过滤
再看create方法,紧接着调用Db.update(sql); 方法执行输入的sql语句,跟进方法
跟踪到
com.jfinal.plugin.activerecord.DbPro类的update方法执行的sql语句
看到这里使用了预编译的方法,但是我们可以直接输入整条sql语句执行,不使用占位符(?, ?, ?),所以这里预编译处理将起不到作用。
2.2.4 payload
update of_cms_link set link_name=updatexml(1,concat(0x7e,(user())),0) where link_id = 4
从响应包可以看到SQL语法报错信息,在报错信息中显示了当前数据库用户信息
2.2 SSTI模板注入
在pom.xml文件的时候发现存在模引擎freemarker的包依赖信息,该模模板引擎存在ssti模板注入。
https://www.cnblogs.com/Eleven-Liu/p/12747908.html
2.2.1 漏洞位置
后台->模板设置->模板文件->模板目录->修改index.html
2.2.2 定位代码
对应的控制器处理方法为 com.ofsoft.cms.admin.controller.cms.TemplateController类的save方法
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();
}
2.2.3 分析传参处理
我们修改的模板在 file_content
使用String fileContent =getRequest().getParameter(“file_content”); 接收我们输入的file_content参数内容,
fileContent = fileContent.replace("<", “<”).replace(">", “>”);
将 内容中的 < 和> 替换为< 和 > (即html解码)
File file = new File(pathFile, fileName);
FileUtils.writeString(file, fileContent);
将内容写入原来的文件名中。
发现并没有做任何的过滤。
2.2.4 payload
<#assign ex="freemarker.template.utility.Execute"?new()>
${ ex("calc") }
在管理后台修改 index.html 模板文件的内容,插入我们的payload并保存
访问首页 http://localhost:8080/ofcms_admin_war/
弹出计算器
2.3 文件上传
2.3.1 漏洞位置
后台->模板设置->模板文件->模板目录->修改index.html
2.3.2 定位代码
在 com.ofsoft.cms.admin.controller.cms.TemplateController类的save方法中还存在任意文件上传漏洞
2.3.3 分析传参
可以看到对 res_path dirs file_name file_content 参数 都是用户输入的 可以控制的 并且没有进行任何的过滤处理。
我们就可以抓包
对文件名修改 或者 添加…/ 跳转目录 在static静态资源目录下 写下js马
文件内容 进行 修改 写入恶意的jsp文件
2.3.4 上传冰蝎马
(1)抓包
(2)修改file_content 为冰蝎马的url编码
全url编码也可以
(3)修改file_name = …/…/…/static/shell.jsp
从index.html跳转到 static 需要三个…/
上传成功
2.3.5 冰蝎连接
连接成功
2.4 XXE漏洞
2.4.1 漏洞位置
在com.ofsoft.cms.admin.controller.ReprotAction类的expReport方法中
2.4.2 分析传参
(1)getParamsMap() 有传参
后边将输入的 值传递给 hm 和 jrxmlFileName
服务器接收用户输入的j参数后,拼接生成文件路径,这里没有进行过滤,可以穿越到其它目录,但是限制了文件后缀为jrxml。
(2)定位 getParamsMap()方法 没有过滤
(3)接下来会调用JasperCompileManager.compileReport()方法,跟进该方法看看
(4)在compileReport方法中又调用了JRXmlLoader.load()方法,继续跟踪
(5)一直跟到调用JRXmlLoader.loadXML()方法,在loadXML方法中调用了Digester类的parse解析我们的XML文档内容,默认是没有禁用外部实体解析的,所以这里是存在XXE漏洞的
2.4.3 漏洞利用
(1)利用之前的文件上传漏洞 写入一个 jrxml 后缀的文件
(2)访问漏洞url xxe成功
http://localhost:8080/ofcms_admin_war/admin/reprot/expReport.html?j=…/…/static/xxe
2.5 存储型xss (前台新闻留言处)
2.5.1 漏洞位置
http://localhost:8080/ofcms_admin_war/
新闻中心- 任选一条新闻–下方的用户评论功能
2.5.2 分析代码传参
在save方法中 调用了getParamsMap方法,获取用户提交的所有参数。 又调用 getRealIp()方法 获取到ip,写入 params参数的comment_ip 键 中。
之后 调用 Db.update()方法将数据更新到数据库中。
没有对用户输入的数据进行过滤。
2.5.3 xss 测试
抓取用户评论的请求数据包,修改comment_content内容为
payload:<script>alert(1)</script>
,提交数据包。
弹窗成功
0x03 总结
跟着 百度 用idea部署了 ofcms 项目 。
看着补天大佬文章学习 审计。
依赖 版本 控制器 过滤器
有无可控传参 有无过滤
getPara 获取请求中的参数
审计了
(1)sql注入 用了预编译方法,但是没有指定sql语句 及占位符 。 传参为整段sql语句,达成报错注入。
(2) ssti模板注入 因为freemarker 依赖 存在 该类注入。 并且 接收到传参后 没有进行 检查过滤 直接写入文件 导致存在该类漏洞。
(3) 任意文件上传,同ssti模板注入处一个功能点,没有对上传的任何参数 内容进行检查过滤,导致可以跳目录 上传 jsp马。
(4) xxe漏洞 在一处接收传参 点后 分析 loadXML方法中 调用了 Digester类的parse解析了 xml文档的内容。 并且 默认没有禁用外部实体解析 导致存在XXE漏洞。
(5)存储型漏洞 获取到用户输入的参数 直接写入数据库中 没有进行过滤。