Recently, SaltStack had a release regarding two vulnerabilities found in their product, CVE-2020–11651 and CVE-2020–1162. These two CVEs were able to be used by attackers to either remotely execute code, or disclose sensitive data from the server. Many organizations were using SaltStack for server orchestration, and as such, many organizations were compromised by these vulnerabilities (most notably Cisco https://threatpost.com/hackers-compromise-cisco-servers-saltstack/156091/).
As security researchers, we often want to discover why these vulnerabilities occur, and what caused them to be so easily exploited. In this article, I will explore the SaltStack CVEs, and explain how the vulnerabilities came to be, why PoCs were easy to develop, and how this could have been avoided
Part One — The Vulnerability
Both of these CVEs have a common root cause, which comes down to how the developers implemented the objects handling API calls. In Salt, the master.py code is responsible for processing API calls sent by a user. There are a number of classes inside of this file, the one we are interested in is called ClearFuncs. The purpose of ClearFuncs is to handle API calls sent in cleartext.
If we look at the ClearFuncs class before the patch was applied, we will see that there are a number of methods that are available, all of which are accessible by any user who wishes to send a request to the API over port 4506. The problem is that the developers never intended for all these methods to be accessible.
To understand this, we need to discuss a bit about object method scoping. In Java and similar languages, we can declare a method or property as private or public depending on how it should be accessed. Due to this, we can create helper functions that are private so that they cannot be accessed outside the object. In Python, no such concept exists, meaning all methods would be considered public unless some sort of protection is used to prevent access to them. In the ClearFuncs object, methods were written that were intended to be used internally, however they were exposed through the API, allowing for an attacker to access them.
The result of this simple oversight is CVE-2020–11651, in which an attacker could access the _prep_auth_info or _send_pub methods to create remote code execution conditions. In addition to this, an attacker could take advantage of unsanitized directory paths to gain directory traversal through get_token() for CVE-2020–11652. Both of these issues were fixed in versions 2019.2.4 and 3000.2 by restricting access to methods, as well as restricting directory path arguments.
The lesson to learn from this section is that APIs need to be carefully regulated to ensure that helper methods are not exposed. If a method or property is exposed, it is possible to use it in an unexpected way to potentially create dangerous conditions.
Part Two — Why Exploitation Was Easy to Achieve
Open source software is typically an easy target for exploitation due to having full access to the source code. In many cases, we can reverse engineer patches to determine how to exploit a vulnerability. In the case of SaltStack, the developers actually provided everyone with what was essentially a fully working exploit. If we look at the patch for CVE-2020–11651, we can see that they added test cases for the exploits:
Using these test cases, we can basically copy and paste, replacing the IP, and get a fully working exploit. After around a few minutes of trial and error, a competent programmer could have a fully working exploit ready to attack any vulnerable server. This is obviously a huge issue, since we are not only revealing two major vulnerabilities, but also providing everyone with a valid exploit for them.
This type of issue is not unique to SaltStack, really every open source library suffers from it. The main thing I want to highlight is the importance of monitoring and picking up updates for any open source you may use. The bar of exploitation for a lot of open source is extremely low, so if a vulnerability like this happens, it is almost trivial to exploit.
Part 3 — Lessons Learned
From this article, I want everyone to have two key takeaways. The first is that when you are working with APIs, it is essential to understand what is being exposed to the user. Languages like Python are easy to use, however the simple syntax can result in major holes if it is not used carefully. If you write a method that is exposed to the user, you need to make sure anything the user does with it will not result in exploitation. Similarly, if you believe a method is not exposed to the user, you should write test cases to prove it, otherwise a simple programming mistake could cause a major exploit.
The second takeaway is a larger point about the usage of open source software in production environments. Open source software is a fantastic resource, but it comes with a major responsibility to monitor security updates. When a software is open source, you should assume any vulnerability is easy to exploit, and as such, you should take every update you possibly can. It took only a month for attackers to automate and exploit the SaltStack issue, so the timeframe between fix and exploitation is very small but crucial. Having appropriate update monitoring and application is one of the most important pieces for a secure system. As open source usage increases, we need to be increasingly vigilant of the vulnerabilities that become present.