Android Applications Basics

Підтримка HackTricks

Модель безпеки Android

Є два рівні:

  • ОС, яка ізолює встановлені додатки один від одного.

  • сам додаток, який дозволяє розробникам експонувати певні функціональності та налаштовувати можливості додатка.

Розділення UID

Кожному додатку призначається конкретний ідентифікатор користувача (User ID). Це відбувається під час встановлення додатка, щоб додаток міг взаємодіяти лише з файлами, що належать його ідентифікатору користувача, або спільними файлами. Тому лише сам додаток, певні компоненти ОС та користувач root можуть отримати доступ до даних додатка.

Спільний UID

Два додатки можуть бути налаштовані на використання одного й того ж UID. Це може бути корисно для обміну інформацією, але якщо один з них буде скомпрометований, дані обох додатків будуть скомпрометовані. Ось чому така поведінка не рекомендується. Щоб поділитися одним UID, додатки повинні визначити однакове значення android:sharedUserId у своїх маніфестах.

Пісочниця

Пісочниця Android-додатків дозволяє запускати кожен додаток як окремий процес під окремим ідентифікатором користувача. Кожен процес має свою віртуальну машину, тому код додатка виконується в ізоляції від інших додатків. З Android 5.0(L) впроваджено SELinux. В основному, SELinux забороняє всі взаємодії процесів, а потім створює політики, щоб дозволити лише очікувані взаємодії між ними.

Дозволи

Коли ви встановлюєте додаток і він запитує дозволи, додаток запитує дозволи, налаштовані в елементах uses-permission у файлі AndroidManifest.xml. Елемент uses-permission вказує назву запитуваного дозволу в атрибуті name. Він також має атрибут maxSdkVersion, який зупиняє запит на дозволи на версіях, вищих за вказану. Зверніть увагу, що Android-додатки не повинні запитувати всі дозволи на початку, вони також можуть запитувати дозволи динамічно, але всі дозволи повинні бути оголошені в маніфесті.

Коли додаток експонує функціональність, він може обмежити доступ лише до додатків, які мають вказаний дозвіл. Елемент дозволу має три атрибути:

  • назва дозволу

  • атрибут permission-group, який дозволяє групувати пов'язані дозволи.

  • рівень захисту, який вказує, як надаються дозволи. Є чотири типи:

  • Нормальний: Використовується, коли немає відомих загроз для додатка. Користувач не зобов'язаний його затверджувати.

  • Небезпечний: Вказує, що дозвіл надає запитуваному додатку певний підвищений доступ. Користувачі повинні затвердити їх.

  • Підпис: Тільки додатки, підписані тим же сертифікатом, що й той, що експортує компонент, можуть отримати дозвіл. Це найсильніший тип захисту.

  • SignatureOrSystem: Тільки додатки, підписані тим же сертифікатом, що й той, що експортує компонент, або додатки, що працюють з доступом на рівні системи, можуть отримати дозволи.

Попередньо встановлені додатки

Ці додатки зазвичай знаходяться в каталогах /system/app або /system/priv-app, і деякі з них оптимізовані (ви навіть можете не знайти файл classes.dex). Ці додатки варто перевірити, оскільки іноді вони працюють з надто багатьма дозволами (як root).

  • Ті, що постачаються з AOSP (Android OpenSource Project) ROM

  • Додані виробником пристрою

  • Додані постачальником мобільного телефону (якщо куплені у них)

Рутування

Щоб отримати доступ root на фізичному пристрої Android, вам зазвичай потрібно експлуатувати 1 або 2 вразливості, які зазвичай є специфічними для пристрою та версії. Після того, як експлуатація спрацювала, зазвичай бінарний файл Linux su копіюється в місце, вказане в змінній середовища PATH користувача, наприклад, /system/xbin.

Після налаштування бінарного файлу su використовується інший Android-додаток для взаємодії з бінарним файлом su та обробки запитів на доступ root, таких як Superuser та SuperSU (доступні в Google Play Store).

Зверніть увагу, що процес рутування є дуже небезпечним і може серйозно пошкодити пристрій.

ROM

Можливо замінити ОС, встановивши власне програмне забезпечення. Це дозволяє розширити корисність старого пристрою, обійти програмні обмеження або отримати доступ до останнього коду Android. OmniROM та LineageOS є двома з найпопулярніших прошивок для використання.

Зверніть увагу, що не завжди необхідно рутувати пристрій, щоб встановити власне програмне забезпечення. Деякі виробники дозволяють розблокування своїх завантажувачів у добре задокументований і безпечний спосіб.

Наслідки

