macOS Process Abuse

Reading time: 26 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

Processes Basic Information

プロセスは実行中の実行可能ファイルのインスタンスですが、プロセスはコードを実行しません。これらはスレッドです。したがって、プロセスは実行中のスレッドのコンテナに過ぎません。メモリ、ディスクリプタ、ポート、権限を提供します...

従来、プロセスは**forkを呼び出すことによって他のプロセス内で開始されました(PID 1を除く)。これにより、現在のプロセスの正確なコピーが作成され、その後子プロセスは一般的にexecveを呼び出して新しい実行可能ファイルをロードして実行します。その後、vforkが導入され、このプロセスをメモリコピーなしで高速化しました。
次に、
posix_spawnが導入され、vforkexecve**を1回の呼び出しで組み合わせ、フラグを受け入れます:

  • POSIX_SPAWN_RESETIDS: 有効なIDを実際のIDにリセット
  • POSIX_SPAWN_SETPGROUP: プロセスグループの所属を設定
  • POSUX_SPAWN_SETSIGDEF: シグナルのデフォルト動作を設定
  • POSIX_SPAWN_SETSIGMASK: シグナルマスクを設定
  • POSIX_SPAWN_SETEXEC: 同じプロセスで実行(オプションが多いexecveのように)
  • POSIX_SPAWN_START_SUSPENDED: サスペンド状態で開始
  • _POSIX_SPAWN_DISABLE_ASLR: ASLRなしで開始
  • _POSIX_SPAWN_NANO_ALLOCATOR: libmallocのナノアロケータを使用
  • _POSIX_SPAWN_ALLOW_DATA_EXEC: データセグメントでrwxを許可
  • POSIX_SPAWN_CLOEXEC_DEFAULT: exec(2)でデフォルトで全てのファイル記述子を閉じる
  • _POSIX_SPAWN_HIGH_BITS_ASLR: ASLRスライドの高位ビットをランダム化

さらに、posix_spawnは生成されたプロセスのいくつかの側面を制御する**posix_spawnattrの配列を指定することを許可し、ディスクリプタの状態を変更するためのposix_spawn_file_actions**を提供します。

プロセスが終了すると、親プロセスに戻りコードを送信します(親が終了した場合、新しい親はPID 1です)し、シグナルSIGCHLDを送信します。親はこの値を取得するためにwait4()またはwaitid()を呼び出す必要があり、その間、子プロセスはゾンビ状態に留まり、リソースを消費しません。

PIDs

PID、プロセス識別子は、ユニークなプロセスを識別します。XNUでは、PIDs64ビットで、単調に増加し、決してラップしません(悪用を避けるため)。

Process Groups, Sessions & Coalations

プロセスグループに挿入され、管理を容易にします。たとえば、シェルスクリプト内のコマンドは同じプロセスグループにあり、killを使用して一緒にシグナルを送信することが可能です。
プロセスをセッションにグループ化することも可能です。プロセスがセッションを開始すると(setsid(2))、子プロセスはセッション内に設定されますが、独自のセッションを開始しない限りです。

コアリションは、Darwinでプロセスをグループ化する別の方法です。コアリションに参加するプロセスは、プールリソースにアクセスでき、台帳を共有したり、Jetsamに直面したりします。コアリションには異なる役割があります:リーダー、XPCサービス、拡張。

Credentials & Personae

各プロセスは、システム内の権限を識別するための資格情報を保持します。各プロセスには1つの主要なuidと1つの主要なgidがあります(ただし、複数のグループに属することがあります)。
バイナリがsetuid/setgidビットを持っている場合、ユーザーおよびグループIDを変更することも可能です。
新しいuid/gidを設定するための関数がいくつかあります。

システムコール**personaは、代替の資格情報のセットを提供します。ペルソナを採用すると、そのuid、gid、およびグループメンバーシップを一度に**引き受けます。ソースコードでは、構造体を見つけることができます:

c
struct kpersona_info { uint32_t persona_info_version;
uid_t    persona_id; /* overlaps with UID */
int      persona_type;
gid_t    persona_gid;
uint32_t persona_ngroups;
gid_t    persona_groups[NGROUPS];
uid_t    persona_gmuid;
char     persona_name[MAXLOGNAME + 1];

/* TODO: MAC policies?! */
}

スレッドの基本情報

  1. POSIXスレッド (pthreads): macOSはPOSIXスレッド(pthreads)をサポートしており、これはC/C++の標準スレッドAPIの一部です。macOSにおけるpthreadsの実装は/usr/lib/system/libsystem_pthread.dylibにあり、これは公開されているlibpthreadプロジェクトから来ています。このライブラリはスレッドを作成し管理するために必要な関数を提供します。
  2. スレッドの作成: pthread_create()関数は新しいスレッドを作成するために使用されます。内部的に、この関数はXNUカーネル(macOSが基づいているカーネル)特有の低レベルのシステムコールであるbsdthread_create()を呼び出します。このシステムコールは、スレッドの動作を指定するpthread_attr(属性)から派生したさまざまなフラグを受け取ります。これにはスケジューリングポリシーやスタックサイズが含まれます。
  • デフォルトスタックサイズ: 新しいスレッドのデフォルトスタックサイズは512 KBで、通常の操作には十分ですが、必要に応じてスレッド属性を介して調整できます。
  1. スレッドの初期化: __pthread_init()関数はスレッドのセットアップ中に重要で、env[]引数を利用してスタックの位置やサイズに関する詳細を含む環境変数を解析します。

macOSにおけるスレッドの終了

  1. スレッドの終了: スレッドは通常、pthread_exit()を呼び出すことで終了します。この関数はスレッドがクリーンに終了し、必要なクリーンアップを行い、スレッドが参加者に戻り値を送信できるようにします。
  2. スレッドのクリーンアップ: pthread_exit()を呼び出すと、pthread_terminate()関数が呼び出され、すべての関連スレッド構造の削除を処理します。これによりMachスレッドポート(MachはXNUカーネルの通信サブシステム)を解放し、スレッドに関連するカーネルレベルの構造を削除するシステムコールbsdthread_terminateが呼び出されます。

同期メカニズム

共有リソースへのアクセスを管理し、競合状態を避けるために、macOSはいくつかの同期プリミティブを提供します。これらはマルチスレッド環境においてデータの整合性とシステムの安定性を確保するために重要です:

  1. ミューテックス:
  • 通常のミューテックス (シグネチャ: 0x4D555458): メモリフットプリントが60バイト(ミューテックス56バイト、シグネチャ4バイト)の標準ミューテックス。
  • ファストミューテックス (シグネチャ: 0x4d55545A): 通常のミューテックスに似ていますが、より高速な操作のために最適化されており、サイズは60バイトです。
  1. 条件変数:
  • 特定の条件が発生するのを待つために使用され、サイズは44バイト(40バイトプラス4バイトのシグネチャ)。
  • 条件変数属性 (シグネチャ: 0x434e4441): 条件変数の設定属性で、サイズは12バイトです。
  1. ワンス変数 (シグネチャ: 0x4f4e4345):
  • 初期化コードが一度だけ実行されることを保証します。サイズは12バイトです。
  1. 読み書きロック:
  • 複数のリーダーまたは1つのライターを同時に許可し、共有データへの効率的なアクセスを促進します。
  • 読み書きロック (シグネチャ: 0x52574c4b): サイズは196バイトです。
  • 読み書きロック属性 (シグネチャ: 0x52574c41): 読み書きロックの属性で、サイズは20バイトです。

tip

これらのオブジェクトの最後の4バイトはオーバーフローを検出するために使用されます。

スレッドローカル変数 (TLV)

スレッドローカル変数 (TLV) は、Mach-Oファイル(macOSの実行可能ファイルの形式)の文脈で、マルチスレッドアプリケーション内の各スレッドに特有の変数を宣言するために使用されます。これにより、各スレッドが変数の独自のインスタンスを持ち、ミューテックスのような明示的な同期メカニズムを必要とせずに競合を避け、データの整合性を維持する方法が提供されます。

Cおよび関連言語では、**__thread**キーワードを使用してスレッドローカル変数を宣言できます。以下は、あなたの例での動作方法です:

c
cCopy code__thread int tlv_var;

void main (int argc, char **argv){
tlv_var = 10;
}

このスニペットは tlv_var をスレッドローカル変数として定義します。このコードを実行している各スレッドは独自の tlv_var を持ち、あるスレッドが tlv_var に加えた変更は他のスレッドの tlv_var に影響を与えません。

Mach-O バイナリでは、スレッドローカル変数に関連するデータが特定のセクションに整理されています:

  • __DATA.__thread_vars: このセクションには、スレッドローカル変数に関するメタデータが含まれており、変数の型や初期化状態などが記載されています。
  • __DATA.__thread_bss: このセクションは、明示的に初期化されていないスレッドローカル変数に使用されます。ゼロ初期化データのために確保されたメモリの一部です。

Mach-O は、スレッドが終了する際にスレッドローカル変数を管理するための特定の API tlv_atexit も提供します。この API を使用すると、スレッドが終了する際にスレッドローカルデータをクリーンアップする特別な関数である デストラクタ を登録できます。

