Sommaire

Introduction

Lors du CTF GreHack édition 2016, il y avait une épreuve hardware (Phreak Me) qui consistait à simuler une carte de téléphone. L’épreuve était décomposée en 2 parties de 300 et 200 points avec comme point d’entrée l’article n°48 de phrack sur les cartes de téléphones. La carte à simuler était une carte de téléphone française. Cabine

Le matériel

Nous avions un Arduino - Nano ATMega328 qui s’enfichait sur un support ZIF pour simuler la télécarte.

Lecteur

structure des données et lectures/écritures sur la carte

L’article nous donne plusieurs informations à la fois sur la structure de données et sur la manière de lire et d’écrire sur une carte de téléphone.

extraits de l’article

Memory map / carte française

    I-6) MEMORY MAP of cards from France and Monaco:
	--------------------------------------------

Bytes       Bits      Binary     Hexa

                    +-----------+-----+
  1        1 --> 8  |           |     | ---> Builder code.
                    +-----------+-----+
  2       9 --> 16  | 0000 0011 | $03 | ---> a French telecard
                    +-----------+-----+
  3      17 --> 24  |           |     |
                    +-----------+-----+
  4      25 --> 32  |           |     |
                    +-----------+-----+
  5      33 --> 40  |           |     |
                    +-----------+-----+
  6      41 --> 48  |           |     |
                    +-----------+-----+
  7      49 --> 56  |           |     |
                    +-----------+-----+
  8      57 --> 64  |           |     |
                    +-----------+-----+
  9      65 --> 72  |           |     |
                    +-----------+-----+
 10      73 --> 80  |           |     |
                    +-----------+-----+
 11      81 --> 88  |           |     |
                    +-----------+-----+
 12      33 --> 40  | 0001 0011 | $13 | ---> 120 units card
                    | 0000 0110 | $06 | --->  50 units card
                    | 0000 0101 | $05 | --->  40 units card
                    +-----------+-----+
 13-31  97 --> 248  |           |     | ---> The units area: each time a unit
                    |           |     |      is used, then a bit is set to "1";
                    |           |     |      Generally the first ten units are
                    |           |     |      fused in factory as test.
                    |           |     |
                    |           |     |
                    |           |     |
                    +-----------+-----+
 32    249 --> 256  | 1111 1111 | $FF | ---> the card is empty
                    +-----------+-----+

On notera une petite erreur sur le deuxième 33 –> 40, qui devrait être 89 –> 96.

Diagramme temporel sur les différentes PINS

    I-5) TIME DIAGRAMS:
	---------------

+21V                                     _____________
+5V ____________________________________|             |_________________ Vpp
					:             :
+5V                  ___________________:_____________:_________________ Reset
0V  ________________|                   :             :
		    :                   :             :
+5V     ____        :      ____         :       ______:______
0V  ___|    |_______:_____|    |________:______|      :      |__________ Clock
       :    :       :     :    :        :      :      :      :
+5V    :    :       :     :    :        :______:______:      :           _
0V  ___:____:_______:_____:____:________|      :      |______:__________ R/W
       :    :       :     :    :        :      :      :      :
+5V    :    :       :_____:    :________:      :      :      :__________
0V  XXXXXXXXXXXXXXXXX_____XXXXXX________XXXXXXXXXXXXXXXXXXXXXX__________ Out
       :    :       :     :    :        :<-----><---->:      :
       :    :       :     :    :        :10 to   10 to       :
       :    :       :     :    :        :50 ms   50ms        :
	Reset        Bit 1        Bit2                           Bit 3
	card        reading      reading  Bit2 writing to 1     reading

Extrait du code fourni pour l’épreuve

 1// pinout
 2#define CLK 2
 3#define RST 3
 4#define RW 4
 5#define IO 5
 6
 7void setup() {
 8
 9  pinMode(RW, INPUT);
10  pinMode(CLK, INPUT);
11  pinMode(RST, INPUT);
12  pinMode(IO, OUTPUT);
13
14  attachInterrupt(digitalPinToInterrupt(CLK), intClk, RISING);
15}
16
17void loop() {
18  
19}

Dans la version fournie dans Kali/Debian/Ubuntu (1.0.5) la fonction digitalPinToInterrupt n’existe pas, nous avons remplacé la valeur par 0 (no d’interruption sur la PIN CLK).

300 points : lire la carte

La première partie consistait à lire la carte, nous avons donc dans un premier temps fait une matrice des 32 octets de la carte

+----+----------+
| 55 | 01010101 | > Builder code (valuer bidon mais différente de 0x00)
| 03 | 00000011 | > code correspondant à une carte française
| 78 | 01111000 | \
| 05 | 00000101 | |
| 74 | 01110100 | |
| 22 | 00100010 | |
| A5 | 10100101 |  > valeurs aléatoires 
| B8 | 10111000 | |  pour éviter de mettre des 0x00 ou 0xFF
| 80 | 10000000 | |
| 01 | 00000001 | |
| E7 | 11100111 | /
| 05 | 00000101 | > carte de 40 unités
| FF | 11111111 | \ 10 bits à 1 (tests usine comme indiqué dans la doc) 
| FF | 11111111 | / + 6 bits à 1 correspondant à 6 unités utilisés
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 |
| 00 | 00000000 | > 0x00 la carte n'est pas terminée sinon c'est 0xFF
+----+----------+

on le traduit avec le code suivant :

1char card[] = { 0x55, 
2                0x03, 
3                0x78, 0x05, 0x74, 0x22, (char)0xA5, (char)0xB8, (char)0x80, 0x01, (char)0xE7, 
4                0x05, 
5                (char)0xFF, (char)0xFF, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x00, 0x00, 0x00, 0x00, 
6                0x00 
7              };

