Insights Blog Chaining Bugs from Self XSS to Account ...

Chaining Bugs from Self XSS to Account Takeover

Written by Behnam Yazdanpanah
Agenda

 

Introduction

During a recent bug bounty engagement, I discovered a fascinating chain of vulnerabilities that escalated from a seemingly benign self-XSS to a full account takeover.

This scenario highlights the importance of understanding how seemingly low-impact vulnerabilities can be leveraged in combination to create severe security risks. Let’s dive into the details

First XSS and WAF Bypass:

I started hunting on an online shop let's call it the redacted.com which was built with PHP and protected by Akamai WAF.

After some time working on the application, I found an endpoint that differed from the others.

Typically, they start with /xhr/mage/account , but this one was /xhr_preferences/index/change/ , which caught my attention.

This page was about customer preferences, where users answer a series of questions like their birth date or preferred brands to receive personalized product recommendations.

I simply input an HTML injection payload, and it worked.

 blogt1

Next, I tried the most famous XSS payload of all time: "><img src=1 onerror=alert(1)>

However, I received a 403 Forbidden response from the server: AkamaiGHost.

blot2

I modified the request slightly and attempted various XSS payloads for almost two hours to bypass the Akamai WAF.

Here are some resources you can try: WAF Bypass XSS Payloads

Unfortunately, none of them worked, and I was running out of ideas.

After taking an espresso and returning with a fresh mind, I reviewed my log history and was surprised to find that in the first name field, I was able to store an XSS payload.

However, attempting this elsewhere resulted in a 403 Forbidden response. What was different about that endpoint?

Bild21

Notably, the request was sent in JSON format, and the response was 200 OK, but this parameter wasn't vulnerable to XSS.

I immediately changed my request to the /xhr_preferences/index/change/ endpoint from query-string to JSON.

Bild20

It returned an HTTP/2 302 Found, indicating I was able to bypass the WAF, but it wasn't saved in my preferences.

So, what now? I needed to send a request like this:

 Bild10-1

 Bild19

and it got triggered

 Bild18

 

congratulations to me on my successful self XSS.

 

Second CSRF Bypass:

 

The backend used a simple mechanism: when users log into their accounts, it sets a cookie called csrf with a random value like Set-Cookie: csrf=7e3f4ebc6d40b5; Path=/.

Whenever I sent a POST request, it would check if csrf existed in both my cookie and header, and if they matched, it would return 200 OK.

 

If not, it would return:

Bild13

 Bild16

As I mentioned before, the /xhr_preferences/index/change/ endpoint was different, so I deleted the CSRF header from my request, and it worked.

Now I had everything I wanted.

This vulnerability allows an attacker to run arbitrary JavaScript, leading to account takeover.

 

Steps to reproduce the vulnerability: 

 Bild17

Attacker Steps:

The attacker edits the POC.html, replacing attacker.com with their own site and saves it.

Victim Steps:

  1. The victim logs into their account.
  2. The victim opens the attacker's site.

 

Impact and Remediation

 

This chain of vulnerabilities demonstrates how seemingly low-risk issues, when combined,Can lead to severe consequences.

Proper input validation and CSRF protection are essential to prevent such attacks.

Developers should always treat user-supplied input with caution and implement robust security measures.

 

 

Key Takeaways

  • Always implement CSRF protection for sensitive actions.
  • Thorough input validation is crucial to prevent XSS and other injection attacks.
  • Security testing should consider chained vulnerabilities, not just individual flaws.