В этом выпус­ке: ана­лиз исполь­зования тре­кин­говых биб­лиотек в при­ложе­ниях, рас­сказ об уяз­вимос­тях, свя­зан­ных с исполь­зовани­ем PendingIntent, статьи о пра­виль­ном завер­шении и син­хро­низа­ции корутин, а так­же статья о неоче­вид­ных тон­костях работы с объ­екта­ми. Ну и как всег­да — под­борка биб­лиотек для раз­работ­чиков.
 

Почитать

 

PendingIntent и безопасность

Re-route Your Intent for Privilege Escalation — пре­зен­тация с Black Hat Europe 2021, пос­вящен­ная уяз­вимос­тям, свя­зан­ным с исполь­зовани­ем так называ­емых PendingIntent в при­ложе­ниях для Android.

Ин­тенты (intent) — одна из клю­чевых идей Android. Интенты поз­воля­ют пересы­лать сооб­щения меж­ду ком­понен­тами при­ложе­ний и сис­темных сер­висов с целью выз­вать опре­делен­ное дей­ствие. Запус­кают­ся при­ложе­ния, откры­вают­ся ссыл­ки, ини­циируют­ся звон­ки и мно­гое дру­гое в Android дела­ется с помощью интентов.

По­верх интентов пос­тро­ен дру­гой механизм — отло­жен­ные интенты (PendingIntent). Он поз­воля­ет передать интент дру­гому при­ложе­нию или ком­понен­ту сис­темы, что­бы то мог­ло отпра­вить интент от име­ни передав­шего его при­ложе­ния.

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

От­ложен­ные интенты чаще все­го исполь­зуют­ся в сле­дующих ком­понен­тах:

  1. Уве­дом­ления. Что­бы перех­ватить их, мы можем соз­дать NotificationListenerService, который будет слу­шать все уве­дом­ления при­ложе­ний и извле­кать из них отло­жен­ные интенты.
  2. SliceProvider. Этот механизм исполь­зует­ся для встра­ива­ния час­тей при­ложе­ния в дру­гие при­ложе­ния, нап­ример встра­ива­ния перек­лючате­ля быс­трых нас­тро­ек в окно ассистен­та. Мы можем получить слайс с помощью клас­са SliceViewManager или ContentResolver и затем получить PendingIntent всех слай­сов.
  3. MediaBrowserService. Механизм, поз­воля­ющий при­ложе­нию дать дос­туп к сво­ей меди­ате­ке с воз­можностью вклю­чить про­игры­вание меди­афай­лов. Получить PendingIntent мож­но, под­клю­чив­шись к при­ложе­нию с помощью клас­са MediaBrowser.
  4. Вид­жеты рабоче­го сто­ла исполь­зуют отло­жен­ные интенты в качес­тве дей­ствий при нажатии на свои эле­мен­ты. Класс AppWidgetHost поз­воля­ет при­ложе­нию при­кинуть­ся лаун­чером и получить дос­туп к вид­жетам при­ложе­ний. Далее PendingIntent мож­но извлечь из самого вид­жета.

В качес­тве при­мера уяз­вимос­ти в одном из этих ком­понен­тов при­ведем CVE-2020-0188. Это уяз­вимость в SliceProvider’е стан­дар­тных нас­тро­ек Android. Бла­года­ря тому что PendingIntent был открыт для изме­нения, его мож­но было вытащить с помощью ContentResolver, а затем изме­нить так, что­бы про­читать при­ват­ные фай­лы при­ложе­ния «Нас­трой­ки»:

Intent hijackIntent = new Intent();
hijackIntent.setPackage(getPackageName());
hijackIntent.setDataAndType(Uri.parse("content://com.android.settings.files/my_cache/NOTICE.html"), "txt/html");
hijackIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
pi.send(getApplicationContext(), 0, hijackIntent, null, null);

По сути, этот код зас­тавля­ет при­ложе­ние «Нас­трой­ки» передать ссыл­ку на свой внут­ренний файл с пра­вами на чте­ние и запись при­ложе­нию‑экс­пло­иту. Оста­ется толь­ко при­нять интент, и мож­но делать с фай­лом все, что угод­но.

Ре­комен­дации раз­работ­чикам:

  • По воз­можнос­ти ука­зывай флаг FLAG_IMMUTABLE при соз­дании PendingIntent.
  • При необ­ходимос­ти исполь­зовать модифи­циру­емый PendingIntent при­меняй явный интент и запол­няй поле ComponetName. В этом слу­чае зло­умыш­ленник не смо­жет перенап­равить интент.
  • Ис­поль­зуй ути­литу PendingIntentScan для ска­ниро­вания при­ложе­ния на наличие модифи­циру­емых PendingIntent.
 