N.B. : les cast en (char) sont là uniquement pour ne pas avoir de warnings à la compilation.

Dans le code fourni, les événements sont déclenchés sur les fronts montants (RISING) de la clock. La PIN Reset détermine ce qu’on doit faire, si elle est à l’état bas (LOW) cela correspond à un Reset et on envoie sur la PIN IO le premier bit qui sera lu au front montant du Reset (cf Bit 1 reading dans le diagramme temporel) et notre compteur de bits repasse à 1 pour se préparer à envoyer les valeurs suivantes.

Lorsqu’un front montant de la clock arrive, on vérifie si on est en mode Reset ou pas. Si on est en mode Reset on redémarre de zéro et on renvoie le premier bit. Ceci permet de gérer les Reset en plein milieu de la lecture et la carte peut être lue autant de fois que nécessaire. Durant l’épreuve c’était le cas, elle était lue plusieurs fois.

Lorsque l’on n’est pas en mode Reset on envoie tour à tour (sur chaque front montant de la clock) les différents bits et ce jusqu’à 256. Arrivé à 256 on recommence le cycle d’envoi depuis 0.

 1#include <pins_arduino.h>
 2
 3// pinout
 4#define CLK 2
 5#define RST 3
 6#define RW 4
 7#define IO 5
 8
 9char card[] = { 0x55, 
10                0x03, 
11                0x78, 0x05, 0x74, 0x22, (char)0xA5, (char)0xB8, (char)0x80, 0x01, (char)0xE7, 
12                0x05, 
13                (char)0xFF, (char)0xFF, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x00, 0x00, 0x00, 0x00, 
14                0x00 
15              };
16
17int count = 0;
18int sending = 0;
19
20
21void sendBit(int count)
22{
23    if(((card[count / 8] >> (7 - (count % 8))) & 0x1) == 0x01)
24    {
25      digitalWrite(IO, HIGH);
26    }
27    else
28    {
29      digitalWrite(IO, LOW);
30    }
31}
32
33
34void intClk() {
35    int reset = digitalRead(RST);
36    int write = digitalRead(RW);
37    
38    if(reset == HIGH)
39    {
40        sendBit(count);
41        count++;
42        if(count >= 256)
43        {
44          count = 0;
45        }
46    }
47    else
48    {
49        sendBit(0);
50        count = 1;
51    }
52}
53
54void setup() {
55
56  pinMode(RW, INPUT);
57  pinMode(CLK, INPUT);
58  pinMode(RST, INPUT);
59  pinMode(IO, OUTPUT);
60
61  attachInterrupt(/*digitalPinToInterrupt(CLK)*/0, intClk, RISING);
62}
63
64void loop() {
65  
66}

A cette phase la carte était lisible, le flag GH16{PhoneHacked} était affiché sur le LCD de la cabine, et nous étions en mesure de passer un appel pour la partie suivante.

200 points : passer un appel

La particularité pour passer un appel c’est que la cabine devait pouvoir “griller” des unités sur la carte. Pour ça il fallait gérer l’écriture dans le micro contrôleur et mémoriser l’état afin de pouvoir le renvoyer à la prochaine lecture de la carte.

A chaque unité utilisée un bit est positionné à 1 à partir du bit no 107.

Pour savoir si la cabine lit ou écrit il faut utiliser la PIN R/W. Si on regarde le diagramme temporel, si Reset est HIGH et R/W est HIGH sur un front montant de la clock alors on écrit 1 en mémoire à l’adresse compteur - 1 (vu que le compteur est déjà positionné sur le bit suivant en vu d’une lecture de la part de la cabine).

Le code suivant valide complètement l’épreuve, et le résultat est donné via de la synthèse vocale à travers le combiné.

 1#include <pins_arduino.h>
 2
 3// pinout
 4#define CLK 2
 5#define RST 3
 6#define RW 4
 7#define IO 5
 8
 9char card[] = { 0x55, 
10                0x03, 
11                0x78, 0x05, 0x74, 0x22, (char)0xA5, (char)0xB8, (char)0x80, 0x01, (char)0xE7, 
12                0x05, 
13                (char)0xFF, (char)0xFF, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x00, 0x00, 0x00, 0x00, 
14                0x00 
15              };
16
17int count = 0;
18int sending = 0;
19
20
21void sendBit(int count)
22{
23    if(((card[count / 8] >> (7 - (count % 8))) & 0x1) == 0x01)
24    {
25      digitalWrite(IO, HIGH);
26    }
27    else
28    {
29      digitalWrite(IO, LOW);
30    }
31}
32
33void receiveBit(int count)
34{
35    card[count / 8] =  card[count / 8] | (1 << (7 - (count % 8))); 
36}
37
38void intClk() {
39    int reset = digitalRead(RST);
40    int write = digitalRead(RW);
41    
42    if(reset == HIGH)
43    {
44        if(write == HIGH)
45        {
46          receiveBit(count-1);
47        }
48        sendBit(count);
49        count++;
50        if(count >= 256)
51        {
52          count = 0;
53        }
54    }
55    else
56    {
57        sendBit(0);
58        count = 1;
59    }
60}
61
62void setup() {
63
64  pinMode(RW, INPUT);
65  pinMode(CLK, INPUT);
66  pinMode(RST, INPUT);
67  pinMode(IO, OUTPUT);
68
69  attachInterrupt(/*digitalPinToInterrupt(CLK)*/0, intClk, RISING);
70}
71
72void loop() {
73  
74}
75

Conclusion

Un grand merci à Phil pour cette épreuve super intéressante qui nous a pris à deux environ deux bonnes heures à réaliser.

Le Phreak c’est Chic :-).