Препарируем Viber. Мини-гид по анализу приложений для Android

Содержание статьи

  • Цель
  • Разделяемые библиотеки
  • Предварительные результаты анализа
  • Функции
  • libFlatBuffersParser.so
  • libsvg.so
  • libnativehttp.so
  • Другие библиотеки
  • Анализ цели
  • Досягаемость функции
  • Фаззинг
  • Эксперименты и улучшения
  • Выводы

Как‑то раз при устрой­стве на работу мне дали весь­ма инте­рес­ное задание — про­ана­лизи­ровать Android-при­ложе­ние Viber. В нем сле­дова­ло най­ти уяз­вимос­ти с пос­леду­ющей экс­плу­ата­цией. На этом при­мере рас­ска­жу о под­ходе к ана­лизу реаль­ного при­ложе­ния с получе­нием кон­крет­ных резуль­татов за корот­кий срок. Если прой­ти все эти эта­пы, то впол­не воз­можно, что тебе удас­тся най­ти в Viber 0-day ?

info

Чи­тая этот недогайд, дер­жи в уме, что мы огра­ниче­ны по вре­мени, поэто­му некото­рые под­ходы ана­лиза, которые мож­но было бы при­менить, будут упо­мяну­ты лишь всколь­зь. И еще: я спе­циаль­но оста­вил опи­сание всех сво­их оши­бок, которые допус­тил при ана­лизе. Как говорит­ся, умный учит­ся на чужих ошиб­ках.

 

Цель

Ис­кать ошиб­ки в при­ложе­нии для Android мож­но по‑раз­ному, так же как и выбирать мес­та для это­го самого поис­ка. В рам­ках этой статьи мы выберем цель пониже уров­нем — раз­деля­емые биб­лиоте­ки, то есть ори­енти­ровать­ся будем на баги memory corruption. Код на Java рас­смот­рим толь­ко в слу­чае, ког­да необ­ходимо выяс­нить его связь с раз­деля­емы­ми биб­лиоте­ками.

Для ана­лиза APK исполь­зовались стан­дар­тные инс­тру­мен­ты из лю­бого пуб­лично­го awesome list, поэто­му я не буду заос­трять вни­мание на их наз­вании, если того не тре­бует кон­текст.

Це­левой APK был получен с од­ного из mirror-сай­тов. К выбору источни­ка APK сто­ит отно­сить­ся серь­езно, пос­коль­ку неред­ко сайт может хра­нить:

  • уже уста­рев­шие вер­сии;
  • толь­ко вер­сии для ненуж­ных плат­форм и архи­тек­тур;
  • мо­дифи­циро­ван­ные при­ложе­ния (воз­можно, с содер­жани­ем мал­вари).

На дан­ном эта­пе име­ет смысл про­вес­ти реког­носци­ров­ку цели: изу­чить CVE, а затем про­вес­ти binary diffing ана­лиз 1-day-уяз­вимос­тей.

 

Разделяемые библиотеки

Пос­ле рас­паков­ки APK в дирек­тории lib мож­но обна­ружить фай­лы биб­лиотек: они не запако­ваны, не зашиф­рованы, не обфусци­рова­ны, не нак­рыты про­тек­тором, что облегча­ет нашу задачу в нес­коль­ко раз. В защиту Viber могу ска­зать, что обыч­но мес­сен­дже­ры не пыта­ются при­менять пас­сивные меры защиты от ана­лиза биб­лиотек, у WhatsApp лишь исполь­зует­ся кас­томный упа­ков­щик, но и то — не ради защиты. Для ана­лиза я выб­рал вер­сии биб­лиотек для архи­тек­туры x86_64 по сле­дующим при­чинам:

  • боль­шее количес­тво инс­тру­мен­тов для этой архи­тек­туры;
  • луч­ше деком­пиляция (это, конеч­но, спор­но, так как мно­гое зависит от выбора инс­тру­мен­та);
  • воз­можность эму­ляции на более высоких ско­рос­тях (моя хост‑машина име­ет архи­тек­туру x86_64);
  • воз­можность час­тично­го ана­лиза на хост‑машине в обход эму­лято­ра;
  • на дан­ном эта­пе нет задачи писать кон­крет­ный экс­пло­ит для пок­рытия боль­шего чис­ла целей, соот­ветс­твен­но, ARM-архи­тек­туры мож­но отбро­сить, если это пот­ребу­ется.

