Skip to content

Commit c9ddd0d

Browse files
committed
Land rapid7#4795, f5_bigip_cookie_disclosure update
2 parents 59b7f32 + b676f5a commit c9ddd0d

File tree

1 file changed

+51
-22
lines changed

1 file changed

+51
-22
lines changed

modules/auxiliary/gather/f5_bigip_cookie_disclosure.rb

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@ def initialize(info = {})
1515
'Name' => 'F5 BigIP Backend Cookie Disclosure',
1616
'Description' => %q{
1717
This module identifies F5 BigIP load balancers and leaks backend
18-
information through cookies inserted by the BigIP devices.
18+
information (pool name, backend's IP address and port, routed domain)
19+
through cookies inserted by the BigIP system.
1920
},
20-
'Author' => [ 'Thanat0s <thanspam[at]trollprod.org>' ],
21+
'Author' =>
22+
[
23+
'Thanat0s <thanspam[at]trollprod.org>',
24+
'Oleg Broslavsky <ovbroslavsky[at]gmail.com>',
25+
'Nikita Oleksov <neoleksov[at]gmail.com>',
26+
'Denis Kolegov <dnkolegov[at]gmail.com>'
27+
],
2128
'References' =>
2229
[
2330
['URL', 'http://support.f5.com/kb/en-us/solutions/public/6000/900/sol6917.html'],
@@ -34,7 +41,7 @@ def initialize(info = {})
3441
end
3542

3643
def change_endianness(value, size=4)
37-
conversion = value
44+
conversion = nil
3845

3946
if size == 4
4047
conversion = [value].pack("V").unpack("N").first
@@ -46,21 +53,30 @@ def change_endianness(value, size=4)
4653
end
4754

4855
def cookie_decode(cookie_value)
49-
back_end = ""
50-
51-
if cookie_value =~ /(\d{8})\.(\d{5})\./
56+
if cookie_value =~ /(\d{8,10})\.(\d{1,5})\./
5257
host = $1.to_i
5358
port = $2.to_i
54-
5559
host = change_endianness(host)
5660
host = Rex::Socket.addr_itoa(host)
57-
5861
port = change_endianness(port, 2)
59-
60-
back_end = "#{host}:#{port}"
62+
elsif cookie_value.downcase =~ /rd\d+o0{20}f{4}([a-f0-9]{8})o(\d{1,5})/
63+
host = $1.to_i(16)
64+
port = $2.to_i
65+
host = Rex::Socket.addr_itoa(host)
66+
elsif cookie_value.downcase =~ /vi([a-f0-9]{32})\.(\d{1,5})/
67+
host = $1.to_i(16)
68+
port = $2.to_i
69+
host = Rex::Socket.addr_itoa(host, v6=true)
70+
port = change_endianness(port, 2)
71+
elsif cookie_value.downcase =~ /rd\d+o([a-f0-9]{32})o(\d{1,5})/
72+
host = $1.to_i(16)
73+
port = $2.to_i
74+
host = Rex::Socket.addr_itoa(host, v6=true)
75+
elsif cookie_value =~ /!.{104}/
76+
host = nil
77+
port = nil
6178
end
62-
63-
back_end
79+
host.nil? ? nil : "#{host}:#{port}"
6480
end
6581

6682
def get_cookie # request a page and extract a F5 looking cookie.
@@ -71,13 +87,17 @@ def get_cookie # request a page and extract a F5 looking cookie.
7187
})
7288

7389
unless res.nil?
74-
# Get the SLB session ID, like "TestCookie=2263487148.3013.0000"
75-
m = res.get_cookies.match(/([\-\w\d]+)=((?:\d+\.){2}\d+)(?:$|,|;|\s)/)
76-
unless m.nil?
77-
cookie[:id] = (m.nil?) ? nil : m[1]
78-
cookie[:value] = (m.nil?) ? nil : m[2]
79-
end
80-
end
90+
# Get the SLB session IDs for all cases:
91+
# 1. IPv4 pool members - "BIGipServerWEB=2263487148.3013.0000",
92+
# 2. IPv4 pool members in non-default routed domains - "BIGipServerWEB=rd5o00000000000000000000ffffc0000201o80",
93+
# 3. IPv6 pool members - "BIGipServerWEB=vi20010112000000000000000000000030.20480",
94+
# 4. IPv6 pool members in non-default route domains - "BIGipServerWEB=rd3o20010112000000000000000000000030o80",
95+
# 5. Encrypted cookies - "BIGipServerWEB=!dcdlUciYEFlt1QzXtD7QKx22XJx7Uuj2I0dYdFTwJASsJyJySME9/GACjztr7WYJIvHxTSNreeve7foossGzKS3vT9ECJscSg1LAc3rc"
96+
97+
m = res.get_cookies.match(/([~_\.\-\w\d]+)=(((?:\d+\.){2}\d+)|(rd\d+o0{20}f{4}\w+o\d{1,5})|(vi([a-f0-9]{32})\.(\d{1,5}))|(rd\d+o([a-f0-9]{32})o(\d{1,5}))|(!(.){104}))(?:$|,|;|\s)/)
98+
cookie[:id] = m.nil? ? nil : m[1]
99+
cookie[:value] = m.nil? ? nil : m[2]
100+
end
81101

82102
cookie
83103
end
@@ -96,17 +116,26 @@ def run
96116
cookie = get_cookie() # Get the cookie
97117
# If the cookie is not found, stop process
98118
if cookie.empty? || cookie[:id].nil?
99-
print_error("#{peer} - F5 Server load balancing cookie not found")
119+
print_error("#{peer} - F5 BigIP load balancing cookie not found")
100120
break
101121
end
102122

103123
# Print the cookie name on the first request
104124
if i == 0
105-
print_status("#{peer} - F5 Server load balancing cookie \"#{cookie[:id]}\" found")
125+
print_status("#{peer} - F5 BigIP load balancing cookie \"#{cookie[:id]} = #{cookie[:value]}\" found")
126+
if cookie[:id].start_with?('BIGipServer')
127+
print_status("#{peer} - Load balancing pool name \"#{cookie[:id].split('BIGipServer')[1]}\" found")
128+
end
129+
if cookie[:value].start_with?('rd')
130+
print_status("#{peer} - Route domain \"#{cookie[:value].split('rd')[1].split('o')[0]}\" found")
131+
end
132+
if cookie[:value].start_with?('!')
133+
print_status("#{peer} - F5 BigIP cookie is probably encrypted")
134+
end
106135
end
107136

108137
back_end = cookie_decode(cookie[:value])
109-
unless back_ends.include?(back_end)
138+
unless back_end.nil? || back_ends.include?(back_end)
110139
print_status("#{peer} - Backend #{back_end} found")
111140
back_ends.push(back_end)
112141
end

0 commit comments

Comments
 (0)