@@ -15,9 +15,16 @@ def initialize(info = {})
15
15
'Name' => 'F5 BigIP Backend Cookie Disclosure' ,
16
16
'Description' => %q{
17
17
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.
19
20
} ,
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
+ ] ,
21
28
'References' =>
22
29
[
23
30
[ 'URL' , 'http://support.f5.com/kb/en-us/solutions/public/6000/900/sol6917.html' ] ,
@@ -34,7 +41,7 @@ def initialize(info = {})
34
41
end
35
42
36
43
def change_endianness ( value , size = 4 )
37
- conversion = value
44
+ conversion = nil
38
45
39
46
if size == 4
40
47
conversion = [ value ] . pack ( "V" ) . unpack ( "N" ) . first
@@ -46,21 +53,30 @@ def change_endianness(value, size=4)
46
53
end
47
54
48
55
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})\. /
52
57
host = $1. to_i
53
58
port = $2. to_i
54
-
55
59
host = change_endianness ( host )
56
60
host = Rex ::Socket . addr_itoa ( host )
57
-
58
61
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
61
78
end
62
-
63
- back_end
79
+ host . nil? ? nil : "#{ host } :#{ port } "
64
80
end
65
81
66
82
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.
71
87
} )
72
88
73
89
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
81
101
82
102
cookie
83
103
end
@@ -96,17 +116,26 @@ def run
96
116
cookie = get_cookie ( ) # Get the cookie
97
117
# If the cookie is not found, stop process
98
118
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" )
100
120
break
101
121
end
102
122
103
123
# Print the cookie name on the first request
104
124
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
106
135
end
107
136
108
137
back_end = cookie_decode ( cookie [ :value ] )
109
- unless back_ends . include? ( back_end )
138
+ unless back_end . nil? || back_ends . include? ( back_end )
110
139
print_status ( "#{ peer } - Backend #{ back_end } found" )
111
140
back_ends . push ( back_end )
112
141
end
0 commit comments