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

Ruby on Rails XML参数注入漏洞(CVE-2013-0156)分析

[复制链接]
跳转到指定楼层
楼主
发表于 2013-1-11 21:16:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Author: wofeiwo#80sec.com % I: m, m% j3 ~6 O

' r3 {3 n6 ^0 P6 A/ F; C注意,本文基本是这篇文章的中文版本,由于我水平有限,因此如果大家看的不是很明白,建议去原文查看。 * ]& ~2 `' f  V

1 g% [9 ~5 D- a9 \9 e* j近日RoR的漏洞大爆发,就在昨天临晨,RoR的官网发布了新的两个安全漏洞补丁,CVE-2013-0155和CVE-2013-0156. 0 X1 K) ^! E% T! _% L

' B9 l0 O9 L0 mCVE-2013-0155主要是防止Json数据解析的nil导致程序DoS,而CVE-2013-0156则是对RoR的XML解析进行修补.其中Json的那个并没有什么值得关注的部分,但是对于XML解析的修补,却很值得玩味.官网对此补丁的描述是:要求所有RoR的用户,必须立即(immediately)升级此补丁.这是本周内除了CVE-2012-6496之外,第二次要求大家”立即”升级的高危漏洞.甚至,连cnbeta都开始报道此漏洞了.
6 t9 X4 m/ d4 \' c, F( {  K4 U  _, h3 M; t  f2 r) m# u4 }
为什么这个漏洞如此的严重?原因就出在RoR框架的灵活性和便利性上.RoR支持用户使用多种格式提交你的参数,而不仅仅是使用HTTP的那些基本格式.你可以使用Json,可以使用XML的方式去对你提交的参数进行描述,因为Ruby是个强类型语言,因此由于HTTP传过来的纯string的参数并不足够描述参数的属性.当你使用XML格式去递交时,就是另一回事了.例如: , d& o9 Z2 h9 L2 w
8 K; w4 ^, \. \. A" x) C
<?xml version="1.0" encoding="UTF-8"?> <hash> <foo type="integer">1</foo> </hash>如果你POST提交这样的一个数据,RoR就会在其中解析为:
1 B( n2 u6 A+ j5 V9 D2 R
* k( a+ P4 Z5 N* J"hash" => {"foo" => 1}这些type的xml属性也就补充说明了一个参数的类型.RoR可以很便利的将其解析出来.可关键问题就在此,Type的取值还可以为Symbol和Yaml. 1 Z/ ~1 t, [, g; f5 g$ y

( f$ |2 z' r9 }0 P% e- L- d说起Symbol,还记得之前提到的另一个高危SQL注入漏洞,CVE-2012-6496,其最大的不可利用问题,就在于他需要提交的参数的key必须是Symbol类型么?
' I( {  O' k( K0 t; R( {
, m2 |- j2 Z/ L8 U4 e/ p0 `然后我们测试下,就会发现,由于框架中对参数进行 data.with_indifferent_access 的操作(会把key全变成string),我们还是无法通过xml去将Key变成Symbol类型。所以,也无法利用此漏洞去利用CVE-2012-6496。
; ~6 N0 M* j) |' O* P* G% e
, Q, \8 \, _4 |* R7 H7 y但是等等,还有另一个参数类型,yaml。 . R: R- M( I; ~+ A' f

5 Q% f' c% r% Z2 v4 A: Z/ p% K: Zyaml强大的地方在于,利用yaml语言,你可以让Rails生成各种类型的数据结构,例如,Object。
) [; s: z8 f& _. }/ K& @3 _8 t
; M# k: b3 k0 R8 K, H4 ~: p<test type="yaml">--- !ruby/object:A
$ j# w0 U5 D$ w3 Baaa: bbb </test>这基本类似于一个变量反序列化的过程,实际用起来基本就相当于一个任意变量覆盖漏洞。如果后续的代码中,有将此Object的aaa属性带入eval/exec/system等关键语句中,就可以执行一些被污染的代码。 9 F& e1 S7 I$ W; F* M
8 A2 F: s7 W4 T' t' s: {5 V- a1 p# Y
如果你熟悉rails的代码,或者其他开源rails的webapp,现在就可以找起来了。或许一个远程执行0day就此诞生。
  L9 v. e% u' D- A6 [2 ^
* C! y+ {, N+ p如果你不熟悉ror,那么也没问题,实际上还有个利用方式,可以直接进行sql注入。
: y7 H: ?6 p  j" L
, C0 ^/ l6 w+ S0 t  i# g; `# _/ Y一般在RoR中都是使用model.find_by_*的方式进行数据库查询(ActiveRecord模式) % o5 e7 e: o/ N9 t: o  ^

7 a$ S2 ^. k# I( ]; h( I% Umodel.find_by_id(params[:id])类似的代码会很常见。我们可以通过yaml去定义这个id变量,使其成为可以注入的内容:
1 r2 z9 m+ C( n" g& l# v
# q3 g3 @7 C0 E2 j; Y<id type=yaml>--- !str:Arel::Nodes::SqlLiteral
) W. y! q, j& \1 [; X+ C1 and 1=2 </id>利用如上代码,通过SqlLiteral对象,即可进行sql注入。 / @/ g, y* M% i  {* I

, I! u4 r' b8 K9 G9 j/ ^irb(main):017:0> a = Arel::Nodes::SqlLiteral.new("1") => "1" irb(main):018:0> Post.find_by_id(a) Post Load (0.0ms)SELECT "posts".* FROM "posts" WHERE "posts"."id" = 1 LIMIT 1 => #<Post id: 1, name: "aaa", title: nil, content: "A new post", created_at: "2013-01-10 05:01:01", updated_at: "2013-01-10 05:01:01"> irb(main):019:0> a = Arel::Nodes::SqlLiteral.new("1 and 1=1") => "1 and 1=1" irb(main):020:0> Post.find_by_id(a) Post Load (0.0ms)SELECT "posts".* FROM "posts" WHERE "posts"."id" = 1 and 1=1 LIMIT 1 => #<Post id: 1, name: "aaa", title: nil, content: "A new post", created_at: "2013-01-10 05:01:01", updated_at: "2013-01-10 05:01:01"> irb(main):021:0> a = Arel::Nodes::SqlLiteral.new("1 and 1=2") => "1 and 1=2" irb(main):022:0> Post.find_by_id(a) Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = 1 and 1=2 LIMIT 1 => nil本文非常感谢@tcpper 的帮助,没有他的解释和测试,我是无法理解RoR及本漏洞的。
- h5 M; V2 w. ^/ _; J! e0 k
2 l# u2 A) I  ~; o6 s& t; w
回复

使用道具 举报

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

本版积分规则

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