We covered a Docker container running a web server that is vulnerable to server side request forgery. We used that vulnerability to execute system commands and gain access to sensitive information stored inside git commits. We learned that a Docker daemon runs on port 2375 but in order to probe and access that container we need to perform port knocking to open the port 2375. Afterwards, we mounted the complete host file system.. This was part of TryHackMe The GreatEscape.
Initial Reconnaissance and Hidden Directories
I started by understanding the initial enumeration. An nmap scan would typically reveal ports 80 (HTTP) and 22 (SSH) open. I explored the web application, noting its “courses,” “admin” login form, “sign up,” and “login” functionalities. I tried basic credential stuffing, SQL injection, and brute-forcing the login form, but they were unsuccessful. The signup form was also disabled. I attempted directory brute-forcing, but it failed due to rate limiting on the web server.
Next, I checked robots.txt
, which revealed disallowed entries: /api
, /exif-utility
, and files ending with .back.txt
. The /api
endpoint showed “nothing to see here,” but /exif-utility
presented an interesting interface for uploading files or providing a URL to extract EXIF data from images.
Exploiting EXIF Utility – SSRF and Command Injection
I tested the EXIF utility by uploading a local image URL, and it successfully displayed EXIF data. However, trying a remote image URL failed, suggesting a firewall was blocking outbound connections. When I provided a local non-image URL (like the server’s own IP), it resulted in an error but also leaked the HTML source code of the page, indicating a Server-Side Request Forgery (SSRF) vulnerability.
My focus then shifted to finding files with the .backup.txt
extension. I created a wordlist using cewl
(cewl http://<target_ip>/ -m 4 -w GreatEscape.txt
) and manually added terms from the website. I then used wfuzz
(wfuzz -w GreatEscape.txt -u http://<target_ip>/FUZZ.back.txt
) with my custom wordlist to find exif-utility.backup.txt
.
This backup file was a goldmine! It revealed an internal API endpoint: api-dev-backup:8080/exif
, which took a URL
parameter. I leveraged the SSRF vulnerability to interact with this internal API. I discovered command injection by appending commands (e.g., id
) after a semicolon in the URL parameter supplied to the EXIF utility. This confirmed code execution as the root
user within the Docker container. Examples of commands I used via URL manipulation were:
http://<target_ip>/exif-utility/show.php?url=image.png;id
http://<target_ip>/exif-utility/show.php?url=image.png;ls+ -la
http://<target_ip>/exif-utility/show.php?url=image.png;pwd
http://<target_ip>/exif-utility/show.php?url=image.png;cd+ /root
http://<target_ip>/exif-utility/show.php?url=image.png;ls+ -la+ /root
http://<target_ip>/exif-utility/show.php?url=image.png;cat+ /root/Dev-note.txt
Enumerating Inside the Container and Git Repository Exploitation
Inside the container, I used commands like ls -la
, pwd
, and cat
via the command injection to explore the file system. I found a note Dev-note.txt
in /root
, which contained a password for “Hydra” (though it didn’t work for SSH). More importantly, I found a .git
directory in /root
.
I exploited the Git repository by using git log
(http://<target_ip>/exif-utility/show.php?url=image.png;git+--git-dir=/root/.git+log
) to list commits. Then, I used git diff <commit_hash>
(http://<target_ip>/exif-utility/show.php?url=image.png;git+--git-dir=/root/.git+diff+<commit_hash>
) to view changes in a specific commit. This revealed a crucial note about setting up Docker for remote administration and mentioned port knocking to open port 2375
(the Docker daemon port). I also found a flag here!
Port Knocking and Docker Daemon Access
To open port 2375
, I created a bash script using telnet
to perform port knocking on a sequence of ports. The script looked something like this:
Bash
#!/bin/bash
telnet <target_ip> 42
telnet <target_ip> 1337
telnet <target_ip> 6969
# ... (other ports from the git diff output)
After successful port knocking, an nmap
scan confirmed that port 2375
was open. I then used the Docker CLI to interact with the exposed Docker daemon remotely. I listed running containers using docker -H tcp://<target_ip>:2375 ps
, which identified the web server container and others.
Escaping the Container
The final step was escaping the container. I used a Docker command to run a new privileged container, mounting the host’s entire file system (/
) to a directory (/mnt
) inside this new container. Then, I changed the root to this mounted directory, effectively giving me root access to the host system. The command I used was: docker -H tcp://<target_ip>:2375 run --rm -it --privileged -v /:/mnt alpine chroot /mnt sh
.
After escaping to the host, I retrieved the final root flag from the host’s /root
directory using cat /root/flag.txt
. I also explored other attempted escape methods like using capsh
for SYS_ADMIN
capabilities or namespace manipulation, but they weren’t successful in this scenario. I also found another flag by accessing /.well-known/security.txt
, which pointed to an API endpoint, and I retrieved it using curl -I http://<target_ip>/api/flag.php
.
This entire experience provided a comprehensive understanding of Docker container penetration testing, from initial enumeration and web application vulnerabilities to privilege escalation and container escape techniques.