hacktricks/linux-hardening/privilege-escalation/docker-security/namespaces/user-namespace.md
2023-06-06 18:56:34 +00:00

12 KiB

Namespace de usuário

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Informações básicas

Um namespace de usuário é um recurso do kernel Linux que fornece isolamento de mapeamentos de ID de usuário e grupo, permitindo que cada namespace de usuário tenha seu próprio conjunto de IDs de usuário e grupo. Esse isolamento permite que processos em diferentes namespaces de usuário tenham privilégios e propriedades diferentes, mesmo que compartilhem os mesmos IDs de usuário e grupo numericamente.

Os namespaces de usuário são particularmente úteis na containerização, onde cada contêiner deve ter seu próprio conjunto independente de IDs de usuário e grupo, permitindo uma melhor segurança e isolamento entre os contêineres e o sistema host.

Como funciona:

  1. Quando um novo namespace de usuário é criado, ele começa com um conjunto vazio de mapeamentos de ID de usuário e grupo. Isso significa que qualquer processo em execução no novo namespace de usuário inicialmente não terá privilégios fora do namespace.
  2. Os mapeamentos de ID podem ser estabelecidos entre os IDs de usuário e grupo no novo namespace e aqueles no namespace pai (ou host). Isso permite que processos no novo namespace tenham privilégios e propriedades correspondentes aos IDs de usuário e grupo no namespace pai. No entanto, os mapeamentos de ID podem ser restritos a intervalos e subconjuntos específicos de IDs, permitindo um controle refinado sobre os privilégios concedidos a processos no novo namespace.
  3. Dentro de um namespace de usuário, os processos podem ter privilégios completos de root (UID 0) para operações dentro do namespace, enquanto ainda têm privilégios limitados fora do namespace. Isso permite que os contêineres sejam executados com capacidades semelhantes às de root dentro de seu próprio namespace sem ter privilégios completos de root no sistema host.
  4. Os processos podem se mover entre namespaces usando a chamada de sistema setns() ou criar novos namespaces usando as chamadas de sistema unshare() ou clone() com a flag CLONE_NEWUSER. Quando um processo se move para um novo namespace ou cria um, ele começará a usar os mapeamentos de ID de usuário e grupo associados a esse namespace.

Laboratório:

Criar diferentes Namespaces

CLI

sudo unshare -U [--mount-proc] /bin/bash

Ao montar uma nova instância do sistema de arquivos /proc usando o parâmetro --mount-proc, você garante que o novo namespace de montagem tenha uma visão precisa e isolada das informações de processo específicas daquele namespace.

Erro: bash: fork: Não é possível alocar memória

Se você executar a linha anterior sem -f, você receberá esse erro.
O erro é causado pelo processo PID 1 sair no novo namespace.

Depois que o bash começa a ser executado, ele bifurca vários novos sub-processos para fazer algumas coisas. Se você executar o unshare sem -f, o bash terá o mesmo pid que o processo "unshare" atual. O processo "unshare" atual chama o sistema de chamada unshare, cria um novo namespace de pid, mas o processo "unshare" atual não está no novo namespace de pid. É o comportamento desejado do kernel do Linux: o processo A cria um novo namespace, o próprio processo A não será colocado no novo namespace, apenas os sub-processos do processo A serão colocados no novo namespace. Então, quando você executa:

unshare -p /bin/bash

O processo unshare executará /bin/bash, e /bin/bash criará vários sub-processos, o primeiro sub-processo do bash se tornará o PID 1 do novo namespace, e o subprocesso sairá após concluir seu trabalho. Então, o PID 1 do novo namespace sairá.

O processo PID 1 tem uma função especial: ele deve se tornar o processo pai de todos os processos órfãos. Se o processo PID 1 no namespace raiz sair, o kernel entrará em pânico. Se o processo PID 1 em um sub-namespace sair, o kernel Linux chamará a função disable_pid_allocation, que limpará a flag PIDNS_HASH_ADDING nesse namespace. Quando o kernel Linux cria um novo processo, ele chama a função alloc_pid para alocar um PID em um namespace, e se a flag PIDNS_HASH_ADDING não estiver definida, a função alloc_pid retornará um erro -ENOMEM. É por isso que você recebeu o erro "Cannot allocate memory".

Você pode resolver esse problema usando a opção '-f':

unshare -fp /bin/bash

Se você executar o comando unshare com a opção '-f', o unshare irá criar um novo processo após criar o novo namespace pid. E executará /bin/bash no novo processo. O novo processo será o pid 1 do novo namespace pid. Em seguida, o bash também irá criar vários sub-processos para realizar algumas tarefas. Como o próprio bash é o pid 1 do novo namespace pid, seus sub-processos podem ser encerrados sem nenhum problema.

Traduzido de https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory

Docker

docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash

Para usar o namespace do usuário, o daemon do Docker precisa ser iniciado com --userns-remap=default (no Ubuntu 14.04, isso pode ser feito modificando o arquivo /etc/default/docker e, em seguida, executando sudo service docker restart).

Verifique em qual namespace está o seu processo

ls -l /proc/self/ns/user
lrwxrwxrwx 1 root root 0 Apr  4 20:57 /proc/self/ns/user -> 'user:[4026531837]'

É possível verificar o mapa de usuários do contêiner docker com:

cat /proc/self/uid_map 
         0          0 4294967295  --> Root is root in host
         0     231072      65536  --> Root is 231072 userid in host

Ou do host com:

cat /proc/<pid>/uid_map 

Encontre todos os namespaces de usuário

{% code overflow="wrap" %}

sudo find /proc -maxdepth 3 -type l -name user -exec readlink {} \; 2>/dev/null | sort -u
# Find the processes with an specific namespace
sudo find /proc -maxdepth 3 -type l -name user -exec ls -l  {} \; 2>/dev/null | grep <ns-number>

{% endcode %}

Entrando em um namespace de usuário

nsenter -U TARGET_PID --pid /bin/bash

Além disso, você só pode entrar em outro namespace de processo se for root. E você não pode entrar em outro namespace sem um descritor apontando para ele (como /proc/self/ns/user).

Criar um novo namespace de usuário (com mapeamentos)

{% code overflow="wrap" %}

unshare -U [--map-user=<uid>|<name>] [--map-group=<gid>|<name>] [--map-root-user] [--map-current-user]

{% endcode %} (This tag should not be translated)

# Container
sudo unshare -U /bin/bash
nobody@ip-172-31-28-169:/home/ubuntu$ #Check how the user is nobody

# From the host
ps -ef | grep bash # The user inside the host is still root, not nobody
root       27756   27755  0 21:11 pts/10   00:00:00 /bin/bash

Recuperando Capacidades

No caso dos espaços de nomes de usuário, quando um novo espaço de nome de usuário é criado, o processo que entra no espaço de nome recebe um conjunto completo de capacidades dentro desse espaço de nome. Essas capacidades permitem que o processo execute operações privilegiadas, como montar sistemas de arquivos, criar dispositivos ou alterar a propriedade de arquivos, mas apenas no contexto de seu espaço de nome de usuário.

Por exemplo, quando você tem a capacidade CAP_SYS_ADMIN dentro de um espaço de nome de usuário, você pode executar operações que normalmente exigem essa capacidade, como montar sistemas de arquivos, mas apenas no contexto de seu espaço de nome de usuário. Qualquer operação que você execute com essa capacidade não afetará o sistema host ou outros espaços de nomes.

{% hint style="warning" %} Portanto, mesmo que obter um novo processo dentro de um novo espaço de nome de usuário lhe dará todas as capacidades de volta (CapEff: 000001ffffffffff), você realmente pode usar apenas aquelas relacionadas ao espaço de nome (montagem, por exemplo), mas não todas. Portanto, isso por si só não é suficiente para escapar de um contêiner Docker. {% endhint %}

# There are the syscalls that are filtered after changing User namespace with:
unshare -UmCpf  bash

Probando: 0x067 . . . Error
Probando: 0x070 . . . Error
Probando: 0x074 . . . Error
Probando: 0x09b . . . Error
Probando: 0x0a3 . . . Error
Probando: 0x0a4 . . . Error
Probando: 0x0a7 . . . Error
Probando: 0x0a8 . . . Error
Probando: 0x0aa . . . Error
Probando: 0x0ab . . . Error
Probando: 0x0af . . . Error
Probando: 0x0b0 . . . Error
Probando: 0x0f6 . . . Error
Probando: 0x12c . . . Error
Probando: 0x130 . . . Error
Probando: 0x139 . . . Error
Probando: 0x140 . . . Error
Probando: 0x141 . . . Error
Probando: 0x143 . . . Error
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