Testy aplikacji na Androida: zmiana sposobu działania aplikacji przez rekompilację pliku APK

27 marca 2015, 17:15 | Teksty | komentarzy 5
: zin o bezpieczeństwie - pobierz w pdf/epub/mobi.

Wstęp

W ostatnich latach praca pentestera coraz częściej składa się też z testów aplikacji mobilnych. Czasem są one tylko cienką nakładką na strony internetowe, kiedy to testowanie ich niewiele różni się od webaplikacji, ale w wielu przypadkach są pełnoprawnymi, dużymi aplikacjami. W przeciwieństwie do typowych aplikacji webowych, gdzie logika zaimplementowana jest głównie po stronie serwera (choć to też przestaje być prawdę od pewnego czasu, gdyż coraz więcej dzieje się po stronie Javascriptu), w aplikacjach mobilnych mamy bezpośredni dostęp do plików wykonywalnych.

Czasem logika działania tychże aplikacji utrudnia bądź uniemożliwia testowanie. Przykładowo:

  • Przy uruchomieniu aplikacja sprawdza, czy telefon jest zrootowany,
  • Aplikacja definiuje własne metody kontroli ważności certyfikatów HTTPS, odmawiając współdziałania z proxy.

Oczywiście nie chcemy „odrootowywać” telefonu na potrzeby jednej aplikacji czy rezygnować z używania proxy, dlatego musimy znaleźć inny sposób, by poradzić sobie z problemem. Zasadniczo możemy zastosować jedno z trzech podejść:

  • Przeanalizować sposób działania uciążliwej funkcji i odnaleźć w niej błąd (np. sprawdzanie czy telefon jest zrootowany może być niewystarczająco dobre),
  • Zmienić w sposób dynamiczny sposób działania aplikacji (np. przez framework Xposed czy Cydia Substrate/Cycript w przypadku iOS),
  • Zdekompilować aplikację, podmienić działanie złośliwej metody i zbudować ponownie plik .apk,

W tym artykule zajmiemy się wyłącznie trzecim sposobem. Do pozostałych (w szczególności do drugiego) prawdopodobnie jeszcze na łamach Sekuraka wrócimy.

Na potrzeby niniejszego artykułu przygotowałem prostą aplikację androidową, której jedynym celem jest próba pobrania pewnego pliku przez HTTPS. W domyślnej konfiguracji jednak się to nie uda (Rys 1.). W kolejnych rozdziałach prześledzimy działanie aplikacji (o której będę dalej pisał jako „testowa aplikacja”) i zmienimy jej kod w taki sposób, by wykonał się poprawnie.

Rys 1. Testowa aplikacja twierdzi, że certyfikat SSL jest niepoprawny

Rys 1. Testowa aplikacja twierdzi, że certyfikat SSL jest niepoprawny

Zanim zaczniemy…

W dalszej części tekstu zakładam, że do przeprowadzenia kolejnych operacji używamy dystrybucji linuksowej Kali, która zawiera w repozytorium (prawie) wszystkie potrzebne pakiety. Oczywiście opisane niżej kroki można wykonywać również na innych systemach, może jednak być wymagana ręczna instalacja narzędzi.

Krok 1. Pobranie pliku APK

Zacznijmy od tego, że musimy mieć plik APK, by mieć na czym przeprowadzać zmiany. W przypadku przeprowadzania testów penetracyjnych, zwykle podsyła je sam klient. Czasem jednak jesteśmy proszeni o instalację aplikacji bezpośrednio z Google Play. W takim wypadku, plik APK możemy pobrać na jeden z dwóch sposobów:

  • Ustawiamy proxy w urządzeniu z Androidem, po czym pobieramy aplikację przez sklep Play. W jednej z odpowiedzi serwera na pewno znajdziemy pełną treść pliku APK,
  • Jeśli mamy roota, plik APK można pobrać bezpośrednio z katalogu /data/app na urządzeniu.

My mamy konkretnego linka do aplikacji testowej, którą musimy najpierw pobrać:

Krok 2. Dekompilacja i poszukiwanie „winnej” metody

