Skip to content

Commit 9e76e0b

Browse files
committed
Simplify. Document. Handle edge cases
Simplify detection logic. Document testing method better Ensure that body doesn't include canary cookie name too Use full_uri in prints when possible
1 parent d4843f4 commit 9e76e0b

File tree

1 file changed

+67
-64
lines changed

1 file changed

+67
-64
lines changed

modules/auxiliary/scanner/http/allegro_rompager_misfortune_cookie.rb

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@ def initialize(info = {})
4040
OptString.new('TARGETURI', [true, 'URI to test', '/'])
4141
], Exploit::Remote::HttpClient
4242
)
43-
44-
register_advanced_options(
45-
[
46-
OptBool.new('REQUIRE_AUTH', [true, 'Require that the tested URI require authentication', false])
47-
], self.class
48-
)
4943
end
5044

5145
def check_host(_ip)
@@ -67,97 +61,106 @@ def run_host(ip)
6761
end
6862
end
6963

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
7176
vprint_status("#{peer} locating suitable canary URI")
7277
0.upto(4) do
7378
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
7787
return canary if res.code == 401 || res.code == 404
7888
end
7989
nil
8090
end
8191

8292
def headers
8393
{
84-
'Referer' => datastore['SSL'] ? 'https' : 'http' + "://#{rhost}:#{rport}"
94+
'Referer' => full_uri
8595
}
8696
end
8797

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.
106105
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)
113108
vprint_error("#{peer} Unable to find a suitable canary URI")
114109
return Exploit::CheckCode::Unknown
115110
end
116111

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.
119117
res = send_request_raw(
120118
'uri' => normalize_uri(target_uri.path.to_s),
121119
'method' => 'GET',
122-
'headers' => headers.merge('Cookie' => "C107373883=#{canary}")
120+
'headers' => headers.merge('Cookie' => canary_cookie)
123121
)
124122

125123
unless res
126-
vprint_error("#{peer} no response")
124+
vprint_error("#{full_uri} no response")
127125
return Exploit::CheckCode::Unknown
128126
end
129127

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)
137131
end
138132

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)
148136
end
149137

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
155160
end
156161
end
157162

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)
162165
end
163166
end

0 commit comments

Comments
 (0)