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

pentesting-iso-8583-payment-sockets.md (6759B)


      1 ---
      2 title: "Pentesting ISO 8583 Payment Sockets"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/pentesting-iso-8583-payment-sockets.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-iso-8583-payment-sockets.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Pentesting ISO 8583 Payment Sockets
     14 
     15 ## Overview
     16 
     17 Some Android POS terminals and payment apps do **not** send payment, refund, or void traffic over HTTP. Instead, they authenticate over a **raw TLS socket** and then exchange **ISO 8583** frames directly with the processor. In these cases, normal Burp-style API testing misses the real payment path.<sup>[[1]](#references)</sup>
     18 
     19 This attack surface is especially relevant when reversing Android POS apps because the mobile APK usually exposes the socket hostname/port, debug toggles, and the pre-auth bootstrap flow.<sup>[[1]](#references)</sup>
     20 
     21 ## Quick protocol refresher
     22 
     23 Per the ISO 8583 message structure, a message is built from:<sup>[[2]](#references)</sup>
     24 
     25 1. **Message type**
     26 2. **One or two 64-bit bitmaps** indicating which fields are present<sup>[[3]](#references)</sup>
     27 3. **Data elements** in bitmap order
     28 
     29 In real deployments there is often also a **transport-specific prefix/header** before the ISO 8583 payload, for example:
     30 
     31 - 4 ASCII digits with the frame length
     32 - a literal marker such as `ISO`
     33 - proprietary auth/bootstrap frames before ISO 8583 is accepted
     34 
     35 Useful fields during testing:
     36 
     37 - **DE2**: PAN/card number
     38 - **DE4**: amount
     39 - **DE11**: STAN
     40 - **DE37**: RRN
     41 - **DE39**: response code (`00` usually means approved)
     42 - **DE41**: terminal ID
     43 - **DE42**: merchant ID
     44 - **DE55**: ICC/EMV data
     45 
     46 ## Reconstructing the hidden payment channel
     47 
     48 If payments do not appear in Burp or the app's REST/API traffic, pivot into the APK and look for:<sup>[[1]](#references)</sup>
     49 
     50 - raw `Socket` / `SSLSocket` usage
     51 - hardcoded processor hostnames and ports
     52 - flags such as `debugMode=false`
     53 - separate REST login + socket auth flows
     54 - code that prints raw request/response hex into Android logs
     55 
     56 A practical workflow is:
     57 
     58 1. Decompile the APK and identify the payment socket endpoint.
     59 2. Enable latent debug logging if present, then rebuild/sign/reinstall the APK.
     60 3. Use `adb logcat` to capture raw frame hex instead of trying to MITM the TLS socket.
     61 4. Recreate any bootstrap flow first (for example: REST login → JWT → socket `AUTH` frame → `AUTHOK`).
     62 5. Replay or mutate ISO 8583 frames over your own client.
     63 
     64 Example log capture patterns:<sup>[[4]](#references)</sup>
     65 
     66 ```bash
     67 adb logcat | grep -iE 'iso|8583|auth|socket|tls'
     68 adb logcat "PaymentSocket:D *:S"
     69 ```
     70 
     71 A common proprietary bootstrap observed in POS apps is:
     72 
     73 ```text
     74 [length:4 ASCII] + AUTH + [jwt_length:4 ASCII] + JWT
     75 [length:4 ASCII] + raw ISO 8583 bytes
     76 ```
     77 
     78 ## What to test
     79 
     80 ### Authentication and state-machine checks
     81 
     82 - Connect and send a valid ISO 8583 frame **before** any auth/bootstrap frame.
     83 - Send malformed or truncated `AUTH` frames and check whether the server still transitions to an authenticated state.
     84 - Reuse a JWT from merchant A on a fresh socket and verify whether the socket session is actually bound to that merchant, terminal, and device.
     85 
     86 If unauthenticated requests are processed, look for **ghost transactions**: processor-side state changes with no merchant history or audit entry.<sup>[[1]](#references)</sup>
     87 
     88 ### Replay and duplicate detection
     89 
     90 Capture a valid financial request and replay it:
     91 
     92 - immediately
     93 - after reconnecting
     94 - after the deduplication/cache window expires
     95 - with the same **DE11** and **DE37**
     96 
     97 Weak processors only cache duplicates briefly and later re-accept the same frame as a new charge. Persistent duplicate detection should bind at least merchant, terminal, amount, card, STAN, RRN, and transaction lifecycle.<sup>[[1]](#references)</sup>
     98 
     99 ### Cross-merchant / object-ownership flaws
    100 
    101 Treat **DE37 (RRN)** as an object reference and test it like an IDOR/BOLA primitive:
    102 
    103 - authenticate as merchant B
    104 - submit a void/refund referencing merchant A's RRN
    105 - modify **DE41** and **DE42** independently from the authenticated session
    106 - try forged or non-existent RRNs such as `000000000000`
    107 
    108 If the backend trusts the RRN alone, one merchant may void or refund another merchant's transactions.<sup>[[1]](#references)</sup>
    109 
    110 ### Bypassing terminal-only checks
    111 
    112 Do not trust POS UI validations.
    113 
    114 If the terminal locally blocks a void/refund because the wrong card was inserted, but the app already generated the raw ISO 8583 frame, recover that frame from logs and send it directly. Backend approval indicates the processor validates only the transaction reference/format, not the original card identity.<sup>[[1]](#references)</sup>
    115 
    116 ### Business-logic mutations
    117 
    118 High-value mutations include:<sup>[[1]](#references)</sup>
    119 
    120 - increase **DE4** above the original amount
    121 - zero amount `000000000000`
    122 - negative/signed encoding edge cases if the implementation supports them
    123 - currency changes mid-flow
    124 - MTI confusion such as turning a valid reversal/void into another reversal/advice type
    125 
    126 Watch both the ISO 8583 response and the merchant/admin dashboard state.
    127 
    128 ### Parser robustness
    129 
    130 ISO 8583 parsers are easy to desynchronise when proprietary field encodings are mixed with LLVAR/LLLVAR and binary TLVs.
    131 
    132 Useful fuzz cases:
    133 
    134 - length indicator larger than real field data
    135 - length indicator shorter than real field data
    136 - set a bitmap bit but omit the corresponding field bytes
    137 - include field bytes while clearing the bitmap bit
    138 - mutate TLVs inside **DE55**
    139 
    140 Expected failures include parser crashes, field shifts, approvals on malformed requests, and inconsistent dashboard state.<sup>[[1]](#references)</sup>
    141 
    142 ## Minimal socket client skeleton
    143 
    144 ```python
    145 jwt = http_login(login_url, username, password, serial)
    146 sock = open_tls_socket(host, port)
    147 payload = b"AUTH" + f"{len(jwt):04d}".encode() + jwt.encode()
    148 sock.sendall(f"{len(payload):04d}".encode() + payload)
    149 assert sock.recv(1024).startswith(b"AUTHOK")
    150 sock.sendall(frame)
    151 print(sock.recv(4096))
    152 ```
    153 
    154 ## References
    155 
    156 - [1] [ISO 8583 Under Fire: Finding Vulnerabilities in a Payment Socket](https://m4kr0.vercel.app/posts/iso-8583-under-fire-finding-vulnerabilities-in-a-payment-socket/)
    157 - [2] [ISO 8583:2023 message structure overview](https://standards.iteh.ai/catalog/standards/iso/b2a1591e-21dd-4f26-934c-415b4952957c/iso-8583-2023)
    158 - [3] [jPOS bitmap packing notes](https://jpos.org/docs/tutorial/iso-packager/bitmap/)
    159 - [4] [Android logcat command-line tool](https://developer.android.com/tools/logcat?hl=en)