Skip to content

Commit 3e2a368

Browse files
author
jvazquez-r7
committed
Merge branch 'rails_json_yaml_scanner' of https://github.com/jjarmoc/metasploit-framework into jjarmoc-rails_json_yaml_scanner
2 parents e298866 + 846052a commit 3e2a368

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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\tDouble 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

Comments
 (0)