PoC Software for Magnetic Stripe Processing of Credit/Debit Cards for Snort SDF

Bill Parker <[email protected]>
Newsgroups gmane.comp.security.ids.snort.devel
Message-ID <CAFrbyQw1NZ0E9OLac6_AuFgbkkPZg_4JbVJj-RFRtOM_iO8x3Q@mail.gmail.com>
Hello All,

   This is a very rough output for processing of Credit/Debit Card
Magnetic Stripe data (this is Track 1, Format B), and while it is
still a work in progress, it does take the data supplied and breaks
it down into the following fields:

Account Number (max of 19 characters):
Card Holder Name (max of 26 characters):
Expiration Date (in MMYY format):
Service Code (3 chars):
Discretionary data (1 to 4 chars)
The Longitudinal redundancy check value (3 chars)

Here is the output from the program below:

Enter Line for Mag Stripe Testing:

%b1234567890123456789^AbCdEfGhIjKlmnopQRStuvwxyz^11171270874?LRC

The Line Entered was:

%b1234567890123456789^AbCdEfGhIjKlmnopQRStuvwxyz^11171270874?LRC

Length of Buffer entered is: 65

Buffer after conversion is:

%B1234567890123456789^ABCDEFGHIJKLMNOPQRSTUVWXYZ^11171270874?LRC

SUCCESS (SO FAR):

Starting sentinel is '%'
Ending sentinel is '?'
Format Code is 'B'

The Account Number is: 1234567890123456789

The Card Holder Name is: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Card Holder Expiration Date is: 1117

Card Holder Service Code is: 127

Card Holder Discretionary data is: 0874

The Longitudinal redundancy check value is: LRC


Process returned 0 (0x0)   execution time : 4.500 s
Press any key to continue.

This is also filed at the following URL:

https://bugzilla.clamav.net/show_bug.cgi?id=11341

The source code is a(n) attachment.

It will be modified to check track 2, and also add
checking for valid service codes, etc.  This is still
a work in progress.

Bill Parker (wp02855 at gmail dot com)

------------------------------------------------------------------------------

_______________________________________________
Snort-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/snort-devel
Archive:
http://sourceforge.net/mailarchive/forum.php?forum_name=snort-devel

Please visit http://blog.snort.org for the latest news about Snort!
main.c (text/x-csrc, 6.4 KB)
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>

/*  function prototypes */

void StringToLower(char *);
void StringToUpper(char *);
void ReverseString(char *);

void StringToLower(char *s)
{
    while (*s) {
        *s = tolower((unsigned char)*s);
        ++s;
    }
}

void StringToUpper(char *s)
{
    while (*s) {
        *s = toupper((unsigned char)*s);
        ++s;
    }
}

void ReverseString(char *s)
{
    size_t len = strlen(s);
    size_t i, j;

    if (len > 0)
        for (i = 0, j = len - 1; i < j; i++, j--)
            s[i] ^= s[j], s[j] ^= s[i], s[i] ^= s[j];
}