По­нача­лу для повер­хностно­го ана­лиза исполь­зовались такие инс­тру­мен­ты, как IDA Pro, Binary Ninja и rizin (Ghidra не взял, потому что задачу сле­дова­ло решить быс­тро): заг­ружа­ешь биб­лиоте­ку, смот­ришь экспор­тирован­ные сим­волы, находишь стро­ки, нем­ного чита­ешь код. Но затем я перешел к oneline-коман­де — по сути, боль­шего мне и не тре­бова­лось: readelf -W --demangle --symbols $(LIBRARY_SO) | tail -n +4 | sort -k 7 | less.

Пос­ле иден­тифика­ции JNI-фун­кций из биб­лиотек про­хожусь rg/grep по smali-коду и нахожу фай­лы, где содер­жится объ­явле­ние native-фун­кций:

$ readelf -W —demangle —symbols libnativehttp.so | tail -n +4 | sort -k 7 | rg «FUNC.Java_.» | less
33: 0000000000001bb5 55 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_HttpEngine_nativeCreateHttp
34: 0000000000001bec 15 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_HttpEngine_nativeDelete
38: 0000000000001bfb 622 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_HttpEngine_nativeTest
44: 00000000000018c3 109 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_NativeDownloader_nativeOnConnected
39: 00000000000015e8 366 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_NativeDownloader_nativeOnData
35: 0000000000001b0c 40 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_NativeDownloader_nativeOnDisconnected
40: 0000000000001930 476 FUNC GLOBAL DEFAULT 13 Java_com_viber_libnativehttp_NativeDownloader_nativeOnHead

$ rg «native.*nativeCreateHttp»
app/src/main/java/com/viber/libnativehttp/HttpEngine.java
9: public static native long nativeCreateHttp();

Даль­не нужен повер­хностный ана­лиз, что­бы выявить, во‑пер­вых, биб­лиоте­ку‑цель, во‑вто­рых, ком­понен­ты open source, иссле­дова­ние которых пред­сто­ит сде­лать поз­днее. Ана­лизи­ровать мож­но с помощью того же readelf или в Rizin либо Binary Ninja: гуг­лим имя экспор­тирован­ного сим­вола и про­водим повер­хностный реверс‑инжи­ниринг, что­бы вос­создать общую кар­тину фун­кций биб­лиоте­ки.

 

Предварительные результаты анализа

Ни­же пред­став­лен спи­сок раз­деля­емых биб­лиотек с крат­ким опи­сани­ем фун­кций или ссыл­кой на про­ект с откры­тыми исходни­ками.

  • libc++_shared.so — C++ standard library.
  • libcrashlytics-common.so, libcrashlytics-handler.so, libcrashlytics-trampoline.so, libcrashlytics.so — Firebase Crashlytics.
  • libreactnativeblob.so, libreactnativejni.so, libglog_init.so, libjscexecutor.so, libjsijniprofiler.so, libjsinspector.so — React Native.
  • libfb.so, libfbjni.so — fbjni.
  • libfolly_futures.so — Folly: Facebook Open-source Library.
  • libfolly_json.so — Folly: Facebook Open-source Library, double-conversion.
  • libglog.so — Google Logging Library.
  • libhermes-executor-release.so, libhermes.so — Hermes JS Engine.
  • libicuBinder.so — ICU extension for SQLite.
  • libimage_processing_util_jni.so — androidx.camera.core.
  • libimagepipeline.so, libnative-filters.so, libnative-imagetranscoder.so — Fresco.
  • libgifimage.so — The GIFLIB project, Fresco.
  • libjingle_peerconnection_so.so — ста­рый ком­понент (libjingle) из WebRTC.
  • libmux.so — FFmpeg из сос­тава fftools.
  • libpl_droidsonroids_gif.so — android-gif-drawable.
  • librenderscript-toolkit.so — RenderScript.
  • libsigner.so — Adjust SDK for Android.
  • libspeexjni.so — Speex.
  • libsqliteX.so — SQLite for Android.
  • libtensorflowlite_gpu_jni.so, libtensorflowlite_jni.so — TensorFlow.
  • libyoga.so — Yoga.
  • libCrossUnblocker.so, libFlatBuffersParser.so, liblinkparser.so, libnativehttp.so, libsvg.so, libViberRTC.so, libvideoconvert.so, libVoipEngineNative.so — самопис­ные биб­лиоте­ки c исполь­зовани­ем open source кода.

