-15% na nową książkę sekuraka: Wprowadzenie do bezpieczeństwa IT. Przy zamówieniu podaj kod: 10000

Niebezpieczeństwa WebView [Android]

21 grudnia 2015, 07:45 | Teksty | komentarzy 5

Komponent WebView sprawia, że aplikacje mobilne mogą zostać wzbogacone o funkcję przeglądarki stron internetowych, co pozwala im na wyświetlanie stron, nawigację, wykonywanie kodu JavaScript, nawiązywanie połączeń szyfrowanych itp. Wszystkie powyższe czynności wykonywane są w kontekście aplikacji mobilnej, a nie w sandboxie przeglądarki takiej jak Chrome czy Firefox. Wraz z tymi dodatkowymi funkcjami pojawiają się dodatkowe zagrożenia i zwiększenie powierzchni ataku na aplikację mobilną. Co więcej, wg. badań z 2015 większość aplikacji bankowych korzysta z tego komponentu do wyświetlania stron HTML i przetwarza JavaScript za pomocą WebView. W tym artykule przedstawię wektory ataku na aplikacje mobilne poprzez WebView oraz sposoby na ograniczenie ryzyk z nimi związanych. W artykule przedstawione są przykłady dla platformy Android, jednakże analogiczne zagrożenia występują w Windows Phone i iOS.

Modele zagrożeń

Zagrożenia dla aplikacji mobilnej poprzez WebView możemy podzielić na dwie kategorie:

  1. Atak z wykorzystaniem podstawionej strony – z uwagi na powszechne korzystanie z publicznych sieci WiFi atak ten ma duże szanse powodzenia. Aplikacje nie zawsze korzystają z połączeń szyfrowanych lub implementacja komunikacji HTTPS jest robiona źle, co umożliwia atakującemu atak Man-in-The-Middle i podstawienie aplikacji mobilnej własnej strony HTML lub jej modyfikację np. JavaScript Injection, HTML injection
  2. Atak z wykorzystaniem złośliwej aplikacji mobilnej – użytkownicy często instalują bezpłatne (skrakowane) wersje płatnych aplikacji z niezaufanych źródeł. Apliacje te często dodatkowo śledzą  komunikację nieświadomych użytkowników z legalnymi serwerami za pomocą klasy WebViewClient .

Użycie WebView i zagrożenia z tym związane

1. Java-to-JavaScript Interface

Deweloperzy korzystając z komponentu WebView muszą mieć świadomość, że niewłaściwa konfiguracja i złe użycie tego komponentu może doprowadzić do powstania krytycznych luk bezpieczeństwa.

Podstawowe użycie WebView w aplikacji mobilnej na Androidzie.

WebView webview = new WebView(this);
setContentView(webview);