スレッドの優先順位

スレッドの優先順位を理解するには、オペレーティングシステムがどのスレッドをいつ実行するかを決定する方法を見ていく必要があります。この決定は、各スレッドに割り当てられた優先度レベルによって影響を受けます。macOS および Unix 系のシステムでは、nicerenice、および Quality of Service (QoS) クラスのような概念を使用してこれを処理します。

Nice と Renice

  1. Nice:
  • プロセスの nice 値は、その優先度に影響を与える数値です。すべてのプロセスには -20(最高優先度)から 19(最低優先度)までの範囲の nice 値があります。プロセスが作成されるときのデフォルトの nice 値は通常 0 です。
  • より低い nice 値(-20 に近い)は、プロセスをより「自己中心的」にし、より高い nice 値を持つ他のプロセスと比較して、より多くの CPU 時間を与えます。
  1. Renice:
  • renice は、すでに実行中のプロセスの nice 値を変更するために使用されるコマンドです。これを使用して、プロセスの優先度を動的に調整し、新しい nice 値に基づいて CPU 時間の割り当てを増減させることができます。
  • たとえば、プロセスが一時的により多くの CPU リソースを必要とする場合、renice を使用してその nice 値を下げることができます。

Quality of Service (QoS) クラス

QoS クラスは、特に Grand Central Dispatch (GCD) をサポートする macOS のようなシステムでスレッドの優先順位を処理するためのより現代的なアプローチです。QoS クラスを使用すると、開発者は作業をその重要性や緊急性に基づいて異なるレベルに 分類 できます。macOS はこれらの QoS クラスに基づいてスレッドの優先順位を自動的に管理します:

  1. ユーザーインタラクティブ:
  • このクラスは、現在ユーザーと対話しているタスクや、良好なユーザーエクスペリエンスを提供するために即時の結果を必要とするタスクに使用されます。これらのタスクには、インターフェースを応答させるために最高の優先度が与えられます(例:アニメーションやイベント処理)。
  1. ユーザー開始:
  • ユーザーが開始し、即時の結果を期待するタスク(例:ドキュメントを開く、計算を必要とするボタンをクリックする)です。これらは高優先度ですが、ユーザーインタラクティブの下に位置します。
  1. ユーティリティ:
  • これらのタスクは長時間実行され、通常は進行状況インジケーターを表示します(例:ファイルのダウンロード、データのインポート)。これらはユーザー開始タスクよりも優先度が低く、即座に完了する必要はありません。
  1. バックグラウンド:
  • このクラスは、バックグラウンドで動作し、ユーザーには見えないタスクに使用されます。これには、インデックス作成、同期、バックアップなどのタスクが含まれます。これらは最低の優先度を持ち、システムパフォーマンスに最小限の影響を与えます。

QoS クラスを使用することで、開発者は正確な優先度番号を管理する必要がなく、タスクの性質に焦点を当てることができ、システムはそれに応じて CPU リソースを最適化します。

さらに、スレッドスケジューリングポリシーの異なる スレッドスケジューリングポリシー があり、スケジューラが考慮する一連のスケジューリングパラメータを指定します。これは thread_policy_[set/get] を使用して行うことができます。これはレースコンディション攻撃に役立つかもしれません。

MacOS プロセスの悪用

MacOS は、他のオペレーティングシステムと同様に、プロセスが相互作用し、通信し、データを共有するためのさまざまな方法とメカニズムを提供します。これらの技術は効率的なシステム機能に不可欠ですが、脅威アクターによって 悪意のある活動を行うために悪用される可能性もあります

ライブラリインジェクション

ライブラリインジェクションは、攻撃者が プロセスに悪意のあるライブラリをロードさせる 技術です。一度注入されると、ライブラリはターゲットプロセスのコンテキストで実行され、攻撃者にプロセスと同じ権限とアクセスを提供します。

macOS Library Injection

関数フック

関数フックは、ソフトウェアコード内の 関数呼び出し またはメッセージを 傍受する ことを含みます。関数をフックすることで、攻撃者はプロセスの 動作を変更 したり、機密データを観察したり、実行フローを制御したりすることができます。

macOS Function Hooking

プロセス間通信

プロセス間通信 (IPC) は、別々のプロセスが データを共有し、交換する 方法を指します。IPC は多くの正当なアプリケーションにとって基本的ですが、プロセスの隔離を覆したり、機密情報を漏洩させたり、無許可のアクションを実行するために悪用される可能性もあります。

macOS IPC - Inter Process Communication

Electron アプリケーションのインジェクション

