Криптографические уязвимости в Skype для бизнеса

Криптографические уязвимости в Skype для бизнеса

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

Автор: John Dunlap

Недавно специалисты компании GDS обнаружили и раскрыли бреши в приложении Skype для бизнеса, связанные с неправильной обработкой криптографической информации. Некорректное использование строковых объектов стало причиной пониженной энтропии в паролях (ключах шифрования), используемых для шифрования конфиденциальной информации в базе данных. Эта уязвимость была обнаружена после декомпиляции необфусцированных Java-исходников, хранящихся внутри контейнера приложения. Данная брешь схожа с проблемой, которая описывалась в статье http://blog.gdssecurity.com/labs/2015/2/18/when-efbfbd-and-friends-come-knocking-observations-of-byte-a.html два года назад авторства Стивена Комала (Stephen Komal) из компании GDS.

База данных, хранящаяся в контейнере приложения под именем databases/EncryptedDataStore.sqlite на платформе Android, использовала ключ слабее оптимального, который обычно применяется для хранения конфиденциальной информации. Несмотря на то, что на практике в большинстве случаев длина ключа достаточная для защиты от компрометирования, сам ключ является искаженным с пониженной энтропией. Опасность этой уязвимости заключается в том, что злоумышленник может найти систему с ключом, который взломать намного проще, чем изначально предполагали авторы приложения. В самом худшем случае, злоумышленник может взломать ключ базы данных, а затем расшифровать и извлечь конфиденциальную информацию.

Во время настройки учетной записи персональная информация шифруется в базе данных sqlite на Android-устройстве при помощи случайного пароля, используемого при генерации ключа функцией PBKDF2 внутри класса SecureRandom. Далее ключ тут же конвертируется в Java-строку.

com/microsoft/office/lync/platform/database/util/SfbDataBaseProvider.java
53:     private String generateRandomPassword() {
54:         byte[] arrby = new byte[42];
55:         new SecureRandom().nextBytes(arrby);
56:         return new String(arrby);
57:     }

Ключ базы данных инициализируется следующим образом:

com/microsoft/office/lync/platform/database/util/SfbDataBaseProvider.java
59:     private String getDbKeys() {
60:         String string2;
61:         String string3 = string2 = CredentialsStoreManager.getInstance().getDatabasePassword();
62:         if (string2 != null) return string3;
63:         Trace.d(TAG, “getDbKeys, Database Encryption not stored, creating new password”);
64:         string3 = this.generateRandomPassword();
65:         try {
66:             CredentialsStoreManager.getInstance().setDatabasePassword(string3);
67:             return string3;
68:         }
69:         catch (CredentialStoreException var2_2) {
70:             Trace.e(TAG, “getDbKeys, storage failed!!!!!”);
71:             DatabaseAnalytics.reportKeyStorageError(var2_2);
72:             return string3;
73:         }
74:     }

Каждому пользователю выдается новый пароль для базы данных, используемый для дешифровки, который не так просто получить без прав суперпользователя на устройстве. Специалистам компании GDS удалось извлечь пароль, используемый при формировании ключа функцией PBKDF, посредством создания специальной «следящей» программы, которая выгружает пароль базы данных из памяти, используемой впоследствии для расшифровки базы данных. Эта задача легко решается, если есть права суперпользователя на устройстве. Функция, о которой идет речь, была обнаружена после декомпиляции необфусцированных файлов с Java-классами.

Отслеживаемая функция показана ниже:

com/microsoft/office/lync/platform/CredentialsStoreManager.java
312:  public String getDatabasePassword() {
313:         Account account = this.getLyncAccount();
314:         if (account != null) {
315:             return this.accountManager.getUserData(account, “persistanceKey”);
316:         }
317:         Trace.i(“CredentialsStoreManager”, “getDatabasePassword, returning null because no database password is currently stored”);
318:         return null;
319:     }
Пароль к базе данных был получен посредством подцепления к этой функции. Образец пароля, используемый при создании тестовой учетной записи, показан ниже.

