1
+ ##
2
+ # This file is part of the Metasploit Framework and may be subject to
3
+ # redistribution and commercial restrictions. Please see the Metasploit
4
+ # Framework web site for more information on licensing and terms of use.
5
+ # http://metasploit.com/framework/
6
+ ##
7
+
8
+ require 'msf/core'
9
+
10
+ class Metasploit3 < Msf ::Auxiliary
11
+
12
+ include Msf ::Exploit ::Remote ::HttpClient
13
+ include Msf ::Auxiliary ::Scanner
14
+
15
+ def initialize ( info = { } )
16
+ super ( update_info ( info ,
17
+ 'Name' => 'Ruby on Rails JSON Processor YAML Deserialization Scanner' ,
18
+ 'Description' => %q{
19
+ This module attempts to identify Ruby on Rails instances vulnerable to
20
+ an arbitrary object instantiation flaw in the JSON request processor.
21
+ } ,
22
+ 'Author' => [
23
+ 'jjarmoc' , # scanner module
24
+ 'hdm' # CVE-2013-0156 scanner, basis of this technique.
25
+ ] ,
26
+ 'License' => MSF_LICENSE ,
27
+ 'References' =>
28
+ [
29
+ [ 'CVE' , '2013-0333' ] ,
30
+ ]
31
+ ) )
32
+
33
+ register_options ( [
34
+ OptString . new ( 'TARGETURI' , [ true , "The URI to test" , "/" ] ) ,
35
+ OptEnum . new ( 'HTTP_METHOD' , [ true , 'HTTP Method' , 'POST' , [ 'GET' , 'POST' , 'PUT' ] ] ) ,
36
+ ] , self . class )
37
+ end
38
+
39
+ def send_probe ( pdata )
40
+ res = send_request_cgi ( {
41
+ 'uri' => datastore [ 'TARGETURI' ] ,
42
+ 'method' => datastore [ 'HTTP_METHOD' ] ,
43
+ 'ctype' => 'application/json' ,
44
+ 'data' => pdata
45
+ } , 25 )
46
+ end
47
+
48
+ def run_host ( ip )
49
+
50
+ # Straight JSON as a baseline
51
+ res1 = send_probe (
52
+ "{ \" #{ Rex ::Text . rand_text_alpha ( rand ( 8 ) +1 ) } \" : \" #{ Rex ::Text . rand_text_alpha ( rand ( 8 ) +1 ) } \" }"
53
+ )
54
+
55
+ unless res1
56
+ vprint_status ( "#{ rhost } :#{ rport } No reply to the initial JSON request" )
57
+ return
58
+ end
59
+
60
+ if res1 . code . to_s =~ /^[5]/
61
+ print_error ( "#{ rhost } :#{ rport } The server replied with #{ res1 . code } for our initial JSON request" )
62
+ print_error ( "\t \t Double check TARGETURI and HTTP_METHOD" )
63
+ return
64
+ end
65
+
66
+ # Deserialize a hash, this should work if YAML deserializes.
67
+ res2 = send_probe ( "--- {}\n " . gsub ( ':' , '\u003a' ) )
68
+
69
+ unless res2
70
+ vprint_status ( "#{ rhost } :#{ rport } No reply to the initial YAML probe" )
71
+ return
72
+ end
73
+
74
+ # Deserialize a malformed object, inducing an error.
75
+ res3 = send_probe ( "--- !ruby/object:\x00 " . gsub ( ':' , '\u003a' ) )
76
+
77
+ unless res3
78
+ vprint_status ( "#{ rhost } :#{ rport } No reply to the second YAML probe" )
79
+ return
80
+ end
81
+
82
+ vprint_status ( "Probe response codes: #{ res1 . code } / #{ res2 . code } / #{ res3 . code } " )
83
+
84
+ if ( res2 . code == res1 . code ) and ( res3 . code != res2 . code ) and ( res3 . code != 200 )
85
+ # If first and second requests are the same, and the third is different but not a 200, we're vulnerable.
86
+ print_good ( "#{ rhost } :#{ rport } is likely vulnerable due to a #{ res3 . code } reply for invalid YAML" )
87
+ report_vuln ( {
88
+ :host => rhost ,
89
+ :port => rport ,
90
+ :proto => 'tcp' ,
91
+ :name => self . name ,
92
+ :info => "Module triggered a #{ res3 . code } reply" ,
93
+ :refs => self . references
94
+ } )
95
+ else
96
+ # Otherwise we're not likely vulnerable.
97
+ vprint_status ( "#{ rhost } :#{ rport } is not likely to be vulnerable or TARGETURI must be set" )
98
+ end
99
+ end
100
+
101
+ end
0 commit comments