GateKeeper Xprotect绕过

现象:解密的速度极其缓慢,而且经常解密很短一段时间后就卡死
原因:GateKeeper对每个文件都进行了扫描,这导致:
  • 规则里有许多yara扫描,本身就会消耗资源
  • GateKeeper将结果存到了 /var/db/SystemPolicyConfiguration/ExecPolicy 这个sqlite db中,长期累积后记录数量能达到数千万,导致插入、查询都非常缓慢,

理解GateKeeper的架构

GateKeeper由几部分组成:
  • syspolicyd:负责调度XProtectService等功能,并执行最终的决策,决定是否允许程序启动
  • XProtectService:负责进行具体的yara scan
 
GateKeeper有几个关键点:
  • syspolicyd注册了相应的接口,可以通过RPC来增加exec policy的记录
  • syspolicyd会将判断的结果存入 /var/db/SystemPolicyConfiguration/ExecPolicy 的policy_cache_by_path_meta 和 policy_cache_meta 表中
  • syspolicyd判定时,如果发现ExecPolicy 中已经完成过yara扫描,那么会直接从库中取出,而不是每次重新扫描。判定时会首先查询policy_scan_cache,如果没查到再继续查policy_scan_cache_by_path。前者是根据vnode id、size、mod time索引,后者则是根据fstype、mountpoint、path、size、mod time
  • XProtectService的规则来自于/Library/Apple/System/Library/CoreServices/XProtect.bundle/var/db/SystemPolicyConfiguration/XProtect.bundle
 
GateKeeper有几种拦截原因,我们在iOS中碰到的主要是这两种:
  • 应用程序中有病毒代码(policy result = 8):例如PayZApp
  • TeamID被拉黑(policy result = 10):例如com.pps.test
 

尝试攻克GateKeeper中的各种失败

尝试1:xattr -d com.apple.quarantine

这是从网上下程序时可以使用的命令,但是实际上用完并没有效果
 

尝试2:提前注册与XprotectService同名的服务

xnu的daemon都是按照包名来划分domain的,很好的防范了水坑攻击

尝试3:RPC注入,配置override,相当于在设置里手动点击允许

并没有卵用,还是被ban
#include <stdio.h> #import <Foundation/Foundation.h> #import "SPExecutionPolicy.h" int main(int argc, char *argv[], char *envp[]) { @autoreleasepool { printf("Hello world!\n"); SPExecutionPolicy *execPolicy = [[SPExecutionPolicy alloc] init]; NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:argv[1]]]; NSError *error = nil; /*[execPolicy addBlockedSoftwareOverride:url error:&error]; if (!!error) { NSLog(@"Error in addBlockedSoftwareOverride: %@", error); return 1; } NSLog(@"add override OK!");*/ [execPolicy setBlockedSoftwareOverride:url isEnabled:NO error:&error]; if (!!error) { NSLog(@"Error in setBlockedSoftwareOverride: %@", error); return 1; } NSLog(@"set override OK!"); return 0; } }

最终的邪修道路

我们用的11.2系统完全可以用CoreTrust bypass洞,所以肯定是从文件下手。
 
首先是把syspolicyd的entitlement整个偷一遍,这个时候我们就已经有直接读写sip的权限了。我直接签了一个busybox、一个sqlite3。
当扫描结果不对时,malware_result会不为0,然后自然出发相应的阻断逻辑。所以我们直接把malware_result都改成0,完美解决。(注意不能删库,要不然重启之后会需要等很久校验Xcode签名)
update policy_scan_cache_by_path set policy_match = 8, malware_result = 0 where malware_result != 0
 
接下来就是个大难题了, team id拉黑的情况完全绕不开,因为这种验证太快了,所以苹果完全不参考数据库的结果,而且blockedOverride也没有用。
考虑从源头的规则下手,/var/db/SystemPolicyConfiguration/XProtect.bundle 里面存的有teamid黑名单列表,所以尝试了:
  • 尝试直接删掉, 发现会自动出现
  • 尝试修改里面的内容,发现并不能应用上去
  • 最后逆向发现XProtect.bundle有签名,通过Sec*** API验证通过后才会被架子啊
这些方法不成立的原因主要还是一方面bundle有签名,另一方面系统里面还内置了一个不可变的/Library/Apple/System/Library/CoreServices/XProtect.bundle,很不幸,2022年的时候我们的目标应用已经上了黑名单。。
费劲九牛二虎之力还是没办法, 最后想到了个阴招。从mount和其他工具偷了许多entitlement,实现能在/Library目录下面进行mount了。然后把XProtect.bundle mount成了一个大小为1m的空文件夹,整个XProtect就失效了,同时程序还能正常加载。配合前面的数据库大法实现了完全解密全部的文件。