AdvancedTCardReader
Při psaní článku Cesta k emulátoru telefonní karty jsem navrhl několik metod prolomení ochrany telefonní karty. Jednou z těchto metod bylo i prolomení hashe pomocí analýzy vstupů a výstupů. Aby bylo něco takového možné, je nutné prvně nasbírat dostatečný počet challenge/response. K tomu jsem napsal krátký program ve Wiringu (v podstatě se jedná o C++ obohacené o arduino api) pro Arduino diecimila.
Během zkoušení programu jsem narazil na zvláštní věc - algoritmus používaný v českých telefonních kartách vrací pro kvadraticky zvětšující se množinu vstupů stejné výstupy. Zatím jsem nedělal žádné pokusy zjistit jak daleko to sahá, ale v praxi to znamená, že vytvoření emulátoru by nemuselo být tak složité - stačilo by zmapovat tabulku vstupů. Mám v plánu na to napsat script v pythonu, který bude zjišťovat rozsahy a ukládat je do databáze, pustím se do toho jakmile budu mít náladu..
Další možnost je, že někde v programu je chyba, pokud jí někdo najdete, budu rád pokud mi dáte vědět.
Ukázka komunikace
Type 'h' for help.
> h
Commands:
d
- print dump
c [p]
- print one c/r result with random number, or [p] as parameter
r [p]
- start with c/r from zero, or [p]
- type anything to interrupt loop
Format:
dump (dec dec2 ... decn)
challenge:response (dec:dec)
...
> d
161 43 99 0 10 118 38 35 0 0 0 0 0 254 185 30
> r
161 43 99 0 10 118 38 35 0 0 0 0 0 254 185 30
0:62214
1:10594
2:48316
3:48316
4:37074
5:37074
6:37074
7:37074
8:43400
9:43400
10:43400
11:43400
12:43400
13:43400
14:43400
15:43400
16:18722
17:18722
18:18722
19:18722
20:18722
21:18722
22:18722
23:18722
24:18722
25:18722
26:18722
27:18722
28:18722
29:18722
30:18722
31:18722
32:24876
33:24876
34:24876
35:24876
36:24876
37:24876
38:24876
39:24876
40:24876
41:24876
42:24876
43:24876
44:24876
45:24876
46:24876
47:24876
48:24876
49:24876
50:24876
51:24876
52:24876
53:24876
54:24876
55:24876
56:24876
57:24876
58:24876
59:24876
60:24876
61:24876
62:24876
63:24876
64:62544
65:62544
66:62544
67:62544
68:62544
69:62544
70:62544
71:62544
72:62544
73:62544
74:62544
75:62544
76:62544
77:62544
78:62544
79:62544
80:62544
81:62544
82:62544
83:62544
84:62544
85:62544
86:62544
87:62544
88:62544
89:62544
90:62544
91:62544
92:62544
93:62544
94:62544
95:62544
96:62544
97:62544
98:62544
99:62544
100:62544
101:62544
102:62544
103:62544
104:62544
105:62544
106:62544
107:62544
108:62544
109:62544
110:62544
111:62544
112:62544
113:62544
114:62544
115:62544
116:62544
117:62544
118:62544
119:62544
120:62544
121:62544
122:62544
123:62544
124:62544
125:62544
126:62544
127:62544
128:25500
129:25500
130:25500
131:25500
132:25500
133:25500
134:25500
135:25500
136:25500
137:25500
138:25500
139:25500
140:25500
141:25500
142:25500
143:25500
144:25500
145:25500
146:25500
147:25500
148:25500
149:25500
150:25500
Source code
/* AdvancedTCardReader v0.9.4 (25.07.2010) by Bystroushaak (bystrousak@kitakitsune.org)
* Lang: Wiring
* Platform: Arduino Diecimila
* Licence: CC by-nc-sa (http://creativecommons.org/licenses/by-nc-sa/3.0/cz/)
*
* This program allows read content of phone cards and also shows results of
* challenge/response security hash alghoritm.
*
* Program works in simple command line mode.
*
* Pins:
* ________________________
* | | |
* | 1 UCC | 4 GND |
* |_______ | ___________|
* | \ / \ |
* | 2 RST | | 5 VPP |
* |_______/ \ /._________|
* | | | |
* | 3 CLK | | 6 I/O |
* `----------^-^-----------'
*
* Parameters:
* UCC: -0.3 .. 6V
* ICC: 5 mA
*
* UI/O: -0.3 .. 6V
*
* I/O0: 0 .. 0.8V
* I/O1: 3.5 .. 3.5V
*
* Temp: -20 .. 55 °C
*/
#define LEN 128 // card length - 128b in Czech republic
#define MAX_NUM 281474976710656LL // 2 ** 48 (maximum range of challenge)
#define CMD_BUFF_LEN 18 // len(str(MAX_NUM)) + 1 (cmd) + 1 (space) + 1 (for sure)
// port definition
#define CLK 13
#define RST 12
#define VPP 11 // just formal definition, this port isn't used
#define IO 10
// CLK puls makro
#define CLKpuls() digitalWrite(CLK, HIGH); digitalWrite(CLK, LOW);
/*= setup ======================================================================
* Initialize pins and serial line.
*
* Argument(s): None.
* Returns: Nothing.
*/
void setup(){
pinMode(RST, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(IO, INPUT);
digitalWrite(RST, LOW);
digitalWrite(CLK, LOW);
// serial initialization
Serial.begin(9600);
delay(200); // serial comunication needs some time to initialization
// initialization for random numbers
randomSeed(analogRead(0));
}
//==============================================================================
/*= resetSeq ===================================================================
* Reset sequence:
*
* _____________
* __| : : |__ RST
* : :_______: :
* __:__| >=1ms |__:__ CLK
*
*
* Argument(s): None.
* Returns: Nothing.
*/
void resetSeq(void){
digitalWrite(RST, HIGH);
digitalWrite(CLK, HIGH);
delay(1);
digitalWrite(CLK, LOW);
digitalWrite(RST, LOW);
}
//==============================================================================
/*= writeSeq ===================================================================
* Write sequence:
*
* __
* __| |______________ RST
* : : :________:
* __:__:__| >=10ms |__ CLK
*
*
* Argument(s): None.
* Returns: Nothing.
*/
void writeSeq(void){
digitalWrite(RST, HIGH);
digitalWrite(RST, LOW);
digitalWrite(CLK, HIGH);
delay(10);
digitalWrite(CLK, LOW);
}
//==============================================================================
/*= readDump ===================================================================
* Reads informations from card into *dump.
*
* Argument(s): byte *dump
* Returns: Nothing.
*/
void readDump(byte *dump){
*dump = 0;
// reset address counter
resetSeq();
// reads informations
for (uint16_t i = 0, n = 128; i < LEN; i++){
if (digitalRead(IO)){
*dump += n;
}
n >>= 1;
// saves every 8 readed bits into *dump
if ((i + 1) % 8 == 0){
*(++dump) = 0;
n = 128;
}
// increment address counter
CLKpuls();
}
}
//==============================================================================
/*= printDump ==================================================================
* Prints dump into serial line.
*
* Argument(s): byte *dump
* Returns: Nothing.
*/
void printDump(byte *dump){
for (uint16_t i = 0; i < LEN / 8; i++){
Serial.print(dump[i], DEC);
Serial.print(' ');
}
Serial.println();
}
//==============================================================================
/*= response ===================================================================
* Send challenge to the card and wait for an response.
*
* Argument(s): uint64_t challenge
* Returns: uint16_t response
*/
uint16_t response(uint64_t challenge){
resetSeq();
// increment address counter to 110
for (uint8_t i = 0; i < 110; i++){
CLKpuls();
}
writeSeq();
for (uint8_t i = 0; i < 177; i++){
CLKpuls();
}
// write challenge bits to the card
pinMode(IO, OUTPUT);
for (int16_t i = 47; i >= 0; i--){
if (challenge >> i)
digitalWrite(IO, HIGH);
else
digitalWrite(IO, LOW);
CLKpuls();
}
pinMode(IO, INPUT);
// read response
uint16_t n = 32768, response = 0;
for (uint8_t i = 0; i < 16; i++){
for (uint8_t j = 0; j < 160; j++){
CLKpuls();
}
if (digitalRead(IO))
response += n;
n >>= 1;
}
return response;
}
//==============================================================================
/*= printParameter =============================================================
* Convert uint64_t to string and print it.
* (Arduino haven't overloaded Serial.print() for uint64_t)
*
* Argument(s): uint64_t parameter
* Returns: None.
*/
void printParameter(uint64_t parameter){
uint64_t tmp = parameter, newtmp;
uint8_t rest = 0, cnt = 0;
char buffer[16];
if (tmp == 0){
Serial.print(0, DEC);
return;
}
// convert uint64_t to string (thx to w (irc://#shadowfall@monka.hysteria.cz) [multiplying is 3kB smaller than dividing])
while (tmp > 0){
newtmp = tmp / 10;
buffer[cnt++] = '0' + tmp - newtmp * 10;
tmp = newtmp;
}
// reverse buffer
for (; cnt > 0;){
Serial.print(buffer[--cnt]);
}
}
//==============================================================================
//==============================================================================
//=========================== Main function ====================================
//==============================================================================
void loop(){
byte dump[LEN / 8];
uint64_t parameter;
char cmd[CMD_BUFF_LEN];
uint8_t cnt = 0;
// ---
Serial.println("Type 'h' for help.");
Serial.print("> ");
while (1){
cnt = 0;
parameter = 0;
// read command, if available
if (Serial.available()){
while (Serial.available() && cnt < CMD_BUFF_LEN) {
cmd[cnt++] = (char) Serial.read();
delay(1);
}
cmd[cnt++] = 0;
}
// parse parameter
if (cnt > 1){
parameter = 0;
for (int i = 0; i < cnt; i++){
if (cmd[i] >= '0' && cmd[i] <= '9'){
parameter *= 10;
parameter += cmd[i] - '0';
}
}
}
// execute command
if (cnt > 0){
Serial.println(cmd);
if (parameter > MAX_NUM){
Serial.println("Parameter too big! Maximum is 2^48.");
continue;
}
switch(cmd[0]){
case 'h':
Serial.println("Commands:");
Serial.println("\td\n\t\t - print dump");
Serial.println("\tc [p]\n\t\t - print one c/r result with random number, or [p] as parameter");
Serial.println("\tr [p]\n\t\t - start with c/r from zero, or [p]");
Serial.println("\t\t - type anything to interrupt loop");
Serial.println("\nFormat:\n\tdump (dec dec2 ... decn)\n\tchallenge:response (dec:dec)\n\t...");
break;
case 'd':
readDump(dump);
printDump(dump);
break;
case 'c':
readDump(dump);
printDump(dump);
// if haven't parameter, generate random number
if (cnt <= 2){
parameter = (uint64_t) random(16777216) * random(16777216);
}
//Serial.print((unsigned long int) parameter, DEC);
printParameter(parameter);
Serial.print(":");
Serial.println((unsigned long int) response(parameter), DEC);
break;
case 'r':
readDump(dump);
printDump(dump);
// show c/r from parameter to 2**48
for (; parameter < MAX_NUM; parameter++){
// break loop
if (Serial.available()){
break;
}
printParameter(parameter);
Serial.print(":");
Serial.println((unsigned long int) response(parameter), DEC);
}
break;
default:
Serial.print("Unknown command \"");
Serial.print(cmd);
Serial.println("\"");
break;
}
Serial.print("> ");
}
}
}
//==============================================================================
/* ______________________
* / \ __
* | I hope it works ^-^ | / \
* \_____________________ / \__/ O . \`.,'/ _----.__
* /_ _\`------./ ; /
* \/` .____. ;;-__.--'
* |// \))
*
*/