# MagTek USB Card Reader Hacking

So just the other day I received my MagTek MSR100 in the mail, this unit only cost me about \$20 and I have to say I’m very satisfied with it. After opening the box it was delivered in I quickly noticed no documentation was provided. No worries I figured, this will make hacking at it that much more fun.

I started out by connecting the USB device to my Gentoo Linux laptop and swiped a card, I noticed on my console prompt the card data was spewed out. That is because this device acts like a HID Keyboard:

# lsusb -vv | grep "Mag-Tek Mini Swipe" -A50 | grep bInterfaceProtocol
bInterfaceProtocol      1 Keyboard


With this information confirmed I figured I would approach it with the same method used in one my older post Python Device Hacking (Keyboard).

Using the k() function outlined in the Keyboard hacking post mentioned above, I received the following while scanning my Pluckers card:

>>> k()
KEY_LEFTSHIFT
KEY_5
KEY_LEFTSHIFT
KEY_B
KEY_7
KEY_2
KEY_3
KEY_1
KEY_5
KEY_3
KEY_7
KEY_7
KEY_1
KEY_0
KEY_5
KEY_6
KEY_6
KEY_2
KEY_3
KEY_2
KEY_5
KEY_0
KEY_4
KEY_7
KEY_6
KEY_7
KEY_9
KEY_1
KEY_3
KEY_9
KEY_7
KEY_0
KEY_3
KEY_8
KEY_LEFTSHIFT
KEY_SLASH
KEY_SEMICOLON
KEY_2
KEY_2
KEY_1
KEY_6
KEY_5
KEY_0
KEY_0
KEY_1
KEY_1
KEY_1
KEY_6
KEY_2
KEY_3
KEY_6
KEY_7
KEY_6
KEY_EQUAL
KEY_1
KEY_LEFTSHIFT
KEY_SLASH


This data looked similar to the results I seen on screen, but not quite.. and printing on the screen at the same time was pretty ugly:

%B723153771056323250476791397088?;221350011623672=1?


At that point I figured it was time for a better approach, and where best to look than our friend Google? A quick search brought up a article describing a similar project, unfortunately our devices must differ as his code didn’t quite work with my device. However this article showed me the PyUSB module.

Using the PyUSB module I whipped up a quick script:

>>> import usb.core
>>> import usb.util
>>>
>>> vendorid = 0x0801
>>> productid = 0x0001
>>> device.detach_kernel_driver(0)
>>> endpoint = device[0][(0,0)][0]
>>>
array('B', [2, 0, 34, 0, 0, 0, 0, 0])
array('B', [0, 0, 0, 0, 0, 0, 0, 0])
array('B', [2, 0, 5, 0, 0, 0, 0, 0])
array('B', [0, 0, 0, 0, 0, 0, 0, 0])
array('B', [0, 0, 36, 0, 0, 0, 0, 0])


At this point I got stuck for a bit, you see the data above was not in ASCII format and did not match my earlier keyboard map. I did figure out the results by comparing onscreen output to my PyUSB output:

I took the known good data (from on screen):

%B723153771056323250476791397088?;221350011623672=1?


Comparing against PyUSB I noticed the 3rd column appeared to be the bits of data I needed:

[2, 0, 34, 0, 0, 0, 0, 0] = %
[2, 0, 5, 0, 0, 0, 0, 0]  = B
[0, 0, 36, 0, 0, 0, 0, 0] = 7
[0, 0, 31, 0, 0, 0, 0, 0] = 2
[0, 0, 32, 0, 0, 0, 0, 0] = 3
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[0, 0, 34, 0, 0, 0, 0, 0] = 5
[0, 0, 32, 0, 0, 0, 0, 0] = 3
[0, 0, 36, 0, 0, 0, 0, 0] = 7
[0, 0, 36, 0, 0, 0, 0, 0] = 7
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[0, 0, 39, 0, 0, 0, 0, 0] = 0
[0, 0, 34, 0, 0, 0, 0, 0] =
[0, 0, 35, 0, 0, 0, 0, 0]
[0, 0, 35, 0, 0, 0, 0, 0]
[0, 0, 31, 0, 0, 0, 0, 0]
[0, 0, 32, 0, 0, 0, 0, 0]
[0, 0, 31, 0, 0, 0, 0, 0]
[0, 0, 34, 0, 0, 0, 0, 0]
[0, 0, 39, 0, 0, 0, 0, 0]
[0, 0, 33, 0, 0, 0, 0, 0]
[0, 0, 36, 0, 0, 0, 0, 0]
[0, 0, 35, 0, 0, 0, 0, 0]
[0, 0, 36, 0, 0, 0, 0, 0]
[0, 0, 38, 0, 0, 0, 0, 0]
[0, 0, 30, 0, 0, 0, 0, 0]
[0, 0, 32, 0, 0, 0, 0, 0]
[0, 0, 38, 0, 0, 0, 0, 0]
[0, 0, 36, 0, 0, 0, 0, 0]
[0, 0, 39, 0, 0, 0, 0, 0]
[0, 0, 32, 0, 0, 0, 0, 0]
[0, 0, 37, 0, 0, 0, 0, 0]
[2, 0, 56, 0, 0, 0, 0, 0] = ?
[0, 0, 51, 0, 0, 0, 0, 0] = ;
[0, 0, 31, 0, 0, 0, 0, 0] = 2
[0, 0, 31, 0, 0, 0, 0, 0] = 2
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[0, 0, 35, 0, 0, 0, 0, 0] = 6
[0, 0, 34, 0, 0, 0, 0, 0] = 5
[0, 0, 39, 0, 0, 0, 0, 0] = 0
[0, 0, 39, 0, 0, 0, 0, 0] = 0
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[0, 0, 35, 0, 0, 0, 0, 0] = 6
[0, 0, 31, 0, 0, 0, 0, 0] = 2
[0, 0, 32, 0, 0, 0, 0, 0] = 3
[0, 0, 35, 0, 0, 0, 0, 0] = 6
[0, 0, 36, 0, 0, 0, 0, 0] = 7
[0, 0, 35, 0, 0, 0, 0, 0] = 6
[0, 0, 46, 0, 0, 0, 0, 0] = =
[0, 0, 30, 0, 0, 0, 0, 0] = 1
[2, 0, 56, 0, 0, 0, 0, 0] = ?
[0, 0, 88, 0, 0, 0, 0, 0]


After trying everything I could think I finally gave up and searched for a Developers Manual for the device. The PDF above gave me a keycode map which made complete sense on the above output (see snippet below): This last piece of information was all I needed to decipher data from my device, and this was the code I ended up with:

#!/usr/bin/env python

# MagTek MSR100 Mini Swipe Card Reader
# Written By: nessy
#
# Some Thanks need to go out to
# for helping me get on the right track

import usb.core
import usb.util

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

# 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: '



I’ve went ahead and uploaded this source to Github in case anyone likes to clone it https://github.com/jness/magtek_cardreader/blob/master/main.py Using this code is very basic and is show below:

# ./main.py
Swipe Card:
%B723153771056323250476791397088?;221350011623672=1?
`

I’ve went ahead and uploaded this source to Github in case anyone likes to clone it https://github.com/jness/magtek_cardreader/blob/master/main.py Using this code is very basic and is show below: