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]
>>>
>>> device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, timeout=5000)
array('B', [2, 0, 34, 0, 0, 0, 0, 0])
>>> device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, timeout=5000)
array('B', [0, 0, 0, 0, 0, 0, 0, 0])
>>> device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, timeout=5000)
array('B', [2, 0, 5, 0, 0, 0, 0, 0])
>>> device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, timeout=5000)
array('B', [0, 0, 0, 0, 0, 0, 0, 0])
>>> device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, timeout=5000)
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
# http://www.micahcarrick.com/credit-card-reader-pyusb.html
# 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: