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)