MagTek USB Card Reader Hacking 2

So back at it, now with some code to decode the common financial card:

Freebird_card

Let start out by showing the end results of scanning my Freebirds card:

# ./main.py
Please swipe your card now:

Raw String: %B???????????^FANATIC/FREEBIRDS^4211?;????????????=????????????

Card Holder: FANATIC/FREEBIRDS
Card Number: ????-????-????-????
Expiration Date: 11/42

As you can see we still have our raw string, this is being decoded from the code I used last time. However now I have the Card Holder’s name, Card Number, and Expiration date, this format was all outlined quite well on Wikipedia.

  • Start sentinel – one character (generally ‘%’)
  • Format code=”B” – one character (alpha only)
  • Primary account number (PAN) – up to 19 characters. Usually, but not always, matches the credit card number printed on the front of the card.
  • Field Separator – one character (generally ‘^’)
  • Name – two to 26 characters
  • Field Separator – one character (generally ‘^’)
  • Expiration date – four characters in the form YYMM.
  • Service code – three characters
  • Discretionary data – may include Pin Verification Key Indicator (PVKI, 1 character), PIN Verification Value (PVV, 4 characters), Card Verification Value or Card Verification Code (CVV or CVC, 3 characters)
  • End sentinel – one character (generally ‘?’)

Once I had this format it was just a matter of using some Python magic to make it happen:

# attempt to identify data types
start_sentinel = sdata[0]
format_code = sdata[1]

## FORMAT TYPE B
if start_sentinel + format_code == '%B':
    track1 = sdata[2:].split(';')[0]
    data = track1.split('^')

    # financial card
    try:
        card_no = data[0]
        name = data[1].strip()
        expyear = data[2][0:2]
        expmon = data[2][2:4]
        print 'Card Holder: %s' % name
        print 'Card Number: %s' % prettycard(card_no)
        print 'Expiration Date: %s/%s' % (expmon, expyear)
    except:
        pass

I also found a small bug in how I was handeling the card reader, you see the card reader has built in memory which will hold all swipes not yet processed. If for some reason a card was swiped when not expected (lets say when not running the script), it would be stored in memory and wait for next read (this would pile up with the new swipe).

To resolve this I run through the device loop just to clear the buffer:

def cleardevice():
    '''Clear the devices memory'''
    while True:
        try:
            results = device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize)
        except usb.core.USBError as e:
            if e.args[1] == 'Operation timed out' :
                break # timeout and swiped means we are done

I also noticed the device I have places a E in the format type if it had issues reading the card.

If a error is returned in track 1 I request a re-swipe:

# A format type of E is a error
while sdata[1] == 'E':
    print 'Failed to read card..'
    sdata = swipeme()

And the full code I wrote looks something like this (very sloppy I know):

#!/usr/bin/env python

# MagTek MSR100 Mini Swipe Card Reader
# Written By: Jeffrey Ness
#
# Some Thanks need to go out to
# http://www.micahcarrick.com/credit-card-reader-pyusb.html
# for helping me get on the right track

import usb.core
import usb.util
from re import findall

# MagTek Device MSR100 Mini Swipe
vendorid = 0x0801
productid = 0x0001

# Small function to return card numbers in blocks of 4
def prettycard(card_no):
    card = '-'.join(findall("[0-9][0-9][0-9][0-9]", card_no))
    return card

# Define our Character Map per Reference Manual
# http://www.magtek.com/documentation/public/99875206-17.01.pdf

chrMap = {
    4:  'a',
    5:  'b',
    6:  'c',
    7:  'd',
    8:  'e',
    9:  'f',
    10: 'g',
    11: 'h',
    12: 'i',
    13: 'j',
    14: 'k',
    15: 'l',
    16: 'm',
    17: 'n',
    18: 'o',
    19: 'p',
    20: 'q',
    21: 'r',
    22: 's',
    23: 't',
    24: 'u',
    25: 'v',
    26: 'w',
    27: 'x',
    28: 'y',
    29: 'z',
    30: '1',
    31: '2',
    32: '3',
    33: '4',
    34: '5',
    35: '6',
    36: '7',
    37: '8',
    38: '9',
    39: '0',
    40: 'KEY_ENTER',
    41: 'KEY_ESCAPE',
    42: 'KEY_BACKSPACE',
    43: 'KEY_TAB',
    44: ' ',
    45: '-',
    46: '=',
    47: '[',
    48: ']',
    49: '\\',
    51: ';',
    52: '\'',
    53: '`',
    54: ',',
    55: '.',
    56: '/',
    57: 'KEY_CAPSLOCK'
}

