【Meterpreter】migrateは何をしているのか─プロセスインジェクションの仕組み
Meterpreter の migrate は「別のプロセスに乗り移る」操作としてよく登場しますが、内部では自分のコードを相手のプロセスに書き込み、そこで実行させるという、少し物騒なことをしています。この記事では、その乗り移りが具体的に何をしているのか、なぜ攻撃者がそれを行うのか、どのプロセスを選ぶのか、そして守る側からはどんな痕跡として見えるのかを、Windows の仕組みと結びつけて解いていきます。攻撃ツールの一機能に見えて、その正体は「プロセスインジェクション」という汎用技術です。
はじめに:プロセス移住(process migration)とは何か
Meterpreter のような遠隔操作エージェントは、侵入した直後、たまたま入り込んだ一時的なプロセスの中で動いています。migrate は、その「実行の場」を別の生きているプロセスへ移す操作です。
ファイルを別フォルダへ動かすのとは根本的に違います。移住では、対象プロセスのメモリに自分のコードを書き込み、その中で新しいスレッドを起こして実行を引き継がせます。操作元との通信は保たれたまま、コードが動く「住所」だけが変わる、というイメージです。
これは特別な裏技ではなく、一般にプロセスインジェクションと呼ばれる技法の一種です。攻撃者にとっては、検知を避けたり足場を安定させたりするための定番手段であり、防御側にとっては、正規プロセスの中で不審なコードが動き出す明確な検知ポイントになります。
そもそも「プロセスを奪う」とは何をしているのか
侵入直後のエージェントは、侵入の過程で偶然起動された一時的なプロセスに「間借り」している状態です。この間借り先は不安定で、いつ終了してもおかしくありません。そこで、より都合のよい別プロセスへ引っ越します。
このとき Windows の API が順番に呼ばれます。おおまかには次の流れです。
| 段階 | 呼ばれる API | 何をしているか |
|---|---|---|
| ① 開く | OpenProcess | 乗り移りたい相手プロセスへのハンドルを取得する |
| ② 場所を確保 | VirtualAllocEx | 相手プロセスのメモリ内に領域を確保する |
| ③ 書き込む | WriteProcessMemory | 確保した領域へ自分のコード(エージェント本体)を書き込む |
| ④ 起動する | CreateRemoteThread | 相手プロセス側で、書き込んだコードを実行する新スレッドを作る |
| ⑤ 離れる | (元スレッドの停止) | 間借りしていた元プロセスのスレッドを終える |
重要なのは、この間も操作サーバとの通信は切れないという点です。Meterpreter のソースコードのコメントにも、移住は「接続を維持したまま」行うと明記されています。新しいプロセスの中から改めて通信を確立し直すので、操作している側から見ると、セッションは途切れずに住所だけが変わったように見えます。
そして注目したいのは、この一連の動作が Meterpreter 固有ではないことです。「他プロセスにメモリを確保し、コードを書き込み、リモートスレッドで走らせる」という骨格は、いわゆる DLL インジェクションやコードインジェクションとまったく同じです。つまり migrate を理解することは、マルウェアが多用するプロセスインジェクションそのものを理解することに直結します。
flowchart TD
A["一時プロセス<br/>寄生中・不安定"]
B["OpenProcess<br/>相手プロセスを開く"]
C["VirtualAllocEx<br/>相手にメモリを確保"]
D["WriteProcessMemory<br/>自分のコードを書き込む"]
E["CreateRemoteThread<br/>相手側で新スレッド起動"]
F["安定プロセスで稼働<br/>操作サーバとの通信は維持"]
A --> B --> C --> D --> E --> F
E -.->|"元プロセスのスレッドは終了"| A
classDef step fill:#6474ef,color:#ffffff,stroke-width:0px;
classDef goal fill:#1f7a8c,color:#ffffff,stroke-width:0px;
classDef caution fill:#fdecec,stroke:#c1121f,stroke-width:2px,color:#c1121f;
class B,C,D,E step;
class F goal;
class A caution;
なぜ移住するのか – 3つの理由
やっていることが分かると、「なぜわざわざ危険な注入までして引っ越すのか」という疑問が湧きます。理由は主に3つあります。
| 理由 | 内容 |
|---|---|
| 生存 | 侵入時の一時プロセスは不安定で、終了すればエージェントも道連れになる。安定した常駐プロセスへ移ることで長生きさせる |
| 整合 | 32bit のエージェントが 64bit OS 上で動いていると、後述の「見え方のズレ」が起きる。プロセスと足並みを揃えると素直に動く |
| 隠蔽 | 見慣れた正規プロセスの中に紛れることで、プロセス一覧をざっと見ただけでは気づかれにくくなる |
「生存」と「整合」は、実際のプロセス一覧を見ると具体的に理解できます。私の作業した検証環境では、間借り元が powershell.exe(PID 3508)で、しかもアーキテクチャが x86、パスが C:\Windows\SysWOW64\...\powershell.exe でした。侵入の過程で一時的に起こされた 32bit のヘルパープロセスに寄生している、という状態がそのまま読み取れます。不安定で、かつ 32bit。移住したくなる条件が二重にそろっていたわけです。