Problem z testową aplikacją jest taki, że próbuje pobrać plik przez HTTPS, jednak certyfikat SSL nie przechodzi walidacji. Możemy domniemywać, że gdzieś w kodzie znajduje się metoda odpowiedzialna za weryfikację poprawności certyfikatów. W tym kroku spróbujemy ją odnaleźć.

Potrzebować będziemy dwóch narzędzi: dex2jar oraz JD-GUI. W dystrybucji Kali ten pierwszy pakiet możemy ściągnąć bezpośrednio z repozytorium:

JD-GUI też znajduje się w repozytorium, ale polecam jednak ściągnąć najnowszą wersję z oficjalnej strony aplikacji:

APK (Android application package) – to format plików używanych do dystrybucji aplikacji na Androida. Zawierają one wszystkie elementy niezbędne do prawidłowego działania aplikacji, takie jak: certyfikaty, podpisy cyfrowe, zasoby (resources/assets), biblioteki i – przede wszystkim – skompilowany kod aplikacji w pliku classes.dex. W rzeczywistości pliki APK są zwykłym archiwum zip, które można rozpakować dowolnym archiwizatorem.

Plik classes.dex zawiera skompilowany kod aplikacji w postaci zrozumiałej dla wirtualnej maszyny Androida (zwanej Dalvik). Narzędzie dex2jar służy do zamiany pliku dex do pliku jar, który z kolei będzie można czytać przez dekompilator.

JD-GUI – to dekompilator plików .jar. Użyjemy go do wygodnego przeglądania kodu aplikacji androidowej.

Wyciągnijmy teraz plik classes.dex z pliku APK, a następnie zamieńmy go do postaci JAR-a.

Narzędzie d2j-dex2jar można uruchomić bezpośrednio na plik apk; nie ma potrzeby wyciągać pliku classes.dex. Plik .dex będzie nam jednak potrzebny później do rekompilacji źródeł, dlatego wypakowałem go na samym początku.

Jak widzimy, utworzony został plik classes-dex2jar.jar. Odpalmy więc dekompilator Javy i zobaczmy, co jest w środku (Rys 2.).

Rys 2. Domyślne okno JD-GUI

Rys 2. Domyślne okno JD-GUI

Z lewej strony widzimy listę klas, zaś po kliknięciu na jednej z nich, jej zdekompilowane źródło pojawia się w głównej części aplikacji. Jak widać, aplikacja testowa jest mało rozbudowana, bowiem składa się wyłącznie z dwóch klas. Oczywiście w rzeczywistych przypadkach najczęściej jest ich o wiele więcej i samo przeglądanie kodu w poszukiwaniu interesującej nas funkcji może zająć sporo czasu.

Szybko możemy znaleźć, że klasa pl.sekurak.ssltest.a zawiera metodę odpowiedzialną za sprawdzanie poprawności certyfikatów SSL.

Okazuje się, że aplikacja sprawdza, czy nazwa wystawcy certyfikatu to "CN=sekurakowy.pl,O=sekurak.pl,C=PL". Oczywiście moglibyśmy na potrzeby testów wystawić certyfikat z taką nazwą. Spróbujemy jednak zmodyfikować aplikację w taki sposób, aby przepuszczała każdy certyfikat, niezależnie od jego parametrów.

Z tego kroku musimy zapamiętać, że metoda, której działanie będziemy chcieli zmienić, znajduje się w klasie pl.sekurak.ssltest.a i nazywa się checkServerTrusted. Logika działania metody jest taka, że jeśli certyfikat jest poprawny, metoda nie zwraca nic; zaś w przeciwnym wypadku rzucany jest wyjątek.

Krok 3. Rekompilacja i podpisanie pliku APK

Aby zacząć wprowadzać zmiany w kodzie pliku classes.dex, musimy najpierw skonwertować do formatu smali.

Smali – to asembler/disasembler plików .dex, którego składnia opiera się na Jasmin. Zestaw narzędzi składa się z dwóch aplikacji: smali – do asemblacji (smali->dex) oraz baksmali (dex->smali).

Zaczynamy od zainstalowania narzędzi smali:

Następnie konwertujemy plik classes.dex do postaci plików smali:

Narzędzia smali/baksmali są w dystrybucji Kali trochę nieszczęśliwie skonfigurowane. Dlatego konieczne jest dodawanie $PWD/ (aktualny katalog roboczy), by brane pod uwagę były pliki z obecnego katalogu.

W wyniku wykonania powyższego polecenia, utworzony zostanie katalog smali składający się z wielu folderów oraz plików o rozszerzeniu .smali, odpowiadających klasom w pliku classes.dex (tym samym, które wcześniej oglądaliśmy z poziomu JD-GUI).

Pamiętamy, że chcieliśmy edytować klasę pl.sekurak.ssltest.a. Dlatego przyjrzymy się zawartości pliku smali/pl/sekurak/ssltest/a.smali:

Powyższy kod odpowiada dokładnie temu,co wkleiłem wcześniej w postaci źródła Javy; różnica polega na tym, że teraz mamy kod w postaci asemblera smali. Zmodyfikujmy kod metody checkServerTrusted w taki sposób, aby natychmiast kończyła swoje działanie. Powinna więc zawierać wyłącznie dyrektywę return-void.

Teraz musimy z powrotem zamienić pliki smali do classes.dex. Robimy to poleceniem smali:

A następnie władowujemy nowy classes.dex do pliku APK:

Pliki APK są podpisane cyfrowo. Skoro zmieniliśmy zawartość pliku, podpis cyfrowy również się zmieni. Na szczęście w ramach dex2jar istnieje narzędzie, które pozwala szybko podpisać plik APK: d2j-apk-sign:

W wyniku wykonywania tego polecenia został utworzony nowy plik: pl.sekurak.ssltest-signed.apk. Pozostaje go tylko zainstalować na urządzeniu.

Krok 4. Instalacja nowego APK

Instalujemy teraz nowy plik apk na urządzeniu z Androidem. Musimy jednak wpierw odinstalować poprzednią wersję aplikacji testowej, ponieważ Android wykryje, że zmienił się podmiot podpisujący aplikację (poprzednio był to deweloper aplikacji, teraz d2j-apk-sign; Rys 3.).

Rys 3. Android odmawia aktualizacji aplikacji z innym podmiotem podpisującym

Rys 3. Android odmawia aktualizacji aplikacji z innym podmiotem podpisującym

Po odinstalowaniu i ponownej instalacji aplikacji, możemy wreszcie uruchomić ją ponownie. Powinniśmy na ekranie zobaczyć to samo co na Rys 4.

Rys 4. Działanie aplikacji testowej po rekompilacji

Rys 4. Działanie aplikacji testowej po rekompilacji

(wyświetlana jest zawartość pliku spod adresu https://raw.githubusercontent.com/securityMB/random-stuff/master/apk-file.txt)

Podsumowanie

W tekście przedstawiłem jak w prosty sposób można zmienić działanie aplikacji na Androida. Ogólnie proces rekompilacji aplikacji dla własnych potrzeb składa się z następujących elementów:

  1. Pobranie pliku .apk,
  2. Dekompilacja pliku .apk w celu odnalezienia metody, której działanie chcemy zmienić,
  3. Deasemblacja skompilowanego pliku classes.dex do plików smali,
  4. Modyfikacja wybranego pliku/wybranych plików smali,
  5. Ponowne skompilowanie pliku classes.dex i utworzenie nowego pliku .apk,
  6. Ponowny podpis pliku .apk.

Wkrótce na Sekuraku przedstawimy inne podejście do tego samego problemu – tj. jak zmienić działanie aplikacji bez modyfikacji oryginalnego pliku APK.

–Michał Bentkowski, prowadzi bloga, pentester w Securitum.

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



Komentarze

  1. mam nizsze wyksztalcenie

    proste, gorzej jak apka jest obfuskowana i posiada z 500 klas ;)

    Odpowiedz
    • ader

      Nee – jak wiesz czego szukać to znajdziesz to w 2 minuty (nazwy Javowych klas i metod nie mogą zostać zmienione)

      Odpowiedz
  2. oi

    ader, może podpowiesz na jakie klasy warto zwrócić uwagę? ;)

    Odpowiedz
    • Michał Bentkowski

      Warto zacząć właśnie od szukania metody checkServerTrusted lub po nazwie klasy SSLSocketFactory.

      Odpowiedz
  3. Radosław

    A jak exploita dodać do jakiejś aplikacj na przykład

    Odpowiedz

Odpowiedz