int main()
{
    char sbuffer[101];      /*  Buffer for Mag Stripe Line  */
    char *sbuf_ptr;         /*  Buffer Pointer  */
    char stripe_buf[66];    /*  Buffer for working with stripe info */

    char account_number[20];
    char *acct_num_ptr;

    char username[30];      /*  the standard shows a maximum of 26 chars for the name   */
    char *username_ptr;

    char expiry_date[5];    /*  expiration date in MMYY format  */
    char *expiry_date_ptr;

    char service_code[4];   /*  Service Code 3 characters   */
    char *srv_code_ptr;

    char discret_data[5];   /*  Discretionary data (1 to 4 chars)   */
    char *discret_data_ptr;

    char lrc[5];           /*  the standard shows a maximum of 3 chars for this field  */
    char *lrc_ptr;

    char start_sentinel = '%';
    char end_sentinel = '?';
    char format_code = 'B';
    char field_separator = '^';

    int i, j, k;            /*  variables for future use    */
    const int BUFLEN = 65;  /*  Buffer length must be at least 65 chars */
    int sbuf_len;
    int index;
    int stripe_buf_len;

    printf("Enter Line for Mag Stripe Testing: ");
    fflush(stdout);
    fgets(sbuffer, sizeof(sbuffer), stdin);
    printf("\nThe Line Entered was: %s\n", sbuffer);
    fflush(stdout);

    sbuf_ptr = &sbuffer[0];

    /*  check line for initial minimum length requirement (65 chars min)    */

    sbuf_len = strlen(sbuffer);
    if (sbuf_len < BUFLEN) {
        fprintf(stderr, "Warning: Buffer length is too short for mag stripe data stream...\n");
        fflush(stdout);
        return(EXIT_FAILURE);
    }

    printf("\nLength of Buffer entered is: %d\n\n", sbuf_len);
    fflush(stdout);

    StringToUpper(sbuf_ptr);

    printf("Buffer after conversion is: %s\n", sbuffer);
    fflush(stdout);

    /*  First Character of buffer must be a %, sbuf_len - 3 must be a ? */

    sbuf_ptr = &sbuffer[0]; /* reset buffer pointer to start of string  */

    if (*sbuf_ptr != start_sentinel) {
        fprintf(stderr, "starting sentinel is not '%c'...exiting\n", start_sentinel);
        fflush(stdout);
        return(EXIT_FAILURE);
    }

#if 0
    for (i = 0; i < sbuf_len; i++)
        printf("Value of sbuffer[%d] is %c\n", i, sbuffer[i]);
    fflush(stdout);
#endif

    /* this is kind of a kludge, needs better work  */

    if (sbuffer[sbuf_len - 5] != end_sentinel) {
        fprintf(stderr, "Ending sentinel is not '%c'...exiting\n", end_sentinel);
        fflush(stdout);
        return(EXIT_FAILURE);
    }

    sbuf_ptr++;

    if (*sbuf_ptr != format_code) {
        fprintf(stderr, "Mag stripe format code is not letter 'B'...exiting\n");
        fflush(stdout);
        return(EXIT_FAILURE);
    }
    sbuf_ptr++;

    printf("SUCCESS (SO FAR):\n");
    printf("\nStarting sentinel is '%c'\n", start_sentinel);
    printf("Ending sentinel is '%c'\n", end_sentinel);
    printf("Format Code is '%c'\n", format_code);
    fflush(stdout);

    /* get the account number (usually the credit/debit card number  */

    index = 0;
    acct_num_ptr = &account_number;

    while (*sbuf_ptr != field_separator) {
        *acct_num_ptr = *sbuf_ptr;
        acct_num_ptr++;
        sbuf_ptr++;
    }

    *acct_num_ptr = '\0';   /*  terminate the account number buffer  */
    sbuf_ptr++; /*  bump pointer to skip field separator    */

    printf("\nThe Account Number is: %s\n", account_number);
    fflush(stdout);

    /*  At this point call Snort SDF CC/DC check for validity   */
    /*  or ClamAV DLP processor for validity check  */

    /*  Get the Account Holder's Name   */

    username_ptr = &username;

    while (*sbuf_ptr != field_separator) {
        *username_ptr = *sbuf_ptr;
        username_ptr++;
        sbuf_ptr++;
    }

    *username_ptr = '\0';   /*  terminate the username buffer   */
    sbuf_ptr++;

    printf("\nThe Card Holder Name is: %s\n", username);
    fflush(stdout);

    /*  Get Expiration Date */

    expiry_date_ptr = &expiry_date;

    for (i = 0; i < 4; i++) {
        *expiry_date_ptr = *sbuf_ptr;
        expiry_date_ptr++;
        sbuf_ptr++;
#if 0
        expiry_date_ptr++;
        sbuf_ptr++;
#endif
    }

    *expiry_date_ptr = '\0';    /*  terminate the expiration date buffer    */

    /* Get Service Code Data    */

    srv_code_ptr = &service_code;

    for (i = 0; i < 3; i++) {
        *srv_code_ptr = *sbuf_ptr;
        srv_code_ptr++;
        sbuf_ptr++;
    }

    *srv_code_ptr = '\0';   /*  terminate the service code buffer   */

    /* Get PVKI/PVV/CVV/CVC data   */

    discret_data_ptr = &discret_data;

    while (*sbuf_ptr != end_sentinel) {
        *discret_data_ptr = *sbuf_ptr;
        discret_data_ptr++;
        sbuf_ptr++;
    }

    *discret_data_ptr = '\0';   /*  terminate the discretionary data buffer  */
    sbuf_ptr++;                 /*  bump pointer to skip field separator    */

    printf("\nCard Holder Expiration Date is: %s\n", expiry_date);
    fflush(stdout);
    printf("\nCard Holder Service Code is: %s\n", service_code);
    fflush(stdout);
    printf("\nCard Holder Discretionary data is: %s\n", discret_data);
    fflush(stdout);

    /*  Process Longitudinal redundancy check (LRC) data    */

    lrc_ptr = &lrc;

    while (*sbuf_ptr) {
        *lrc_ptr = *sbuf_ptr;
        lrc_ptr++;
        sbuf_ptr++;
    }

    *lrc_ptr = '\0';    /*  terminate the LRC buffer    */
    sbuf_ptr = NULL;    /*  set original buffer pointer to NULL (sanity check)  */

    printf("\nThe Longitudinal redundancy check value is: %s\n", lrc);
    fflush(stdout);

#if 0
    ReverseString(sbuf_ptr);
    printf("\nString after Reversal is: %s\n", sbuffer);
#endif // 1

    return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.