Ключ:

EF BF BD 6C  EF BF BD EF  BF BD 1D EF  BF BD EF BF  BD 68 09 0D  EF BF BD 0A
EF BF BD EF  BF BD EF BF  BD D7 BB EF  BF BD EF BF  BD 57 30 6A  18 EF BF BD
2E 15 EF BF  BD 3F 09 65  38 EF BF BD  31 EF BF BD  EF BF BD EF  BF BD 04 EF
BF BD EF BF  BD EF BF BD  EF BF BD EF  BF BD

В примере выше большая часть пароля была заменена байтовой последовательностью в кодировке Unicode, используемой в качестве «заменяемого символа» (EF BF BD).

Причина этого явления кроется в использовании строкового Java-класса для хранения бинарных криптографических данных. Строковой класс не предназначен для хранения сырых байтов, и кодируется строки по разному в зависимости от настроек платформы. Байты, которые изначально сгенерированы функцией, при создании строки некорректно преобразовались в кодировку UTF-8, что стало причиной появления неправильных последовательностей символов. Проблема решается посредством отказа от использования строкового класса в пользу байтовых массивов.

Кроме того, следует отметить, что приложение постоянно использует Java-строки при обработке криптографической информации, тем самым создавая сложности при решение обнаруженной проблемы. Например, приложение использует класс для хранения пароля во время некоторых операций и хранит пароль в качестве строки:

com/microsoft/office/lync/platform/CredentialsStoreManager.java
668: public static class Password {
669:         private final String m_passwordEncrypted;
670:         private String m_passwordPlaintext = null;
671:
672:         private Password(String string2) {
673:             this.m_passwordEncrypted = string2;
674:         }
675:
676:         public static Password fromEncrypted(Context context, String string2) {
677:             return new Password(string2);
678:         }
679:
680:         public static Password fromPlainText(Context object, String string2) {
681:             if (TextUtils.isEmpty((CharSequence)string2)) {
682:                 object = “”;
683:                 return new Password((String)object);
684:             }
685:             object = CryptoUtils.encrypt(string2);
686:             return new Password((String)object);
687:         }

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

com/microsoft/office/lync/platform/CredentialsStoreManager.java
396:   String loadPrivateKey(Account object, ICredentialStore.Service service) throws SfbCryptoException {
397:         String string2;
398:         String string3 = string2 = null;
399:         if (object == null) return string3;
400:         object = this.accountManager.getUserData((Account)object, this.privateKeyAccountDataKey(service));
401:         string3 = string2;
402:         if (object == null) return string3;
403:         return CryptoUtils.decrypt((String)object);
404:     }

Проблема была решена посредством конвертирования байтов пароля в кодировку base64 перед возвратом функцией generateRandomPassword(). Таким образом, первоначальные байты полностью сохраняются и не изменяются из-за преобразований в новую кодировку. Тот же метод решения использовался в других места приложения, где были схожие проблемы.

com/microsoft/office/lync/platform/database/util/SfbDataBaseProvider.java
private String generateRandomPassword()
{
byte[] arrby = new byte[42];
new SecureRandom().nextBytes(arrby);
-  return new String(arrby);
+  return Base64.encodeToString(arrby,0);
}

Хронология событий

Специалисты компании GDS сообщили о проблеме в компанию Microsoft в ноябре 2016 года. Проблема в приложении Skype для бизнеса была устранена в декабре 2016 года в версии 16.11.0.0. 

Microsoft не присваивала этой проблеме код CVE и не раскрывала технические детали уязвимости. В январе 2017 года исследователь компании GDS Джон Данлоп (John Dunlap) был упомянут в разделе “Security Researcher Acknowledgements”, который можно найти по адресу https://technet.microsoft.com/en-us/security/cc308589.aspx.

Домашний Wi-Fi – ваша крепость или картонный домик?

Узнайте, как построить неприступную стену