Date Tags PrivateBin / Security

On 31st of July 2018, @cryptolok reported a cryptographic vulnerability in PrivateBin due to the incorrect use of SJCL when used on very old browsers. Vulnerability write-up done by @rugk and @elrido.
The vulnerability has been fixed in PrivateBin v1.2.1. Admins are urged to upgrade to this version to protect the affected users.

Affected versions

Any ZeroBin and PrivateBin lower then version 1.2 (which did not support the affected browsers) since the first commit to ZeroBin.

Conditions

The condition is only met when a paste is first created, during the generation of a random key used for the encryption of the paste and any subsequent discussion topics. Viewing the paste does not pose a risk in itself, as the key already is known to the viewer.

  • Browsers that expose the web crypto API function crypto.getRandomValues() and nodeJS (in case of the CLI client) are not affected. See the timeline of browser releases with web crypto support in the appendix below.
  • For browser versions that do not provide this API, SJCL provides a fallback using collected randomness from mouse movements, keypresses, motion sensors, etc. While ZeroBin and PrivateBin did implement this fallback and a check to ensure that enough entropy got collected, the incorrect use of the randomwords function in SJCL allowed a premature generation of the paste key, even if not enough entropy had been collected. The collection of entropy takes around 20 - 90 seconds, depending on the performance of the system (minimum and maximums as found during testing on 800 Mhz single core and 2.7 GHz quad core CPU systems).

Steps to reproduce

  1. Find a way to install an affected browser or use a system that still has such an old browser installed. Our tests if the mitigation were performed primarily using Firefox 10.
  2. Visit a PrivateBin or ZeroBin site running a release earlier then version 1.2.
  3. Quickly paste some content into the text area, set options and hit send within less then 20 - 60 seconds (depending on the performance of the environment).

If the entropy is not ready, PrivateBin before version 1.2 would suppress any error, generate the key regardless and submit the paste. PrivateBin 1.2 doesn't support these old browsers, sending the paste to the URL "undefined" and fails to submit the paste. PrivateBin v1.2.1 asks you to move your mouse, etc. to create entropy on these older browsers, as intended.

Impact

On affected browsers the pastes may have been generated with low entropy. Viewing pastes on any browser does not pose a risk. When comments are posted on such a paste, the low entropy key gets reused. There is no obvious way to detect a key with insufficient entropy. It will have the same length as usual and seem random to the human eye.

We have to assume that pastes generated with a low entropy key can be brute forced easier then with a completely random key. With a lower entropy, the total amount of different generated keys would be lower then 2^256 (we use 256bit long keys).

Real-life impact

We have not conducted any research on how frequent such affected pastes are. However, on the instance of one of the maintainers, the oldest found paste was created in 2015 and so seems unlikely to be affected, while on PrivateBin.net the oldest paste is from 2017. By default most pastes are set to expire within a week. A user would have had to set the expiration explicitly to "never" for it to be still available.

At the time of the first ZeroBin commit affected by this issue in April 21st 2012, the then current releases of Chrome and Safari already supported the required web crypto API call and were not affected. One and a half years later, end of October of 2013, releases of Firefox, Internet Explorer, iOS and Android where available that supported the new API also and were no longer affected. Opera as of March 2014 is also unaffected.

When ZeroBin was first released, about 60% of the used browsers were affected (see browser market share in the appendix below). By the end of 2013 the market share of browsers still affected in their latest release was below 3%. Even during this time pastes created with affected browsers may have had sufficient entropy as the key is generated just before sending the paste, as long as the user creating the paste spent more then ~30 seconds on the page. On the other hand, users that send a paste "too quickly" could have easily created a paste with a key with limited entropy within a few seconds.

Mitigation

Users that know of old pastes generated with outdated browsers may want to clone the pastes using a more recent browser and delete the old paste, if they still have the delete token URL.

Administrators should update their instances to PrivateBin version 1.2.1.

Timeline

  • 2018-07-31 – Reporter raised an issue, after reviewing the PrivateBin source code.
  • 2018-07-31 – Receipt confirmed, started preparing vulnerability report to collect findings.
  • 2018-08-01 – Issue confirmed, research of versions and timelines, aquired access to environement with legacy browsers for testing.
  • 2018-08-04 – Patch developed and tested to resolve the issue in legacy browsers.
  • 2018-08-05 – Worked on vulnerability report, release preparations.
  • 2018-08-xx – Release published & Vulnerability details published.

Appendix

Release history of unaffected browsers / affected ZeroBin versions

  • 2014-04-14 - Windows Phone 8.1
  • 2014-03-04 - Opera 20
  • 2013-10-31 - Android 4.4
  • 2013-10-17 - Internet Explorer 11
  • 2013-09-18 - iOS 7.0
  • 2013-05-14 - Firefox 21
  • 2012-04-21 - first commit of ZeroBin
  • 2011-10-25 - Chrome 15
  • 2010-06-07 - Safari 5

Disclaimer: In the case of Chrome, Android, iOS and Windows Phone, there may have been earlier versions that were not affected, but we did not have access to any of these (in the case of iOS version 4.3.2 was found to be affected). See the details on the tested browser versions below.

Browser market share in April 2012

Source: Statista - Market share of browsers worldwide since 2009

  • IE 30.8%
  • Chrome 28.24%
  • Firefox 22.5%
  • Safari 8.72%
  • Opera 3.62%
  • Android 2.31%
  • UC Browser 0.74%

Source code of the used SJCL-Test page

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>SJCL randomwords test</title>
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script type="text/javascript" src="https://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script>
  <script type="text/javascript">
        // IE polyfill
        if (!Date.now) {
            Date.now = function now() {
                return new Date().getTime();
            };
        }

        function log(string) {
            var e = document.createElement('p');
            e.innerHTML = string;
            document.body.appendChild(e);
        }

        var time = Date.now(),
            i = 0;

        sjcl.random.addEventListener('progress', function() {
            log('waiting ... ' + i);
            i++;
        });

        sjcl.random.addEventListener('seeded', function() {
            log((Date.now() - time) + ' milliseconds');
        });

        // set the paranoia level explicitly:
        sjcl.random.setDefaultParanoia(10);

        log("without startCollectors");
        setTimeout(function() {
            log("startCollectors")
            // start random number generator collector.
            sjcl.random.startCollectors();
            log(
                'progress so far is ' + (sjcl.random.getProgress() * 100) +
                '%, isReady says: ' + sjcl.random.isReady() +
                ', 8 randomwords are: ' + sjcl.random.randomWords(8)
            );
        }, 1000);

        log(
            'progress so far is ' + (sjcl.random.getProgress() * 100) +
            '%, isReady says: ' + sjcl.random.isReady() +
            ', 8 randomwords are: ' + sjcl.random.randomWords(8)
        );
    }
  </script>
</head>
<body></body>
</html>

Details on the tested browsers versions

The following screenshots were collected while running the above SJCL library test website to detect browsers that fall back on collecting entropy instead of the web crypto API for generating random numbers. In some cases we didn't have enough versions at our disposal to find the precise version and just documented the state of those available to us.

The test website had to be offered via HTTP, since most of the affected older browsers don't support modern TLS 1.3 and certificate authorities and so would fail to connect using HTTPS.

Firefox

Version 21 (left) was the first to support the web crypto API, while the much older version 3 did not (right):

SJCL test on Firefox version 21 SJCL test on Firefox version 3

Chrome

The oldest version at our disposal was Chrome version 15 which already did support the web crypto API. No screenshots were collected.

Safari

Version 5 (left) did support the web crypto API, while version 4 did not (right):

SJCL test on Safari version 5 SJCL test on Safari version 4

Internet Explorer

Version 11 did support the web crypto API, while versions 8 and 10 did not (below):

SJCL test on Internet Explorer version 10 SJCL test on Internet Explorer version 8

Opera

Version 20 did support the web crypto API, while version 15 did not (version 11.6 below):

SJCL test on Opera version 11.6

Edge

All Edge versions support the web crypto API. No screenshots were collected.

Android

The oldest version at our disposal was Android 4.4 which already did support the web crypto API.

SJCL test on Android version 4.4

iOS

Version 7 (left) did support the web crypto API, while version 4.3.2 did not (right):

SJCL test on iPhone 5S, iOS version 7 SJCL test on iPad 2, iOS version 4.3.2

Windows Phone

The only version at our disposal was Windows Phone version 8.1 which did support the web crypto API (below):

SJCL test on Windows Phone version 8.1

Sailfish OS

All Nightly browser versions support the web crypto API. No screenshots were collected.