/bilhete

reverse engineer bilhete unico

Reverse engineering from public transportation cards used in SP back in the days.

I did a lot of tests, backing up the card, using it and loading the backed up data, bringing back the credits as before.

I did contact the authorities back in the days to report it. It is here just for historical reasons.. hardware used was an arduino with powerpack, case, sd cart and a NFC card wing. 
That allowed me to generate the snapshots after every reacharge or spend.

Engenharia reversa Bilhete Unico

O Cartão é o MIFARE CLASSIC 4K. Os dados são organizados em setores, cada setor com 4 blocos de 16 bytes. 
O primeiro bloco eh read-only e tem o UID do cartao + dados do fabricante do cartao
O ultimo bloco de cada sector sempre tem as chaves a e b e o direito de acesso. O ultimo sector estar organizado mais ou menos assim (olhar um hexdump qualquer):

chave A            direitos   chave b
----------------- ----------  ---------------- 
a0 a1 a2 a3 a4 a5 08 77 8f 69 b0 b1 b2 b3 b4 b5


exemplo de como os dados sao organizados no cartao

0000000 9e 49 37 b0 50 08 04 00 62 63 64 65 66 67 68 69 bloco 0, sector 0: uid do cartao 9e4937b0, dados do fabricante 0804006263646566676869
0000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 bloco 1, sector 0
0000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..
0000030 ff ff ff ff ff ff ff 07 80 69 ff ff ff ff ff ff bloco 3, sector 0: chave a, direitos de acesso e chave b
0000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 bloco 0, sector 1
0000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..
0000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..
0000070 a0 a1 a2 a3 a4 a5 08 77 8f 69 b0 b1 b2 b3 b4 b5 bloco 3, sector 1: chave a, direitos de acesso e chave b


Eu tenho 3 cartões, os arquivos *.mfd são as chaves de authenticação de cada setor. Pra variar, usam chaves default. Dai todo dia, depois de andar de onibus, venho para casa e leio o conteudo do cartão, salvando os dumps no diretórios. O cada dump está identificado com um timestamp. O timestamp não está correto. O dia, ano e mes sim, mas a hora e o minuto não.

O Cartão do Bilhete unico funciona da seguinte maneira:

* Você carrega em uma central (casa lotérica)
* Toda vez que se entra no onibus vc passa o cartão. Se for a primeira vez, o valor é descontado. Se não for a primeira vez mas tiver dentro do periodo de validade (1 hora), então o valor não é descontado.

* Os *.dump são dump binários. Deles eu extrai com o hexdump -v os arquivos *.hex ai se pode comparar os *.hex com um visualizador de diff (vimdiff por exemplo)

Documentos que podem ser uteis:

* http://www.libnfc.org/community/topic/160/mifare-data-analysis/
* http://code.google.com/p/mfcuk/wiki/MifareClassicKnownCardsDataFormat
* http://www.youtube.com/watch?v=wSYcTl0B7MY (video from CCC, você tem que assistir)
* http://www.nxp.com/documents/application_note/AN10787.pdf

* PlainText conhecidos:

No cartão 9e4937b0:

* dump 201112011015
 * fiz carga de 8 reais. saldo: R$ 10.02

* dump  201111281500 e 201111281515 usei o cartão 2 x mas só foi descontado uma vez.
 * 201111281500 usei o onibus 5154-10
 * 201111281515 usei o onibus 6418-10

* dump 201112151145
  * onibus 5154-10
  * saldo cartão R$ 7.02


No Cartão fcd4cf1f:
* Usei o trem, peguei na estação berrine até estação shopping morumbi e voltei. No caso do trem se cobra 2x portanto, deve constar como ultima viagem shopping morumbi -> berrine. 
  saldo cartão: R$ 2.15

No Cartão 7eb2258a
* Tem sempre o mesmo onibus, numero 6414

* novos testes que irei fazer:

* pegar 2 x O MESMO onibus, sem cobrar o valor (dentro da uma hora de validade) pra ver se muda algo
* Comprar um cartão NOVO com crédito e ver se conseguimos fazer a engenharia reversa do valor



Algo o que eu já vi:

Sector 0, Sector 1, Sector 2 não há mudança
Sector 3 e Sector 4 são repetidos
Sector 8 e Sector 9

o sector 3, block 3 guarda ou valor ou timestamp. isso pq ao usar 2 x onibus no mesmo dia e sem cobrar denovo (dentro de periodo de 1 hora) os primeiros 7 bytes não mudaram. somente o ultimo (que pode ser a casa dos minutos em um timestamp ou um CRC para validar campo)