Следующая новость
Предыдущая новость

Android: уязвимость StrandHogg и обход ограничений на доступ к камере и микрофону

24.12.2019 0:25
Android: уязвимость StrandHogg и обход ограничений на доступ к камере и микрофону

Содержание статьи

  • Почитать
  • StrandHogg — уязвимость с «подменой» приложений
  • Обход защиты на снятие скриншотов
  • Обход ограничения на доступ к камере, микрофону и местоположению в фоне
  • Разработчику
  • Хорошие и плохие приемы программирования на Kotlin
  • Typealias в Kotlin
  • Инлайновые классы в Kotlin
  • Корректное выделение текста на фоне
  • Статистика распределения версий Android
  • Инструменты
  • Библиотеки

Сегодня в выпуске: подробности уязвимости StrandHogg, которая позволяет подменить любое приложение в любой версии Android; обход защиты на доступ к камере, микрофону и местоположению; обход защиты на снятие скриншотов; хорошие и плохие приемы программирования на Kotlin; псевдонимы типов данных и инлайновые классы в Kotlin; а также статистика по версиям Android от PornHub и подборка библиотек для программистов.

Почитать

StrandHogg — уязвимость с «подменой» приложений

The StrandHogg vulnerability — подробности нашумевшей уязвимости всех версий Android (включая 10), позволяющей подменить экран (активность) одного приложения на экран другого.

Что произошло: специалисты норвежской компании Promon обнаружили в Android уязвимость, которая позволяет подменить экран (активность) легитимного приложения, подсунув вместо нее экран зловредного приложения. В результате у злоумышленников появляется возможность провести атаку с использованием фишинга или, например, запросить для зловредного приложения дополнительные полномочия якобы от лица другого приложения.

Что произошло на самом деле: в Android у активностей есть флаг taskAffinity. Он позволяет указать имя задачи (task), в стек активностей которой попадет указанное приложение. Это нужно для более тонкого управления стеками обратных переходов. Но есть одна проблема: по умолчанию значение taskAffinity равно имени пакета приложения, а это значит, что в ряде случаев можно незаметно всунуть активность своего приложения в стек активностей чужого. А если еще и указать флаг allowTaskReparenting="true", эту активность можно передвинуть на самый верх и при следующем клике по иконке целевого приложения она появится на экране первой (то есть будет находиться на вершине стека).

Страшно? Конечно, но, как и обычно, стоит копнуть глубже — и страх пройдет.

Во-первых, об этой «уязвимости» известно уже много лет. Предыдущая ее вариация называлась Android Task Hijacking, и мы писали о ней еще в 2017 году.

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

В-третьих, Google действительно отказывается исправлять уязвимость на протяжении нескольких лет. Просто потому, что это так называемый design flaw, то есть ошибка проектирования, исправление которой сломает существующий софт.

Наконец, в-четвертых, у проблемы уже давно есть решение. Достаточно указать taskAffinity="" в элементе Application, и все активности твоего приложения станут неуязвимы к атаке.

Мораль: не читайте советских газет, читайте доки по безопасности.

Обход защиты на снятие скриншотов

Android Frida hooking: disabling FLAG_SECURE — статья о том, как с помощью Frida отключить защиту на снятие скриншота приложения.

Кратко: Android позволяет разработчику приложения запретить снимать скриншоты определенных активностей приложения. Для этого необходимо установить флаг FLAG_SECURE для окна:

public class FlagSecureTestActivity extends Activity {     @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);         setContentView(R.layout.main);         ...     } } 

Обойти эту защиту можно несколькими способами. Например, использовать модуль Xposed DisableFlagSecure, который перехватывает функцию setFlags и просто отфильтровывает флаг FLAG_SECURE:

@Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {     XposedHelpers.findAndHookMethod(Window.class, "setFlags", int.class, int.class, mRemoveSecureFlagHook); }  private final XC_MethodHook mRemoveSecureFlagHook = new XC_MethodHook() {     @Override     protected void beforeHookedMethod(MethodHookParam param) throws Throwable {         Integer flags = (Integer) param.args[0];         flags &= ~WindowManager.LayoutParams.FLAG_SECURE;         param.args[0] = flags;     } }; 

Однако Xposed требует права root на устройстве (есть проект VirtualXposed, не требующий root, но многие модули в нем не работают). Frida, с другой стороны, может работать на любом устройстве без необходимости получать права root.

Вот как выглядит тот же код отключения в варианте для Frida:

Java.perform(function () {     var FLAG_SECURE = 0x2000;     var Window = Java.use("android.view.Window");     var setFlags = Window.setFlags;      setFlags.implementation = function (flags, mask) {        console.log("Disabling FLAG_SECURE...");        flags &= ~FLAG_SECURE;        setFlags.call(this, flags, mask);     }; }); 

Использовать так:

$ frida -U -l наш_скрипт.js -f имя.пакета.приложения --no-pause  

Обход ограничения на доступ к камере, микрофону и местоположению в фоне

Androids Invisible Foreground Services and How to (Ab)use Them — доклад с конференции Black Hat Europe 2019 с описанием очень простой техники обхода защиты на доступ к камере, микрофону и местоположению в Android 9 и 10.

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

Исключение дается только приложениям, имеющим активный foreground-сервис, который, в свою очередь, обязан вывести видимое пользователю уведомление и иконку в строке состояния.

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

Решение: начиная с пятой версии в Android есть механизм JobScheduler, который позволяет запускать код периодически или при наступлении определенных событий (например, подключение к зарядному устройству). Мы могли бы использовать его для периодического запуска наших шпионских функций, но задачи JobScheduler’а тоже выполняются в фоне.

Выход состоит в том, чтобы при наступлении события JobScheduler’а запустить сервис, затем сделать его foreground-сервисом с помощью startForeground, быстро получить доступ к камере, микрофону и местоположению и остановить сервис:

@Override public int onStartCommand(Intent intent, int flags, int startId){     Notification notification = createCustomNotification();     this.startForeground(1, notification)     accessMicrophone();     stopForeground(true);     return START_STICKY; } 

Трюк состоит в том, что, если сделать работу достаточно быстро (по утверждению автора доклада — за пять секунд), система просто не покажет уведомление.

Proof of concept есть на GitHub. Баг уже исправлен, теперь уведомление будет показано в любом случае.

Разработчику

Хорошие и плохие приемы программирования на Kotlin

Good And Bad Practices Of Coding In Kotlin — статья о практиках программирования на Kotlin, хороших и плохих.

Первый пример

fun main {     val file = File("/my_file")     val writer = file.printWriter()     try {         writer.println("Hello World")     } catch(__: Exception){         // Обработка исключения     } finally {        writer.close()     } } 

Это стандартный способ записи строки в файл: открываем файл и с помощью PrintWriter записываем строку. В завершение закрываем PrintWriter даже в том случае, если будет выброшено исключение.

Этот код можно переписать так:

fun main () {     val file = File("/my_file")     file.printWriter().use {         it.println("Hello World")     } } 

В случае с объектами, реализующими интерфейс Closeable (здесь PrintWriter), функция-расширение use автоматически вызывает метод close после выполнения кода лямбды.

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

1 год

4990 р.

1 месяц

720 р.

Я уже участник «Xakep.ru»

Источник

Последние новости