アーキテクチャのねじれ(32bit と 64bit)
「整合」の理由をもう少し掘り下げます。64bit の Windows は、32bit アプリを WOW64 という互換レイヤの上で動かします。このとき、32bit プロセスにはファイルとレジストリがリダイレクトされた「32bit 用の景色」として見えます。代表的なものは次のとおりです。
| 32bit プロセスからの見え方 | 実際に向かう先 |
|---|---|
| C:\Windows\System32 | C:\Windows\SysWOW64 |
| HKLM\Software | HKLM\Software\WOW6432Node |
この「景色のズレ」は通常のアプリには透過的で問題になりませんが、システム領域のファイルやレジストリを直接あたりにいく後続の操作(post-exploitation)では、意図しない場所を見てしまう余地があります。だからネイティブな x64 プロセスへ移り、OS と同じ景色に揃えておくと素直です。
なお、正確を期すと、Meterpreter は 32bit から 64bit への移住自体は行えます(WOW64 をまたぐ注入に対応しています)。「x86 だと必ず失敗する」わけではありません。今回はあくまで予防として先に x64 側へ揃えました。特定の操作が 32bit のままで必ず失敗するかどうかは状況次第で、私が試した範囲では断定できるものではありませんでした。ここは「揃えておくとハマりにくい」という実務的な予防策として捉えるのが正確です。
どのプロセスに移るか — 選ぶ基準
移住先は、ps で出したプロセス一覧の中から選びます。良い移住先の条件は次のように整理できます。
| 条件 | 理由 |
|---|---|
| そのプロセスを開ける権限があるか | 権限が足りなければ注入そのものができない |
| アーキテクチャが一致するか(x64 なら x64) | 前述の WOW64 の景色のズレを避ける |
| 今の権限を維持できるか | 権限の低いプロセスへ移ると、格が下がってしまう |
| 安定・常駐で、壊れても影響が小さいか | セッションを長生きさせつつ、巻き添えの被害を避ける |
最後の条件には注意が必要です。たとえば全サービスの親玉である services.exe や、認証情報を扱う lsass.exe は、いかにも常駐していて狙いたくなりますが、システムの根に近すぎて、万一不安定にすると影響が大きい。手動で選ぶなら避けておくのが無難です。実際には winlogon.exe や spoolsv.exe のような、安定した常駐プロセスがよく選ばれるようです。
ただし、「重要プロセスは避けるべき」はあくまで手動選択のときの安全側の判断であって、絶対のルールではありません。実際、Metasploit の標準モジュール(priv_migrate)が自動で移住先を選ぶ際の既定候補には、services.exe や winlogon.exe、さらに lsass.exe までが含まれています。つまりツールに任せれば重要プロセスも普通に候補になる、という現実があります。手で選ぶときの慎重さと、ツールの割り切りは別物だと理解しておくと混乱しません。
移住が終わったら、必ず現在の権限を確認します。乗り移った先のプロセスの権限を引き継ぐため、うっかり低い権限のプロセスに移ると格下げになるからです。移住後に権限を確認する、という一手を習慣にしておくと事故が減ります。

