In many situations, minor vulnerabilities might seem like small fish in the vast ocean of cybersecurity threats. They’re often marked as low severity and thus, overlooked by developers who assume that the conditions for their exploitation are too complicated to be met. However, in this article, we’re going to challenge that assumption and show you how chaining several ‘minor’ vulnerabilities can lead to a Mass Account Takeover.
Let’s begin by explaining some tech jargon:
Vulnerability Chain: Think of this as a domino effect. Multiple connected vulnerabilities can culminate into a serious one. A prime example is a reflected cross-site scripting (XSS) attack. On its own, it’s often considered as medium severity. However, when combined with cookies without the appropriate security flags, it can escalate to an account takeover.
Cache Mechanism: Developers use this to store data “closer” to the user, thus preventing them from loading it directly from the database. This mechanism saves significant resources, especially when thousands of users are simultaneously active. The cache can be set either individually or shared among users.
Application Features: These are functionalities added to the application to enhance the user experience. For instance, when you type a word into a search engine, it offers suggestions for the next word, such as “the most interesting…”, “the most fascinating…”, and so on.
So, what went wrong in the tested application? Why was a Mass Account Takeover a real scenario?
During the application audit, one of our test methodologies involved identifying application parameters and monitoring their behavior within the application environment. Imagine a parameter called SEARCH. Naturally, we’d check if this parameter was vulnerable to SQL injection, XSS, server-side request forgery (SSRF), server-side template injection (SSTI), and so on. We started with a basic check for the reflected value.
The auditor sends the server a TEST value for the SEARCH parameter.
REQUEST:
1 2 3 4 5 |
GET /?SEARCH=TEST HTTP/2 Host: […REDACTED-HOST…] User-Agent: […REDACTED…] … |
RESPONSE:
1 2 3 4 5 6 |
HTTP/2 200 OK … [APPLICATION SOURCE CODE] TEST [APPLICATION SOURCE CODE] … |
If the application returns the TEST value in the response body, that’s important information for the auditor (in black box tests, auditors do not know what parameters are processed by the application – we are learning how the application works, how a hacker would behave in a real attack scenario). Now it’s time to test more advanced payloads, such as:
1 |
><script>alert(document.domain)</script> |
Let’s see how the application behaves.
REQUEST:
1 2 3 4 5 |
GET /?SEARCH=><script>alert(document.domain)</script> HTTP/2 Host: […REDACTED-HOST…] User-Agent: […REDACTED…] … |
RESPONSE:
1 2 3 4 5 6 7 |
HTTP/2 200 OK … [SOURCE CODE OF APPLICATION] \u003e\u003cscript\u003ealert(document.domain)\u003c/script\u003e [SOURCE CODE OF APPLICATION] … |
Everything seemed okay. The SEARCH parameter appeared to be sanitized, so the auditor moved on to another parameter. However, the story took an unexpected turn. What happens if the exact same request is repeated?
Repeating the request for the same payload.
REQUEST:
1 2 3 4 5 |
GET /?SEARCH=><script>alert(document.domain)</script> HTTP/2 Host: […REDACTED-HOST…] User-Agent: […REDACTED…] … |
RESPONSE:
1 2 3 4 5 6 7 |
HTTP/2 200 OK … [APPLICATION SOURCE CODE] ><script>alert(document.domain)</script> [APPLICATION SOURCE CODE] … |
Why might an application behave like this if the first response was correctly sanitized, but the second one allows arbitrary JavaScript code execution? This is due to a BROKEN CACHE mechanism. In the tested application, the cache mechanism worked individually for each user, making it impossible to poison the cache for all users. So how is this even exploitable?
Example 1 – Stealing sensitive user cookies:
To steal sensitive user data like session cookies, two conditions must be met. First, the XSS (Cross Site Scripting) vulnerability must exist in the application, and second, the cookies flags must not be set with HttpOnly. In the tested application, neither of these conditions were met because the application parameters were sanitized, and the cookies had appropriate flags set. But two things went wrong. The cache mechanism allowed the bypassing of sanitization if at least two of the same requests were sent to the application, and unfortunately, the response body contained an object with session cookies.
Example 2 – Stealing sensitive cookies of many users:
In example 1, it is necessary to target potential victims and convince them to click on a link twice or visit a malicious website. Nowadays, awareness of this type of attack is very common, so it can be challenging to trick someone into this scenario. The application also has a feature that suggests phrases in the search engine. By poisoning the search engine with malicious suggestions, mass XSS execution may be possible, leading to a Mass Account Takeover.
Two separate issues, the cache mechanism allowing the bypassing of sanitization and the response body containing an object with session cookies, culminated into a serious problem. The application also had a feature that suggested phrases in the search engine. By poisoning the search engine with malicious suggestions, mass XSS execution could be possible, leading to a Mass Account Takeover.
To sum up, it is crucial not to underestimate minor vulnerabilities. When combined, they can escalate into serious security threats. This article highlights the importance of considering all possible vulnerabilities, no matter how insignificant they may seem on their own. Prevention, thorough testing, and proactive mitigation strategies are essential to safeguarding your applications and their users.