Password theft via supply chain, development artifacts, and XSS.
TLDR: During an engagement our team leveraged chaining of multiple lower risk vulnerabilities to produce a serious exploit capturing credentials, underscoring the need to address lower risk issues as part of an overall security strategy.
Detail
During a recent application penetration test, we discovered a stored cross-site scripting (XSS) vulnerability in an applications login functionality. The application detected potentially malicious content in user-provided HTML string, and either removed or sanitized the input string. HTML “<script>” blocks were removed while some other tags were also sanitized, but their content remained intact and event handlers were renamed to be harmless. Fuzzing was conducted using the “<img>” tag, and adding a list of known event handlers, which resulted in OSec identifying application sanitization rules of events. These efforts permitted for the identification of the event “onanimationend”.
By using an “onanimationend” XSS payload and embedding “<script>” blocks in the payload, the application was able to be forced to execute scripts on the login page.
After confirming the XSS exploit on the login page, theft of user credentials was identified as the most opportune attack vector. Given the complexity of the task, a less cumbersome approach to deliver code onto the login page was beneficial to the execution of the attack. Additional application enumeration identified an image upload functionality that allowed for “.png” files. Subsequent testing revealed that when “.jpg” files were uploaded, the application renamed them to “.png” without manipulating the content. However, the application did verify file contents by inspecting the byte headers.
A Javascript function was created through the XSS exploit to accept an image file URL, fetch the file from the server, seek past the binary JPEG header, and execute the remaining content using `eval`. This limited the effort of bypassing all the server-side sanitization of event handlers and Javascript functions to a small portion of the exploit.
Using the 4-byte JPEG header followed by a Javascript payload, a user can upload a file to the server that can be used by the previous function to execute arbitrary code, all performed without requiring any bypass or avoidance of sanitization.
The next hurdle was bypassing the Content Security Policy (CSP). The application contained lengthy CSP headers, imposing restrictions on what is accessible to the client-side code. However, while reviewing the connect-src section of the policy headers, an entry was found for “https://*.sentry.io”. A static review of the available source code and dynamic analysis of the application failed to identify any references for interactions to Sentry services. It was determined the “https://*.sentry.io” entry was most likely an artifact from a development environment.
At this juncture, OSec signed up for a free 14-day trial of Sentry.io’s services. This provided the Javascript initialization with code to embed within the application for Sentry.io’s services. Attempts at utilizing the Sentry.io code resulted in failure due to CSP headers while embedding the scripts into image uploads was also unsuccessful.
Leveraging Burpsuite’s built-in proxy Match and Replace Rules, OSec stripped off the CSP headers to allow the browser to fetch the Sentry.io scripts. Then, using the “captureMessage” function from Sentry.io’s API, a test message was sent and the POST request was captured. Further utilizing the captured POST message, OSec was able to create a custom Javascript function to post messages to the Sentry.io trial instance and upload the script as an image to the application. The payload would also create event listeners to attach to the username and password fields of the login page.
Once the payload was complete, the login page XSS was modified to retrieve the correct image and execute the scripts.
With everything in place, it was time to test the exploit using fake data.
After OSec reported the exploit chain to the client, their developers logged in and validated the finding. As an added bonus, the login resulted in Sentry.io delivering an email to OSec with the client’s valid credentials.
Prevention
The multiple components of this exploit chain illustrate the need for a defense in depth approach to remediation. Various approaches could/should be use to prevent these kinds of exploit chains from happening:
- Properly sanitize/encode all user inputs reflected back in HTML output. Validate expected input types. OWASP has comprehensive coverage of how to prevent XSS issues here.
- Improve file upload validation – Check file headers and extensions to allow only intended types. Scan contents for scripts. More details can be found here.
- Restrict CSP directives – Remove unused directives (like *.sentry.io) that broaden exposure. Allow only necessary sources. More on CSP here.
- Harden APIs – Check validity of API requests and limit data exposure. OWASP has some great coverage on API security here.
- Implement credential management – Use robust hashing, salting for storage. Rotate passwords/API keys periodically.
- Monitor for suspicious activity – Out of the box, most logging is pretty basic, so if you want to detect more complicated attacks you are going to need to work on your SIEM, or with your MSSP to create detection rules. Our purple team services can be a big help in this area.