Kolejnym krokiem mogłoby być odwołanie się do zasobów w sieci web (http:// lub https://):

webview.loadUrl("http://good-website.com");

Atakujący, który ma kontrolę nad ruchem sieciowym w przejętej sieci WiFI posiada możliwość przekierowanie do innego zasobu i/lub modyfikacji danej strony poprzez wstrzyknięcie własnego kodu HTML. W przypadku aplikacji, które nie stosują takich mechanizmów jak cert pinning atakujący ma realne szanse modyfikacji ruchu https.

Często deweloperzy włączają różne dodatkowe opcje komponentu WebView poprzez klasę WebSettings, które domyślnie nie są uruchomione, jedną z najczęściej uruchamianych opcji jest włączenie obsługi kodu JavaScript.

WebSettings settings = webView.getWebSettings();
settings.setJavascriptEnabled(true);

Taka konfiguracja zwiększa dodatkowo ryzyka związane z atakami typu Cross-Site Scripting.

Platforma Android zapewnia również budowanie mostów łączących kod JavaScript z kodem Java aplikacji mobilnych – JavascriptInterface.
Funkcjonalność ta umożliwia dostęp z poziomu JavaScript do publicznych metod udostępnionego obiektu Javy. Na przełomie 2012 i 2013 zostały publicznie przedstawione sposoby wykorzystania tego mechanizmu do przejęcia kontroli nad aplikację poprzez wykorzystanie mechnizmu refleksji. Przygotowany został również PoC w postaci exploita dostępnego we frameworku Metasploit. Przykład użycia tego modułu: http://resources.infosecinstitute.com/android-hacking-security-part-7-attacks-android-webviews/

Użycie interfejsu JavaScript-to-Java dla API<17 (niebezpieczne)

webview.addJavascriptInterface(new JSbridge(), "JSbridge");

class JSbridge {
    JSbridge () { }
    public String getString() {
      return "string";
    }
 }

Odwołanie w kodzie strony wyglądałoby następująco:

<script>
var String = window.bridge.getString();
</script>

Atakujący wykrorzystując mechanizm refleksji może zmusić aplikację do wykonania dowolnego kodu Javy poprzez odwołanie się do obiektu Runtime i wykonanie polecenia systemowego Android lub poprzez odwołanie się do innych klas Android np. SmSManager, co może służyć do wysyłania SMS-ów premium. Podatność oznaczona numerem CVE-2012-6636 i  CVE-2013-4710 daje szerokie możliwości wykorzystania przez atakującego.

<script>
cmd = ['/system/bin/sh', '-c', <tu podać dowolne polecenie powłoki Android> ];
window.JSbridge.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(cmd);
<script>

Teoretycznie, podatność została załatana od wersji Androida 4.2, gdzie każda udostępniona przez JavaScriptInterface metoda musi być jawnie oznaczona za pomocą adnotacji @JavascriptInterface a w pliku manifestu należy wskazać SDK większe niż 16.

<uses-sdk android:minSdkVersion="17"
android:targetSdkVersion="17"/>

Gdybyśmy zastosowali minSdkVersion mniejszą od 17, aby zapewnić uruchamianie aplikacji na większęj liczbie urządzeń należy liczyć się z tym, że w takim przypadku JavaScriptInterface jest nieaktywny i nie ma możliwości odwołania się do obiektów Javy z poziomu JavaScript.

W celu weryfikacji, czy aplikacja jest podatna na RCE poprzez JavaScriptInterface można użyć narzędzia do analizy aplikacji Android – Drozer. W tym celu należy doinstalować również odatkowy moduł checkjavascriptbridge.

dz> module install javascript
Processing jubax.javascript... Done.
Successfully installed 1 modules, 0 already installed

dz> run scanner.misc.checkjavascriptbridge -a pl.poc.jsi
Package: pl.poc.jsi
- vulnerable to WebView.addJavascriptInterface + targetSdkVersion=16

Należy jednak pamiętać, że istnieje kilka ukrytych ryzyk związanych z tą podatnością:

  • mimo zastosowania SDK >= 17, komponenty firm trzecich np. SDK sieci reklamowych, które dołączane są do aplikacji mobilnych mogą dalej wykorzystywać przestarzały, podatny kod skompilowany dla starszych wersji,  a od którego jesteśmy zależni i nie mamy możliwości modyfikacji. Dlatego tak ważny jest profesjonalny audyt kodu i wybór sieci reklam mobilnych nie tylko na podstawie kryterium zysków, ale również na podstawie pielęgnacji kodu pod kątem bezpieczeństwa. http://labs.bromium.com/2014/07/31/remote-code-execution-on-android-devices/
  • istnieją prognozy, że 95% urządzeń Android będzie odpornych na lukę Java-to-JavaScript dopiero na początku 2018 roku (sic!) Warto przeczytać artykuł poświęcony cyklom życia luk bezpieczeństwa na Android, który bazuje na analizie tej podatności. Szacuje się, że średni czas życia podatności na tej platformie to średnio 5 lat…
  • wprowadzenia adnotacji @JavascriptInterface (Android 4.2 API 17) do zablokowania użycia mechanizmu refleksji nie jest w stanie uchronić udostępnionej metody, przed złośliwym użyciem, jeśli została nieostrożnie zaimplementowana. Poniższy kod wskazuje na potencjalne wykorzystanie przez atakującego metody sendSMS().
@JavascriptInterface
public void sendSMS(String phonenumber, String text){
        android.telephony.SmsManager sm = SmsManager.getDefault();
        sm.sendTextMessage(phonenumber, null, text, null, null);
    }
    
webview.addJavascriptInterface(new SMSbridge(), "SMSbridge");

atakujący poprzez wstrzyknięcie JavaScript

<script>
SMSbridge.sendSMS(+123456789,'SMS PREMIUM');
</script>

wykorzysta urządzenie ofiary do wysyłania SMS-ów na podstawione numery.

2. Dostęp do zasobów lokalnych

Domyślnie klasa WebView może odwoływać się i przetwarzać pliki z lokalnych zasobów poprzez schemat file://

webView.loadUrl("file:///data/data/com.good.app");

w przypadku kodu aplikacji, w którym URI pobierany jest z Intencji, czyli jest możliwość wstrzyknięcia przez atakującego Intencji ze zmodyfikowanymi wartościami np.:

String url = getIntent().getStringExtra("URL");
webView.loadUrl(url);

zmodyfikowana Intencja wysłana przez złośliwą aplikację com.malicious.app,a odebrana przez filtr aplikacji com.good.app:

Intent intent = new Intent();
intent.putExtra("URI",“file:///data/data/com.malicious.app/evil.html”);
sendBroadcast(intent);

W pliku evil.html atakujący umieszcza złośliwy kod. Jest to przykład ataku XAS (CAS)- Cross Application Scripting.

Klasa WebSettings zapewnia jeszcze trzy metody, które w przypadku jawnego włączenia mogą zwiększyć skalę tego ataku:

  • setAllowFileAccessFromFileURLs – umożliwia plikowi evil.html wczytanemu poprzez schemat file:/// dostęp do lokalnych plików atakowanej aplikacji (np. bazy danych aplikacji, SharedPreferences itp.)
  • setAllowUniversalAccessFromFileURLs – umożliwia plikowi evil.html wczytanemu poprzez schemat file:/// dostęp do dowolnych zasobów, w tym wczytania zdalnych plików.

Innym ciekawym przykładem ataku typu XAS jest odkryta podatność we frameworku Apache Cordova (silnie bazuje na WebView) przedstawiona w https://securityintelligence.com/apache-cordova-phonegap-vulnerability-android-banking-apps/

3. Pluginy

WebView ma możliwość uruchomienia pluginów, które mogą zwiększyć powierzchnię ataku lub bezpośrednio przyczynić się do powstania krytycznej luki np. poprzez uruchomienie Flash’a

Domyślnie pluginy są w stanie OFF, a sama metoda setPluginState() została uznana za przestarzałą.

Zabezpieczanie WebView

Zamiast podsumowania, przedstawię szereg zaleceń mających ograniczyć ataki na aplikację mobilną poprzez WebView:

  1. używaj połączeń szyfrowanych i stosuj cert pinning
  2. zasoby zdalne, z którymi łaczy się aplikacja są zwykle znane i należy w czasie połączenia dokonywać walidacji, czy aplikacja łączy się z odpowiednim adresem URL poprzez nadpisanie  metody shouldOverrideUrlLoading() z klasy WebViewClient
    private class MyWebViewClient extends WebViewClient {
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
        private static final String LOG_TAG = "MWRLabs";
        Log.d(LOG_TAG, "[x] getHost: " + Uri.parse(url).getHost());
        Log.d(LOG_TAG, "[x] getScheme: " + Uri.parse(url).getScheme());
        Log.d(LOG_TAG, "[x] getPath: " + Uri.parse(url).getPath());
        if (Uri.parse(url).getHost().equals("labs.mwrinfosecurity.com")){return true;}
        return false;
      }
    }

    lub poprzez nadpisanie bardziej uniwersalnej metody shouldInterceptRequest() z tej samej klasy. Ta metoda dodatkowo umożliwia przechwytywanie zapytań XmlHttpRequest lub odwołań do zasobów realizowanych poprzez atrybut src ze znaczników HTML.

    @Override
      public WebResourceResponse shouldInterceptRequest (final WebView view, String url) {
        if (url.contains(".js")){return getWebResourceResponseFromString();}
        else {return super.shouldInterceptRequest(view, url);}
      }
  3. wyłącz obsługę JavaScript jeśli nie jest to konieczne – setJavaScriptEnabled(false) 
  4. nie używaj addJavascriptInterface() pomiędzy Javą a a JavaScriptem,a jeśli jest to niezbędne, to stosuj kompilację kodu na poziomie API 17 lub wyższym android:targetSdkVersion=”17″
  5. nie włączaj dodatkowych pluginów setPluginState(PluginState.OFF)
  6. ogranicz dostęp do zasobów poprzez WebView:
  • setAllowFileAccess(false) – blokada dostępu do lokalnych plików – wyłącznie lokalne zasoby aplikacji : file:///android_res i file:///android_asset,
  • setAllowFileAccessFromFileURLs(false) – blokada dostępu do innych plików nawet jeśli strona została wczytana z lokalnych zasobów ,
  • setAllowUniversalAccessFromFileURLs(false) – blokada dostępu do zasobów zdalnych np. z Internetu
  • setAllowContentAccess(false) – blokada dostępu do dostawców treści (content providers) na urządzeniu

 

Źródła:

  1. http://www.cis.syr.edu/~wedu/Research/paper/webview_acsac2011.pdf
  2. https://labs.mwrinfosecurity.com/blog/2012/04/23/adventures-with-android-webviews/
  3. https://labs.mwrinfosecurity.com/blog/2013/09/24/webview-addjavascriptinterface-remote-code-execution/
  4. https://www.cl.cam.ac.uk/~drt24/papers/spw15-07-Thomas.pdf

Bartosz Jerzman

 

 

 

 

 

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



Komentarze

  1. Maciej

    „Wprowadzenia adnotacji @JavascriptInterface (Android 4.2 API 17) do zablokowania użycia mechanizmu refleksji nie jest w stanie uchronić udostępnionej metody, przed złośliwym użyciem, jeśli została nieostrożnie zaimplementowana” – na czym polega tutaj ta nieostrożność, bo nie zrozumiałem? Z góry dziękuję za wyjaśnienie.

    Odpowiedz
    • Nieostrożność w tym wypadku została przedstawiona w przykładowym kodzie udostępnionym poniżej tego opisu. Pomimo tego, że wykorzystywane jest API >= 17 i stosowane są adnotacje @JavascriptInterface, które chronią aplikacje przed atakiem z wykorzystaniem refleksji Javy, to jednak adnotacje nie ochronią przed złośliwym użyciem metod obiektów Javy udostępnionych dla JavaScript. W przedstawionym przykładzie deweloper udostępnił metodę sendSMS(), która przyjmuje dwa parametry: numer telefonu i treść wiadomości. Atakujący, który kontroluje ruch sieciowy np. w sieci WiFi, może wykorzystać udostępnione metody np. do wysłania wiadomości SMS na inne numery niż przewidywali twórcy aplikacji poprzez wstrzyknięcie własnych tagów HTML z kodem JavaScript. Jeśli niezbędne jest zastosowanie Java-to-JavaScript Interface, to należy zwrócić szczególną uwagę na to, czy potencjalny atakujący nie jest w stanie użyć udostępnionych metod w inny niż zamierzony sposób. Takie miejsca są często jednymi ze słabych punktów aplikacji i podlegają szczególnym sprawdzeniom.

      Odpowiedz
      • Maciej

        Nie skumałem tak naprawdę, jak się ma SMSBridge do sendSMS, ale doczytałem to w dokumentacji Androida (zabrakło mi tu może sygnatury klasy na początku wycinka kodu). Ale dodatkowe uwagi również pomagają w zrozumieniu istoty problemu, więc dzięki za wyjaśnienie.

        Odpowiedz
  2. manto

    Świetny artykuł. Więcej takich poproszę.

    Odpowiedz
  3. Korsarz

    W Lollipop Webview jest w osobnym apie i można go wyłączyć, ale nie wiem czy to dużo daje.

    Odpowiedz

Odpowiedz na Maciej