- Отключение проверок состояния среды исполнения в Android-приложении
- Уязвимости Android 2020
- Архитектура ОС Android
- CVE-2020-0082
- CVE-2020-8913
- CVE-2020-8899
- CVE-2020-0022
- Выводы
- Уязвимости в андроид приложениях. Как их найти и предотвратить эксплуатацию?
- Для кого эта статья?
- Используемый софт:
- Как работают Android приложения?
- Структура приложения
- Как выглядит отреверсированный код?
- Чувствительные данные, хранящиеся открытым текстом
- Уязвимости бекенда
- Проблемы с криптографией
- Примитивные логические уязвимости
- Небезопасное хранение данных
- Использование Журналов сбоев для поиска утечек
Отключение проверок состояния среды исполнения в Android-приложении
В прошлой статье я делал обзор на OWASP Mobile TOP 10 и тогда у меня не было годного кейса для демонстрации необходимости защиты исходного кода. Интересный кейс для демонстрации появился только недавно и кому интересно посмотреть на наш опыт обхода проверок состояния среды, давайте под кат.
При проведении оценки работы одного из проектов, наша команда, сразу поняла, что кейс не будет лёгким. Разработчики хорошо подошли к вопросу защиты информации в программе и внедрили проверки состояния среды исполнения. Приложение не запускалось при любом из следующих условий:
- аппарат был рутованным;
- использовался эмулятор;
- наличие подключения через USB;
- использование режима разработчика.
Разработчики не обфуцировали исходный код и не была встроена проверка на модификацию кода, что позволило мне проанализировать способы, которыми выполнялись проверки и выполнить необходимые манипуляции с ними.
Итак, начнём. Согласно OWASP Mobile TOP 10, который мы используем в качестве базовой методологии тестирования в компании Hacken анализ исходного кода (Reverse Engineering) — эта уязвимость включает в себя анализ бинарных файлов для определения исходного кода, библиотек, алгоритмов и т.д. Программное обеспечение, такое как IDA Pro, Hopper, otool и другие инструменты реверс-инжиниринга могут дать представление о внутренней работе приложения. Это может быть использовано для поиска уязвимостей приложения, извлечения критичной информации, такой как бэкенд-сервера, ключей шифрования или интеллектуальной собственности.
Для проведения базового статического анализа я использовал такой интересный инструмент, как MobSF, который выполнил декомпиляцию и базовый статический анализ. После декомпиляции меня интересовал java- и smali-коды программы. Java-код нужен для анализа, а в smali-код будем вносить изменения. Более подробно, как smali и java соотносятся можно прочитать здесь.
Просмотрев список классов, я обнаружил файл, который отвечает за проверку рутованности телефона (см. Рис. 1) — rootingcheck/RootBeerNative.java.
Рис. 1. Список классов приложения
Проанализировав класс, стало понятно, что нужно дальше искать вызовы функций checkForRoot() и setLogDebugMessage() (см. Рис. 2).
Рис. 2. Исходный код класса проверки на рутованость
С помощью команды grep получим следующие результаты, которые нам показывают, в каких файлах есть вызов методов checkForRoot() и setLogDebugMessage().
Результаты выполнения поиска:
root@kali:
/Desktop# grep -nr ‘RootBeerNative’ ********_v_0.9.2/
/Desktop# grep -nr ‘setLogDebugMessages’ ********_v_0.9.2/
Но это были не все проверки. Проанализировав класс MainActivity.java, был найдены вызовы функций, куда передаются строки “su”, “test-keys” и “which”, c помощью которых проводится проверка (см. Рис. 3).
Рис.3. Проверки на рутованость
И снова командой grep ищем в smali-файлах проверки рутованости:
Результаты выполнения поиска:
root@kali:
/Desktop# grep -nr ‘su’ ********_v_0.9.2/
/Desktop# grep -nr ‘test-keys’ ********_v_0.9.2/
/Desktop# grep -nr ‘which’ ********_v_0.9.2/
В статье я покажу лишь одну из найденных модификаций проверок рутованности. После небольшой манипуляции, а именно смены 1 на 0 — проверки на рутованность убраны.
Рис. 4. Значение переменной равно единице, если телефон рутованый
Рис. 5. Теперь значение переменной равно нулю, если телефон рутованный
После этого — программу можно собрать, подписать своим релизным ключом и запустить на мобильном телефоне. Но если-бы не два НО! А именно:
- проверка подключения к USB;
- проверка включения Developer mode — подключение к USB и включенный Developer mode позволяют проводить динамический анализ.
Проверка Developer mode выключается тем же путём, что и проверка рутованости — сменой в проверках единицу на ноль
В классе MainActivity.java находим строку, которая отвечает за проверку Developer mode (см. Рис 6). После этого grep-ом ищем файлы в которых присутствует строка “development_settings_enabled” и модифицируем проверку — меняем 1 на 0 (см. Рис. 7 и 8).
Рис. 6. Проверка, включён ли Developer mode на телефоне
Результаты выполнения поиска:
grep -nr «development_settings_enabled» ********_v_0.9.2\
Рис. 7. Место где нужно провести модификацию
Рис. 8. Модификация
После всех манипуляций можно запускать программу в режиме Developer mode.
Дальше отключаем проверку подключения по USB. Эта проверка находится в классе MainActivity.java (см. Рис. 9). Без применения grep, находим строку в MainActivity.smali, находим строку, которая содержит строку с проверкой USB — android.hardware.usb.action.USB_STATE. После этого, в smali-коде модифицируем строку на любой другой permissions, который возвращает “false” (см. Рис. 10).
Рис. 9. Проверка на подключение USB в коде MainActivity.java
Рис. 10. Строка кодa, которую нужно удалить в MainActivity.smali
Теперь осталось сгенерировать свой релизный ключ и подписать им приложение. Это делается следующим образом:
- Нужно установить два приложения: Keytool и Jarsinger.
- Выполнить команду на собрание приложения:
- apktool b C:\Users\User\Desktop\********
- Далее:cd ********\dist\
- Далее: Keytool.exe -genkey -alias key.keystore -keyalg RSA -validity 20000 -keystore key.keystore
- Далее:Jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore key.keystore ********.apk key.keystore
- Далее:jarsigner -verify -verbose -certs ********.apk
Вот в принципе все манипуляции и закончены. Теперь устанавливаем приложение на телефон с помощью adb install или из директории смартфона и можно проводить динамическое тестирование на уязвимости.
После установки приложения запускаем его (см. Рис. 11 и Рис. 12).
Рис. 11. Включаем режим Developer mode и подключаем USB | Рис. 12. Запуск приложения |
На практическом примере я показал, как можно отключить некоторые проверки состояния среды исполнения. Дальше уже с помощью других тулзов провели анализ на уязвимость, но это другая история…
К чему может привести халатное отношение к защите кода:
- это обхождения тех или иных проверок, которые вложены в программу
- внедрение стороннего кода, после чего программа может быть опубликована и использоваться как вредоносная
Как можно защититься? Мы в ByteCode решили не изобретать велосипед и предложили клиенту обфусцировать исходный код и использовать функции которые проверяют модификацию исходного кода.
Можно использовать более продвинутый способ анализа — это smali debugging. Более подробнее можно почитать об этом в мануале.
Немного для справки, я сформулировал список строк который применяется для проверки на рутованость:
Источник
Уязвимости Android 2020
Привет, Хабр. Делимся с вами полезной статьей, автором которой является Александр Колесников.
Операционная система Android считается одной из самых защищенных операционных систем в наше время. Разработчики этой ОС на своем официальном сайте рассказывают, что в ОС сделано очень много работы для того чтобы создание традиционных эксплойтов было нерентабельно, сложно, невозможно. Возникает вопрос, а есть ли вообще уязвимости в ОС, которые могли бы привести к компрометации системы? Будут ли эти уязвимости отличаться от стандартных уязвимостей программного обеспечения? Можно ли найти эти уязвимости в CWE TOP 25? Или в Android уникальные уязвимости? Эта статья попытка собрать воедино несколько уязвимостей платформы Android в разных частях её архитектуры за 2020 год.
Архитектура ОС Android
Без описания хотя бы поверхностно работы этой ОС не обойтись, но постараемся сделать это максимально быстро. На картинке ниже представлена архитектура ОС Android.
Подробное её описание можно найти здесь. Нас же интересует всего 2 факта об архитектуре:
Каждый уровень архитектуры отделен друг от друга и выполняет функции на различных уровнях привилегий;
Все уровни Android впитали в себя самое лучшее, что было на момент создания ОС из других open source проектов с точки зрения безопасности.
Если объединить эти два факта, то получается, что для того чтобы атаковать эту операционную систему необходимо, чтобы у атакующего было в арсенале по 1 уязвимой функции на каждом из уровней ОС. Это достаточно серьезно усложняет процесс создания эксплойта для атаки на ОС. Однако, все равно ресечеры со всего мира находят способы как можно атаковать эту ОС и делают это достаточно успешно. Под эту деятельность даже есть отдельное мероприятие.
CVE-2020-0082
Уязвимость в операционной системе Android 10. Если обратиться к общей классификации уязвимостей CWE Top 25, то уязвимость можно отнести к классу CWE-502. Данный класс уязвимостей может возникать как в веб, так и в десктопных приложениях. Основной особенностью уязвимости считается тот факт, что при помощи нее можно абсолютно незаметно для ОС и пользователя внедрить свой код в уязвимое приложение. Возможно это за счет того, что объекты, которые подвергаются процедуре десериализации или сборке могут описывать функцию-сборщик, которая может выполнять производные функции. Уязвимость известна довольно давно и при неосторожном использовании функций десериализации может стать критической.
В ОС Android так и случилось. При успешном использовании уязвимости можно захватить контроль над привилегированным пользователем system_server.
Эксплуатация уязвимости возможна через создание объекта Parsel для » android.accounts.IAccountAuthenticatorResponse «.
CVE-2020-8913
Уязвимость в Android Play Сore библиотеке. Уязвимый receiver позволял перезаписывать файлы и запускать произвольный код в ОС. Запуск кода снова возможен за счет десериализации данных, которые передаются за счет объекта Parcel. Фрагмент эксплойта с использованием приложения Google Chrome:
CVE-2020-8899
Уязвимость в библиотеке для разбора картинок. Нельзя 100% утверждать, что это уязвимость Android, но все же эта версия ОC очень популярна. Используется на телефонах Samsung.
Как известно, различные вендоры мобильных устройств очень часто создают собственные модификации ОС Android и благополучно забывают о них.
Уязвимость в данном случае заключается в том, что происходит повреждение памяти процесса и приложение, которое использует уязвимую функцию для работы с изображениями. Падение эксплуатабельно и можно выполнять любые операции от имени привилегированного пользователя ОС. Уязвимость относится к классу CWE-787.
CVE-2020-0022
Уязвимость в BlueTooth стеке ОС Android 8 и 9. Уязвимость позволяет обрушить ОС. Класс уязвимости CWE-787.
Некорректная обработка длины пакета. Для триггера уязвимости достаточно отправить фрагментированные широковещательные запросы длиной 300 и 33 байт.
Выводы
Похоже, что даже разделение привилегий, использование самых передовых технологий не спасает от самых распространенных ошибок программного обеспечения. ОС можно атаковать и классическими эксплойтами на повреждение памяти и более современными аналогами, которые используют механизмы ОС.
Совсем скоро у нас стартуют курсы по Android-разработке двух уровней. Узнать подробнее о курсах можно по ссылкам ниже.
Источник
Уязвимости в андроид приложениях. Как их найти и предотвратить эксплуатацию?
Дисклеймер: Не стоит переживать, если вы не знакомы с разработкой под Android и языком программирования Java. В этой статье я постараюсь обрисовать все максимально ясно и для новичков (с минимальными знаниями программирования). Так же все практические примеры утрированы для общего понимания уязвимостей.
Для кого эта статья?
- Для новичков в разработке под Android.
- Для новичков в ремесле пентестинга Android приложений.
- Для владельцев Android приложений.
Думаю, не нужно объяснять, какое множество Android приложений существует на данный момент. Большинство крупных компаний помимо веб ресурсов имеют свои Андроид приложения, которые могут стать источником угрозы, если руки злого хакера смогут это приложение взломать. О том, как взламываются и защищаются андроид приложения, мы сейчас и поговорим.
Используемый софт:
Но для дальнейшего понимания уязвимостей мы должны разобраться, как эти приложения функционируют.
Как работают Android приложения?
Код приложения хранится в файле APK, в котором есть файл .dex с двоичным байт-кодом Dalvik. Dalvik — это формат данных, понятный для ОС Android, но нечитаемый для человека. Поэтому для работы с файлами .dex необходимо преобразовать их в читаемый для человека формат, т.е в smali код. Если вы мало что поняли, то не волнуйтесь, по ходу статьи все встанет на свои места.
Структура приложения
Больше всего нас интересуют следующие файлы:
- AndroidManifest.xml
В этом файле хранятся необходимые разрешения для андроид приложения. Наверняка при первом запуске приложений вы сталкивались с тем, что приложение запрашивает доступ к геолокации, памяти, чтению смс и тому подобное. Все эти разрешения описаны в файле манифеста.
Код для основного(главного) экрана вашего андроид приложения. Для тех, кто не особо знаком с работой андроид приложений, поясню — любое андроид приложение представляет интерфейс для взаимодействия в виде так называемых activity. Activity — это не что иное, как экран вашего приложения (экран настроек, экран регистрации, экран открытия чата и т.д).
Каждому активити соответствует свой личный Java(Kotlin) класс, который «программирует» поведение экрана. (именно поэтому выше мы можем увидеть activity_main.xml, которому и соответствует наш MainActivity)
В этом файле хранятся, неожиданно, строки. Но возникает резонный вопрос, а зачем это вообще нужно?
Ответ прост, допустим у нас есть приложение, которое выполняет функцию энциклопедии, где в коде прописаны все описания для всех разделов энциклопедии, но согласитесь, хранить строки огромных размеров в коде приложения не совсем хорошо, ибо это банально плохо читается, поэтому файл strings и используется для хранения строк, т.к это банально удобно.
Как выглядит отреверсированный код?
Напишем самое простое приложение, которое складывает два числа и выводит результат на экран:
А теперь посмотрим на это приложение с точки зрения хакера, используя java-bytecode-viewer:
Как вы можете заметить, наш процесс реверсинга завершился успешно, и мы видим практически изначальный исходный код.
Чувствительные данные, хранящиеся открытым текстом
Давай зададим себе вопрос: за чем в первую очередь охотится хакер? Верно, пароли, API ключи и прочая чувствительная информация.
Зачастую разработчики банально забывают обфусцировать (запутать) чувствительные данные в коде.
Так же могут возникнуть проблемы, если приложение сообщается с внутренним апи сервиса, например, у нас есть крупное приложение, которое стало прототипом крупного сайта, взаимодействие с бэкэндом которого может происходить с помощью апи ключей или специально сформированных запросов, которые могут храниться в коде открытым текстом.
Мы уже видели, что хакер может получить строки с открытым текстом, при вскрытии приложения.
Рассмотрим пример участка кода приложения «Погода».
Как вы могли увидеть, в коде открытым текстом хранится апи ключ.
Давайте попробуем его вытащить при помощи bytecode-viewer.
Как вы можете наблюдать, в реверсированном коде мы четко видим API ключ, который хранится открытым текстом, и достать его совершенно не составило никакого труда.
Стоит понимать, что вместо API ключа там может быть криво составленный запрос на бекенд, об уязвимостях которого мы поговорим ниже.
Рекомендации по безопасности:
- Обфусцируйте (запутывайте) строки.
- Не задавайте строки с чувствительными данными явно в коде.
Уязвимости бекенда
Эта уязвимость вытекает из уязвимости выше.
Если хакер каким-то образом смог перехватить трафик между приложением и сервером или же прочитать запросы к внутренней инфраструктуре в строках кода, то он может начать атаковать веб сервер, что может привести к катастрофическим последствиям.
Поэтому, разрабатывая андроид приложения, не забывайте про защиту бэкенда, на который стучит ваше приложение.
Рекомендации по безопасности:
- Регулярно доставляйте обновления ПО на сервера, к которым обращается ваше приложение.
- Регулярно проводите аудиты внутренней инфраструктуры, с которой общается приложение.
Проблемы с криптографией
Если же вы решили шифровать ключи и пароли, которые могут храниться на устройстве, стоит выбирать стойкое шифрование данных.
Например, у нас есть внутренняя база данных, важные файлы для работы приложения, логи и т.д. По велению программиста все это может храниться на устройстве юзера. Допустим, хакер знает, какие интересные файлы могут быть на устройстве у цели, значит, он напишет вредонос, который захочет украсть эти самые файлы.
И тут возникает проблема с шифрованием этих файлов, ведь если эти файлы плохо зашифрованы, то хакеру не составит труда эти файлы привести в начальный вид и начать атаку на пользователя.
Рассмотрим пример с реализацией слабого решения
- Считываем ввод пароля.
- Кодируем его в Base64. (который декодируется за секунды)
- Записываем в файл на устройстве.
Код:
Вот так выглядит интерфейс:
Теперь давайте посмотрим в файлы приложения:
Если декодировать значение файла, мы получим строку «password», которая и была введена в приложении.
Так что же будет самым хорошим решением данной проблемы?
Банально, использование криптостойких алгоритмов шифрования. Например, тот же RSA. Не стоит использовать: RC4, MD4, MD5, SHA1. Если хэши используются для хранения паролей, следует использовать хэши, устойчивые к брутфорсу, с солью.
Так же желательно обфусцировать весь код, дабы усложнить жизнь хакеру, но стоит помнить про APKiD, который может детектировать обфускаторы, алгоритмы которых может узнать хакер, чтобы получить более читаемый код вашего приложения.
Рекомендации по безопасности:
- Используйте криптостойкие алгоритмы.
- Если вы используете свой алгоритм обфускации или шифрования данных, то сделайте его логически сложным, что хакер не мог его распутать по реверснутому коду.
- Избегайте хранения ключей шифрования в коде.
Примитивные логические уязвимости
Давайте рассмотрим логические уязвимости на примере приложения, которое просит купить премиум функции.
Вот как оно выглядит:
На самом деле в этом приложении два экрана, тот, который мы видим без купленного премиума, и второй экран, который скрыт от нас:
Теперь давайте взглянем под капот программы, чтобы понять логику получения премиума:
У нас есть три класса. (MainActivity, PremiumActivity, CheckPremium)
CheckPremium класс реализует следующую логику:
Как вы могли заметить, метод checkPremiumInDatabase всегда возвращает ноль, что в булевой логике соответствует значению «ложь».
Естественно, в реальном приложении в этом методе был бы реализован примерно такой алгоритм:
- Найти залогиненного пользователя в базе данных.
- Найти столбец в базе данных, отвечающий за наличие премиума, приобретенного, например, через официальный сайт.
- Отдать в значение возврата 1 или 0. (Премиум куплен/Не куплен)
После записи нуля в значение метода идет проверка в MainActivity:
В этом участке кода идет проверка значения метода checkPremiumInDatabase, если он равен 1, то вызывается второе активити, если нет, то ничего не происходит.
А теперь давайте и сделаем то, что описано в этой главе, переделаем приложение так, чтобы оно при запуске всегда открывало нам активити со вторым экраном:
- Впишем в консоль команду
Данная команда позволит декомпилировать наше приложение в вид smali кода, который мы сможем поменять через обычный текстовый редактор, чтобы изменить логику приложения (в bytecode-viewer нельзя изменить smali, поэтому будем это делать при помощи apktool).
- Изменим значение возврата функции checkPremiumInDatabase
Сменим с нуля на единицу. (что в булевой алгебре означает «истина», ведь нужно вернуть именно единицу, дабы пройти проверку на премиум)
Но давайте для ясности поймем, что именно и где нужно менять в smali? (ведь он в разы менее читабелен, чем декомпилированный код)
В рамках данного примера мы вновь должны вернуться в декомпилированный код данной функции:
Мы видим по этому скриншоту, что логика проверки премиума располагается с 4 по 7 строку кода.
А теперь вновь посмотрите на участок кода smali, где мы поменяли значение с нуля на единицу. Вверху мы видим вполне понятную надпись «.line7», которую в более крупном проекте мы бы могли использовать как зацепку для обнаружения слабого места программы.
Итак, мы поменяли значение возврата с «0» на «1», сохранили. Теперь нужно его пересобрать:
Осталось только запустить, но. Приложение не запустится.
- Подпись приложения
Любое приложение перед запуском должно быть подписано, но когда приложение меняется, меняется и подпись, а вот уже на такое наша система Android не готова, приложение должно быть подписано заново.
Для начала создадим ключ для подписи:
Теперь подпишем наше приложение этим ключом
- Запуск измененного приложения
Итак, второй экран запущен и примитивная логика проверки премиума не отработала должным образом.
Рекомендации по безопасности
- Если ваше приложение имеет премиум функции или другой платный контент, сделайте сложную логическую проверку, которую будет невозможно угадать. (либо реализуйте отстук у приложения на сервер, где хранится информация о покупке премиума, не записывая значения о покупке в сам код)
Небезопасное хранение данных
Излишние разрешения приложения, описанные в манифесте могут привести к краже и манипуляциям с данными, если на целевое устройство попадет вредоносное приложение.
Настройка манифеста, где присутствует MODE_WORLD_READABLE и MODE_WORLD_WRITEABLE может привести к краже конфиденциальных данных с устройства. Но почему так?
MODE_WORLD_READABLE и MODE_WORLD_WRITEABLE — это настройки в файле манифеста, которые позволяют другим приложениям читать файлы вашего приложения. Да, во многих ситуациях это может быть полезным и даже необходимым, но тут возникает другая проблема — вредоносы.
Если вредонос заточен на кражу данных приложений с устройства, то с этими настройками вирус спокойно украдет данные.
Android предоставляет возможность каждому приложению сохранять XML файлы по пути:
Иногда в этой папке хранятся конфиденциальные данные открытым текстом.
Также ОС Android позволяет каждому приложению сохранять базы данных sqlite по пути:
Эту папку необходимо проверить на наличие файлов, хранящихся открытым текстом.
Также стоит упомянуть, что пароль от базы данных sqlite, хранящейся на устройстве, может располагаться в коде приложения, поэтому стоит проверить следующий путь в памяти устройства:
Даже если БД зашифрована, утечка пароля через код также является уязвимостью.
Конечно, стоит проверить файл strings.xml, где разработчики случайно могут оставить чувствительные данные в виде паролей, ключей и т.д.
Рекомендации по безопасности:
- Избегайте лишних разрешений в файле манифеста.
- Никогда не храните чувствительные данные в файле strings.xml.
- Не храните пароль от БД в виде открытого текста в коде приложения.
- Шифруйте файлы баз данных.
Использование Журналов сбоев для поиска утечек
Некоторые приложение реализуют функцию отправки журналов сбоев на удаленные сервера, чтобы сотрудники компании и разработчики могли закрыть какую-то проблему. Эти журналы должны передаваться по SSl соединению, чтобы вредоносное приложение не смогло прочитать эти журналы, в которых может быть конфиденциальная информация. Если журналы постоянно хранятся на устройстве, то в процессе разработки вам обязательно нужно следить за тем, чтобы в этих журналах не оказалось лишнего, в виде паролей или ключей.
Рекомендации по безопасности:
- Обязательно используйте SSL для передачи любых данных.
- Следите за тем, что записывается в журналы сбоев.
Общие рекомендации, не вошедшие в пункты статьи:
- Реализуйте проверку на эмулятор, в котором, скорее всего, и будет запущено ваше приложение. (особенно касается банковских приложений)
- Если в приложении есть ввод чувствительных данных (снова возьмем в пример банковские приложения), то создайте собственную клавиатуру для ввода данных. Это поможет защититься от атак с подменой клавиатуры.
- В файле манифеста з апретите создание резервной копии данных при подключении мобильного устройства к компьютеру, прописав android:allowBackup в значение false.
- Используйте черное фоновое изображение, которое будет перекрывать экран приложения во время навигации по недавно запущенным приложениям, если в вашем приложении есть чувствительная информация, т.к вредонос может незаметно сделать скриншот.
- Реализуйте ограничения на посылку запросов для входа в аккаунт через приложение.
- Обфусцируйте названия классов и методов приложения после сборки приложения дабы запутать хакера при проведении реверс инжиниринга. (для этого можно использовать программу ProGuard)
Источник