Всем привет! Меня зовут Дмитрий Терёшин, в СберМаркете я занимаюсь Application Security — безопасностью веб- и мобильных приложений.

Во время аудитов мобильных приложений я часто натыкался на плавающие уязвимости: они появляются только в конечной сборке, которая отправляется в стор. Я разработал утилиту, которая автоматически их отлавливает. Она бесплатна и свободна для распространения. Вот ссылки на GitHub и DockerHub с кодом и готовым образом:

Тем, кому интересно, как утилита работает, и кто хочет сделать аналогичную, я расскажу о самих уязвимостях и где их искать.

Что такое плавающие уязвимости и зачем нужна утилита для поиска

Плавающие уязвимости — те, которых в коде приложения может не быть, но в итоговой сборке они иногда появляются. Я насчитал 5 типов:

  1. Некорректная сетевая конфигурация.

  2. Небезопасные URL.

  3. Скомпрометированные токены, ключи, пароли и креды.

  4. Небезопасные настройки WebView.

  5. Небезопасные настройки из public-компонентов.

Мне хотелось автоматизировать отлов плавающих уязвимостей, но ни одно из Open source tools-решений мне не подошло:

  • mobsfscan — статический анализатор для телефонов. Он проверяет исходники системным анализом. Итоговый дистрибутив он проверять не умеет.

  • MobSF — фреймворк для проверки мобильных приложений. Он много чего умеет, но плохо встраивается в pipeline. Выдает много мусора, аналитической информации вроде «вот я нашел здесь кучу строк». И непонятно, что это всё значит.

  • ApkUrlGrep — утилита, которая грепает в сборе только URL. Анализирует только Android-приложения, работать с iOS не умеет.

  • apk_api_key_extractor — утилита, которая грепает API-ключи регулярными выражениями. Тоже работает только с Android-приложениями.

Поэтому я создал свою утилиту — CheckKarlMarx. Это скрипт на Python, завернутый в Docker. Архив с итоговой сборкой приложения распаковывается, и в декомпилированных исходниках ищутся выражения, характерные для плавающих уязвимостей. В результате проверки получаем отчёт с уязвимостями.

Как работает утилита CheckKarlMarx

Для запуска достаточно спулить образ с DockerHub и примонтировать папку со сборкой. Утилита отдаёт отчёт в HTML или в sarif-формате.

Формат sarif — унифицированный формат для статических анализаторов. Sarif-отчёт можно отправлять в vulnerability-management-систему, например в DefectDojo.

Когда мы встраивали утилиту в pipeline, у нас использовался TeamCity для CI. Отчёт HTML мы вставляли в отдельную вкладку с отчётами от других линтеров прямо в TeamCity.

В рамке отчёта основная информация о сборке. Для Android проверяются сетевые мисконфиги, URL, ключи, токены, компоненты и WebView. По каждому из разделов указаны уязвимости и детали по ним. Для iOS-проверок меньше: network, URL и ключи.

Можно выводить результат в файл или консоль и кастомизировать отчёт. Есть коды выхода: когда не нашлось ни одной уязвимости, возвращается 0, когда есть уязвимость — 1.

В текущей конфигурации exit code = 1, только когда нашлись уязвимости уровня major и normal. Например, если ключ утёк в сборку или сетевая конфигурация некорректна.

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

Уязвимость: некорректная сетевая конфигурация

Это неправильные настройки сети, которые открывают некоторые возможные вектора атак. Выставить неправильные настройки можно и в Android, и в iOS. Расскажу о некоторых из множества способов.

В Android-приложениях есть файл AndroidManifest.xml. Он описывает главные свойства, компоненты приложения и различные опции.

В теге application этого файла можно подключить опцию usesCleartextTraffic = ”true”. Она разрешает незашифрованный HTTP-трафик на уровне всего приложения. Такой трафик небезопасен.

Можно подключить Network Security Config — xml-файл, который лежит по пути res/values/network_security_config.xml. В нём прописывают конфигурации приложения и сети. Там тоже можно разрешить незашифрованный трафик на уровне всего приложения или для каких-то конкретных доменов.

Свойство Network Security Config, в котором можно сделать сетевую конфигурацию небезопасной
Свойство Network Security Config, в котором можно сделать сетевую конфигурацию небезопасной

Через конфиг можно разрешить доверие к пользовательским сертификатам. Если пользователь нечаянно установит вредоносный сертификат с помощью фишинга, то злоумышленник сможет провести MITM-атаку. Но для этого надо включить доверие к пользовательским сертификатам в настройках Android.

Алгоритм сборки манифестов и ресурсов в единый файл
Алгоритм сборки манифестов и ресурсов в единый файл

Android собирает все файлы манифестов из сторонних или из собственных core-библиотек и соединяет в один. Поэтому, если в сторонней библиотеке есть конфиг со включенным Network Security, он же появится в смёрженном файле. Поэтому настройка может попасть в релизную сборку, даже если её нет в исходниках.

На iOS доверие к сертификатам и незашифрованный трафик включаюется настройкой NS App в файле info.plist. Её можно включить только для конкретных доменов. Например, для example.com — разрешить соединение по небезопасной версии TLS 1.1.

