EDUCATIONAL ECOSYSTEM FOR CYBERSECURITY SPECIALISTS
HackMag is an educational ecosystem where cybersecurity specialists share practical knowledge in exchange for financial rewards and recognition. Access to this knowledge significantly increases the hands-on educational level of fellow specialists and the security of computer systems throughout the world.
Today, there is a great number of available tools allowing quick OS deployment and configuration, status monitoring and maintenance of the desired configuration. Here, the absolute leader for Win is SCCM. While full-featured analogues for *nix have just started to take on momentum. Nowadays, an administrator has to cope with a variety of tools and each of them performs its own role. This is convenient for development, but greatly complicates the support, while the results are not quite obvious. Foreman project, to be more precise, The Foreman is, in fact, an add-on for some open source solutions, which provides system management throughout system lifecycles from deployment and configuration to monitoring (Provisioning, Configuration, Monitoring). With it you can easily automate any repetitive tasks, manage changes on thousands of servers located on bare hardware or in the cloud, monitoring their status. The concept of server groups “config group” allows giving commands to multiple systems regardless of their location.
After the release of Kinect sensor, in the wake of its success, other non-contact motion control devices began to appear. Kinect was the basis for the growth and development of the market for such devices: Investors have seen the prospects and understood the value of investing into gesture control devices. However, the most significant and successful was the Leap Motion Controller. As its prototype, the latter version is based on motion capture technology. This device connects to the USB port; in size, it is like two flash drives put together. Technically, there is Leap device that captures the projection of the user’s hands in space by using two optical sensors (cameras) and an infrared light source (the developers do not exclude the possibility that the future versions of the device will have a different number of cameras).
If you think that the only possible variant for such a malware is a classic school-based .bat file with ‘format c:’ string inside, then you’re mistaken. The opportunity to automate various routine operations within the system with the help of .bat scripts has long grown into a full-scale trend for malware coding, for which almost all the anti-virus companies have rendered a special segment in their malware specifications.
I’d like to make a reservation right away that the vulnerabilities considered in the paper are typical virtually for all PLC types rather than only for PLC Delta DVP–14SS211R, which we will study. And these are not misses of a certain particular manufacturer but it is a sort of fundamental problem being the heritage of the time when the simplicity of implementation and economic expediency dominated rather than information safety and a threat of tampering.
As you most likely know, there are two methods of application analysis: static and dynamic. The former includes disassembly, decompilation, and app-manifest analysis. The latter assumes the application is launched in a special environment that permits its behavior to be analyzed under “real conditions,” so to speak. In practice, both methods are usually used in parallel. But as we have already reviewed static analysis (“Anatomy with Preparation”, No. 170), in this article, we are going to concentrate on dynamic analysis.
In late March 2020, a bug was discovered in a popular web-based tool called GitLab. The error enables the attacker to advance from reading files in the system to executing arbitrary commands. The vulnerability was recognized critical because the attacker doesn’t need any special rights in the target system. This article explains the origin of the bug and shows how to exploit it.
The exploit was developed by an Austrian researcher and developer William Bowling (vakzz). He found out that under certain conditions, the class UploadsRewriter does not check the path to the file. This allows the attacker to copy any file in the system and use it as an attachment when an issue is moved from one project to another one.
The researcher transformed this particular local file reader into an RCE vulnerability. The attacker can read the file secrets.yml containing a token used to sign cookies, while a specially crafted and signed cookie makes it possible to execute arbitrary code on the server.
The vulnerability belongs to the path traversal category; its registration number in the National Vulnerability Database is CVE-2020-10977. The bug affects EE/CE GitLab versions starting from 8.5 и 12.9, respectively. In the framework of the bug bounty program, GitLab has paid $20,000 to William Bowling for its discovery.
It’s not a big deal to create test environment for this bug because GitLab has an official docker repository. Using a simple command, I can run the container with any given version of the application. I choose the latest vulnerable release: 12.9.0.
docker run --rm-d--hostnamegitlab.vh -p443:443 -p80:80 -p2222:22 --name gitlab gitlab/gitlab-ce:12.9.0-ce.0
“CE” refers to the Community Edition; in theory, I could use the Enterprise Edition (EE) as well – but it requires a key for the trial period. CE is sufficient for demonstration purposes because both versions are equally vulnerable.
At the first start, GitLab asks to set an admin password. The default login is email@example.com.
Then I have to create two new projects.
The test system is up and running. However, I also need to download the GitLab source code to demonstrate what its sections contain the error.
Reading local files
The problem originates from the Clone Issue feature.
I create a new issue in the Test project.
When you create an issue, you can produce its description in the Markdown format and upload an arbitrary file (e.g. a screenshot showing the error or a log file) to simplify the life of the developers.
All uploaded files are stored in the folder /var/opt/gitlab/gitlab-rails/uploads/ on the hard drive. The FileUploader class is responsible for this.
The name transmitted during the upload becomes the file name.
After uploading the attachment, a link to it in the Markdown format is added to the issue description, and I save it.
GitLab allows you to move issues from one project to another; this is very useful if an issue affects several products of the same developer.
I press the button and select a project to move the issue to.
When you move in issue, it closes in the old project and appears in the new one.
Important: the attachments are copied, not moved. In other words, the program creates new files and links to them.
Time to examine the code and find out how the transfer is implemented. All issue-related routes are stored in the routes folder, in the file issues.rb. The move route (the one that processes the user’s POST request with the required parameters) is also kept there.
At this point, Issues::UpdateService.new is called; and the project ID, user who has initiated the move, and project the issue is moved to are passed as arguments. Then control is transferred to the class UpdateService, which, in turn, calls the method move_issue_to_new_project.
165:# Return a new uploader with a file copy on another project
183:record_upload# after_store is not triggered
As you can see, neither find_file, nor copy_to, nor copy_file checks the file name; therefore, any file in the system can be easily transformed into an attachment.
To test this hypothesis, I exit the directory using a standard method: ../. I must determine the required number of steps ‘up’. By default, the full path to uploaded files in the GitLab container is as shown on the screenshot below.
The full path to the picture from my issue is as follows:
A long piece of code in the middle is the unique hash of the current project. Therefore, I need at least ten ../ constructs to get to the root directory of the container.
Now let’s try to read the file /etc/passwd. I edit the issue description and add the required number of ../ constructs into the path to the file. I recommend using more such constructs to make sure that you get where you want to get.
Then I save and move the file to another project.
Now I can download the passwd file and view the content of /etc/passwd.
In other words, I can read everything accessible to the user on whose behalf GitLab is running (in the case of Docker, it is git). And the question is: can I find any useful stuff there?
From file reading to code execution
Of course, such a large-scale project as GitLab contains plenty of interesting files (various access tokens, data stored in private repositories, configs, etc.), and the attacker can read them and use the information to compromise the system. In addition, GitLab includes a very special file: data contained in it enable you to execute any code in the system. The path to this file is as follows:
The file stores the important, secret_key_base variable, which is used to sign cookies.
Similar to many modern solutions, cookies in GitLab are serialized and signed to prevent their substitution. The signature is verified on the server side, and only then the cookie is deserialized. By default, the serializer is defined as :hybrid.
This enables me use to the Marshal format and call various objects. I will need the Embedded Ruby (ERB) template engine, which allows inter alia to execute console commands. In ERB, expression values are described in constructs having the following format: <% [expression] %>. Inside this tag, I can call functions of the template engine, including code written in Ruby. To execute this system command, I can use either backticks or %x.
erb=ERB.new("<%= `uname -a` %>")
For the testing purposes, I am going to use the test docker container and the command that calls the Rails console: gitlab-rails console.
The next construct is required to declare the result method of the ERB class deprecated.
In other words, any 32-character string consisting of characters from 0 to 9 and from a to f would fit. Then I save the issue and move it to another project. As a result, I get the attached secrets.yml file.
To perform the next step, I launch GitLab and specify the obtained variable as secret_key_base. This allows me to generate a cookie in GitLab that contains payload and has a valid signature: this cookie will pass the verification on the attacked machine. Because I am dealing with a test system, I perform all manipulations on it. First, I run gitlab-rails console again.
Then I create a new request and specify GitLab environment variables as the config.
Voila! The command has been executed, and the file /tmp/owned successfully created.
Vulnerability demonstration (video)
The examined vulnerability is easy-to-exploit and very dangerous. GitLab is a popular tool; so, thousands of services critical for corporate networking infrastructures are at risk. Just imagine that attackers can gain access to source files of all your projects!..
The bug had persisted in the code for more than four years and successfully migrated from one branch to another starting from version 8.5 released in February 2016. Therefore, upgrade to version 12.9.1 ASAP to get rid of this vulnerability!