Skip to content

Instantly share code, notes, and snippets.

@pvieito
Last active March 7, 2024 14:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pvieito/6224eed92c99b069f6401996c548d0e4 to your computer and use it in GitHub Desktop.
Save pvieito/6224eed92c99b069f6401996c548d0e4 to your computer and use it in GitHub Desktop.
Read EMV contactless debit and credit cards.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# PayPass.py is based on:
#
# - paypass.py
# Mert Sarica <mert.sarica@gmail.com>
# - ChasePayPassBlink.py
# Author: Brad Antoniewicz adam@algroup.co.uk
# - ChaAP.py
# Author: Adam Laurie <adam@algroup.co.uk>
#
'''PayPass.py - Pedro José Pereira Vieito © 2016
Read EMV contactless debit and credit cards.
Usage:
PayPass.py [-hv]
Options:
-v, --verbose Verbose mode
-h, --help Show this help
'''
from __future__ import print_function
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnection import CardConnection
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.Exceptions import CardRequestTimeoutException
import os
import getopt
import sys
import re
import string
import binascii
from hexdump import hexdump
from operator import *
from docopt import docopt
from colorama import init
from colorama import Fore, Back, Style
args = docopt(__doc__)
verbose = args["--verbose"]
Protocol = CardConnection.T0_protocol
AIDs = {
'VISA': [0xa0, 0x00, 0x00, 0x00, 0x03],
'VISA Debit/Credit': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10],
'VISA Credit': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x01],
'VISA Debit': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x02],
'VISA Electron': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x20, 0x10],
'VISA Interlink': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x30, 0x10],
'VISA Plus': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x10],
'VISA ATM': [0xa0, 0x00, 0x00, 0x00, 0x03, 0x99, 0x99, 0x10],
'MASTERCARD': [0xa0, 0x00, 0x00, 0x00, 0x04, 0x10, 0x10],
'Maestro': [0xa0, 0x00, 0x00, 0x00, 0x04, 0x30, 0x60],
'Maestro UK': [0xa0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01],
'Maestro TEST': [0xb0, 0x12, 0x34, 0x56, 0x78],
'Self Service': [0xa0, 0x00, 0x00, 0x00, 0x24, 0x01],
'American Express': [0xa0, 0x00, 0x00, 0x00, 0x25],
'ExpressPay': [0xa0, 0x00, 0x00, 0x00, 0x25, 0x01, 0x07, 0x01],
'Link': [0xa0, 0x00, 0x00, 0x00, 0x29, 0x10, 0x10],
'Alias AID': [0xa0, 0x00, 0x00, 0x00, 0x29, 0x10, 0x10],
}
# Define the APDUs used in this script
GET_RESPONSE = [0x00, 0xC0, 0x00, 0x00]
SELECT = [0x00, 0xA4, 0x04, 0x00]
CMD = [0x00, 0xB2, 0x01, 0x0C, 0x00]
# Define SW1 return values
SW1_RESPONSE_BYTES = 0x61
SW1_WRONG_LENGTH = 0x6c
SW12_OK = [0x90, 0x00]
SW12_NOT_SUPORTED = [0x6a, 0x81]
SW12_NOT_FOUND = [0x6a, 0x82]
SW12_COND_NOT_SAT = [0x69, 0x85]
def print_intro():
print("================================")
print(" PayPass Credit Card Reader ")
print("================================")
def try_cmd(card):
le = 0x00
apdu = CMD
response, sw1, sw2 = send_apdu(apdu)
if response:
print('[+]', card, 'detected')
return response
else:
print_verbose('[V] False positive, not a', card, 'card')
return False, 0, ''
def check_return(sw1, sw2):
if [sw1, sw2] == SW12_OK:
return True
return False
def send_apdu(apdu):
response, sw1, sw2 = cardservice.connection.transmit(apdu, Protocol)
if sw1 == SW1_WRONG_LENGTH:
apdu = apdu[:len(apdu) - 1] + [sw2]
return send_apdu(apdu)
if sw1 == SW1_RESPONSE_BYTES:
apdu = GET_RESPONSE + [sw2]
response, sw1, sw2 = cardservice.connection.transmit(apdu, Protocol)
return response, sw1, sw2
def select_aid(aid):
apdu = SELECT + [len(aid)] + aid + [0x00]
response, sw1, sw2 = send_apdu(apdu)
if check_return(sw1, sw2):
return True, response, sw1, sw2
else:
return False, [], sw1, sw2
def bruteforce_cc(data):
cc_response = binascii.hexlify(bytearray(data))
# Regex to find Track 2 Equivalent Data
pattern = re.compile("(?P<PAN>[\d]{16})d(?P<ED>[\d]{4})"
"(?P<SC>[\d]{3})(?P<DD>[\d]*)f")
match = re.search(pattern, cc_response)
return match.group("PAN"), match.group("ED")
def split_string(w, n):
for i in range(0, len(w), n):
yield w[i:i + n]
def print_ccdata(cc_number, expire_date):
print("[+] Primary Account Number (PAN):" + Style.BRIGHT +
Fore.GREEN, ' '.join(split_string(cc_number, 4)),
Fore.RESET + Style.RESET_ALL)
print("[+] Expiration Date:", Style.BRIGHT + Fore.YELLOW +
"{1}/{0}".format(*tuple(split_string(expire_date, 2))),
Fore.RESET + Style.RESET_ALL)
def isbinary(data):
index = 0
while index < len(data):
if data[index] < 0x20 or data[index] > 0x7e:
return True
index += 1
return False
def hexprint_verbose(bin):
if verbose:
hexprint(bin)
def print_verbose(*string):
if verbose:
print(*string)
def hexprint(int_array):
hexdump(str(bytearray(int_array)))
if __name__ == '__main__':
print_intro()
try:
try:
cardtype = AnyCardType()
print('[ ] Insert a card...')
cardrequest = CardRequest(timeout=20, cardType=cardtype)
cardservice = cardrequest.waitforcard()
cardservice.connection.connect(Protocol)
compatible = False
print('[ ] Connecting...')
for card in AIDs:
aid = AIDs[card]
print_verbose("[V] Trying", card + "...")
selected, response, sw1, sw2 = select_aid(aid)
if selected:
compatible = True
print_verbose("[V] Maybe", card, "detected?")
hexprint_verbose(response)
print_verbose("[V] Testing", card, "response")
cc_response = try_cmd(card)
if cc_response[0]:
hexprint_verbose(cc_response)
cc_number, expire_date = bruteforce_cc(cc_response)
print_ccdata(cc_number, expire_date)
break
if not compatible:
print("[x] Not PayPass compatible card")
print("[ ] Closed connection")
except CardRequestTimeoutException:
print('[+] Time-out: no card inserted during last 20s')
except KeyboardInterrupt:
print("[ ] Closed connection")
sys.exit()
@kraveironman2017
Copy link

What smartcard reader did you use when developing this program?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment