Всем привет! Меня зовут Дмитрий Терёшин, в СберМаркете я занимаюсь Application Security — безопасностью веб- и мобильных приложений. Во время аудитов мобильных приложений я часто натыкался на плавающие уязвимости: они появляются только в конечной сборке, которая отправляется в стор. Я разработал утилиту, которая автоматически их отлавливает. Она бесплатна и свободна для распространения. Вот ссылки на GitHub и DockerHub с кодом и готовым образом: Ссылка на GitHub, Ссылка на Docker Hub. Тем, кому интересно, как утилита работает, и кто хочет сделать аналогичную, я расскажу о самих уязвимостях и где их искать. Плавающие уязвимости — те, которых в коде приложения может не быть, но в итоговой сборке они иногда появляются. Я насчитал 5 типов: Некорректная сетевая конфигурация. Небезопасные URL. Скомпрометированные токены, ключи, пароли и креды. Небезопасные настройки WebView. Небезопасные настройки из public-компонентов. Мне хотелось автоматизировать отлов плавающих уязвимостей, но ни одно из Open source tools-решений мне не подошло: mobsfscan — статический анализатор для телефонов. Он проверяет исходники системным анализом. Итоговый дистрибутив он проверять не умеет. MobSF — фреймворк для проверки мобильных приложений. Он много чего умеет, но плохо встраивается в pipeline. Выдает много мусора, аналитической информации вроде «вот я нашел здесь кучу строк». И непонятно, что это всё значит. ApkUrlGrep — утилита, которая грепает в сборе только URL. Анализирует только Android-приложения, работать с iOS не умеет. apk_api_key_extractor — утилита, которая грепает API-ключи регулярными выражениями. Тоже работает только с Android-приложениями. Поэтому я создал свою утилиту — CheckKarlMarx. Это скрипт на Python, завернутый в Docker. Архив с итоговой сборкой приложения распаковывается, и в декомпилированных исходниках ищутся выражения, характерные для плавающих уязвимостей. В результате проверки получаем отчёт с уязвимостями. Для запуска достаточно спулить образ с 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. В нём прописывают конфигурации приложения и сети. Там тоже можно разрешить незашифрованный трафик на уровне всего приложения или для каких-то конкретных доменов. Через конфиг можно разрешить доверие к пользовательским сертификатам. Если пользователь нечаянно установит вредоносный сертификат с помощью фишинга, то злоумышленник сможет провести MITM-атаку. Но для этого надо включить доверие к пользовательским сертификатам в настройках Android. Android собирает все файлы манифестов из сторонних или из собственных core-библиотек и соединяет в один. Поэтому, если в сторонней библиотеке есть конфиг со включенным Network Security, он же появится в смёрженном файле. Поэтому настройка может попасть в релизную сборку, даже если её нет в исходниках. На iOS доверие к сертификатам и незашифрованный трафик включаюется настройкой NS App в файле info.plist. Её можно включить только для конкретных доменов. Например, для example.com — разрешить соединение по небезопасной версии TLS 1.1. С iOS-приложением был похожий случай: в исходниках всё было нормально, но Info.plist подменялся на CI. Из-за этого небезопасный мисконфиг вываливался в релизную сборку. Если пользователь будет ходить по незащищённым ссылкам, злоумышленник сможет перехватить трафик или же вытянуть данные для авторизации из самой ссылки. Уязвимость работает и в Android-, и в iOS-приложениях. Примеры: http://example.com/static/tariffs.pdf, http://example.com/static/image.png. Сама уязвимость достаточно минорная, но небольшой риск она всё же даёт. Например, можно подменить картинку, и пользователь получит информацию со сторонней рекламой или ссылками, на которые он перейдёт. Так возникнет простор для фишинга. В моей практике случилась такая история — по небезопасному протоколу HTTP приложение получало статику: картинки, PDF с соглашениями и с информацией о тарифах. Небезопасных URL не было в репозитории и в исходниках приложения, но они появились в релизной сборке. Оказалось, что конфиги со ссылками подтягивались из стороннего сервиса, который наполнялся не разработчиками, а аналитиками. Пример: https://example-qa.com. На тестовые стенды любят заливать продовые данные. И название у теста обычно как у прода, но с суффиксом qa, qa2, dev, stage, test, uat и так далее. Если злоумышленник найдёт тестовый урл в конечной сборке и сможет авторизоваться в базе, то получит данные аналогичные продовым. Лучше такого не допускать. Пример: 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} Мини-браузер WebView встраивается в приложения. Моя утилита проверяет мисконфиги WebView только для Android, потому что в iOS их не так много и сложнее сделать их небезопасными. Вот какие мисконфиги проверяются: EnableSafeBrowsing — настройка в AndroidManifest. Если выставить ей false, то пользователь не узнает о том, что перешёл по небезопасной ссылке. SetJavaScriptEnabled — включение JavaScript. С включенной настройкой злоумышленник может в скрипте использовать вредоносный код. SetAllowAccess — доступ к файлам в песочнице приложения. Если ему присвоить true или оставить по дефолту, доступ останется. В файлах песочницы могут быть данные авторизации, и злоумышленник сможет подключить сторонний сайт к приложению. ShouldOverrideURLLoading — в значении true позволяет пользователю переходить по всем ссылкам на странице, загруженной в WebView. Внутри WebView пользователь ходит по ссылкам и открывает другие страницы, например фишинговые. Это экспортированные activity, ресиверы, сервисы и провайдеры, которые обеспечивают межпроцессное взаимодействие приложений на устройстве. В моём инструменте я проверяю их только для Android. При сборке происходит мержинг манифестов, и компоненты могут подтягиваться из других библиотек. Экспортированные компоненты из других приложений, которые не защищены разрешениями, открыты для взаимодействия всему миру. Потенциально это несёт проблемы. Допустим, можно отправить в Broadcast Receiver неожиданные параметры из другого приложения и он упадет с ошибкой. Приложение аварийно прекратит работу. Получится локальный DOS: одно приложение будет держать в дауне другое. Пользователь не сможет воспользоваться приложением, когда оно в дауне. CheckKarlMarx можно использовать также в составе опенсорс-пайплайнов от компании Whitespots для автоматизации сканирования уязвимостей. Если у вас есть опыт автоматизации сканирования и встраивания его в pipeline, буду рад о нём узнать. Поделитесь им и своими проектами в комментариях. Мы завели соцсети с новостями и анонсами Tech-команды. Если хотите узнать, что под капотом высоконагруженного e-commerce, следите за нами там, где вам удобнее всего: Telegram, VK.  #1 на рынке e-grocery в России