Tag: jsonp
2013
06.26

Summary

It was possible for a third party website to retrieve information about the currently logged in user via the Bitbucket API. This data included email addresses, SSH public keys, and repository information.

This vulnerability was first reported and patched in mid-2012. It was rediscovered and patched again in mid-2013.

What is JSONP?

From http://en.wikipedia.org/wiki/JSONP:

JSONP or “JSON with padding” is a communication technique used in JavaScript. It provides a method to request data from a server in a different domain, something prohibited by typical web browsers because of the same origin policy.

I gave a presentation late last year which has a bit more information on JSONP and more examples of sites that had JSONP-related vulnerabilities in the past (including the original instance of this vulnerability).

Vulnerability Details: Mid-2012

Back in 2012, Bitbucket’s REST API was accessible at https://api.bitbucket.org/1.0/. The API at that URL was meant to use OAuth tokens for authentication. In my investigation, I discovered that the API could also be accessed via a second URL, https://bitbucket.org/!api/1.0/. The difference between the two was that the second URL could authenticate requests using the browser’s cookies. Both forms of the REST API supported JSONP via a callback parameter passed in the URL.

As a result, it was possible for a third-party website to add a <script> tag that would pull in user information via JSONP API queries. To demonstrate the issue I built a proof of concept page which would make simple queries to the API. Those queries could uncover user information, email addressed, and SSH keys linked to an account. More complicated queries (ie: those involving repositories that the currently logged in user could access) were possible as well although not built in to the proof of concept.

I reported the issue to security@atlassian.com and it was patched approximately six hours later.

Vulnerability Details: Mid-2013

In mid-2013 I retested the site and discovered, to my surprise, that the vulnerability had reappeared. Looking at the API documentation, the main endpoint had been moved to https://bitbucket.org/api/1.0. Now no matter which URL I used I was able to extract user information via JSONP. In addition, although the API endpoints I used to fetch email and SSH public key information were no longer documented, my existing proof of concept worked without any modifications. I reported the issue to Atlassian again and it was patched again.

Disclosure Timeline

  • May 30th, 2012 11:08 AM: Initial email with proof of concept sent to security@atlassian.com.
  • May 30th, 2012 6:48 PM: Response from Atlassian, fix has been rolled out. Ask for confirmation that issue has been resolved.
  • May 30th, 2012 6:58 PM: Reply to Atlassian confirming fix.
  • June 11th, 2013 11:11 AM: Email sent to security@atlassian.com informing them that vulnerability has reappeared. Included previous correspondence, link to proof of concept.
  • June 11th, 2013 8:36 PM: Reply from Atlassian, claim that vulnerability was patched last year and that patch was still in place.
  • June 11th, 2013 8:56 PM: Email sent to Atlassian, disputing assertion that vulnerability is patched. Screenshots and additional information related to proof of concept attached.
  • June 11th, 2013 9:09 PM: Reply from Atlassian, confirming that vulnerability has reappeared.
  • Prior to June 26th, 2013: Testing confirms that vulnerability is patched in production.
  • June 26th, 2013: Published blog post
2013
06.04

Summary

At the beginning of May I found and reported a security vulnerability in Coinbase, a Bitcoin exchange. The vulnerability I reported allowed an attacker to steal the CSRF token for the currently logged in user, which meant that an attacker could bypass the site’s CSRF protection. Coinbase acknowledged the report and fixed the underlying vulnerability.

Details

Several URLs on coinbase.com used to return valid JavaScript which was intended to populate modal dialog boxes on the site. One example of such a URL was https://coinbase.com/api_key. The content of those dialog boxes was generated dynamically based on the currently logged in user.

If the dialog box contained a form, the complete HTML for that form was included in the response. That HTML included a hidden form field (authenticity_token) which is the CSRF token used by the site for that user. Because these URLs returned valid JavaScript via a GET request, a third-party website (whether malicious or benign) could extract the HTML for the dialog box, including the CSRF token.

For example, here is what I saw when I browsed to https://coinbase.com/api_key:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$('#api_key_modal').html("<div class=\"modal-header\">\n
  <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">&times;<\/button>\n
  <h4>Show API Key<\/h4>\n
<\/div>\n
<div class=\"modal-body\">\n
  <form accept-charset=\"UTF-8\" action=\"/api_key/authenticate\" class=\"form-inline\" data-remote=\"true\" method=\"post\">
<div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" />
<input name=\"authenticity_token\" type=\"hidden\" value=\"qGeCEw6MkTPZt2dLZJ43ftXmR36gYYNXWRwywKcsxE4=\" />
<\/div>\n
    \n
    \n
    <p>Please type your password to continue.<\/p>\n
    <p>\n
      <input class=\"focus\" id=\"password\" name=\"password\" placeholder=\"password\" type=\"password\" />\n
      <a href=\"#\" class=\"btn btn-primary submit-form\" data-disable-with=\"Verify\">Verify<\/a>\n
    <\/p>\n
<\/form><\/div>\n
<div class=\"modal-footer\">\n
  <a href=\"#\" class=\"btn\" data-dismiss=\"modal\">Close<\/a>\n
<\/div>");
$('#api_key_modal').modal('show');

Other sensitive information could also be disclosed under limited circumstances. For example, if the user had authenticated to see their API key the dialog box would not have prompted for authentication, as it does above, but instead would return the account’s API key.

The solution here was simple: the server-side scripts should not have been returning valid JavaScript as part of a GET request. The Coinbase developers have modified all of their dialog endpoints to require a POST request, which prevents them from being loaded via a <script> tag.

Disclosure Timeline

  • May 1st, 3:18 PM: Submitted basic details of vulnerability to whitehat@coinbase.com.
  • May 1st, 9:56 PM: Sent clarification of initial report, including additional information about CSRF leakage.
  • May 6th, 5:03 PM: Sent followup email, asking for feedback on the initial report.
  • May 6th, 5:04 PM: Provided additional vulnerable URL, as well as clarification of the initial report.
  • May 7th, 12:24 AM: Received reply: “Thank you for the disclosure, we appreciate it. This issue was already reported by others and we are working on a fix.”
  • May 19th, 6:44 PM: Informed Coinbase of intentions to publish this blog post on May 28th.
  • May 28th, 9:00 AM: Discovered that developers had attempted to patch the website but that they had forgotten to remove an endpoint.
  • May 28th, 9:29 AM: Emailed Coinbase to inform them of the incomplete patch. Informed them that publication of the blog post would be delayed by a week so they would have time to fix the vulnerability.
  • June 4th, 12:00 AM: Confirmed that final endpoint had been patched.
  • June 4th, 12:45 AM: Public disclosure via blog post
2013
03.15

Summary

Because of a security vulnerability in fitbit.com, malicious third-party websites could have extracted personal information from logged in users.

What is Fitbit

According to http://www.fitbit.com/company:

Fitbit is dedicated to helping people lead healthier, more active lives. We take a common sense approach to fitness, and believe that the key is to make it easier for consumers to be more active, eat smarter, and get enough sleep — in short, that small changes to your daily routine can add up to big results. To that end, we aim to create innovative, inspiring products and online services that harness the power of new technologies to make people more aware of their everyday activities and motivate them to do more.

The company produces a number of devices which all sync data to fitbit.com. This data can then be viewed, visualized, shared, etc. I was given a device as a holiday present and I’ve enjoyed it a lot.

What is JSONP?

From http://en.wikipedia.org/wiki/JSONP:

JSONP or “JSON with padding” is a communication technique used in JavaScript. It provides a method to request data from a server in a different domain, something prohibited by typical web browsers because of the same origin policy.

I gave a presentation late last year which has a bit more information on JSONP and more examples of sites that had JSONP-related vulnerabilities in the past.

In this case, fitbit.com did not use JSONP by default but did allow attackers to request data in a JSONP format. An attacker who requested data in this way could read out data that is normally restricted to users on the Fitbit website, including data on calories burned and steps taken.

Examples

Here are some examples of URLs and the responses that were returned by fitbit.com using my account (I own a Fitbit device):

http://www.fitbit.com/graph/getGraphData?apiFormat=json&type=minutesActive&dateFrom=2012-12-23&dateTo=2012-12-23&callback=a

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
a({
    "result": {
        "chart": {
            "columnWidth": 70,
            "datasets": [
                [{
                        "color": "a3e0e0",
                        "description": "0.08 hours lightly active on Sun, Dec 23",
                        "label": "",
                        "name": "1356220800000",
                        "url": "/activities/2012/12/23",
                        "value": 0.08
                    }
                ],
                [{
                        "color": "ffbb33",
                        "description": "0.12 hours fairly active on Sun, Dec 23",
                        "label": "",
                        "name": "1356220800000",
                        "url": "/activities/2012/12/23",
                        "value": 0.12
                    }
                ],
                [{
                        "color": "ff3366",
                        "description": "0 hours very active on Sun, Dec 23",
                        "label": "",
                        "name": "1356220800000",
                        "url": "/activities/2012/12/23",
                        "value": 0
                    }
                ]
            ],
            "expiresOn": 1361055371096,
            "gridCategoryAlpha": 0,
            "gridValueAlpha": 100,
            "isCanvasBorderOn": true,
            "isDescEnabled": true,
            "isLinkEnabled": true,
            "isSkipZeros": false,
            "maxAge": 300,
            "plotAreaAlpha": 100,
            "plotAreaBorderAlpha": 0,
            "plotAreaColor": "\#ffffff",
            "plotAreaMarginsBottom": 40,
            "plotAreaMarginsLeft": 40,
            "plotAreaMarginsRight": 20,
            "plotAreaMarginsTop": 5,
            "precision": 2,
            "rotateNames": 0,
            "timePeriod": "INTRADAY",
            "valuesCategoryEnabled": true,
            "valuesCategoryFrequency": 6,
            "valuesValueEnabled": true,
            "valuesValueFrequency": 1,
            "valuesValueIntegersOnly": false,
            "yMax": 3.12,
            "yMin": 0
        },
        "success": true
    }
});

http://www.fitbit.com/ajaxapi?callback=a&request={“serviceCalls”:[{“name”:”trackerSettings”,”method”:”getAlarms”},{“name”:”device”,”method”:”getOwnerDevices”}]}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
a({
    "ajaxResponse": {
        "result": [
            [],
            [{
                    "id": 111,
                    "type": "GALILEO",
                    "battery": "High",
                    "lastSyncTime": 1361044707000,
                    "productName": "Zip",
                    "settingsUrl": "/settings/device/tracker"
                }
            ]
        ],
        "newResult": {
            "getAlarms": {
                "status": 200,
                "result": []
            },
            "getOwnerDevices": {
                "status": 200,
                "result": [{
                        "id": 111,
                        "type": "GALILEO",
                        "battery": "High",
                        "lastSyncTime": 1361044707000,
                        "productName": "Zip",
                        "settingsUrl": "/settings/device/tracker"
                    }
                ]
            }
        }
    }
});

There may be other pages on the site which disclose similar information or have other forms of security vulnerabilities. This is not the first security or privacy issue related to Fitbit that has been publicly disclosed. [1] [2]

Disclosure Timeline

  • December 23rd, 2012: Initial email with proofs of concept sent to Fitbit support.
  • December 25th, 2012: Reply from Fitbit, details have been sent to engineering department.
  • January 2nd, 2013: Email from recruiter at Fitbit. Was asked to reach out to me because of my report. Asked if I would be interested in a possible software engineering role there.
  • January 2nd, 2013: Replied to recruiter, explained I’m already happily employed.
  • January 2nd, 2013: Email from recruiter acknowledging reply.
  • February 9th, 2013, 1:38 AM: Sent followup to support, asking for update on issue.
  • February 9th, 2013, 4:59 PM: Reply from support. Issues were passed off to engineering, no updates to provide at the current time.
  • February 9th, 2013, 5:15 PM: Sent followup to support, asking for ETA on fixes.
  • February 16th, 2013: Sent email to support. Informed them of intention to write this post and publish it in a little over a week.
  • February 17th, 2013: Reply from support. Issues were passed off to engineering, support will follow up with engineering.
  • February 18th, 2013: Reply from support. Engineering has been contacted.
  • February 21st, 2013, 9:09 AM: Reply from support. Issue is schedule to be patched on March 15th. Told to expect direct contact from engineering.
  • February 21st, 2013, 9:16 AM: Sent email to support. Agreed to hold off publication of post until after March 15th.
  • March 9th, 2013, 2:03 PM: Reply from support asking if engineering had followed up directly.
  • March 9th, 2013, 2:03 PM: Sent email to support indicating that no followup had occurred.
  • March 10th, 2013, 1:51 PM: Reply from support, following up with engineering.
  • March 10th, 2013, 11:31 PM: Reply from support, engineering has released a preliminary fix.
  • March 10th, 2013, 11:43 PM: Sent email to support, confirming that fix appears to mitigate vulnerabilities.
  • March 15th, 2013: Published post, contacted support with link to post.