macOS Gatekeeper / Quarantine / XProtect

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)

Gatekeeper

Gatekeeper是为Mac操作系统开发的安全功能,旨在确保用户在其系统上仅运行可信软件。它通过验证用户从App Store之外的来源下载并尝试打开的软件(如应用程序、插件或安装程序包)来发挥作用。

Gatekeeper的关键机制在于其验证过程。它检查下载的软件是否由已知开发人员签名,确保软件的真实性。此外,它还确定软件是否被苹果公证,以确认其不包含已知恶意内容并且在公证后未被篡改。

此外,Gatekeeper通过提示用户批准首次打开下载软件来加强用户控制和安全性。这种保护措施有助于防止用户无意中运行可能被误认为是无害数据文件的潜在有害可执行代码。

应用程序签名

应用程序签名,也称为代码签名,是Apple安全基础设施的关键组成部分。它用于验证软件作者的身份(开发人员)并确保代码自上次签名以来未被篡改。

工作原理如下:

  1. 签署应用程序:当开发人员准备分发他们的应用程序时,他们会使用私钥对应用程序进行签名。此私钥与开发人员在加入Apple开发人员计划时获得的证书相关联。签名过程涉及创建应用程序所有部分的加密哈希,并使用开发人员的私钥对此哈希进行加密。

  2. **分发应用程序:**签名的应用程序随后与开发人员的证书一起分发给用户,该证书包含相应的公钥。

  3. 验证应用程序:当用户下载并尝试运行应用程序时,他们的Mac操作系统使用开发人员证书中的公钥来解密哈希。然后,它根据应用程序的当前状态重新计算哈希,并将其与解密的哈希进行比较。如果它们匹配,这意味着应用程序自开发人员签名以来未被修改,系统允许应用程序运行。

应用程序签名是Apple Gatekeeper技术的重要组成部分。当用户尝试打开从互联网下载的应用程序时,Gatekeeper会验证应用程序签名。如果它使用由苹果颁发给已知开发人员的证书签名且代码未被篡改,则Gatekeeper允许应用程序运行。否则,它会阻止应用程序并警告用户。

从macOS Catalina开始,Gatekeeper还会检查应用程序是否已被苹果公证,增加了额外的安全层。公证过程会检查应用程序是否存在已知的安全问题和恶意代码,如果这些检查通过,苹果会向应用程序添加Gatekeeper可以验证的凭证。

检查签名

在检查一些恶意软件样本时,您应始终检查二进制文件的签名,因为签署它的开发人员可能已与恶意软件有关。

# Get signer
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"

# Check if the app’s contents have been modified
codesign --verify --verbose /Applications/Safari.app

# Get entitlements from the binary
codesign -d --entitlements :- /System/Applications/Automator.app # Check the TCC perms

# Check if the signature is valid
spctl --assess --verbose /Applications/Safari.app

# Sign a binary
codesign -s <cert-name-keychain> toolsdemo

验证

苹果的验证流程作为一项额外的保障措施,旨在保护用户免受潜在有害软件的侵害。这涉及开发人员提交其应用以供苹果的验证服务检查,这与应用审核不应混淆。这项服务是一个自动化系统,会审查提交的软件是否存在恶意内容以及代码签名是否存在任何潜在问题。

如果软件通过此检查而没有引起任何疑虑,验证服务将生成一个验证票证。然后开发人员需要将此票证附加到其软件上,这个过程称为“装订”。此外,验证票证也会在线发布,Gatekeeper,苹果的安全技术,可以访问它。

在用户首次安装或执行软件时,验证票证的存在 - 无论是装订到可执行文件上还是在线找到 - 通知 Gatekeeper 软件已由苹果进行验证。因此,Gatekeeper 在初始启动对话框中显示一个描述性消息,指示该软件已经通过苹果的恶意内容检查。这个过程增强了用户对其系统上安装或运行的软件安全性的信心。

枚举 Gatekeeper

Gatekeeper 既是几个安全组件,用于阻止不受信任的应用程序执行,也是其中一个组件

可以使用以下命令查看 Gatekeeper 的状态

# Check the status
spctl --status

请注意,GateKeeper 签名检查仅针对具有Quarantine 属性的文件执行,而不是针对每个文件执行。

GateKeeper 将检查二进制文件是否可以执行,根据偏好设置和签名

保存此配置的数据库位于**/var/db/SystemPolicy**。您可以以 root 身份检查此数据库:

# Open database
sqlite3 /var/db/SystemPolicy

# Get allowed rules
SELECT requirement,allow,disabled,label from authority where label != 'GKE' and disabled=0;
requirement|allow|disabled|label
anchor apple generic and certificate 1[subject.CN] = "Apple Software Update Certification Authority"|1|0|Apple Installer
anchor apple|1|0|Apple System
anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9] exists|1|0|Mac App Store
anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and (certificate leaf[field.1.2.840.113635.100.6.1.14] or certificate leaf[field.1.2.840.113635.100.6.1.13]) and notarized|1|0|Notarized Developer ID
[...]

注意第一个规则以“App Store”结束,第二个规则以“Developer ID”结束,并且在之前的图像中它被启用以执行来自App Store和已识别开发者的应用程序。 如果您将该设置修改为App Store,那么“已经过公证的开发者ID”规则将消失。

还有成千上万个类型为GKE的规则:

SELECT requirement,allow,disabled,label from authority where label = 'GKE' limit 5;
cdhash H"b40281d347dc574ae0850682f0fd1173aa2d0a39"|1|0|GKE
cdhash H"5fd63f5342ac0c7c0774ebcbecaf8787367c480f"|1|0|GKE
cdhash H"4317047eefac8125ce4d44cab0eb7b1dff29d19a"|1|0|GKE
cdhash H"0a71962e7a32f0c2b41ddb1fb8403f3420e1d861"|1|0|GKE
cdhash H"8d0d90ff23c3071211646c4c9c607cdb601cb18f"|1|0|GKE

这些哈希值来自于 /var/db/SystemPolicyConfiguration/gke.bundle/Contents/Resources/gke.auth, /var/db/gke.bundle/Contents/Resources/gk.db/var/db/gkopaque.bundle/Contents/Resources/gkopaque.db

或者你可以列出前面提到的信息:

sudo spctl --list

spctl 的选项 --master-disable--global-disable 将完全禁用这些签名检查:

# Disable GateKeeper
spctl --global-disable
spctl --master-disable

# Enable it
spctl --global-enable
spctl --master-enable

当完全启用时,将出现一个新选项:

可以使用以下方法检查应用程序是否会被 GateKeeper 允许

spctl --assess -v /Applications/App.app

可以通过以下方式向 GateKeeper 添加新规则,允许执行特定应用程序:

# Check if allowed - nop
spctl --assess -v /Applications/App.app
/Applications/App.app: rejected
source=no usable signature

# Add a label and allow this label in GateKeeper
sudo spctl --add --label "whitelist" /Applications/App.app
sudo spctl --enable --label "whitelist"

# Check again - yep
spctl --assess -v /Applications/App.app
/Applications/App.app: accepted

隔离文件

在下载应用程序或文件时,特定的 macOS 应用程序,如 Web 浏览器或电子邮件客户端,会向下载的文件附加一个称为“隔离标志”(quarantine flag)的扩展文件属性。该属性作为一项安全措施,将文件标记为来自不受信任的来源(互联网),并可能携带风险。然而,并非所有应用程序都会附加此属性,例如,常见的 BitTorrent 客户端软件通常会绕过此过程。

隔离标志的存在在用户尝试执行文件时会触发 macOS 的 Gatekeeper 安全功能。

隔离标志不存在的情况下(例如通过某些 BitTorrent 客户端下载的文件),Gatekeeper 的检查可能不会执行。因此,用户在打开从不太安全或未知来源下载的文件时应谨慎。

验证代码签名的有效性是一个资源密集型的过程,包括生成代码及其所有捆绑资源的加密哈希。此外,检查证书的有效性涉及在线检查苹果服务器,以查看证书是否在签发后被吊销。出于这些原因,每次启动应用程序时运行完整的代码签名和公证检查是不切实际的。

因此,这些检查仅在执行带有隔离属性的应用程序时运行

此属性必须由创建/下载文件的应用程序设置

但是,受沙盒限制的文件将使每个它们创建的文件都设置此属性。非沙盒应用程序可以自行设置,或在 Info.plist 中指定 LSFileQuarantineEnabled 键,系统将在创建的文件上设置 com.apple.quarantine 扩展属性。