shiftchrMap = {
    4:  'A',
    5:  'B',
    6:  'C',
    7:  'D',
    8:  'E',
    9:  'F',
    10: 'G',
    11: 'H',
    12: 'I',
    13: 'J',
    14: 'K',
    15: 'L',
    16: 'M',
    17: 'N',
    18: 'O',
    19: 'P',
    20: 'Q',
    21: 'R',
    22: 'S',
    23: 'T',
    24: 'U',
    25: 'V',
    26: 'W',
    27: 'X',
    28: 'Y',
    29: 'Z',
    30: '!',
    31: '@',
    32: '#',
    33: '$',
    34: '%',
    35: '^',
    36: '&',
    37: '*',
    38: '(',
    39: ')',
    40: 'KEY_ENTER',
    41: 'KEY_ESCAPE',
    42: 'KEY_BACKSPACE',
    43: 'KEY_TAB',
    44: ' ',
    45: '_',
    46: '+',
    47: '{',
    48: '}',
    49: '|',
    51: ':',
    52: '"',
    53: '~',
    54: '<',
    55: '>',
    56: '?',
    57: 'KEY_CAPSLOCK'
}

# find our device by id
device = usb.core.find(idVendor=vendorid, idProduct=productid)
if device is None:
    raise Exception('Could not find USB Card Reader')

# remove device from kernel, this should stop
# reader from printing to screen and remove /dev/input
if device.is_kernel_driver_active(0):
    try:
        device.detach_kernel_driver(0)
    except usb.core.USBError as e:
        raise Exception("Could not detatch kernel driver: %s" % str(e))

# load our devices configuration
try:
    device.set_configuration()
    device.reset()
except usb.core.USBError as e:
    raise Exception("Could not set configuration: %s" % str(e))

# get device endpoint information
endpoint = device[0][(0,0)][0]

def cleardevice():
    '''Clear the devices memory'''
    while True:
        try:
            results = device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize)
        except usb.core.USBError as e:
            if e.args[1] == 'Operation timed out' :
                break # timeout and swiped means we are done

def swipeme():
    '''Swipe function'''
    swiped = False
    datalist = []
    cleardevice()

    print 'Please swipe your card now:'
    while True:
        try:
            results = device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize)
            datalist.append(results)
            swiped = True

        except usb.core.USBError as e:
            if e.args[1] == 'Operation timed out' and swiped:
                break # timeout and swiped means we are done

    # create a list of 8 bit bytes and remove
    # empty bytes
    ndata = []
    for d in datalist:
        if d.tolist() != [0, 0, 0, 0, 0, 0, 0, 0]:
            ndata.append(d.tolist())

    # parse over our bytes and create string to final return
    sdata = ''
    for n in ndata:
        # handle non shifted letters
        if n[2] in chrMap and n[0] == 0:
            sdata += chrMap[n[2]]
        # handle shifted letters
        elif n[2] in shiftchrMap and n[0] == 2:
            sdata += shiftchrMap[n[2]]

    return sdata

# run first swipe
sdata = swipeme()

# A format type of E is a error
while sdata[1] == 'E':
    print 'Failed to read card..'
    sdata = swipeme()

# print raw string always
print '\nRaw String: %s\n' % sdata

# attempt to identify data types
start_sentinel = sdata[0]
format_code = sdata[1]

## FORMAT TYPE B
if start_sentinel + format_code == '%B':
    track1 = sdata[2:].split(';')[0]
    data = track1.split('^')

    # financial card
    try:
        card_no = data[0]
        name = data[1].strip()
        expyear = data[2][0:2]
        expmon = data[2][2:4]
        print 'Card Holder: %s' % name
        print 'Card Number: %s' % prettycard(card_no)
        print 'Expiration Date: %s/%s' % (expmon, expyear)
    except:
        pass

One comment

  1. I have the MagTek BulleT card reader and did ah few swipes at work, now my only problem is that i dont no how to retrieve the credit card data from this device. I have a usb cable plugged from the device to my labtop and it doesn’t pop up like if you connect any other devices to your computer. Help is very much needed with this problem i have and i would highly appreciate it if anyone could help or point me in the right direction.

    Ty
    Grapemaster

Leave a Reply to grapemaster Cancel reply

Your email address will not be published. Required fields are marked *