Анализ использования трекинговых библиотек в приложениях

Are iPhones Really Better for Privacy? Comparative Study of iOS and Android Apps — иссле­дова­ние исполь­зования тре­кин­говых биб­лиотек в при­ложе­ниях для Android и iOS. Авто­ры работы взя­ли 12 тысяч при­ложе­ний для каж­дой плат­формы, про­ана­лизи­рова­ли их код и сетевые под­клю­чения и приш­ли к сле­дующим выводам:

  • В сред­нем при­ложе­ния исполь­зуют око­ло трех раз­личных тре­кин­говых биб­лиотек.
  • 3,73% при­ложе­ний для Android и 3,13% при­ложе­ний для iOS исполь­зуют боль­ше десяти тре­кин­говых биб­лиотек.
  • 88,73% при­ложе­ний для Android и 79,35% при­ложе­ний для iOS содер­жат хотя бы одну тре­кин­говую биб­лиоте­ку.
  • Са­мые популяр­ные тре­кин­говые биб­лиоте­ки на Android — Google Play Services (87,3%), Google AdMob (61,7%), Google Firebase (57,6%).
  • Са­мые популяр­ные тре­кин­говые биб­лиоте­ки на iOS — SKAdNetwork (69,6%), Google Firebase (53,9%), Facebook (25,5%).
  • Са­мые исполь­зуемые раз­решения в при­ложе­ниях для Android (исклю­чая те, что дают­ся без зап­роса поль­зовате­ля) — дос­туп к кар­те памяти, мес­тополо­жению и камере.
  • Са­мые исполь­зуемые раз­решения в при­ложе­ниях для iOS — хра­нили­ще фотог­рафий, камера, мес­тополо­жение.
  • Са­мые популяр­ные домены для отправ­ки ста­тис­тики — googleads.g.doubleclick.net (Android) и app-measurement.com (iOS).
  • Боль­шая часть тре­кин­говых ком­паний при­над­лежит Alphabet (Google) и Facebook.
Сравнительная таблица использования трекинговых библиотек
Срав­нитель­ная таб­лица исполь­зования тре­кин­говых биб­лиотек
Самые запрашиваемые разрешения
Са­мые зап­рашива­емые раз­решения
 

Разработчику

 

Синхронизация корутин

Coroutines and Java Synchronization Don’t Mix — неболь­шая замет­ка о неоче­вид­ной для некото­рых прог­раммис­тов осо­бен­ности вза­имо­дей­ствия корутин Kotlin и бло­киро­вок.

Все мы зна­ем об анно­тации @Synchronized (или бло­ке synchronized), которая говорит о том, что код фун­кции может выпол­нять­ся толь­ко в одном потоке одновре­мен­но:

repeat(2) {
thread { criticalSection() }
}
@Synchronized
fun criticalSection() {
println("Starting!")
Thread.sleep(10)
println("Ending!")
}

Два потока в этом при­мере выпол­нят код фун­кции пос­ледова­тель­но, один за дру­гим:

Starting!
Ending!
Starting!
Ending!

Од­нако если мы заменим потоки корути­нами, то все изме­нит­ся:

val scope = CoroutineScope(Job())
repeat(2) {
scope.launch { criticalSectionSuspending() }
}
@Synchronized
suspend fun criticalSectionSuspending() {
println("Starting!")
delay(10)
println("Ending!")
}

Вы­вод будет таким:

Starting!
Starting!
Ending!
Ending!

Дру­гими сло­вами, анно­тация @Synchronized буд­то бы не работа­ет в слу­чае корутин.

На самом деле объ­ясне­ние в том, что обе корути­ны в дан­ном при­мере работа­ют в одном потоке. А это вле­чет за собой два следс­твия:

  1. Ком­пилятор, поняв, что в synchronized-блок вхо­дит толь­ко один поток, может пол­ностью уда­лить син­хро­низа­цию.
  2. Блок synchronized обла­дает свой­ством reentrace, ког­да один и тот же поток может заходить в synchronized-блок, не сни­мая бло­киров­ку.

Дру­гими сло­вами, @Synchronized прос­то не име­ет смыс­ла для корутин, работа­ющих в одном потоке. И вмес­то нее сле­дует исполь­зовать класс Mutex.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии