Нелегкий путь к динамическому анализу мобильных приложений
Привет, Хабр!
Каждую свою статью я начинаю с упоминания о том, что наша команда разрабатывает платформу анализа защищенности мобильных приложений. Почему? Размещая свои посты, информацию, которая мне кажется полезной, различные находки и трюки, мне хочется делиться с единомышленниками, помогать тем, кто идет по тому же пути, рассказывать об интересном. Я уверен, что не только у нас возникают трудности в процессе создания своих разработок, и здесь мы можем обменяться опытом. Сегодня мне хочется рассказать немного о том, с чем мы столкнулись в последние месяцы, работая над новым релизом нашего продукта. Возможно, это даст кому-то новый импульс, а может, кто-то даст нам совет со своей стороны. Мы открыты к общению!
Оглавление
Введение
Для начала, коротко о сути нашего решения. Платформа Стингрей — это динамический анализатор мобильных приложений. Основная его задача — смотреть на то, как приложение ведет себя на устройстве, к каким системным вызовам обращается, как общается с другими приложениями, что передает на сервер, как и что хранит локально и так далее. При этом, конечно, мы используем и статический анализ, и анализ ресурсов приложения, и многие другие техники. Все, что было описано в моих предыдущих статьях, основано на нашем опыте применения различных техник анализа приложений.
Мы стремимся к тому, чтобы нашим продуктом было легко и удобно пользоваться. Все, кто работает с разными сканерами, анализаторами и прочими инструментами по ИБ (даже не в контексте анализа мобильных приложений), знает, что с ними не так-то просто иметь дело! А нам хочется, чтобы в идеале даже люди, которые никогда не занимались анализом мобилок, могли загрузить приложение, потыкать мышкой в интерфейс и получить понятный отчет с реальными уязвимостями. Чтобы даже из коробки все работало максимально просто, быстро и качественно. Но при этом не забывать и о тех, кто хочет более тонко настроить инструмент и заточить его под себя и свои приложения. Но вот эта простота для пользователя, к которой мы стремимся, создает огромные сложности при разработке и проектировании системы. И наверняка кому-то из вас будет интересно «поднять капот» и посмотреть, как обстоит все внутри на самом деле.
Хотелось бы написать больше, но посмотрим, насколько такой формат повествования будет уместным. Если все будет хорошо, я обязательно напишу краткую историю трансформации нашего продукта и всех сложностей, с которыми мы столкнулись (, а их было достаточно). В начале нашего пути мой коллега, когда его просили описать, что из себя представляет наша система, отметил: «Можно сказать, мы собираем Python в Linux, развернутом внутри Android-эмулятора в Docker». Так было раньше и это было весело, но сейчас все намного интереснее.
Динамический анализ iOS
Довольно долгое время мы специализировались только на Android-приложениях. Это было логично и понятно, ведь Android-устройства более доступные, для них легче получить права суперпользователя, да и в целом система более открытая, есть эмуляторы и много других аспектов. Мы долго планировали добавить полноценную динамику iOS-приложений и несколько раз подступались к ней, но не хватало то времени, то компетенций. И вот, наконец, мы реализовали этот непростой сценарий, но по пути, конечно, набили немало шишек.
Во-первых, мы имеем дело с живыми устройствами со всеми вытекающими проблемами и особенностями. Кроме того, нужно учитывать, что iOS — это закрытая система, и, когда случаются проблемы, просто посмотреть реализацию в исходном коде и понять, в чем причина, не представляется возможным. То есть приходится либо искать какие-то материалы, либо реверсить самостоятельно необходимый функционал.
Во-вторых, необходимо содержать парк устройств для того, чтобы реализовать полноценный запуск и тестирование приложения. А значит, нужно организовать правильное место, где все эти девайсы будут жить, продумать их размещение, подачу питания, стабильный канал связи, охлаждение и кучу остальных мелочей, о которых мы даже не догадывались до недавнего времени. В результате, у нас появился отдельный стенд в серверной, где аккуратно разложены и подключены к бесперебойнику все наши устройства и сопутствующая инфраструктура. Охлаждает все это пара вентиляторов на распечатанных стойках, чтобы можно было максимально быстро и удобно их включать/выключать и изменять угол и направление обдува. После расширения мы планируем оборудовать специальный шкаф для всех устройств с огнестойкой защитой (на всякий случай).
Процесс подготовки устройств
В-третьих, ряд сложностей связан с подготовкой устройств. Нужно вручную разбираться с большим количеством девайсов, ставить на них все необходимые пакеты, проверять корректную работу, ничего при этом не потеряв. Конечно, делать все это руками — сумасшедший труд, а потому мы специально создали вспомогательный софт, который всем этим занимается.
В-четвертых, еще одна головная боль — обновления устройств. С каждым новым релизом мы что-то меняем в конфигурации. Чтобы не делать это руками, разработали механизм автоматического обновления конфигурации устройств и внедрили его напрямую в продукт. При выходе нового релиза система автоматически все обновляет.
В-пятых, обязательно нужно организовать мониторинг всей инфраструктуры. Нужно следить за состоянием устройств и автоматическим исправлением возникающих проблем и уведомлять администраторов, если что-то нельзя сделать удаленно (например телефон перестал заряжаться). Это позволяет всегда быть уверенными, что девайсы в любой момент времени могут принять в себя задачу на анализ приложения, и они всегда в актуальном и исправном состоянии. Также этот механизм запускается перед каждым сканированием, чтобы убедиться в актуальности конфигурации и сэкономить время пользователя. В случае возникновения проблем он сообщает, что сканирование провести на этом девайсе не получится.
Я не буду сейчас рассказывать про архитектуру решения, которое мы спроектировали и реализовали, (думаю, это тема для отдельной статьи), но отмечу, что нам тоже пришлось поломать голову, как обеспечить постоянную работоспособность, удобство конфигурирования и администрирования всего «зоопарка» и завязать мониторинг в единую систему. Скажу лишь только, что профили устройств в iOS и pfSense совместно с Radius очень нам в этом помогли.
Полноценный IAST для Android-приложений
Итак, более-менее понятно, что происходило с iOS, а как же Android? Его мы тоже не оставили в стороне. До сегодняшнего дня мы отлично умели находить любую чувствительную информацию, которую обрабатывает, хранит или передает приложение и имели в арсенале обнаружение нескольких более интересных уязвимостей, вроде потенциального выполнения кода в контексте приложения, но этого было мало.
Как вы уже знаете, мы «держим руку на пульсе» и всегда прорабатываем все отчеты, writeup«ы, открытые баги в багбаунти-системах и еще львиную долю материалов, многие из которых я публикую, и у нас накопилось достаточно много уязвимостей, поиск которых мы хотели автоматизировать. Все это — реальные баги, которые можно реализовать на нерутованных устройствах, просто поставив рядышком приложение, а иногда и просто кликнув по ссылке. Это самые сложные и самые «вкусные» уязвимости, поиск которых мы всегда хотели добавить. Мы наметили ближайший план по автоматизации и уже начали точечно их реализовывать.
Классическая схема IAST
Но после добавления нескольких таких типов стало понятно, что процесс — очень трудоемкий и требует больших «костылей», да и в целом не сильно удобно. В итоге, мы откатились на предыдущее состояние системы, потратив много времени практически впустую. Это подстегнуло нас к попытке найти решение, которое бы упростило дальнейшее добавление новых типов уязвимостей и позволило бы нам абстрагироваться от конкретных проблем безопасности и применить некоторый «общий» подход к их поиску. В течение месяца мы пересмотрели и перепробовали много различных вариантов, исписав всю стену офиса и, после стольких бессонных ночей, кучи кода и экспериментов, нам это удалось.
Во главу угла мы поставили пользователя и то, что он вводит в приложение, поскольку все это может привести к проблемам, если в итоге попадет в потенциально опасную функцию. Таким образом, мы поняли, — если сможем точно определить, что данные, которые пришли к нам извне, попадают в неизменном виде в потенциально опасные функции, у нас получится определять практически любые уязвимости. И это то, что нам нужно! Ведь у нас уже есть полный контроль над приложением, над всеми данными внутри и любыми вызовами любого API. Оставалось лишь реализовать все это так, чтобы можно было описывать уязвимости через сигнатуры.
И тут, применив немного магии и потратив еще тьму времени, мы получили систему, которая принимает на вход специально сформированные правила, определяющие, что и как необходимо перехватывать, каким образом помечать данные, какие функции нас интересуют и как это в дальнейшем складывать в модель вызовов внутри приложения. При наличии пути движения данных по приложению от точки входа до точки выхода мы получаем возможность выявления практически любой уязвимости. И при этом — минимально возможное количество ложных срабатываний, так как связь через данные либо есть, либо ее нет.
Раньше такого рода системы и методики анализа мне встречались только для Web-приложений. Получается, что для мобильных приложений появился первый полноценный IAST-движок. Благодаря простой системе конфигурирования, добавление новых типов уязвимостей практически не занимает времени. Основное, чему приходится уделять внимание, — анализ проблем, понимание их сути и движения данных внутри. После того, как это сделано, достаточно написать пару строчек кода, построить связи и — вуаля — новая уязвимость добавлена и может быть проверена на сотне приложений, которые мы периодически разбираем.
Обновленный дизайн
Почему-то именно с UI у нас очень интересные взаимоотношения. Если вспомнить начало нашей истории, то самый первый вариант — это просто html, который мы генерировали на стороне сервера и отдавали в браузер. Второй версией стала моя покупка темы для Angular и разработка нового интерфейса, который был отделен от сервера и представлял собой полноценный SPA. Что сказать, это была одна из самых бесполезных покупок в моей жизни. Я вооружился скачанным курсом по Angular, новой купленной темой, которая практически сразу ушла в корзину, запасом энергетика и написал свой первый SPA, который просуществовал достаточно долго, пока мы не нашли толкового и выделенного разработчика под эти задачи. Посмотрев на тот ужас, что творился в коде, было решено переписать все практически с нуля и реализовать интерфейс, используя современные технологии и правильные подходы. Это привело нас к проектированию каждой страницы (правда ввиду ограниченности ресурсов на тот момент — на листочке в клеточку, но это не важно) и к последовательной их реализации. Как итог — мы получили стабильно работающий, хороший интерфейс, который просуществовал достаточно долго.
Три версии одного экрана
На протяжении всей жизни этой версии мы собирали обратную связь от пользователей, подмечали различные неудобные моменты, и на основе всего этого сформировали неплохой список улучшений и пожеланий к новому интерфейсу. Изучив все фичи, которые нам хотелось бы реализовать, и взглянув на то, что есть у нас, мы решились на очередную авантюру — переписать и перерисовать «лицо» нашей системы практически полностью. По факту, единственное, что осталось неизменным, — это функционал по получению данных и работе с API. Все остальное (включая элементы интерфейса, даже кнопки, переключатели, шрифты, поля ввода, обработки файлов и картинок) переосмыслили, изменили и отрисовали вручную. Все переходы между экранами, весь «пользовательский путь» был переработан и переделан, наконец-то появилась полная адаптивность интерфейса под различные разрешения экрана. Все, чего не хватало прежде, появилось в новой версии. На самом деле, изменений столько, что в какой-то момент мы перестали их считать и записывать, а просто полностью ушли в работу.
В какой-то момент мне казалось, что наш фронтенд-разработчик меня ненавидит, но зато теперь использовать Стингрей не только удобно, но еще и визуально приятно и, в некоторых случаях, намного более очевидно и просто.
Интеграции
Наша команда прекрасно понимает, что без наличия интеграций со смежными системами, когда инструмент «стоит в стороне» от основной разработки, никакого полноценного процесса выстроить не получится.
Именно поэтому мы решили поразмыслить над добавлением новых способов получения приложений для анализа. Итогом стала возможность загружать и отправлять на анализ системы из Firebase, Google Play и App Store, но скольких седых волос нам это стоило.
При разработке этих интеграций было очень сложно сделать так, чтобы все не просто функционировало, а не сбоило, чтобы не возникало проблем. И ведь каждая система дистрибуции и магазин приложений реализует функционал загрузки по-своему, а кто-то специально его прячет или вообще не дает такой возможности.
Взять, к примеру, интеграцию с Firebase. Если зайти в Web-приложение, то там есть замечательная большая кнопка «Скачать дистрибутив». Но при этом никакого внешнего API для загрузки нет, не было и не планируется. Для того, чтобы все-таки реализовать возможность скачать приложение, пришлось изрядно потрудиться, изучить строение внутренних вызовов внутри Firebase, определить, как и на чем основывается аутентификация и авторизация в сервисах Google, понять, какие внутренние вызовы нужно совершить, с какими заголовками и много-много чего еще.
Казалось бы, разобрались с аутентификацией в Google, теперь можно и Play Store безболезненно подключить. Как бы не так! Судя по всему, разрабатывают их абсолютно разные команды с разными подходами и степенью продуманности интерфейсов. И все, что мы делали для Firebase, оказалось абсолютно неприменимо для интеграции с магазином приложений. Поэтому пришлось начинать все с чистого листа: изучать API, способы регистрации устройства и дальнейший процесс получения apk-файлов. В итоге, мы реализовали это функционал, но вот незадача — буквально на днях Google изменил процесс логина в магазин приложений, и теперь нам приходится снова искать варианты для обхода ограничений. Нужно снова смотреть трафик и понять, что же сделал Гугл.
С Apple AppStore, на удивление, возникло куда как меньше проблем, потому что нам удалось найти практически готовое решение, которые мы интегрировали в наш общий скрипт. Окрыленные успехом, мы замахнулись на святая святых, на загрузку файлов из системы дистрибуции TestFlight, на данный момент известную как Apple Connect. И тут нас ждал большой облом. Раньше, еще до переименования, в консоли TestFlight была замечательная кнопка по загрузке тестовых сборок, и можно было относительно легко ей воспользоваться, но сейчас, после того, как произошла реорганизация системы дистрибуции Apple, эту возможность убрали в принципе. Потратив несколько недель на поиск решения, оплатив разработческий аккаунт, пройдя через несколько кругов ада на подтверждение своих данных, зарегистрировавшись в нескольких программах, мы поняли, что варианта скачать приложение найти не можем. Заглянув в трафик приложения TestFlight, удалось поймать интересный запрос на загрузку ipa-файла, но при попытке установить загруженное приложение ничего не получалось. По итогу, мы пока не добавили эту интеграцию, но как только появится время, я думаю, мы попробуем вернуться к этому вопросу и все-таки попробовать заставить это работать.
По интеграциям планируется отдельная статья, в которой мы расскажем про целевой процесс анализа мобильных приложений в контексте разработки, и выпустим подготовленную версию нашего скрипта для загрузки приложений из различных источников. Он и сейчас доступен в репозитории на Github, но пока не доведен до идеального состояния. Но им можно пользоваться и надеюсь, он покажется вам полезным.
Заключение
В заключение хотелось бы сказать, что для нас этот год начался не совсем так, как мы планировали. Пришлось столкнуться с достаточным количеством проблем и сложностей, большую часть из которых нам удалось преодолеть и даже написать об этом. Но мы абсолютно точно не хотим и не будем останавливаться на достигнутом, мы собираемся и дальше ставить перед собой кажущиеся невозможными задачи и реализовывать их.
Такой формат статей немного выбивается из общего цикла, посвященного безопасности мобильных приложений, но, оглядываясь на то, через что мы прошли, я просто не мог об этом не написать и не поделиться своими мыслями.
И, конечно, эта статья никогда бы не появилась без потрясающей команды, которая реализовала все, о чем написано, и много больше. Поэтому хотелось бы поблагодарить всех, кто приложил руку к созданию нашего продукта. Ребята, спасибо вам огромное, вы самая лучшая команда!
Всем спасибо за время и внимание, и до новых встреч!