flowchart TD
S["移住先の候補を選ぶ"]
Q1{"その権限で<br/>開けるか"}
Q2{"アーキが一致するか<br/>x64 なら x64"}
Q3{"今の権限を<br/>維持できるか"}
Q4{"安定・常駐で<br/>影響が小さいか"}
OK["採用<br/>移住後に権限を確認"]
NG1["注入できない<br/>対象外"]
NG2["景色のズレに注意<br/>できれば揃える"]
NG3["格下げ<br/>対象外"]
NG4["重要すぎて危険<br/>手動なら避ける"]
S --> Q1
Q1 -->|"いいえ"| NG1
Q1 -->|"はい"| Q2
Q2 -->|"ずれる"| NG2
Q2 -->|"一致"| Q3
Q3 -->|"下がる"| NG3
Q3 -->|"維持"| Q4
Q4 -->|"いいえ"| NG4
Q4 -->|"はい"| OK
classDef step fill:#6474ef,color:#ffffff,stroke-width:0px;
classDef goal fill:#1f7a8c,color:#ffffff,stroke-width:0px;
classDef caution fill:#fdecec,stroke:#c1121f,stroke-width:2px,color:#c1121f;
class S,Q1,Q2,Q3,Q4 step;
class OK goal;
class NG1,NG2,NG3,NG4 caution;
守る側から見たプロセス移住
ここまでは攻める側の視点でしたが、この操作は守る側にとって格好の検知対象です。攻撃の各動作が、そのまま監視すべきイベントの裏返しになっています。プロセスインジェクションは MITRE ATT&CK では T1055 として体系化されており、検知の考え方も整理されています。
Windows の監視ツール Sysmon を使うと、次のイベントが手がかりになります。
| Sysmon Event ID | 何を捉えるか | 移住のどの段階に対応するか |
|---|---|---|
| Event ID 8(CreateRemoteThread) | あるプロセスが別プロセスの中にスレッドを作った | 「④起動する」の実行トリガーそのもの |
| Event ID 10(ProcessAccess) | あるプロセスが別プロセスのハンドルを取得した | 「①開く」の準備段階 |
単にこれらのイベントが出たかどうかだけでなく、「どのプロセスが → どのプロセスに」注入したか、という送り元と送り先の組み合わせを突き合わせるのが要点です。lsass.exe や winlogon.exe、svchost.exe といった重要プロセスに対して、普段そんなことをしないプロセスから注入が走っていれば、それは強い危険信号になります。
さらに、注入されたコードは最終的に外部の操作サーバへ通信を返します。そのため「本来ネットワーク通信をしないはずの正規プロセスが、突然外向きの接続を張った」という異常も、有力な検知の切り口になります。攻撃者が正規プロセスに紛れようとするほど、「その正規プロセスらしくない振る舞い」が逆に目立つ、という構図です。
まとめ
- migrate の正体は「プロセスインジェクション」で、相手プロセスにメモリを確保し(VirtualAllocEx)、自分のコードを書き込み(WriteProcessMemory)、リモートスレッドで実行する(CreateRemoteThread)操作である。
- 通信は維持されたまま、コードの動く場所だけが移る。侵入時の不安定な一時プロセスから、安定した常駐プロセスへ引っ越すのが主目的。
- 32bit エージェントは WOW64 の「景色のズレ」(System32→SysWOW64、Software→WOW6432Node)を抱えるため、x64 プロセスへ揃えるとハマりにくい。ただし「32bit だと必ず失敗する」わけではない。
- 移住先は「そのプロセスを開ける・アーキテクチャの一致・権限維持・安定して影響が小さい」で選ぶ。重要プロセスを避けるのは手動時の安全策で、ツールの既定候補には重要プロセスも含まれる。
- 守る側では Sysmon Event ID 8(CreateRemoteThread)と 10(ProcessAccess)が検知の起点。送り元と送り先の組み合わせ、正規プロセスの想定外の外向き通信に注目する(MITRE ATT&CK T1055)。
参考にしたサイト
- metasploit-payloads / base_inject.c(Rapid7, GitHub)
reateRemoteThread でコード注入を行っている実装コード - client_core.rb(Rapid7 metasploit-framework, GitHub)
「移住してもサーバとの接続は維持される」という公式コメント - Metasploit Weekly Wrap-Up: 11/01/24(Rapid7 Blog)
現行 Meterpreter が kernel32!CreateRemoteThread で注入していること - Process migration in Meterpreter(Jorge Lajara)
OpenProcess → VirtualAllocEx → WriteProcessMemory → CreateRemoteThread という注入の API シーケンス - Process Injection(T1055)(MITRE ATT&CK)
プロセスインジェクションの定義と、12個のサブテクニックの分類。 - Detecting process injection (T1055)(ManageEngine Log360)
Sysmon Event ID 8 / 10、送り元・送り先の相関、重要プロセスへの注入の危険度 - File System Redirector(Microsoft Learn)
32bit プロセスで System32 が SysWOW64 にリダイレクトされる仕組み - Registry Redirector(Microsoft Learn)
32bit プロセスで HKLM\Software が WOW6432Node にリダイレクトされる仕組み