此外,由调用 qtn_proc_apply_to_self 的进程创建的所有文件都会被隔离。或者使用 API qtn_file_apply_to_path 可将隔离属性添加到指定文件路径上。

可以通过以下方式检查其状态并启用/禁用(需要 root 权限):

spctl --status
assessments enabled

spctl --enable
spctl --disable
#You can also allow nee identifies to execute code using the binary "spctl"

您还可以使用以下方法查找文件是否具有隔离扩展属性

xattr file.png
com.apple.macl
com.apple.quarantine

检查扩展 属性,找出写入隔离属性的应用程序:

xattr -l portada.png
com.apple.macl:
00000000  03 00 53 DA 55 1B AE 4C 4E 88 9D CA B7 5C 50 F3  |..S.U..LN.....P.|
00000010  16 94 03 00 27 63 64 97 98 FB 4F 02 84 F3 D0 DB  |....'cd...O.....|
00000020  89 53 C3 FC 03 00 27 63 64 97 98 FB 4F 02 84 F3  |.S....'cd...O...|
00000030  D0 DB 89 53 C3 FC 00 00 00 00 00 00 00 00 00 00  |...S............|
00000040  00 00 00 00 00 00 00 00                          |........|
00000048
com.apple.quarantine: 00C1;607842eb;Brave;F643CD5F-6071-46AB-83AB-390BA944DEC5
# 00c1 -- It has been allowed to eexcute this file (QTN_FLAG_USER_APPROVED = 0x0040)
# 607842eb -- Timestamp
# Brave -- App
# F643CD5F-6071-46AB-83AB-390BA944DEC5 -- UID assigned to the file downloaded

实际上一个进程"可以为它创建的文件设置隔离标志"(我尝试在创建的文件中应用USER_APPROVED标志,但它不会应用):

源代码应用隔离标志

```c #include #include

enum qtn_flags { QTN_FLAG_DOWNLOAD = 0x0001, QTN_FLAG_SANDBOX = 0x0002, QTN_FLAG_HARD = 0x0004, QTN_FLAG_USER_APPROVED = 0x0040, };

#define qtn_proc_alloc _qtn_proc_alloc #define qtn_proc_apply_to_self _qtn_proc_apply_to_self #define qtn_proc_free _qtn_proc_free #define qtn_proc_init _qtn_proc_init #define qtn_proc_init_with_self _qtn_proc_init_with_self #define qtn_proc_set_flags _qtn_proc_set_flags #define qtn_file_alloc _qtn_file_alloc #define qtn_file_init_with_path _qtn_file_init_with_path #define qtn_file_free _qtn_file_free #define qtn_file_apply_to_path _qtn_file_apply_to_path #define qtn_file_set_flags _qtn_file_set_flags #define qtn_file_get_flags _qtn_file_get_flags #define qtn_proc_set_identifier _qtn_proc_set_identifier

typedef struct _qtn_proc *qtn_proc_t; typedef struct _qtn_file *qtn_file_t;

int qtn_proc_apply_to_self(qtn_proc_t); void qtn_proc_init(qtn_proc_t); int qtn_proc_init_with_self(qtn_proc_t); int qtn_proc_set_flags(qtn_proc_t, uint32_t flags); qtn_proc_t qtn_proc_alloc(); void qtn_proc_free(qtn_proc_t); qtn_file_t qtn_file_alloc(void); void qtn_file_free(qtn_file_t qf); int qtn_file_set_flags(qtn_file_t qf, uint32_t flags); uint32_t qtn_file_get_flags(qtn_file_t qf); int qtn_file_apply_to_path(qtn_file_t qf, const char *path); int qtn_file_init_with_path(qtn_file_t qf, const char path); int qtn_proc_set_identifier(qtn_proc_t qp, const char bundleid);

int main() {

qtn_proc_t qp = qtn_proc_alloc(); qtn_proc_set_identifier(qp, "xyz.hacktricks.qa"); qtn_proc_set_flags(qp, QTN_FLAG_DOWNLOAD | QTN_FLAG_USER_APPROVED); qtn_proc_apply_to_self(qp); qtn_proc_free(qp);

FILE *fp; fp = fopen("thisisquarantined.txt", "w+"); fprintf(fp, "Hello Quarantine\n"); fclose(fp);

return 0;

}

</details>

然后使用以下命令**删除**该属性:
```bash
xattr -d com.apple.quarantine portada.png
#You can also remove this attribute from every file with
find . -iname '*' -print0 | xargs -0 xattr -d com.apple.quarantine

