Analiza aplikacji React Native

Reading time: 10 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Aby potwierdzić, czy aplikacja została zbudowana na frameworku React Native, wykonaj następujące kroki:

  1. Zmień nazwę pliku APK na plik zip i rozpakuj go do nowego folderu, używając polecenia cp com.example.apk example-apk.zip oraz unzip -qq example-apk.zip -d ReactNative.

  2. Przejdź do nowo utworzonego folderu ReactNative i zlokalizuj folder assets. Wewnątrz tego folderu powinieneś znaleźć plik index.android.bundle, który zawiera React JavaScript w zminimalizowanym formacie.

  3. Użyj polecenia find . -print | grep -i ".bundle$" aby wyszukać plik JavaScript.

Uwaga: Jeśli otrzymasz Android App Bundle (.aab) zamiast APK, najpierw wygeneruj uniwersalne APK, a następnie rozpakuj pakiet:

bash
# Get bundletool.jar and generate a universal APK set
java -jar bundletool.jar build-apks \
--bundle=app-release.aab \
--output=app.apks \
--mode=universal \
--overwrite

# Extract the APK and then unzip it to find assets/index.android.bundle
unzip -p app.apks universal.apk > universal.apk
unzip -qq universal.apk -d ReactNative
ls ReactNative/assets/

Javascript Code

Jeśli sprawdzając zawartość index.android.bundle znajdziesz kod JavaScript aplikacji (nawet jeśli jest zminimalizowany), możesz analizować go w celu znalezienia wrażliwych informacji i luk w zabezpieczeniach.

Ponieważ pakiet zawiera właściwie cały kod JS aplikacji, możliwe jest podzielenie go na różne pliki (potencjalnie ułatwiając jego inżynierię wsteczną) przy użyciu narzędzia react-native-decompiler.

Webpack

Aby dalej analizować kod JavaScript, możesz przesłać plik do https://spaceraccoon.github.io/webpack-exploder/ lub postępować zgodnie z tymi krokami:

  1. Utwórz plik o nazwie index.html w tym samym katalogu z następującym kodem:
html
<script src="./index.android.bundle"></script>
  1. Otwórz plik index.html w Google Chrome.

  2. Otwórz Pasek Narzędzi Dewelopera, naciskając Command+Option+J dla OS X lub Control+Shift+J dla Windows.

  3. Kliknij na "Sources" w Pasie Narzędzi Dewelopera. Powinieneś zobaczyć plik JavaScript podzielony na foldery i pliki, tworzące główny pakiet.

Jeśli znajdziesz plik o nazwie index.android.bundle.map, będziesz mógł analizować kod źródłowy w formacie niezmienionym. Pliki map zawierają mapowanie źródła, co pozwala na mapowanie zminifikowanych identyfikatorów.

Aby wyszukać wrażliwe dane uwierzytelniające i punkty końcowe, wykonaj następujące kroki:

  1. Zidentyfikuj wrażliwe słowa kluczowe do analizy kodu JavaScript. Aplikacje React Native często korzystają z usług stron trzecich, takich jak Firebase, punkty końcowe usługi AWS S3, klucze prywatne itp.

  2. W tym konkretnym przypadku zaobserwowano, że aplikacja korzysta z usługi Dialogflow. Wyszukaj wzór związany z jej konfiguracją.

  3. Miałeś szczęście, że wrażliwe dane uwierzytelniające zakodowane na sztywno zostały znalezione w kodzie JavaScript podczas procesu rekonesansu.

Szybkie polowanie na sekrety/punkty końcowe w pakietach

Te proste grepy często ujawniają interesujące wskaźniki nawet w zminifikowanym JS:

bash
# Common backends and crash reporters
strings -n 6 index.android.bundle | grep -Ei "(api\.|graphql|/v1/|/v2/|socket|wss://|sentry\.io|bugsnag|appcenter|codepush|firebaseio\.com|amplify|aws)"

# Firebase / Google keys (heuristics)
strings -n 6 index.android.bundle | grep -Ei "(AIza[0-9A-Za-z_-]{35}|AIzaSy[0-9A-Za-z_-]{33})"

# AWS access key id heuristic
strings -n 6 index.android.bundle | grep -E "AKIA[0-9A-Z]{16}"

# Expo/CodePush deployment keys
strings -n 6 index.android.bundle | grep -Ei "(CodePush|codepush:\\/\\/|DeploymentKey)"

# Sentry DSN
strings -n 6 index.android.bundle | grep -Ei "(Sentry\.init|dsn\s*:)"

Jeśli podejrzewasz frameworki aktualizacji Over-The-Air, poszukaj również:

  • kluczy wdrożeniowych Microsoft App Center / CodePush
  • konfiguracji Expo EAS Updates (expo-updates, expo\.io, certyfikaty podpisujące)

Zmień kod JS i odbuduj

W tym przypadku zmiana kodu jest łatwa. Musisz tylko zmienić nazwę aplikacji, aby używała rozszerzenia .zip i wyodrębnić ją. Następnie możesz zmodyfikować kod JS wewnątrz tego pakietu i odbudować aplikację. To powinno wystarczyć, aby umożliwić wstrzyknięcie kodu do aplikacji w celach testowych.

Hermes bytecode

Jeśli pakiet zawiera Hermes bytecode, nie będziesz w stanie uzyskać dostępu do kodu Javascript aplikacji (nawet do wersji zminimalizowanej).

Możesz sprawdzić, czy pakiet zawiera Hermes bytecode, uruchamiając następujące polecenie:

bash
file index.android.bundle
index.android.bundle: Hermes JavaScript bytecode, version 96

Jednak możesz użyć narzędzi hbctool, zaktualizowanych forków hbctool, które obsługują nowsze wersje bajtowego kodu, hasmer, hermes_rs (biblioteka/API w Rust), lub hermes-dec, aby rozłożyć bajtowy kod i także dekompilować go do pewnego kodu JS. Na przykład:

bash
# Disassemble and re-assemble with hbctool (works only for supported HBC versions)
hbctool disasm ./index.android.bundle ./hasm_out
# ...edit ./hasm_out/**/*.hasm (e.g., change comparisons, constants, feature flags)...
hbctool asm   ./hasm_out ./index.android.bundle

# Using hasmer (focus on disassembly; assembler/decompiler are WIP)
hasmer disasm ./index.android.bundle -o hasm_out

# Using hermes-dec to produce pseudo-JS
hbc-disassembler ./index.android.bundle /tmp/my_output_file.hasm
hbc-decompiler   ./index.android.bundle /tmp/my_output_file.js

Tip: Projekt open-source Hermes dostarcza również narzędzia deweloperskie, takie jak hbcdump, w określonych wersjach Hermes. Jeśli zbudujesz odpowiadającą wersję Hermes używaną do produkcji pakietu, hbcdump może zrzucić funkcje, tabele ciągów i bajtowy kod do głębszej analizy.

Zmień kod i odbuduj (Hermes)

Idealnie powinieneś być w stanie zmodyfikować zdisassemblowany kod (zmieniając porównanie, wartość lub cokolwiek, co musisz zmodyfikować), a następnie odbudować bajtowy kod i odbudować aplikację.

  • Oryginalne hbctool wspiera zdisassemblowanie pakietu i odbudowę po zmianach, ale historycznie wspierało tylko starsze wersje bajtowego kodu. Forki utrzymywane przez społeczność rozszerzają wsparcie na nowsze wersje Hermes (w tym mid-80s–96) i często są najbardziej praktyczną opcją do łatania nowoczesnych aplikacji RN.
  • Narzędzie hermes-dec nie wspiera odbudowy bajtowego kodu (tylko dekompilator/zdisassembler), ale jest bardzo pomocne w nawigacji po logice i zrzucaniu ciągów.
  • Narzędzie hasmer ma na celu wspieranie zarówno zdisassembly, jak i assembly dla wielu wersji Hermes; assembly wciąż się rozwija, ale warto spróbować na niedawnym bajtowym kodzie.

Minimalny workflow z assemblerami podobnymi do hbctool:

bash
# 1) Disassemble to HASM directories
hbctool disasm assets/index.android.bundle ./hasm

# 2) Edit a guard or feature flag (example: force boolean true)
#    In the relevant .hasm, replace a LoadConstUInt8 0 with 1
#    or change a conditional jump target to bypass a check.

# 3) Reassemble into a new bundle
hbctool asm ./hasm assets/index.android.bundle

# 4) Repack the APK and resign
zip -r ../patched.apk *
# Align/sign as usual (see Android signing section in HackTricks)

Zauważ, że format bajtów Hermes jest wersjonowany, a assembler musi odpowiadać dokładnemu formatowi na dysku. Jeśli otrzymasz błędy formatu, przełącz się na zaktualizowany fork/alternatywę lub odbuduj odpowiadające narzędzia Hermes.

Analiza dynamiczna

Możesz spróbować dynamicznie analizować aplikację, używając Frida, aby włączyć tryb dewelopera aplikacji React i użyć react-native-debugger, aby się do niej podłączyć. Jednak do tego potrzebujesz źródła aplikacji. Więcej informacji na ten temat znajdziesz w https://newsroom.bedefended.com/hooking-react-native-applications-with-frida/.

Włączanie wsparcia dewelopera w wersji release z Frida (ostrzeżenia)

Niektóre aplikacje przypadkowo dostarczają klasy, które umożliwiają przełączanie wsparcia dewelopera. Jeśli są obecne, możesz spróbować wymusić, aby getUseDeveloperSupport() zwracało true:

javascript
// frida -U -f com.target.app -l enable-dev.js
Java.perform(function(){
try {
var Host = Java.use('com.facebook.react.ReactNativeHost');
Host.getUseDeveloperSupport.implementation = function(){
return true; // force dev support
};
console.log('[+] Patched ReactNativeHost.getUseDeveloperSupport');
} catch (e) {
console.log('[-] Could not patch: ' + e);
}
});

Ostrzeżenie: W poprawnie zbudowanych wersjach release, DevSupportManagerImpl i pokrewne klasy tylko do debugowania są usuwane, a przełączanie tej flagi może spowodować awarię aplikacji lub nie mieć żadnego efektu. Gdy to działa, zazwyczaj możesz wywołać menu dewelopera i podłączyć debugery/inspektory.

Przechwytywanie sieci w aplikacjach RN

React Native Android zazwyczaj polega na OkHttp w tle (poprzez natywny moduł Networking). Aby przechwycić/obserwować ruch na urządzeniu bez roota podczas testów dynamicznych:

  • Użyj proxy systemowego + zaufaj użytkownikowi CA lub użyj innych ogólnych technik omijania TLS w Androidzie.
  • Wskazówka specyficzna dla RN: jeśli aplikacja przypadkowo pakuje Flipper w wersji release (narzędzia debugowania), wtyczka Flipper Network może ujawniać żądania/odpowiedzi.

Aby uzyskać ogólne techniki przechwytywania i omijania pinów w Androidzie, zapoznaj się z:

Make APK Accept CA Certificate

Objection Tutorial

Ostatnie problemy w popularnych bibliotekach RN (na co zwrócić uwagę)

Podczas audytowania modułów stron trzecich widocznych w pakiecie JS lub bibliotekach natywnych, sprawdź znane luki i zweryfikuj wersje w package.json/yarn.lock.

  • react-native-mmkv (Android): wersje przed 2.11.0 rejestrowały opcjonalny klucz szyfrowania w logach Androida. Jeśli ADB/logcat jest dostępny, sekrety mogą być odzyskane. Upewnij się, że masz >= 2.11.0. Wskaźniki: użycie react-native-mmkv, komunikaty logów wspominające o inicjalizacji MMKV z szyfrowaniem. CVE-2024-21668.
  • react-native-document-picker: wersje < 9.1.1 były podatne na przejście ścieżki w Androidzie (wybór pliku), naprawione w 9.1.1. Waliduj dane wejściowe i wersję biblioteki.

Szybkie kontrole:

bash
grep -R "react-native-mmkv" -n {index.android.bundle,*.map} 2>/dev/null || true
grep -R "react-native-document-picker" -n {index.android.bundle,*.map} 2>/dev/null || true
# If you also have the node_modules (rare on release): grep -R in package.json / yarn.lock

Odniesienia

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks