Ядовитая экосистема - (не)Уникальный опыт

Ядовитая экосистема


Несколько лет назад был тренд на постройку экосистем мобильных приложений. Это же так круто, когда приложения одной компании могут общаться друг с другом используя какие-то системные механизмы и дарить радость пользователю. Потом правда маятник качнулся в другую сторону и все начали делать суперапы, но о проблемах связанных с ними мы поговорим в другой раз. Сегодня разберем один интересный баг, который хорошо показывает почему доверие внутри экосистемы должно базироваться на чем-то более надежном чем просто имя пакета.

/img/poisonous-ecosystem/logo.gif

Разведка

Для того чтобы задекларировать список приложений с которыми нужно взаимодействовать, разработчик должен добавить блок <queries> в манифест и описать там необходимый набор взаимодействий:

<queries>
    <package android:name="string" />
    <intent>
        ...
    </intent>
    <provider android:authorities="list" />
    ...
</queries>

Самым интересным здесь является ключ package, который раскрывает информацию о тех пакетах, с которыми будет работать приложение. Увидев такие строчки в манифесте, я сразу понял, что имею дело с одним из приложений некой экосистемы:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.well.known.app"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:compileSdkVersion="30">
    ...
    <queries>
        ...
        <package android:name="com.android.vending" />
        <package android:name="com.google.android.gms" />
        <package android:name="com.well.known.store" />
        <package android:name="com.well.known.settings" />
        <package android:name="com.well.known.services" />
        ...
    </queries>
</manifest>

Лишний раз заглянем в документацию, чтобы убедиться, что эта находка действительно полезна

<package> - Specifies a single app that your app intends to access. This other app might integrate with your app, or your app might use services that the other app provides.

Звучит неплохо!

Поиск по декомпилированному коду указанных выше пакетов, приводит к такой загадочной конструкции:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
HashMap<String, String> configuration = new HashMap<String, String>();
...
for (PackageInfo packageInfo : context.getApplicationContext().getPackageManager().getInstalledPackages(0)) {
    if (packageInfo.packageName.startsWith("com.well.known.settings") {
        loadSettings(context, packageInfo.packageName)
        ...
    }
    ...
}
...
private static void loadSettings(Context context, String str) {
    Resources resources = context.getApplicationContext()
        .getPackageManager()
        .getResourcesForApplication(str);
    
    String id = resources.getIdentifier("settings", "string", str);
    String settings = resources.getString();

    parseSettings(settings);
    ...
}

Фактически, здесь происходит загрузка каких-то настроек из стороннего приложения и дальше они как-то используются в исследуемом приложении. Делаю пометку об этом и иду искать вызовы HashMap-а, в который попадают эти настройки после парсинга. Довольно быстро нахожу такой код:

if (configuration.containsKey("debug")) {
    enableDebugMode(); // Все золото находится здесь, нужно только открыть ящик...
}

Здесь круг замыкается. Получается, что есть возможность управлять состоянием другого приложениея если каким-то образом получить контроль над приложением с пакетом com.well.known.settings. И тут начинается самое интересное. Объявление пакета в <queries>, просто включает возможность коммуникации между приложениями. Режим “видимости”, если быть более точным. Никаких дополнительных механизмов безопасности тут не задействуется. А значит реализация безопасной коммуникации полностью ложится на плечи приложения, которое декларирует внешний пакет у себя в манифесте. Ошибка разработчика приложения com.well.known.app состояла в том, что он не озаботился дополнительными проверками, а просто поверил случайному приложению в системе. А может это была исключительно отладочная возможность, которую забыли в релизной версии… Не важно! Давайте писать эксплойт 😎

Эксплуатация

Я создал приложение с пакетом com.well.known.settings (потому что, кто мне запретит?) и еще раз внимательно посмотрел на тип и содержимое ресурса, который нужно было создать:

String id = resources.getIdentifier("settings", "string", str);

Это строковый ресурс с именем settings куда нужно поместить значение debug:

<resources>
    <string name="app_name">Exploit</string>
    <string name="settings">debug</string>
</resources>

Сборка, установка, profit!
Целевое приложение прочитало настройку из моего эксплойта и радостно переключилось в отладочный режим, который, среди прочего, позволял читать конфиденциальную информацию из песочницы приложения.
А ведь в этой экосистеме есть и другие приложения…. Но это уже совсем другая история.

Что там в дикой природе?

Да-да, %username%, вижу как ты уже побежал шерстить bug bounty программы чтобы нахаляву купить себе ламборгини. Не торопись. Я уже просмотрел все bug bounty за тебя и хочу немного огорчить. В тех компаниях, которые действительно интересуются безопасностью, уже подумали об этой проблеме. Рассмотрим на примере приложения Dropbox Paper.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<queries>
    <intent>
        <action android:name="android.intent.action.VIEW"/>
        <data android:scheme="http"/>
    </intent>
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE"/>
    </intent>
    <package android:name="com.dropbox.android"/>
</queries>

Видим, что оно каким-то образом взаимодействует с основным приложением Dropbox: Cloud Photo Storage. Поиск по коду довольно быстро приводит нас сюда:

/img/poisonous-ecosystem/auth-intent.svg
Выглядит так, как будто мы можем прикинуться другим приложением и украсть данные для аутентификации. И это бы сработало, если бы не код метода DbxOfficialAppConnector.getDropboxAppPackage
/img/poisonous-ecosystem/signatures.svg
Который и ломает весь флоу атаки. Чтож, в этот раз придется обойтись без ламборгини. Но может на open redirect-ах удасться подняться…

Стоит сказать, что в некоторых приложениях, имеющих публичные bug bounty программы эта ошибка встречается. Но импакт ее довольно низкий - просто запуск приложения без каких-либо параметров. Конечно тут можно поиграть в фишинг, но это все уже не так красиво и дорого, как могло бы быть.

/img/poisonous-ecosystem/bb.webp

Ссылки


Смотрите также

comments powered by Disqus