特定の環境変数で実行される Electron アプリケーションは、プロセスインジェクションに対して脆弱である可能性があります:

macOS Electron Applications Injection

Chromium インジェクション

--load-extension および --use-fake-ui-for-media-stream フラグを使用して ブラウザ内の攻撃 を実行し、キー入力、トラフィック、クッキーを盗んだり、ページにスクリプトを注入したりすることが可能です:

macOS Chromium Injection

ダーティ NIB

NIB ファイルは ユーザーインターフェース (UI) 要素 とそのアプリケーション内での相互作用を 定義します。ただし、これらは 任意のコマンドを実行することができNIB ファイルが変更されても すでに実行されたアプリケーションの実行を止めることはできません。したがって、任意のプログラムが任意のコマンドを実行するために使用される可能性があります:

macOS Dirty NIB

Java アプリケーションのインジェクション

特定の Java 機能(_JAVA_OPTS 環境変数など)を悪用して、Java アプリケーションが 任意のコード/コマンドを実行する ようにすることが可能です。

macOS Java Applications Injection

.Net アプリケーションのインジェクション

.Net デバッグ機能 を悪用して .Net アプリケーションにコードを注入することが可能です(macOS の保護(ランタイムハードニングなど)によって保護されていません)。

macOS .Net Applications Injection

Perl インジェクション

Perl スクリプトが任意のコードを実行するためのさまざまなオプションを確認します:

macOS Perl Applications Injection

Ruby インジェクション

Ruby 環境変数を悪用して、任意のスクリプトが任意のコードを実行することも可能です:

macOS Ruby Applications Injection

Python インジェクション

環境変数 PYTHONINSPECT が設定されている場合、Python プロセスは終了後に Python CLI にドロップします。また、PYTHONSTARTUP を使用して、インタラクティブセッションの開始時に実行する Python スクリプトを指定することも可能です。
ただし、PYTHONINSPECT がインタラクティブセッションを作成する際には PYTHONSTARTUP スクリプトは実行されません。

他の環境変数(PYTHONPATHPYTHONHOME など)も、Python コマンドが任意のコードを実行するのに役立つ可能性があります。

pyinstaller でコンパイルされた実行可能ファイルは、埋め込まれた Python を使用して実行されていても、これらの環境変数を使用しないことに注意してください。

caution

全体として、環境変数を悪用して Python が任意のコードを実行する方法を見つけることができませんでした。
ただし、ほとんどの人は Homebrew を使用して Python をインストールし、デフォルトの管理者ユーザーのために 書き込み可能な場所 に Python をインストールします。次のようにハイジャックできます:

mv /opt/homebrew/bin/python3 /opt/homebrew/bin/python3.old
cat > /opt/homebrew/bin/python3 <<EOF
#!/bin/bash
# 追加のハイジャックコード
/opt/homebrew/bin/python3.old "$@"
EOF
chmod +x /opt/homebrew/bin/python3

これにより、root でも Python を実行する際にこのコードが実行されます。

検出

Shield

Shield (Github) は、プロセスインジェクション アクションを 検出およびブロック できるオープンソースアプリケーションです:

  • 環境変数を使用: 次の環境変数のいずれかの存在を監視します: DYLD_INSERT_LIBRARIESCFNETWORK_LIBRARY_PATHRAWCAMERA_BUNDLE_PATH および ELECTRON_RUN_AS_NODE
  • task_for_pid 呼び出しを使用: あるプロセスが他のプロセスの タスクポートを取得しようとする 時を見つけるために使用され、これによりプロセスにコードを注入できます。
  • Electron アプリのパラメータ: 誰かが --inspect--inspect-brk および --remote-debugging-port コマンドライン引数を使用して、デバッグモードで Electron アプリを起動し、コードを注入することができます。
  • シンボリックリンク または ハードリンク を使用: 一般的な悪用は、ユーザー権限でリンクを作成しより高い権限の 場所を指すことです。リンクを作成するプロセスがターゲットファイルとは 異なる権限レベル を持っている場合、アラート を作成します。残念ながら、シンボリックリンクの場合は、作成前にリンクの宛先に関する情報がないため、ブロックは不可能です。これは Apple の EndpointSecurity フレームワークの制限です。

他のプロセスによって行われた呼び出し

このブログ記事 では、task_name_for_pid 関数を使用して、他の プロセスがプロセスにコードを注入している 情報を取得し、その他のプロセスに関する情報を取得する方法を見つけることができます。

この関数を呼び出すには、プロセスを実行しているのと同じ uid であるか、root である必要があります(この関数はプロセスに関する情報を返し、コードを注入する方法を返すわけではありません)。

参考文献

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする