Adventures Into The MeowCorp Bug Bounty Program
After hacking into a private program for a while now, I found some nice bugs, mostly through recon and chaining one clue after another. In this blog post, I'll discuss the same as well as my approach to finding them. Since I've signed an NDA with them, all references to the project and company are redacted. For the sake of this blog, I am going to refer to the project as MeowCorp project and their primary domain as meowcorp.io.
#1 /.git/config file to root shell
After running regular subdomain enumeration tools, I picked up some interesting subdomains. One of them was api.scan.meowcorp.io. While performing content discovery on this subdomain, I found git config file. Quickly I dumped the files from .git dir with GitTools but it was all static CSS, JS files that were of no use. When I was about to close the terminal tab, I noticed that the git repo belonged to a personal GitHub profile.
The company has its own GitHub org profile but the reference to a personal profile in prod API got my attention. That personal profile had only one public repo named "redacted-tool". They were also using GitHub actions for CI/CD pipelines so there were workflows-related files in .github/workflows. Inside the same directory, I found CICD.yml file. They mistakenly pushed their SSH credentials and they removed it too, but you know.. what happens in git, stays in git. Looking at the commit history, I was able to extract the host details and the SSH credentials.
The password for the redacted-user was not changed, so I was able to SSH into the box. After logging in to the box, I randomly entered "sudo -l" to check sudo rights and I was surprised to see (ALL:ALL) ALL output.
Now, popping root shell is as easy as "sudo su -"
Root shell popped! I read some files from /root directory for proof of concept and immediately sent the report with all details. The GitHub profile was taken down and credentials were changed within ~1hr of sending the report.
#2 Github Recon, NFS share, and access to employee's Dockerhub account
I checked MeowCorp's Github org profile, as well as each repo and users who contributed to them. redacted-user was one of them who pushed frequent commits to the MeowCorp's github repo so, I checked his GitHub profile for any references to MeowCorp. On one of the repo, I found MongoDB credentials hardcoded in a python script.
The credential was valid and I logged in to the database. The database was mostly filled with junk and random data so it was of no use. Since I had a new IP address, I performed a full port scan with nmap and it returned a bunch of open ports. Of all the open ports, I found port 2049 interesting which is used for Network File System (NFS). I used "showmount" utility to list the available shares of NFS and found that the "/data/share" of the remote host can be mounted.
$ mount -t nfs 125.xx.xx.xx:/data/share /tmp/test/
Now, I can view the files from my local /tmp/test directory as shown in the below screenshot.
I checked all directories to see if I could find any sensitive information to escalate this issue further and found config.json file in the portainer directory. The config.json had base64 encoded credentials for dockerhub.
I immediately went to hub.docker.com, supplied those credentials, and to my surprise, I was able to log in to it. No MFA yayyy!! 🎉
I got full access to a user's DockerHub account and I could read/write/delete private/public images or delete everything and disrupt the supply chain.
#3 Shodan recon and access to prod MySQL database
Utilizing my 1337 shodan recon skillz, I found an asset belonging to meowcorp - 157.xx.xx.xx
I ran a full port scan on the IP and discovered a number of open ports that were mostly running web apps and seemed like a staging environment.
I also have been keeping notes of passwords found from github, dehashed, and other publicly available data. Furthermore, I also added some easy to guess passwords like passwords from seclists, meowcorp123, meowcorp2020, meowcorp2021, meowcorp2022, Fname123, fname.lastname123 and so on.
Using the above-mentioned password wordlist, I sprayed for SSH, postgresql, redis, mysql, etc. Luckily, I got a hit for MySQL as root user and the password was meowcorp2021 🤦♂️
I was able to log in to the database as root user and there was a non-default database named "redacted-database". I was still thinking it was a staging environment with test data only but when I checked the table "emailVerification", I saw entries with recent dates. The table had information like email address, user id, and verification code to verify the email address.
There were other tables too which gave a hint that the database is used for another project of MeowCorp - doggocorp.io. To verify it is indeed a prod database, I registered an account in doggocorp.io, and the verification code was sent to email..
.. and when I checked the table, another entry was made with the same verification code and my email address.
Now it was confirmed that I could indeed access the production database and modify the user details too.
#4 SSRF and GCP secrets
MeowCorp has another project named "redacted-project". It is related to AI training, managing datasets, community building, etc. In the datasets section, there was a feature to import images from external links. When an image link like (https://example[.]com/image.jpg) was supplied, the image would be fetched and saved in the google bucket "meowcorpstudio". So, instead of an image link, I tried to hit localhost and it was successful. I was curious what other protocols were allowed and tried file protocol to read local files and it also worked.
Upon reading passwd and hosts file, it was confirmed that the webapp was running inside a docker container. Since there was no way to list files on the server, it was very hard to guess the files.
Proc files to the rescue!
The image fetcher was not consistent and sometimes it errored out and didn't save binary files to the bucket. To verify it could fetch files from /proc directory, I fetched /proc/1/cmdline and cmdline was saved to the bucket. It was available at https://storage.googleapis.com/meowcorpstudio/prod/project_000/cmdline.
Process number 1 was the same process that was running the web application. The content of cmdline was:
/usr/bin/python3 label_studio/manage.py runserver 0.0.0.0:8080
I checked the env variables from /proc/1/environ and found Postgres database credentials and a variable named GOOGLE_APPLICATION_CREDENTIALS which pointed to a json file with secrets - /usr/src/app/keys/gcp.json.
gcp.json file had project_id, client_id, private_key, client_email, etc. which were enough to authenticate to Google Cloud. I crafted another json file to match the format to authenticate with gcloud cli and finally I was able to list instances and buckets.
Listing the contents of the bucket meowcorpstudio:
The 2 instances didn't have any relation to prod environment and their status was also terminated. But the bucket was their primary one which was used for storing static files (CSS, JS, images), user-uploaded files, etc. An attacker could have modified the js file so that they could silently exfiltrate user data, steal sessions, delete users' files, deface the website, replace logo/images, and so on.
It was a quite fun experience to hack into meowcorp as well as reporting and communication part. I reported total 7 bugs (4 mentioned above, 3 were low-hanging API bugs), and most of them were fixed within ~3 hrs of reporting. They were also okay with me going a step ahead to prove the impact which I loved the most about hacking on this program. Despite the fact that the bounties were insignificant in comparison to the potential damage, I am glad that I found a program that I really enjoyed hacking for months, found critical vulnerabilities when I was not in a good state, and gave me a good confidence boost.
Thank you for making it to the end. If you liked the blog, check out my SoundCloud as well.