Після рутування пристрою будь-який додаток може запитати доступ як root. Якщо зловмисний додаток отримає його, він матиме доступ до майже всього і зможе пошкодити телефон.

Основи Android-додатків

  • Формат Android-додатків називається APK file format. Це, по суті, ZIP файл (перейменувавши розширення файлу на .zip, вміст можна витягти та переглянути).

  • Вміст APK (не вичерпний)

  • AndroidManifest.xml

  • resources.arsc/strings.xml

  • resources.arsc: містить попередньо скомпільовані ресурси, такі як бінарний XML.

  • res/xml/files_paths.xml

  • META-INF/

  • Тут знаходиться сертифікат!

  • classes.dex

  • Містить байт-код Dalvik, що представляє скомпільований Java (або Kotlin) код, який додаток виконує за замовчуванням.

  • lib/

  • Містить рідні бібліотеки, розділені за архітектурою ЦП в підкаталогах.

  • armeabi: код для процесорів на базі ARM

  • armeabi-v7a: код для процесорів ARMv7 та вище

  • x86: код для процесорів X86

  • mips: код лише для процесорів MIPS

  • assets/

  • Зберігає різні файли, необхідні додатку, потенційно включаючи додаткові рідні бібліотеки або DEX файли, іноді використовувані авторами шкідливих програм для приховування додаткового коду.

  • res/

  • Містить ресурси, які не скомпільовані в resources.arsc

Dalvik & Smali

У розробці Android використовується Java або Kotlin для створення додатків. Замість використання JVM, як у настільних додатках, Android компілює цей код у Dalvik Executable (DEX) байт-код. Раніше цим байт-кодом займалася віртуальна машина Dalvik, але тепер Android Runtime (ART) бере на себе цю функцію в новіших версіях Android.

Для реверс-інжинірингу Smali стає критично важливим. Це читабельна людиною версія DEX байт-коду, яка діє як асемблерна мова, перетворюючи вихідний код на інструкції байт-коду. Smali та baksmali відносяться до інструментів асемблювання та розбирання в цьому контексті.

Інтенти

Інтенти є основним засобом, за допомогою якого Android-додатки спілкуються між своїми компонентами або з іншими додатками. Ці об'єкти повідомлень також можуть переносити дані між додатками або компонентами, подібно до того, як використовуються запити GET/POST у HTTP-комунікаціях.

Отже, Інтент - це, по суті, повідомлення, яке передається між компонентами. Інтенти можуть бути спрямовані на конкретні компоненти або додатки, або можуть бути надіслані без конкретного отримувача. Простими словами, Інтент можна використовувати:

  • Для запуску Activity, зазвичай відкриваючи інтерфейс користувача для додатку

  • Як трансляції, щоб повідомити систему та додатки про зміни

  • Для запуску, зупинки та взаємодії з фоновим сервісом

  • Для доступу до даних через ContentProviders

  • Як зворотні виклики для обробки подій

Якщо вразливі, інтенти можуть бути використані для виконання різноманітних атак.

Фільтр Інтентів

Фільтри Інтентів визначають як активність, сервіс або приймач трансляцій можуть взаємодіяти з різними типами Інтентів. По суті, вони описують можливості цих компонентів, такі як дії, які вони можуть виконувати, або типи трансляцій, які вони можуть обробляти. Основне місце для оголошення цих фільтрів - це файл AndroidManifest.xml, хоча для приймачів трансляцій також є можливість їх кодування.

Фільтри Інтентів складаються з категорій, дій та фільтрів даних, з можливістю включення додаткових метаданих. Ця конфігурація дозволяє компонентам обробляти конкретні Інтенти, які відповідають оголошеним критеріям.

Критичним аспектом Android-компонентів (активності/сервіси/постачальники контенту/приймачі трансляцій) є їх видимість або публічний статус. Компонент вважається публічним і може взаємодіяти з іншими додатками, якщо він експортується зі значенням true або якщо для нього в маніфесті оголошено фільтр Інтентів. Однак є спосіб для розробників явно зберегти ці компоненти приватними, забезпечуючи їх ненавмисну взаємодію з іншими додатками. Це досягається шляхом встановлення атрибута експортується на false у їхніх визначеннях маніфесту.

Більше того, розробники мають можливість додатково захистити доступ до цих компонентів, вимагаючи специфічних дозволів. Атрибут permission може бути встановлений, щоб забезпечити доступ лише для додатків з призначеним дозволом, додаючи додатковий рівень безпеки та контролю над тим, хто може з ним взаємодіяти.

<activity android:name=".MyActivity" android:exported="false">
<!-- Intent filters go here -->
</activity>

Імпліцитні наміри

Наміри створюються програмно за допомогою конструктора Intent:

Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));

The Action of the previously declared intent is ACTION_SEND and the Extra is a mailto Uri (the Extra if the extra information the intent is expecting).

Цей намір повинен бути оголошений у маніфесті, як у наступному прикладі:

<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

Фільтр намірів повинен відповідати дії, даним та категорії, щоб отримати повідомлення.

Процес "розв'язання намірів" визначає, яка програма повинна отримати кожне повідомлення. Цей процес враховує атрибут пріоритету, який можна встановити в оголошенні фільтра намірів, і той, що має вищий пріоритет, буде обраний. Цей пріоритет може бути встановлений в межах від -1000 до 1000, і програми можуть використовувати значення SYSTEM_HIGH_PRIORITY. Якщо виникає конфлікт, з'являється вікно "вибору", щоб користувач міг вирішити.

Явні наміри

Явний намір вказує на ім'я класу, на який він націлений:

Intent downloadIntent = new (this, DownloadService.class):

В інших додатках, щоб отримати доступ до раніше оголошеного наміру, ви можете використовувати:

Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);

Pending Intents

Ці дозволяють іншим додаткам виконувати дії від імені вашого додатку, використовуючи ідентичність та дозволи вашого додатку. При створенні Pending Intent потрібно вказати намір та дію, яку потрібно виконати. Якщо оголошений намір не є явним (не вказує, який намір може його викликати), зловмисний додаток може виконати оголошену дію від імені жертви. Більше того, якщо дія не вказана, зловмисний додаток зможе виконати будь-яку дію від імені жертви.

Broadcast Intents

На відміну від попередніх намірів, які отримує лише один додаток, широкомовні наміри можуть бути отримані кількома додатками. Однак, починаючи з версії API 14, можливо вказати додаток, який повинен отримати повідомлення, використовуючи Intent.setPackage.

Альтернативно, також можливо вказати дозвіл при відправці широкомовлення. Додаток-отримувач повинен мати цей дозвіл.

Існує два типи широкомовлень: Звичайні (асинхронні) та Упорядковані (синхронні). Порядок базується на налаштованому пріоритеті в елементі отримувача. Кожен додаток може обробляти, передавати або відхиляти широкомовлення.

Можливо відправити широкомовлення за допомогою функції sendBroadcast(intent, receiverPermission) з класу Context. Ви також можете використовувати функцію sendBroadcast з LocalBroadCastManager, яка забезпечує, що повідомлення ніколи не покидає додаток. Використовуючи це, вам навіть не потрібно експортувати компонент отримувача.

Sticky Broadcasts

Цей вид широкомовлень може бути доступний довго після їх відправлення. Вони були застарілі на рівні API 21, і рекомендується не використовувати їх. Вони дозволяють будь-якому додатку підслуховувати дані, але також їх модифікувати.

Якщо ви знайдете функції, що містять слово "sticky", такі як sendStickyBroadcast або sendStickyBroadcastAsUser, перевірте вплив і спробуйте їх видалити.

У додатках Android глибокі посилання використовуються для ініціювання дії (Intent) безпосередньо через URL. Це робиться шляхом оголошення конкретної схеми URL в межах активності. Коли пристрій Android намагається доступитися до URL з цією схемою, вказана активність в додатку запускається.

Схема повинна бути оголошена в файлі AndroidManifest.xml:

[...]
<activity android:name=".MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="examplescheme" />
</intent-filter>
[...]

Схема з попереднього прикладу - exampleapp:// (також зверніть увагу на category BROWSABLE)

Тоді в полі даних ви можете вказати host та path:

<data android:scheme="examplescheme"
android:host="example"
/>

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

<a href="examplescheme://example/something">click here</a>
<a href="examplescheme://example/javascript://%250dalert(1)">click here</a>

Щоб знайти код, який буде виконано в додатку, перейдіть до активності, викликаної глибоким посиланням, і знайдіть функцію onNewIntent.

Дізнайтеся, як викликати глибокі посилання без використання HTML-сторінок.

AIDL - Мова визначення інтерфейсу Android

Мова визначення інтерфейсу Android (AIDL) призначена для полегшення зв'язку між клієнтом і сервісом в Android-додатках через міжпроцесорну комунікацію (IPC). Оскільки безпосередній доступ до пам'яті іншого процесу не дозволений в Android, AIDL спрощує процес, перетворюючи об'єкти в формат, зрозумілий операційній системі, що полегшує зв'язок між різними процесами.

