Monday, February 21, 2011

"Tracking" Down Credit Card Dumps

I have been examining numerous computers and media cards to support fraud investigations in the past year.  One group of thieves has been installing skimmers (devices that record magnetic stripe data) in the magnetic stripe readers on doors of certain banking institutions that limit access to their ATMs after hours.  Then the thieves install micro video cameras in the light fixtures of the ATMs to capture the users' pin codes.  The thieves later match the recorded pin code to the skimmed account number at the door, encode new cards, and pillage bank accounts by getting cash at another ATM location.

It is not difficult to find the ATM videos on the media cards from the cameras or on the computer hard drives.  The credit card/ATM card numbers can be bit tougher, however.  Searching for 16 digit numbers in a Windows computer will yield a huge volume of false hits.  And, if the operation has been running for a while, many of the account numbers will be deleted.   Searching unallocated space is necessary to be thorough and to ensure your suspects' get the full reward of their illicit activities.

All of the skimmers I have encountered are serial devices that communicate with software made for Windows-based computers by means of a USB-to-serial cable.  The cables do not look dramatically different than a standard USB cable, but they contain a chip that bridges the two protocols.  In a Windows computer, a USB driver for the cable must be installed before the program can communicate with the device.

The applications that communicate with the skimmer devices write the data to disk differently--some create a database while others use text files.  In my experience, both formats contain the complete track 1 and/or track 2 data.  Magnetic stripes contain three tracks, the first two in common use and encoded with particular standards.

Track 1 (IATA)

Track 1, known as "International Air Transport Association" format, has alphanumeric data.  It takes on the following format (from wikipedia):

Track 1, Format B:
  • 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 CVK, 3 characters)
  • End sentinel — one character (generally '?')
  • Longitudinal redundancy check (LRC) — it is one character and a validity character calculated from other data on the track. Most reader devices do not return this value when the card is swiped to the presentation layer, and use it only to verify the input internally to the reader.
Targeting track 1 data in a grep search is very simple:
$ grep -E ^'%.[0-9]{16,19}\^' file


Track 2 (ABA)

Track 2, known as the "American Banking Association" format, contains only numeric data.  It takes on the following format (from wikipedia):

Track 2: This format was developed by the banking industry (ABA). This track is written with a 5-bit scheme (4 data bits + 1 parity), which allows for sixteen possible characters, which are the numbers 0-9, plus the six characters  : ; < = > ? . The selection of six punctuation symbols may seem odd, but in fact the sixteen codes simply map to the ASCII range 0x30 through 0x3f, which defines ten digit characters plus those six symbols. The data format is as follows:
  • Start sentinel — one character (generally ';')
  • Primary account number (PAN) — up to 19 characters. Usually, but not always, matches the credit card number printed on the front of the card.
  • Separator — one char (generally '=')
  • Expiration date — four characters in the form YYMM.
  • Service code — three digits. The first digit specifies the interchange rules, the second specifies authorisation processing and the third specifies the range of services
  • Discretionary data — as in track one
  • End sentinel — one character (generally '?')
  • Longitudinal redundancy check (LRC) — it is one character and a validity character calculated from other data on the track. Most reader devices do not return this value when the card is swiped to the presentation layer, and use it only to verify the input internally to the reader.
Targeting track 2 data in a grep search is also straight forward, though a reading of the above standard suggests the following search can miss.  I haven't seen any different start sentinels or separators than those in the expression:
$ grep -E ^';[0-9]{16,19}=' file
Though the preceding search has worked for me, the specifications for track 2 allow for other start sentinels and field separators.  A better but slower search would be:
$ grep -e ^'[:;<=>?][0-9]{16,19}[:;<=>?]'

Tracking Down Both Tracks at Once

I composed the following search to track down both tracks, and display the date and time of the swipe typically captured by the skimmer device.  The "-B1" argument shows one line of data before the hit, which is where the date and time are recorded.
$ grep -E -B1 ^'%.[0-9]{16,19}\^|;[0-9]{16,19}=' file
You may have noticed the caret ("^") preceding the single quoted search in each of the grep expressions.  It requires the expression to be matched at the beginning of a line of data.  This is a search optimization.  I will now demonstrate two additional optimizations, one for searching allocated files, and the other for unallocated space (using the the sleuthkit tool "blkls"):
Searching mounted file systems (find files, export 7-bit strings, grep for track data):
$ find . -type f | while read i; do strings "$i" |  grep -E -B1 -H --label="$i" ^'%.[0-9]{16,19}\^|;[0-9]{16,19}='; done
Searching unallocated space of a forensic image (export unallocated, filter out 7-bit strings showing offset, grep for track data)
$ blkls -o63 image.dd | strings -td  |  grep -E -B1 ^'%.[0-9]{16,19}\^|;[0-9]{16,19}='