Файл свойств, компонентов и опций приложения на iOS
Файл свойств, компонентов и опций приложения на iOS

С iOS-приложением был похожий случай: в исходниках всё было нормально, но Info.plist подменялся на CI. Из-за этого небезопасный мисконфиг вываливался в релизную сборку.

Уязвимость: небезопасные URL

Если пользователь будет ходить по незащищённым ссылкам, злоумышленник сможет перехватить трафик или же вытянуть данные для авторизации из самой ссылки. Уязвимость работает и в Android-, и в iOS-приложениях.

URL по небезопасному протоколу

Примеры:

Сама уязвимость достаточно минорная, но небольшой риск она всё же даёт. Например, можно подменить картинку, и пользователь получит информацию со сторонней рекламой или ссылками, на которые он перейдёт. Так возникнет простор для фишинга.

В моей практике случилась такая история — по небезопасному протоколу HTTP приложение получало статику: картинки, PDF с соглашениями и с информацией о тарифах.

Небезопасных URL не было в репозитории и в исходниках приложения, но они появились в релизной сборке. Оказалось, что конфиги со ссылками подтягивались из стороннего сервиса, который наполнялся не разработчиками, а аналитиками.

Тестовые URL

Пример: https://example-qa.com.

На тестовые стенды любят заливать продовые данные. И название у теста обычно как у прода, но с суффиксом qa, qa2, dev, stage, test, uat и так далее. Если злоумышленник найдёт тестовый урл в конечной сборке и сможет авторизоваться в базе, то получит данные аналогичные продовым. Лучше такого не допускать.

URL с Basic-кредами

Пример: https://username:password@example.com.

Если URL имеет формат «юзернейм: пароль @ хост», значит, на хосте есть Basic-авторизация. Когда креды передают в URL и он попадает в сборку, креды компрометируются. Любой желающий получит доступ к хосту сайта, авторизовавшись через Basic-креды, например, под админским пользователем.

Уязвимость: скомпрометированные токены, ключи, пароли и креды

Утекают и в Andriod, и в iOS. Оставлять их в коде категорически нельзя. Иначе кто захочет — возьмёт ключ и украдёт три магнитофона, три кинокамеры заграничных данные или получит доступ к функционалу приложения.

Basic Auth и Bearer-токены

Basic — YmlsbHk6c2VjcmV0cGFzc3dvcmQ=

Bearer — <token>

API-ключи для доступа к тестовым стендам

Auth-Token: YWQG5pyYPq…

Закрытые ключи

-----BEGIN PRIVATE

KEY-----\nprivate-key\n-----END PRIVATE

KEY-----\n"

Legacy FCM Server Key

AAAA[A-Za-z0-9_-]{7}:[A-Za-z0-9_-]{140}

Google API-ключ

AIzaSy[0-9A-Za-z_-]{33}

В дизассемблированном Android-приложении утёк хедер
В дизассемблированном Android-приложении утёк хедер
Конфиг с API-ключом в iOS-приложении
Конфиг с API-ключом в iOS-приложении

Уязвимость: небезопасные настройки WebView

Мини-браузер WebView встраивается в приложения. Моя утилита проверяет мисконфиги WebView только для Android, потому что в iOS их не так много и сложнее сделать их небезопасными. Вот какие мисконфиги проверяются:

  • EnableSafeBrowsing — настройка в AndroidManifest. Если выставить ей false, то пользователь не узнает о том, что перешёл по небезопасной ссылке.

  • SetJavaScriptEnabled — включение JavaScript. С включенной настройкой злоумышленник может в скрипте использовать вредоносный код.

  • SetAllowAccess — доступ к файлам в песочнице приложения. Если ему присвоить true или оставить по дефолту, доступ останется. В файлах песочницы могут быть данные авторизации, и злоумышленник сможет подключить сторонний сайт к приложению.

  • ShouldOverrideURLLoading — в значении true позволяет пользователю переходить по всем ссылкам на странице, загруженной в WebView. Внутри WebView пользователь ходит по ссылкам и открывает другие страницы, например фишинговые.

Уязвимость: небезопасные настройки из public-компонентов

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

Пример небезопасной настройки public-компонента
Пример небезопасной настройки public-компонента

Экспортированные компоненты из других приложений, которые не защищены разрешениями, открыты для взаимодействия всему миру. Потенциально это несёт проблемы. Допустим, можно отправить в Broadcast Receiver неожиданные параметры из другого приложения и он упадет с ошибкой. Приложение аварийно прекратит работу.

Получится локальный DOS: одно приложение будет держать в дауне другое. Пользователь не сможет воспользоваться приложением, когда оно в дауне.

Итог

CheckKarlMarx можно использовать также в составе опенсорс-пайплайнов от компании Whitespots для автоматизации сканирования уязвимостей.

Если у вас есть опыт автоматизации сканирования и встраивания его в pipeline, буду рад о нём узнать. Поделитесь им и своими проектами в комментариях.

Комментарии (0)