并使用以下命令查找所有被隔离的文件:

find / -exec ls -ld {} \; 2>/dev/null | grep -E "[x\-]@ " | awk '{printf $9; printf "\n"}' | xargs -I {} xattr -lv {} | grep "com.apple.quarantine"

隔离信息也存储在由LaunchServices管理的中央数据库中,位于 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2

Quarantine.kext

内核扩展仅通过系统上的内核缓存可用;但是,您可以从 https://developer.apple.com/ 下载 Kernel Debug Kit,其中包含扩展的符号化版本。

XProtect

XProtect 是 macOS 中内置的 反恶意软件 功能。XProtect 会对任何应用程序在首次启动或修改时与其已知恶意软件和不安全文件类型的数据库进行检查。当您通过某些应用程序(如 Safari、Mail 或 Messages)下载文件时,XProtect 会自动扫描该文件。如果文件与其数据库中的任何已知恶意软件匹配,XProtect 将 阻止文件运行 并向您发出威胁警报。

XProtect 数据库由 Apple 定期更新新的恶意软件定义,并这些更新会自动下载并安装到您的 Mac 上。这确保了 XProtect 始终与最新已知威胁保持同步。

然而,值得注意的是 XProtect 不是完整的防病毒解决方案。它仅检查特定已知威胁列表,不像大多数防病毒软件那样执行访问扫描。

您可以获取有关最新 XProtect 更新的信息运行:

system_profiler SPInstallHistoryDataType 2>/dev/null | grep -A 4 "XProtectPlistConfigData" | tail -n 5

XProtect位于SIP受保护位置**/Library/Apple/System/Library/CoreServices/XProtect.bundle**,在bundle内部,您可以找到XProtect使用的信息:

  • XProtect.bundle/Contents/Resources/LegacyEntitlementAllowlist.plist:允许具有这些cdhashes的代码使用传统授权。

  • XProtect.bundle/Contents/Resources/XProtect.meta.plist:禁止通过BundleID和TeamID加载的插件和扩展列表,或指示最低版本。

  • XProtect.bundle/Contents/Resources/XProtect.yara:用于检测恶意软件的Yara规则。

  • XProtect.bundle/Contents/Resources/gk.db:带有已阻止应用程序和TeamIDs哈希的SQLite3数据库。

请注意,还有另一个与XProtect相关的App位于**/Library/Apple/System/Library/CoreServices/XProtect.app**,与Gatekeeper进程无关。

非Gatekeeper

请注意,Gatekeeper不会每次执行应用程序时都执行,只有在您执行已由Gatekeeper执行和验证的应用程序时,AppleMobileFileIntegrity(AMFI)才会验证可执行代码签名

因此,以前可以执行一个应用程序以使用Gatekeeper缓存它,然后修改应用程序的非可执行文件(如Electron asar或NIB文件),如果没有其他保护措施,该应用程序将带有恶意添加内容。

然而,现在这是不可能的,因为macOS阻止修改应用程序包内的文件。因此,如果尝试Dirty NIB攻击,您将发现不再可能滥用它,因为在执行应用程序以使用Gatekeeper缓存它后,您将无法修改bundle。例如,如果更改Contents目录的名称为NotCon(如在漏洞利用中指示的那样),然后执行应用程序的主二进制文件以使用Gatekeeper缓存它,将触发错误并且不会执行。

Gatekeeper绕过

任何绕过Gatekeeper的方法(成功让用户下载并在Gatekeeper应该禁止时执行)都被视为macOS中的漏洞。以下是一些过去允许绕过Gatekeeper的技术分配的CVE:

观察到,如果使用Archive Utility进行提取,路径超过886个字符的文件将不会收到com.apple.quarantine扩展属性。这种情况无意中允许这些文件绕过Gatekeeper的安全检查。

查看原始报告获取更多信息。