Ключові концепції

  • Прив'язані сервіси: Ці сервіси використовують AIDL для IPC, дозволяючи активностям або компонентам підключатися до сервісу, робити запити та отримувати відповіді. Метод onBind у класі сервісу є критично важливим для ініціювання взаємодії, що робить його важливою областю для перевірки безпеки в пошуках вразливостей.

  • Messenger: Працюючи як прив'язаний сервіс, Messenger полегшує IPC з акцентом на обробку даних через метод onBind. Важливо уважно перевірити цей метод на предмет небезпечного оброблення даних або виконання чутливих функцій.

  • Binder: Хоча безпосереднє використання класу Binder є менш поширеним через абстракцію AIDL, корисно розуміти, що Binder діє як драйвер на рівні ядра, що полегшує передачу даних між пам'яттю різних процесів. Для подальшого розуміння доступний ресурс за адресою https://www.youtube.com/watch?v=O-UHvFjxwZ8.

Компоненти

Це включає: Активності, Сервіси, Отримувачі трансляцій та Провайдери.

Активність запуску та інші активності

У Android-додатках активності подібні до екранів, що показують різні частини інтерфейсу користувача додатку. Додаток може мати багато активностей, кожна з яких представляє унікальний екран для користувача.

Активність запуску є основним шлюзом до додатку, запускається, коли ви натискаєте на іконку додатку. Вона визначена у файлі маніфесту додатку з конкретними MAIN та LAUNCHER намірами:

<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Не всі додатки потребують активності запуску, особливо ті, що не мають інтерфейсу користувача, як фонові сервіси.

Активності можуть бути доступні іншим додаткам або процесам, якщо позначити їх як "експортовані" у маніфесті. Ця настройка дозволяє іншим додаткам запускати цю активність:

<service android:name=".ExampleExportedService" android:exported="true"/>

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

Життєвий цикл активності починається з методу onCreate, налаштовуючи UI та готуючи активність до взаємодії з користувачем.

Підклас додатку

У розробці Android додаток має можливість створити підклас класу Application, хоча це не є обов'язковим. Коли такий підклас визначено, він стає першим класом, який створюється в додатку. Метод attachBaseContext, якщо він реалізований у цьому підкласі, виконується перед методом onCreate. Це налаштування дозволяє здійснити ранню ініціалізацію перед початком роботи решти додатку.

public class MyApp extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Initialization code here
}

@Override
public void onCreate() {
super.onCreate();
// More initialization code
}
}

Services

Services - це фонові операції, здатні виконувати завдання без інтерфейсу користувача. Ці завдання можуть продовжувати виконуватись навіть коли користувачі переходять до інших додатків, що робить сервіси важливими для тривалих операцій.

Сервіси універсальні; їх можна ініціювати різними способами, при цьому Intents є основним методом для їх запуску як точки входу додатку. Як тільки сервіс запущено за допомогою методу startService, його метод onStart активується і продовжує працювати, поки метод stopService не буде явно викликаний. Альтернативно, якщо роль сервісу залежить від активного з'єднання клієнта, використовується метод bindService для прив'язки клієнта до сервісу, активуючи метод onBind для передачі даних.

Цікаве застосування сервісів включає відтворення фонової музики або отримання мережевих даних без перешкоджання взаємодії користувача з додатком. Більше того, сервіси можуть бути доступні для інших процесів на тому ж пристрої через експорт. Це не є поведінкою за замовчуванням і вимагає явної конфігурації у файлі Android Manifest:

<service android:name=".ExampleExportedService" android:exported="true"/>

Broadcast Receivers

Broadcast receivers діють як слухачі в системі обміну повідомленнями, дозволяючи кільком додаткам реагувати на одні й ті ж повідомлення з системи. Додаток може зареєструвати приймач двома основними способами: через Manifest додатка або динамічно в коді додатка за допомогою registerReceiver API. У Manifest трансляції фільтруються за допомогою дозволів, тоді як динамічно зареєстровані приймачі також можуть вказувати дозволи під час реєстрації.

Intent filters є важливими в обох методах реєстрації, визначаючи, які трансляції активують приймач. Коли надсилається відповідна трансляція, викликається метод onReceive приймача, що дозволяє додатку реагувати відповідно, наприклад, коригуючи поведінку у відповідь на сигнал про низький рівень заряду батареї.

Трансляції можуть бути асинхронними, досягаючи всіх приймачів без порядку, або синхронними, де приймачі отримують трансляцію на основі встановлених пріоритетів. Однак важливо зазначити потенційний ризик безпеки, оскільки будь-який додаток може пріоритизувати себе, щоб перехопити трансляцію.

Щоб зрозуміти функціональність приймача, шукайте метод onReceive у його класі. Код цього методу може маніпулювати отриманим Intent, підкреслюючи необхідність валідації даних приймачами, особливо в Ordered Broadcasts, які можуть змінювати або скасовувати Intent.

Content Provider

Content Providers є важливими для обміну структурованими даними між додатками, підкреслюючи важливість реалізації дозволів для забезпечення безпеки даних. Вони дозволяють додаткам отримувати доступ до даних з різних джерел, включаючи бази даних, файлові системи або веб. Специфічні дозволи, такі як readPermission і writePermission, є важливими для контролю доступу. Крім того, тимчасовий доступ може бути наданий через налаштування grantUriPermission у маніфесті додатка, використовуючи атрибути, такі як path, pathPrefix і pathPattern для детального контролю доступу.

Валідація введення є надзвичайно важливою для запобігання вразливостям, таким як SQL-ін'єкції. Content Providers підтримують основні операції: insert(), update(), delete() і query(), полегшуючи маніпуляцію даними та обмін між додатками.

FileProvider, спеціалізований Content Provider, зосереджується на безпечному обміні файлами. Він визначається в маніфесті додатка з конкретними атрибутами для контролю доступу до папок, позначеними android:exported і android:resource, що вказують на конфігурації папок. Обережність рекомендується при обміні каталогами, щоб уникнути випадкового розкриття чутливих даних.

Приклад декларації маніфесту для FileProvider:

<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

І приклад вказування спільних папок у filepaths.xml:

<paths>
<files-path path="images/" name="myimages" />
</paths>

Для отримання додаткової інформації перегляньте:

WebViews

WebViews - це міні веб-браузери всередині Android додатків, які отримують контент або з вебу, або з локальних файлів. Вони стикаються з подібними ризиками, як і звичайні браузери, але існують способи зменшити ці ризики через специфічні налаштування.

Android пропонує два основних типи WebView:

  • WebViewClient підходить для базового HTML, але не підтримує функцію JavaScript alert, що впливає на те, як можна тестувати XSS атаки.

  • WebChromeClient більше схожий на повний досвід браузера Chrome.

Ключовий момент полягає в тому, що браузери WebView не ділять куки з основним браузером пристрою.

Для завантаження контенту доступні методи, такі як loadUrl, loadData, і loadDataWithBaseURL. Важливо переконатися, що ці URL або файли є безпечними для використання. Налаштування безпеки можна керувати через клас WebSettings. Наприклад, вимкнення JavaScript за допомогою setJavaScriptEnabled(false) може запобігти XSS атакам.

JavaScript "Bridge" дозволяє Java об'єктам взаємодіяти з JavaScript, вимагаючи, щоб методи були позначені @JavascriptInterface для безпеки з Android 4.2 і далі.

Дозволяючи доступ до контенту (setAllowContentAccess(true)), WebViews можуть отримувати доступ до Content Providers, що може бути ризиком, якщо URL контенту не перевірені як безпечні.

Для контролю доступу до файлів:

  • Вимкнення доступу до файлів (setAllowFileAccess(false)) обмежує доступ до файлової системи, з винятками для певних активів, забезпечуючи їх використання лише для не чутливого контенту.

Інші компоненти додатків та управління мобільними пристроями

Цифровий підпис додатків

  • Цифровий підпис є обов'язковим для Android додатків, забезпечуючи їх автентичне авторство перед установкою. Цей процес використовує сертифікат для ідентифікації додатка і повинен бути перевірений менеджером пакетів пристрою під час установки. Додатки можуть бути самопідписаними або сертифікованими зовнішнім CA, захищаючи від несанкціонованого доступу та забезпечуючи, щоб додаток залишався незмінним під час доставки на пристрій.

Перевірка додатків для підвищення безпеки

  • Починаючи з Android 4.2, функція під назвою Verify Apps дозволяє користувачам перевіряти додатки на безпеку перед установкою. Цей процес перевірки може попереджати користувачів про потенційно шкідливі додатки або навіть запобігати установці особливо шкідливих, підвищуючи безпеку користувачів.

Управління мобільними пристроями (MDM)

  • MDM рішення забезпечують нагляд та безпеку для мобільних пристроїв через Device Administration API. Вони вимагають установки Android додатка для ефективного управління та захисту мобільних пристроїв. Основні функції включають забезпечення політик паролів, обов'язкове шифрування зберігання та дозволення віддаленого видалення даних, забезпечуючи всебічний контроль та безпеку мобільних пристроїв.

// Example of enforcing a password policy with MDM
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminComponent = new ComponentName(context, AdminReceiver.class);

if (dpm.isAdminActive(adminComponent)) {
// Set minimum password length
dpm.setPasswordMinimumLength(adminComponent, 8);
}
Підтримайте HackTricks

Last updated