Інформаційна безпека

Відключення перевірок стану середовища виконання в 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/

********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:1:.class public Lrootingcheck/RootBeerNative;
********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:17: sput-boolean v0, Lrootingcheck/RootBeerNative;->?:Z
********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:28: sput-boolean v0, Lrootingcheck/RootBeerNative;->?:Z
********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:57: sget-boolean v0, Lrootingcheck/RootBeerNative;->?:Z

********_v_0.9.2/smali/o/CM.smali:591: new-instance v1, Lrootingcheck/RootBeerNative;
********_v_0.9.2/smali/o/CM.smali:593: invoke-direct {v1}, Lrootingcheck/RootBeerNative;-><init>()V

********_v_0.9.2/smali/o/CM.smali:685: new-instance v0, Lrootingcheck/RootBeerNative;
********_v_0.9.2/smali/o/CM.smali:687: invoke-direct {v0}, Lrootingcheck/RootBeerNative;-><init>()V
********_v_0.9.2/smali/o/CM.smali:689: invoke-static {}, Lrootingcheck/RootBeerNative;->?()Z
********_v_0.9.2/smali/o/CM.smali:753: new-instance v4, Lrootingcheck/RootBeerNative;
********_v_0.9.2/smali/o/CM.smali:755: invoke-direct {v4}, Lrootingcheck/RootBeerNative;-><init>()V
********_v_0.9.2/smali/o/CM.smali:764: invoke-virtual {v4, v3}, Lrootingcheck/RootBeerNative;->checkForRoot([Ljava/lang/Object;)I

********_v_0.9.2/smali/o/xZ$5.smali:257: new-instance v1, Lrootingcheck/RootBeerNative;
********_v_0.9.2/smali/o/xZ$5.smali:259: invoke-direct {v1}, Lrootingcheck/RootBeerNative;-><init>()V
********_v_0.9.2/smali/o/xZ$5.smali:261: invoke-static {}, Lrootingcheck/RootBeerNative;->?()Z

root@kali:~/Desktop# grep -nr ‘setLogDebugMessages’ ******** _v_0.9.2/


********_v_0.9.2/smali/o/CM.smali:599: invoke-virtual {v1, v0}, Lrootingcheck/RootBeerNative;->setLogDebugMessages(Z)I
********_v_0.9.2/smali/o/CM.smali:761: invoke-virtual {v4, v0}, Lrootingcheck/RootBeerNative;->setLogDebugMessages(Z)I

Але це були не всі перевірки. Проаналізувавши клас MainActivity.java був знайдені виклики функцій, куди передаються рядка “su”, “test-keys” і “which”, c допомогою яких проводиться перевірка (див. Рис. 3).


Рис.3. Перевірки на рутованость

І знову командою grep шукаємо в smali-файлах перевірки рутованости:

Результати пошуку:
root@kali:~/Desktop# grep -nr ‘su’ ******** _v_0.9.2/

********_v_0.9.2/smali/o/CM.smali:443: const-string v2, "su"
********_v_0.9.2/smali/o/CM.smali:706: const-string v2, "su"
********_v_0.9.2/smali/o/xZ$5.smali:172: const-string v1, "su"
********_v_0.9.2/smali/o/xZ$5.smali:347: const-string v0, "su"

root@kali:~/Desktop# grep -nr ‘test-keys’ ******** _v_0.9.2/

********_v_0.9.2/smali/o/xZ$5.smali:141: const-string v1, "test-keys"
********_v_0.9.2/smali/o/xZ$5.smali:374: const-string v0, "test-keys"

root@kali:~/Desktop# grep -nr ‘which’ ******** _v_0.9.2/

********_v_0.9.2/smali/o/CM.smali:437: const-string v2, "which"

У статті я покажу лише одну із запропонованих модифікацій перевірок рутованности. Після невеликої маніпуляції, а саме зміни 1 на 0 — перевірки на рутованность прибрані.


Рис. 4. Значення змінної дорівнює одиниці, якщо телефон рутованый


Рис. 5. Тепер значення змінної дорівнює нулю, якщо телефон рутованний

Після цього — програму можна зібрати, підписати своїм релізних ключем і запустити на мобільному телефоні. Але якщо б не два АЛЕ! А саме:

  1. перевірка підключення до USB;
  2. перевірка включення 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

Binary file ********_v_0.9.2/build/apk/classes.dex matches
********_v_0.9.2/smali/o/xZ$1.smali:49: const-string v1, "development_settings_enabled"


Рис. 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. Рядок коду, яку потрібно видалити MainActivity.smali

Тепер залишилося створити свій релізний ключ і підписати їм додаток. Це робиться наступним чином:

  1. Потрібно встановити два додатки: Keytool і Jarsinger.
  2. Виконати команду на збори додатка:
  3. apktool b C:UsersUserDesktop********
  4. Далі:cd ********dist
  5. Далі: Keytool.exe -genkey -alias key.keystore -keyalg RSA -validity 20000 -keystore key.keystore
  6. Далі:Jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore key.keystore ********.apk key.keystore
  7. Далі:jarsigner -verify -verbose -certs ********.апк

Ось в принципі всі маніпуляції і закінчені. Тепер встановлюємо додаток на телефон з допомогою adb install або з директорії смартфона і можна проводити динамічне тестування на уразливості.

Після установки програми запускаємо його (див. Рис. 11 і Рис. 12).

Рис. 11. Включаємо режим Developer mode і підключаємо USB Рис. 12. Запуск програми

Висновки

На практичному прикладі я показав, як можна відключити деякі перевірки стану середовища виконання. Далі вже за допомогою інших тулзов провели аналіз на уразливість, але це інша історія…

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

  • це поводження тих чи інших перевірок, які вкладені в програму
  • впровадження стороннього коду, після чого програма може бути опублікована і використовуватися як шкідлива

Як можна захиститися? Ми в Hacken вирішили не винаходити велосипед і запропонували клієнту обфусцировать вихідний код і використовувати функції, які перевіряють модифікацію вихідного коду.

P. S.

Можна використовувати більш просунутий спосіб аналізу — це smali debugging. Більш детальніше можна почитати про це в мануалі.

Трохи для довідки, я сформулював список рядків який застосовується для перевірки на рутованость:

  • “test-keys”;
  • “/system/app/Superuser.апк”;
  • “/sbin/su”;
  • “/system/bin/su”;
  • “/system/xbin/su”;
  • “/data/local/xbin/su”;
  • “/data/local/bin/su”;
  • “/system/sd/xbin/su”;
  • “/system/bin/failsafe/su”;
  • “/data/local/su”;
  • “/su/bin/su”;
  • “/system/xbin/which”;
  • “su”;
  • “which”.

Related Articles

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Close