6
6
require 'msf/core'
7
7
8
8
class Metasploit3 < Msf ::Auxiliary
9
-
10
9
include Msf ::Auxiliary ::Report
11
10
include Msf ::Exploit ::Remote ::HttpClient
12
11
@@ -30,125 +29,131 @@ def initialize(info = {})
30
29
[ 'URL' , 'http://support.f5.com/kb/en-us/solutions/public/6000/900/sol6917.html' ] ,
31
30
[ 'URL' , 'http://support.f5.com/kb/en-us/solutions/public/7000/700/sol7784.html?sr=14607726' ]
32
31
] ,
33
- 'License' => MSF_LICENSE
32
+ 'License' => MSF_LICENSE ,
33
+ 'DefaultOptions' =>
34
+ {
35
+ 'SSLVersion' => 'TLS1'
36
+ }
34
37
) )
35
38
36
39
register_options (
37
40
[
41
+ OptInt . new ( 'RPORT' , [ true , 'The BigIP service port to listen on' , 443 ] ) ,
42
+ OptBool . new ( 'SSL' , [ true , "Negotiate SSL for outgoing connections" , true ] ) ,
38
43
OptString . new ( 'TARGETURI' , [ true , 'The URI path to test' , '/' ] ) ,
39
- OptInt . new ( 'REQUESTS' , [ true , 'Number of requests to send to disclose back ' , 10 ] )
44
+ OptInt . new ( 'REQUESTS' , [ true , 'The number of requests to send' , 10 ] )
40
45
] , self . class )
41
46
end
42
47
43
- def change_endianness ( value , size = 4 )
48
+ def change_endianness ( value , size = 4 )
44
49
conversion = nil
45
-
46
50
if size == 4
47
51
conversion = [ value ] . pack ( "V" ) . unpack ( "N" ) . first
48
52
elsif size == 2
49
53
conversion = [ value ] . pack ( "v" ) . unpack ( "n" ) . first
50
54
end
51
-
52
55
conversion
53
56
end
54
57
55
58
def cookie_decode ( cookie_value )
56
- if cookie_value =~ /(\d {8,10})\. (\d {1,5})\. /
57
- host = $1. to_i
58
- port = $2. to_i
59
+ backend = { }
60
+ case
61
+ when cookie_value =~ /(\d {8,10})\. (\d {1,5})\. /
62
+ host = Regexp . last_match ( 1 ) . to_i
63
+ port = Regexp . last_match ( 2 ) . to_i
59
64
host = change_endianness ( host )
60
65
host = Rex ::Socket . addr_itoa ( host )
61
66
port = change_endianness ( port , 2 )
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
67
+ when cookie_value . downcase =~ /rd\d +o0{20}f{4}([a-f0-9]{8})o(\d {1,5})/
68
+ host = Regexp . last_match ( 1 ) . to_i ( 16 )
69
+ port = Regexp . last_match ( 2 ) . to_i
65
70
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 )
71
+ when cookie_value . downcase =~ /vi([a-f0-9]{32})\. (\d {1,5})/
72
+ host = Regexp . last_match ( 1 ) . to_i ( 16 )
73
+ port = Regexp . last_match ( 2 ) . to_i
74
+ host = Rex ::Socket . addr_itoa ( host , true )
70
75
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
+ when cookie_value . downcase =~ /rd\d +o([a-f0-9]{32})o(\d {1,5})/
77
+ host = Regexp . last_match ( 1 ) . to_i ( 16 )
78
+ port = Regexp . last_match ( 2 ) . to_i
79
+ host = Rex ::Socket . addr_itoa ( host , true )
80
+ else
76
81
host = nil
77
82
port = nil
78
83
end
79
- host . nil? ? nil : "#{ host } :#{ port } "
84
+
85
+ backend [ :host ] = host . nil? ? nil : host
86
+ backend [ :port ] = port . nil? ? nil : port
87
+ backend
80
88
end
81
89
82
90
def get_cookie # request a page and extract a F5 looking cookie.
83
91
cookie = { }
84
- res = send_request_raw ( {
85
- 'method' => 'GET' ,
86
- 'uri' => @uri
87
- } )
92
+ res = send_request_raw ( { 'method' => 'GET' , 'uri' => @uri } )
88
93
89
94
unless res . nil?
90
95
# Get the SLB session IDs for all cases:
91
96
# 1. IPv4 pool members - "BIGipServerWEB=2263487148.3013.0000",
92
97
# 2. IPv4 pool members in non-default routed domains - "BIGipServerWEB=rd5o00000000000000000000ffffc0000201o80",
93
98
# 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
101
-
99
+ # 4. IPv6 pool members in non-default route domains - "BIGipServerWEB=rd3o20010112000000000000000000000030o80"
100
+
101
+ regexp = /
102
+ ([~_\. \- \w \d ]+)=(((?:\d +\. ){2}\d +)|
103
+ (rd\d +o0{20}f{4}\w +o\d {1,5})|
104
+ (vi([a-f0-9]{32})\. (\d {1,5}))|
105
+ (rd\d +o([a-f0-9]{32})o(\d {1,5})))
106
+ (?:$|,|;|\s )
107
+ /x
108
+ m = res . get_cookies . match ( regexp )
109
+ cookie [ :id ] = ( m . nil? ) ? nil : m [ 1 ]
110
+ cookie [ :value ] = ( m . nil? ) ? nil : m [ 2 ]
111
+ end
102
112
cookie
103
113
end
104
114
105
115
def run
106
- unless datastore [ 'REQUESTS' ] > 0
107
- print_error ( "Please, configure more than 0 REQUESTS" )
108
- return
109
- end
110
-
111
- back_ends = [ ]
116
+ requests = datastore [ 'REQUESTS' ]
117
+ backends = [ ]
112
118
@uri = normalize_uri ( target_uri . path . to_s )
113
119
print_status ( "#{ peer } - Starting request #{ @uri } " )
114
120
115
- for i in 0 ... datastore [ 'REQUESTS' ]
116
- cookie = get_cookie ( ) # Get the cookie
121
+ ( 1 .. requests ) . each do | i |
122
+ cookie = get_cookie # Get the cookie
117
123
# If the cookie is not found, stop process
118
124
if cookie . empty? || cookie [ :id ] . nil?
119
125
print_error ( "#{ peer } - F5 BigIP load balancing cookie not found" )
120
- break
126
+ return
121
127
end
122
128
123
129
# Print the cookie name on the first request
124
- if i == 0
125
- print_status ( "#{ peer } - F5 BigIP load balancing cookie \" #{ cookie [ :id ] } = #{ cookie [ :value ] } \" found" )
130
+ if i == 1
131
+ print_good ( "#{ peer } - F5 BigIP load balancing cookie \" #{ cookie [ :id ] } = #{ cookie [ :value ] } \" found" )
126
132
if cookie [ :id ] . start_with? ( 'BIGipServer' )
127
- print_status ( "#{ peer } - Load balancing pool name \" #{ cookie [ :id ] . split ( 'BIGipServer' ) [ 1 ] } \" found" )
133
+ print_good ( "#{ peer } - Load balancing pool name \" #{ cookie [ :id ] . split ( 'BIGipServer' ) [ 1 ] } \" found" )
128
134
end
129
135
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" )
136
+ print_good ( "#{ peer } - Route domain \" #{ cookie [ :value ] . split ( 'rd' ) [ 1 ] . split ( 'o' ) [ 0 ] } \" found" )
134
137
end
135
138
end
136
139
137
- back_end = cookie_decode ( cookie [ :value ] )
138
- unless back_end . nil? || back_ends . include? ( back_end )
139
- print_status ( "#{ peer } - Backend #{ back_end } found" )
140
- back_ends . push ( back_end )
140
+ backend = cookie_decode ( cookie [ :value ] )
141
+ unless backend [ :host ] . nil? || backends . include? ( backend )
142
+ print_good ( "#{ peer } - Backend #{ backend [ :host ] } : #{ backend [ :port ] } found" )
143
+ backends . push ( backend )
141
144
end
142
145
end
143
146
144
147
# Reporting found backends in database
145
- unless back_ends . empty?
146
- report_note (
147
- :host => rhost ,
148
- :type => "f5_load_balancer_backends" ,
149
- :data => back_ends
150
- )
148
+ unless backends . empty?
149
+ report_note ( host : rhost , type : 'f5_load_balancer_backends' , data : backends )
151
150
end
152
151
152
+ rescue ::Rex ::ConnectionRefused
153
+ print_error ( "#{ peer } - Network connection error" )
154
+ rescue ::Rex ::ConnectionError
155
+ print_error ( "#{ peer } - Network connection error" )
156
+ rescue ::OpenSSL ::SSL ::SSLError
157
+ print_error ( "#{ peer } - SSL/TLS connection error" )
153
158
end
154
159
end
0 commit comments