当使用Automator创建应用程序时,关于其需要执行的信息位于application.app/Contents/document.wflow中,而不是在可执行文件中。可执行文件只是一个名为Automator Application Stub的通用Automator二进制文件。

因此,您可以使application.app/Contents/MacOS/Automator\ Application\ Stub指向系统内另一个Automator Application Stub的符号链接,它将执行document.wflow中的内容(您的脚本)而不触发Gatekeeper,因为实际可执行文件没有quarantine xattr。

预期位置示例:/System/Library/CoreServices/Automator\ Application\ Stub.app/Contents/MacOS/Automator\ Application\ Stub

查看原始报告获取更多信息。

在此绕过中,创建了一个zip文件,从application.app/Contents开始压缩,而不是从application.app开始。因此,quarantine attr被应用于来自application.app/Contents的所有文件,但未应用于application.app,Gatekeeper正在检查的文件,因此Gatekeeper被绕过,因为当触发application.app时,它没有quarantine属性

zip -r test.app/Contents test.zip

查看原始报告以获取更多信息。

即使组件不同,利用此漏洞的过程与先前的非常相似。在这种情况下,我们将从**application.app/Contents生成一个苹果存档,这样当通过Archive Utility解压缩时,application.app将不会获得隔离属性**。

aa archive -d test.app/Contents -o test.app.aar

查看原始报告以获取更多信息。

ACL writeextattr 可用于防止任何人在文件中写入属性:

touch /tmp/no-attr
chmod +a "everyone deny writeextattr" /tmp/no-attr
xattr -w attrname vale /tmp/no-attr
xattr: [Errno 13] Permission denied: '/tmp/no-attr'

此外,AppleDouble 文件格式会复制一个文件,包括其ACEs。

源代码中,可以看到存储在名为**com.apple.acl.text的xattr中的ACL文本表示将被设置为解压后文件的ACL。因此,如果您使用AppleDouble**文件格式将应用程序压缩到zip文件中,并附带一个ACL,防止其他xattr被写入它...隔离xattr 将不会被设置到应用程序中:

chmod +a "everyone deny write,writeattr,writeextattr" /tmp/test
ditto -c -k test test.zip
python3 -m http.server
# Download the zip from the browser and decompress it, the file should be without a quarantine xattr

查看原始报告以获取更多信息。

请注意,这也可以利用AppleArchives:

mkdir app
touch app/test
chmod +a "everyone deny write,writeattr,writeextattr" app/test
aa archive -d app -o test.aar

发现Google Chrome没有设置下载文件的隔离属性,因为一些 macOS 内部问题。

AppleDouble 文件格式将文件属性存储在以 ._ 开头的单独文件中,这有助于在macOS设备之间复制文件属性。然而,注意到在解压 AppleDouble 文件后,以 ._ 开头的文件没有被赋予隔离属性

mkdir test
echo a > test/a
echo b > test/b
echo ._a > test/._a
aa archive -d test/ -o test.aar

# If you downloaded the resulting test.aar and decompress it, the file test/._a won't have a quarantitne attribute

能够创建一个不会设置隔离属性的文件,这样就有可能绕过 Gatekeeper。技巧是使用 AppleDouble 命名约定(以 ._ 开头)创建一个 DMG 文件应用程序,并创建一个可见文件作为对这个没有隔离属性的隐藏文件的符号链接。当执行 dmg 文件时,由于它没有隔离属性,它将绕过 Gatekeeper。

# Create an app bundle with the backdoor an call it app.app

echo "[+] creating disk image with app"
hdiutil create -srcfolder app.app app.dmg

echo "[+] creating directory and files"
mkdir
mkdir -p s/app
cp app.dmg s/app/._app.dmg
ln -s ._app.dmg s/app/app.dmg

echo "[+] compressing files"
aa archive -d s/ -o app.aar

uchg (from this talk)

  • 创建一个包含应用程序的目录。

  • 为应用程序添加 uchg。

  • 将应用程序压缩为 tar.gz 文件。

  • 将 tar.gz 文件发送给受害者。

  • 受害者打开 tar.gz 文件并运行应用程序。

  • Gatekeeper 不会检查该应用程序。

防止隔离 xattr

在 ".app" 捆绑包中,如果未添加隔离 xattr,则在执行时Gatekeeper 不会触发

最后更新于