В ито­ге у нас появ­ляет­ся спи­сок инте­рес­ных биб­лиотек. Сос­тавлял­ся он исхо­дя все­го из одно­го усло­вия: как мож­но боль­ше самопис­ного кода, мень­ше ком­понен­тов open source. Вот этот спи­сок:

  • libCrossUnblocker.so;
  • libFlatBuffersParser.so;
  • liblinkparser.so;
  • libnativehttp.so;
  • libsvg.so;
  • libViberRTC.so;
  • libvideoconvert.so;
  • libVoipEngineNative.so.

 

Функции

Преж­де чем ана­лизи­ровать какую‑либо фун­кцию, сна­чала нуж­но выяс­нить, может ли ата­кующий до нее доб­рать­ся. Для это­го отсорти­руем по при­ори­тету все биб­лиоте­ки и фун­кции, а затем про­верим, отку­да вызыва­ются пос­ледние. Для ана­лиза Java-кода я буду исполь­зовать связ­ку jadx (деком­пиляция) + Android Studio (рефак­торинг) + Understand (ана­лиз гра­фов свя­зей перемен­ных, фун­кций и дан­ных).

До­пол­нитель­но про­верим в каж­дой биб­лиоте­ке наличие JNI-фун­кций. Может быть, есть те, что исполь­зуют­ся с помощью RegisterNatives.

 

libFlatBuffersParser.so

При более деталь­ном ана­лизе выяс­няет­ся, что это open source биб­лиоте­ка FlatBuffers. Оставля­ем ее ана­лиз на потом.

 

libsvg.so

Поль­зуем­ся ути­литой strings и Ghidra, что­бы получить стро­ки из бинар­ного фай­ла. По ним мы понима­ем, что код написан на C++:

[...]
_ZTVN10__cxxabiv121__vmi_class_type_infoE
_ZNSt6__ndk119__shared_weak_countD2Ev
_ZTINSt6__ndk119__shared_weak_countE
__android_log_print
_ZNKSt6__ndk16locale9has_facetERNS0_2idE
_ZNKSt6__ndk16locale9use_facetERNS0_2idE
[...]

Про­верим еще и наличие RTTI-информа­ции — в нашем слу­чае уда­ча бла­гово­лит нам, таковая име­ется. С помощью пла­гина для Ghidra Ghidra C++ Class and Run Time Type Information Analyzer вос­ста­новим струк­туру клас­сов кода C++.

Ре­зуль­тат вос­ста­нов­ления RTTI-информа­ции — клас­сы C++ и их методы

На пер­вый взгляд, здесь исполь­зует­ся собс­твен­ная SVG-биб­лиоте­ка, что хорошо. В ходе даль­нейше­го ана­лиза Java-кода (ана­лиз дерева вызовов) выяс­няет­ся, что фун­кции биб­лиоте­ки задей­ство­ваны в основном для заг­рузки ассе­тов при­ложе­ния (дирек­тория ./assets/svg в APK-фай­ле), а это нам не под­ходит. Одна­ко же цепоч­ка вызовов натив­ной фун­кции nativeParseFdparseFile исполь­зует­ся для пар­синга сти­керов. А вот это уже инте­рес­но! Но я решил оста­вить эту фун­кцию на потом, пос­коль­ку моя инту­иция под­ска­зала: бес­смыс­ленно писать пар­сер SVG с нуля. Соот­ветс­твен­но, исполь­зует­ся что‑то из open source.

Граф вызова фун­кций SVG native в Understand 

libnativehttp.so

В ходе ана­лиза воз­ника­ет воп­рос, с какой целью соз­давалась эта биб­лиоте­ка, ведь кажет­ся, что ее воз­можнос­ти не очень широки: обер­тки над фун­кци­ями обра­бот­ки сетевых дан­ных. Обра­бот­чики при воз­никно­вении событий вызыва­ют все тот же Java-код, а не что‑то натив­ное. Может быть, здесь ког­да‑то были какие‑то фун­кци­ональ­ные воз­можнос­ти, ну или пред­полага­лись? Подоб­ное я уже видел в мес­сен­дже­ре Telegram: legacy-кода хоть отбавляй, от такого боль­шого attack surface понача­лу чешут­ся руки, но пос­ле ана­лиза все вста­ет на свои мес­та. Поэто­му, ува­жаемый читатель, при­нимай во вни­мание, что иног­да могут встре­чать­ся не толь­ко dead code, но и dead libraries, на ана­лиз которых мож­но впус­тую пот­ратить кучу цен­ного вре­мени.

Источник: xakep.ru

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *