Получение криптографических ключей через iOS Runtime Hooking

Получение криптографических ключей через iOS Runtime Hooking

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

Автор: Рон Гутиеррез (Ron Gutierrez)

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

После анализа трафика приложения стало очевидно, что криптографические ключи не передаются со стороны сервера. После зачистки iOS Keychain и всего Application-контейнера, я сделал обоснованное предположение, что ключи или зашиты в само приложение или получаются на основе определенной информации из устройства.

Используя Hopper Disassembler (доступный в магазине приложений для Mac OS, Mac App Store), я выяснил, что для шифрования данных приложение использует библиотеку Common Crypto. Я проверил перекрестные ссылки на вызовы функции CCCryptorCreate для того, чтобы найти участки кода, ответственные за шифрование. На следующем скриншоте показывается методgetSymmetricKeyBytes, вызываемый перед функцией CCCryptorCreate. Я был почти уверен, что цель метода getSymmetricKeyBytes – возвратить симметричный ключ, используемый при шифровании.

Я решил создать патч на основе Mobile Substrate для того, чтобы перехватить функцию getSymmetricKeyBytes и прочитать возвращаемое значение. Я использовал утилиту class-dump-z, чтобы получить перечень всех доступных интерфейсов Objective-C. Отсюда проще получить более детальную информацию о методе: имя класса, тип возвращаемого значения и необходимые входные параметры. Ниже показан небольшой кусок кода, который я извлек из результатов работы class-dump-z.

@interface SecKeyWrapper : XXUnknownSuperclass {

NSData* publicTag;
NSData* privateTag;
NSData* symmetricTag;
unsigned typeOfSymmetricOpts;
SecKey* publicKeyRef;
SecKey* privateKeyRef;
NSData* symmetricKeyRef;
}
[..snip..]
-(id)getSymmetricKeyBytes;
(id)doCipher:(id)cipher key:(id)key context:(unsigned)context padding:(unsigned*)padding;
[..snip..]

Теперь мы по-быстрому можем сделать патч, используя Theos framework. Патч выглядит так:

%hook SecKeyWrapper
- (id)getSymmetricKeyBytes {
NSLog(@”HOOKED getSymmetricKey”);
id theKey = %orig;
NSLog(@”KEY: %@”, theKey);
return theKey;
}
%end

%ctor {
NSLog(@”SecKeyWrapper is created.”);
%init;
}

Вышеупомянутый код считывает возвращаемое значение первоначального метода и выводит его на экран. Также я удостоверился, что на другом устройстве используется тот же самый симметричный ключ. Следующий шаг: расшифровка файлов. Мы могли бы перехватить метод doCipher:key:context:padding и распечатать первый параметр для получения незашифрованных данных. Это сработало бы, однако код не был бы воспроизводимым, поскольку патч запускается только когда метод doCipher:key:context:padding выполняется в приложении. Поискав в гугле класс SecWrapper, я нашел пример кода от Apple:

http://developer.apple.com/library/ios/#samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_m.html

Используя эту обертку, стало возможно создать автономный скрипт для расшифровки данных приложения.

Во время исследования примера использования класса я обратил внимание на два момента. Разработчик приложения изменил реализацию метода getSymmetricKeyBytes, который стал возвращать статический ключ. Другое интересное открытие: использование плохих практик в методе doCipher:key:context:padding в примере от Apple. Следующий кусок кода показывает, что будет использоваться статическая переменная IV размером в 16 байт, состоящая из нулей.

Альтернативный метод решения той же самой задачи – использовать cycript, у которого есть Javascript-интерпретатор для перехвата произвольного выполняемого objective-c-кода. Также cycript позволяет подключаться к iOS-приложением во время их выполнения без создания патчей на Mobile Substrate. Следующий пример демонстрирует, как при помощи cycript можно получить симметричный криптографический ключ:

rgutie01s-iPad:~ root# cycript -p 290
cy# var sharedwrapper = [SecKeyWrapper sharedWrapper];

@”<SecKeyWrapper: 0x183080>”
cy# [sharedwrapper getSymmetricKeyBytes]
@”<[Symmetric Key Value Omitted>”

Краткие итоги:

  1. Анализ в режиме реального времени iOS-приложений можно использовать для взлома механизма шифрования, когда исходный текст недоступен и без погружения в ассемблерный код.
  2. Разработчики должны быть осторожны при использовании примеров, особенно примеров крипто-функций, поскольку сложно понять, как они работают (что показал пример от Apple). 

Цифровые следы - ваша слабость, и хакеры это знают.

Подпишитесь и узнайте, как их замести!