Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

$EFS, cz. 2. DPAPI internals

Przygód z EFS ciąg dalszy. Dziś docieramy do obszarów, które wykorzystywane są również w innych miejscach systemu, dlatego niezbędny jest osobny tekst i odpowiedni podtytuł. Jedziemy!

Certyfikat

W poprzedniej części dotarliśmy do miejsca, w którym powiązaliśmy zaszyfrowany FEK z certyfikatem użytkownika. Zajrzyjmy do menadżera certyfikatów (tylko informacyjnie, bo przecież w trybie offline nie będziemy mieli już takiego komfortu!).


Rys 1. Właściwości certyfikatu powiązanego z szyfrowaniem EFS

Mając w pamięci certyfikat widziany z poziomu certmgr, zaglądamy szybko do pliku certyfikatu, który - jak przypomnę - znajduje się w profilu użytkownika: %APPDATA%\Microsoft\SystemCertificates\My\Certificates\ i ma nazwę związaną z thumbprintem certyfikatu, czyli skrótem SHA1: EFF5EDAB8123D06B6EFEA7D87716B03F9C8F48CD.


Rys 2. Plik certyfikatu z wyróżnionymi najważniejszymi polami.

Plik certyfikatu z Rys 2. zawiera wyłącznie część publiczną klucza, którego fragment widzimy na zrzucie z ekranu (Rys 1.) i dla ułatwienia zaznaczyłem na pomarańczowo w Rys 2. Najistotniejsza część, czyli sam klucz publiczny to 256 bajtów zaznaczone na czerwono. Dodatkowo, zaznaczony na zielono obszar to kompletny plik certyfikatu (w formacie ASN), który uzyskalibyśmy klikając ‘Copy to file’ w oknie z Rys 1 i wybierając opcję ‘No, don’t export private key’ oraz wskazując format ‘DER encoded binary X.509 (.CER)’. Wyodrębnijmy zatem tę część do osobnego pliku i przepuśćmy przez systemowy certutil:

>certutil -asn EFF5EDAB8123D06B6EFEA7D87716B03F9C8F48CD_18Ch_2FBh_selection
0000: 30 82 02 f7                               ; SEQUENCE (2f7 Bajtów)
0004:    30 82 01 df                            ; SEQUENCE (1df Bajtów)
0008:    |  a0 03                               ; OPTIONAL[0] (3 Bajtów)
000a:    |  |  02 01                            ; INTEGER (1 Bajtów)
000c:    |  |     02
000d:    |  02 10                               ; INTEGER (10 Bajtów)
000f:    |  |  32 3d 71 91 d3 af 92 96  4c 64 36 ff 0d 17 a3 61
001f:    |  30 0d                               ; SEQUENCE (d Bajtów)
0021:    |  |  06 09                            ; OBJECT_ID (9 Bajtów)
0023:    |  |  |  2a 86 48 86 f7 0d 01 01  05
         |  |  |     ; 1.2.840.113549.1.1.5 sha1RSA
002c:    |  |  05 00                            ; NULL (0 Bajtów)
002e:    |  30 10                               ; SEQUENCE (10 Bajtów)
0030:    |  |  31 0e                            ; SET (e Bajtów)
0032:    |  |     30 0c                         ; SEQUENCE (c Bajtów)
0034:    |  |        06 03                      ; OBJECT_ID (3 Bajtów)
0036:    |  |        |  55 04 03
         |  |        |     ; 2.5.4.3 Przydomek (CN)
0039:    |  |        13 05                      ; PRINTABLE_STRING (5 Bajtów)
003b:    |  |           41 64 6d 69 6e                                    ; Admin
         |  |              ; "Admin"
0040:    |  30 20                               ; SEQUENCE (20 Bajtów)
0042:    |  |  17 0d                            ; UTC_TIME (d Bajtów)
0044:    |  |  |  31 35 30 32 32 35 31 38  30 39 30 31 5a           ; 150225180901Z
         |  |  |     ;  2015-02-25 19:09
0051:    |  |  18 0f                            ; GENERALIZED_TIME (f Bajtów)
0053:    |  |     32 31 31 35 30 32 30 31  31 38 30 39 30 31 5a     ; 21150201180901Z
         |  |        ;  2115-02-01 19:09
0062:    |  30 10                               ; SEQUENCE (10 Bajtów)
0064:    |  |  31 0e                            ; SET (e Bajtów)
0066:    |  |     30 0c                         ; SEQUENCE (c Bajtów)
0068:    |  |        06 03                      ; OBJECT_ID (3 Bajtów)
006a:    |  |        |  55 04 03
         |  |        |     ; 2.5.4.3 Przydomek (CN)
006d:    |  |        13 05                      ; PRINTABLE_STRING (5 Bajtów)
006f:    |  |           41 64 6d 69 6e                                    ; Admin
         |  |              ; "Admin"
0074:    |  30 82 01 22                         ; SEQUENCE (122 Bajtów)
0078:    |  |  30 0d                            ; SEQUENCE (d Bajtów)
007a:    |  |  |  06 09                         ; OBJECT_ID (9 Bajtów)
007c:    |  |  |  |  2a 86 48 86 f7 0d 01 01  01
         |  |  |  |     ; 1.2.840.113549.1.1.1 RSA (RSA_SIGN)
0085:    |  |  |  05 00                         ; NULL (0 Bajtów)
0087:    |  |  03 82 01 0f                      ; BIT_STRING (10f Bajtów)
008b:    |  |     00
008c:    |  |     30 82 01 0a                   ; SEQUENCE (10a Bajtów)
0090:    |  |        02 82 01 01                ; INTEGER (101 Bajtów)
0094:    |  |        |  00
0095:    |  |        |  9f d5 8c ad a1 9e 95 dc  94 48 6a a8 ad fb 26 3a
00a5:    |  |        |  22 b8 9f 72 e0 c3 14 d6  b9 47 74 25 75 c9 e5 1f
00b5:    |  |        |  b8 7d b6 46 b6 9b 5b 93  87 a7 d5 9f a9 99 2d b0
00c5:    |  |        |  d7 db 68 f2 ee b1 f7 06  4d 16 c7 fb a3 0f 93 31
00d5:    |  |        |  2b 4a 39 32 0d 0c 2d fb  c0 68 4b ca ba 02 da 43
00e5:    |  |        |  8a b3 59 c9 42 e7 07 cd  7a 53 ea 25 a5 e1 6a dc
00f5:    |  |        |  07 63 03 4f ee 2d 96 61  57 b3 1b e6 b2 d6 5d cb
0105:    |  |        |  67 b0 25 91 30 8b bc 2a  71 95 87 db 57 e1 45 f4
0115:    |  |        |  ab b3 ea 09 f6 24 5c 98  71 81 f5 98 9c 90 b6 d3
0125:    |  |        |  fa 4b 78 06 d7 9f 6c 2d  6c 26 c5 66 23 90 e9 6f
0135:    |  |        |  81 3a e2 9e 1d f2 4f c2  99 16 1f 85 1e 5b c3 aa
0145:    |  |        |  16 1d 58 26 bb b9 12 f1  78 58 35 04 d9 51 f5 55
0155:    |  |        |  00 b7 60 6e 41 71 d5 6a  a4 b8 4a 54 52 3d 12 76
0165:    |  |        |  d2 96 51 03 9d 4e 5f 2e  61 6a a3 ff 78 d9 72 e2
0175:    |  |        |  9e 69 8d 5c 36 36 2b d0  0c 8f 2d 1d 3e 17 14 bc
0185:    |  |        |  7b 1c f2 af be 3d 20 1a  15 56 5c c6 af 26 27 0f
0195:    |  |        02 03                      ; INTEGER (3 Bajtów)
0197:    |  |           01 00 01
019a:    |  a3 4b                               ; OPTIONAL[3] (4b Bajtów)
019c:    |     30 49                            ; SEQUENCE (49 Bajtów)
019e:    |        30 15                         ; SEQUENCE (15 Bajtów)
01a0:    |        |  06 03                      ; OBJECT_ID (3 Bajtów)
01a2:    |        |  |  55 1d 25
         |        |  |     ; 2.5.29.37 Ulepszone użycie klucza
01a5:    |        |  04 0e                      ; OCTET_STRING (e Bajtów)
01a7:    |        |     30 0c                   ; SEQUENCE (c Bajtów)
01a9:    |        |        06 0a                ; OBJECT_ID (a Bajtów)
01ab:    |        |           2b 06 01 04 01 82 37 0a  03 04
         |        |              ; 1.3.6.1.4.1.311.10.3.4 System szyfrowania plików
01b5:    |        30 25                         ; SEQUENCE (25 Bajtów)
01b7:    |        |  06 03                      ; OBJECT_ID (3 Bajtów)
01b9:    |        |  |  55 1d 11
         |        |  |     ; 2.5.29.17 Alternatywna nazwa podmiotu
01bc:    |        |  04 1e                      ; OCTET_STRING (1e Bajtów)
01be:    |        |     30 1c                   ; SEQUENCE (1c Bajtów)
01c0:    |        |        a0 1a                ; OPTIONAL[0] (1a Bajtów)
01c2:    |        |           06 0a             ; OBJECT_ID (a Bajtów)
01c4:    |        |           |  2b 06 01 04 01 82 37 14  02 03
         |        |           |     ; 1.3.6.1.4.1.311.20.2.3 Nazwa główna
01ce:    |        |           a0 0c             ; OPTIONAL[0] (c Bajtów)
01d0:    |        |              0c 0a          ; UTF8_STRING (a Bajtów)
01d2:    |        |                 41 64 6d 69 6e 40 56 4d  37 00                    ; Admin@VM7.
         |        |                    ; "Admin@VM7"
01dc:    |        30 09                         ; SEQUENCE (9 Bajtów)
01de:    |           06 03                      ; OBJECT_ID (3 Bajtów)
01e0:    |           |  55 1d 13
         |           |     ; 2.5.29.19 Podstawowe warunki ograniczające
01e3:    |           04 02                      ; OCTET_STRING (2 Bajtów)
01e5:    |              30 00                   ; SEQUENCE (0 Bajtów)
01e7:    30 0d                                  ; SEQUENCE (d Bajtów)
01e9:    |  06 09                               ; OBJECT_ID (9 Bajtów)
01eb:    |  |  2a 86 48 86 f7 0d 01 01  05
         |  |     ; 1.2.840.113549.1.1.5 sha1RSA
01f4:    |  05 00                               ; NULL (0 Bajtów)
01f6:    03 82 01 01                            ; BIT_STRING (101 Bajtów)
01fa:       00
01fb:       01 34 a6 07 0e 4b b1 0f  e5 07 3b 0e 2e d8 38 7b
020b:       f7 45 ed 09 01 42 80 8d  45 13 3a 8c 11 06 ca 0b
021b:       9b ce c5 7d ba 6e 9a 95  c1 2d d9 56 d4 ce 90 a5
022b:       99 36 9f 0f 87 04 58 3b  29 99 a3 11 fd 33 97 1b
023b:       c3 1a 82 a8 6a 8b cc d3  b6 aa 86 ed 65 2d 84 45
024b:       b0 b4 de 6e e9 ea 49 0b  1e 84 90 4c af 26 12 84
025b:       03 8a 11 e9 fc 82 81 67  8b 0c e8 7c cc 20 3d 45
026b:       36 17 8e f8 89 6e 4e f6  b7 da d2 0a bd 4d 9f 93
027b:       b1 22 35 cc b3 c6 23 19  17 5c 2f ab c4 0c a9 8a
028b:       46 6b da 49 db c3 bb c0  4f cd 87 e7 d9 1d e2 94
029b:       32 36 80 57 34 93 77 ed  32 e8 aa 4d ac 5b 8a 13
02ab:       b7 cd 2b bc 26 dd 4c dc  05 ee 9c a4 23 3d f8 e1
02bb:       f0 2c 9a c6 a6 e4 0f 5c  0e 2d 4c af a4 7a 5b 75
02cb:       92 e6 d1 8a 98 eb ce f8  9e b3 fc d2 54 06 e5 46
02db:       81 32 0c 47 1e 5c 73 4c  d3 0f e6 0e b2 67 26 d2
02eb:       81 4e c4 82 22 f0 cd 91  dd 55 5a 68 30 78 3e 19
CertUtil: polecenie -asn zostało wykonane pomyślnie.


W tym momencie mamy już dużo szczegółów dotyczących pliku certyfikatu: wiemy, że użyte zostało RSA, certyfikat przeznaczony jest do użycia w systemie szyfrowania plików, znamy daty ważności pliku, etc., jednak najważniejsza informacja kryje się na Rys 2. pod niebieskim zaznaczeniem. Jest to Key container zapisany w UTF-16LE, który w zrzucie z certutil zaprezentuje nam się następująco:

>certutil -user -store My
My
================ Certificate 0 ================
Serial Number: 323d7191d3af92964c6436ff0d17a361
Issuer: CN=Admin
 NotBefore: 2/25/2015 7:09 PM
 NotAfter: 2/1/2115 7:09 PM
Subject: CN=Admin
Signature matches Public Key
Root Certificate: Subject matches Issuer
Template:
Cert Hash(sha1): ef f5 ed ab 81 23 d0 6b 6e fe a7 d8 77 16 b0 3f 9c 8f 48 cd
  Key Container = 0d29406b-f9e6-4659-90e4-c407201049d2
  Unique container name: 7023b50b1cb2749ef32e108926d13a7d_2f51b5ee-3fb6-43b6-9ba
a-ba5e4247b0df
  Provider = Microsoft Enhanced Cryptographic Provider v1.0
Encryption test passed


i pozwala nam na jednoznaczne zidentyfikowanie pliku zawierającego klucz prywatny tego certyfikatu. W powyższym zrzucie narzędzia certutil występuje jeszcze Unique container name, który jest jeszcze ciekawszy. Zawiera on wprost nazwę pliku z kluczem prywatnym, jednak sposób otrzymania Unique container name jest dla mnie zagadką i w trybie offline nie jestem w stanie jej odtworzyć. To, co udało mi się zauważyć, to to, że nazwa składa się z dwóch części: <dynamic_guid>.<machine_guid>, przy czym <machine_guid> zapisany jest w rejestrze w kluczu HKLM\Software\Microsoft\Cryptography we wpisie MachineGuid, natomiast pochodzenia <dynamic_guid> nie udało mi się ustalić. Mogę tylko przypuszczać, że może to być jakiś skrót fragmentu, bądź całości certyfikatu, ale większych testów i poszukiwań nie przeprowadziłem. Jeśli ktoś wie coś więcej, to zapraszam do podzielenia się swoją wiedzą :)
Mając Key Container, pubkey oraz datę utworzenia pliku certyfikatu jestem w stanie dosyć szybko odnaleźć drugą, brakującą część układanki.

Klucze RSA

Użycie RSA wiąże się z utworzeniem pliku zawierającego wszystkie parametry RSA. Zapisywany on jest w profilu użytkownika, a dokładniej %APPDATA%\Microsoft\Crypto\RSA\{SID}. W omawianym przeze mnie przypadku będzie to: C:\Users\Admin\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-580747136-2243477503-2994681153-1000.
Już pierwszy rzut oka na zawartość tego katalogu pozwala na zorientowanie się, że wszystkie nazwy mają podobny schemat, o którym kilka zdań wyżej pisałem nieco więcej. Pamiętajmy, że RSA używane jest w różnych miejscach systemu i pliki z kluczami nie muszą być powiązane z żadnym certyfikatem, bo przecież to tylko jedno z wielu możliwych użyć RSA. Kolejna rzecz - z moich obserwacji wynika, że system nie mając informacji o tym, że klucz RSA nie jest już do niczego przydatny, nie może usunąć plików i pozostawia je tam nietknięte. Przestrzegam jednak przed ‘porządkami’ w kluczach, bo może się okazać, że gdzieś jednak klucz jest jeszcze używany i wtedy może być troszkę gorzej ;)
Mając jednak same: pubkey, key container oraz datę pliku (z pliku certyfikatu) musimy przeczesać wszystkie pliki w poszukiwaniu tego, który nas interesuje. I jeśli tylko odpowiedni plik istnieje, to go znajdziemy. Poniżej wynik naszych poszukiwań.


Rys 3. Plik zawierający klucze RSA

Plik podzielony jest z grubsza na 4 główne części:
[] nagłówek - w którym znajdziemy podstawowe informacje dotyczące pozostałych elementów oraz wyróżniony na [] czerwono key container, który widzieliśmy wcześniej w pliku certyfikatu (tu mamy kodowanie ASCII);
[] rsaheader - z częścią publiczną klucza oraz jednym z parametrów algorytmu (pubexp = 65537, co jest najczęściej używaną wartością);
[] blob DPAPI zawierający klucz prywatny RSA;
[] blob DPAPI zawierajacy dodatkowe dane służące do odszyfrowania klucza prywatnego.

Jako ciekawe i bardzo pouczające zadanie pozostawiam odnalezienie klucza publicznego w sekcji pomarańczowej :)

Na Rys 4 możemy znaleźć więcej szczegółów opisanych wyżej pierwszych dwóch składowych wraz z wyróżnioną nazwą key containera.


Rys 4. Zgrubny podział pliku zawierającego klucze RSA.

Dziwić może nadmiarowy rozmiar tablicy zawierającej klucz publiczny - w końcu powinien wynosić 256, a nie 264 bajtów. Rzut oka na zawartość tablicy i wszystko jasne - wystarczy obciąć ostatnie 8 zerowych bajtów i mamy kluczyk (obcinamy tak naprawdę do bitlength / 8).

Wszystko fajnie, ale gdzie jest klucz prywatny? Przecież bez niego nie odszyfrujemy efs-owego FEKa i nie będziemy w stanie dostać się do zawartości zaszyfrowanego pliku! Odpowiedzi należy szukać w dwóch tajemniczych polach: rsapk oraz rsaFlags, które zapisane są z użyciem tej samej struktury: DPAPIBlob. Czas na bardzo głębokie zanurzenie!

DPAPI

Struktury danych oraz algorytmy użyte w DPAPI przez długi czas stanowiły zagadkę i w zasadzie dopiero prace przy DPAPIck doprowadziły do względnego uporządkowania dostępnej wiedzy. Niemal 4 lata temu w swojej blotce o zabezpieczeniach związanych z SecureString  wspominałem już o DPAPI (a także o efs), jednak nie wchodziłem bardzo głęboko w szczegóły. Prawdę powiedziawszy od tamtego czasu niewiele się w tej materii zmieniło, temat nadal jest słabo omawiany i poza DPAPIck w zasadzie brakuje narzędzi pozwalających na eksplorację. Jak widać, nawet tak długi czas pozwala na zupełnie świeże jego przedstawienie: po polsku nie znalazłem nic interesującego, więc albo temat nie jest ciekawy, albo nikt, kto rozpoznał go w całości nie podjął się szerszej prezentacji. Czas tę lukę wypełnić, zapraszam w otchłań podstawowych mechanizmów systemowych związanych z zabezpieczaniem wrażliwych danych użytkownika.

Podstawowym założeniem DPAPI jest umożliwienie użytkownikowi przechowywanie jego wrażliwych danych (np. danych logowania do różnych systemów, kluczy szyfrujących, etc.) w sposób bezpieczny. Przy czym ‘sposób bezpieczny’ należy rozumieć jako taki, który zapewnia, iż odzyskanie oryginalnych danych jest bardzo trudne, lub wręcz niemożliwe, bez znajomości pewnych faktów. Informacją, na której opiera się bezpieczeństwo całego systemu jest hasło użytkownika, a precyzyjniej skrót hasła (SHA1 - najczęściej; czasem MD4). Na podstawie skrótu hasła generowany jest zestaw kluczy (masterkeys), które służą do odszyfrowywania blobów DPAPI. Aby zabawę nieco urozmaicić pomyślmy o tym, co się dzieje, gdy użytkownik zmieni hasło. W takim momencie bieżący skrót hasła  nie może zostać wykorzystany do odszyfrowywania masterkeys, więc system musi skądś ten skrót wziąć. Miejscem tym jest plik CREDHIST, w którym zapisane są wszystkie skróty haseł użytkownika, które były w użyciu w momencie korzystania z DPAPI.
Po tym krótkim wstępie wróćmy do naszego certyfikatu, a dokładniej pliku zawierającego klucz prywatny RSA. Dwie ostatnie składowe pliku to bloby DPAPI, i dla poprawy czytelności skupimy się na drugim z nich. Struktury są bowiem identyczne, jednak długość pierwszego jest znacznie większa od drugiego, więc zajmowanie się dłuższym na pewno nie poprawi zrozumienia, a wręcz przeciwnie. Najciekawsze pola tego bloba znajdziemy na Rys 5 (kolor poprzedzającego bloba zmieniłem na czarny).


Rys 5. Blob DPAPI - rsaFlags

Bardziej szczegółowy opis znajdziemy na Rys 6.


Rys 6. Bloby DPAPI z pokolorowanymi niektórymi polami.

W tym momencie najważniejsze pole to mkguid, które w przypadku obu blobów jest identyczne:
f36aeda2-00fc-40d3-bac6-41866e959715. Zanim go omówimy dokładniej, rzućmy okiem na pozostałe wyróżnione pola bloba:
[] provider - Guid providera, który został użyty przez DPAPI do szyfrowania. Występuje w zasadzie we wszystkich blobach DPAPI i tym samym stanowi jego wyróżnik, którego można użyć w poszukiwaniu blobów rozsianych po dysku, rejestrze, etc.;
[] cipherAlgo (0x6610) - liczba określająca użyty algorytm symetryczny;
[] hashAlgo (0x800E) - liczba określająca użyty algorytm wyliczania skrótu;
[] salt - tablica bajtów zawierająca sól użytą podczas wyliczania klucza deszyfrującego;
[] hmac - dla porównania tablica bajtów gwarantująca, że nikt nie gmerał przy całym blobie :)
[] cipherText - tablica bajtów zawierająca zaszyfrowane dane;
[] sign - tablica bajtów zawierająca blob podpisany hmacem do potwierdzenia integralności bloba.

Można się w tym momencie zastanawiać, dlaczego w kluczu RSA znajdują się dwa bloby DPAPI, ale odpowiedź na to pytanie przyjdzie później, teraz pomyślmy skąd wziąć klucz deszyfrujący dla bloba.

Ścieżka prowadzi poprzez tajemniczy mkguid. Czas wejść w trzewia DPAPI.

Masterkey

Wszystkie pliki związane z DPAPI znajdują się w profilu użytkownika, w katalogu %APPDATA%\Microsoft\Protect (Rys 7)


Rys 7. Katalog główny DPAPI

Omawiany guid to po prostu nazwa pliku zawierającego masterkey, który znajduje się w podkatalogu %APPDATA%\Microsoft\Protect\{SID}, gdzie {SID} to oczywiście sid użytkownika (Rys 8).


Rys 8. Katalog z plikami masterkeys.

Zaznaczony plik to interesujący nas masterkey, który zawiera klucz deszyfrujący bloba DPAPI. Jesteśmy już bardzo blisko rozwiązania, niemal czujemy zapach klucza :) Zobaczmy zatem, jak wygląda plik masterkey.


Rys 9. Masterkey z wyróżnionymi najciekawszymi elementami

Już na pierwszy rzut oka możemy odnaleźć masterkey guid (mkguid), który zapisany jest w postaci łańcucha znaków w kodowaniu UTF-16LE. Pozostałe wyróżnione elementy wymagają dodatkowego opisu struktury, który znajdziemy na Rys 10.


Rys 10. Struktura pliku masterkey

Z najciekawszych pól na szczególną uwagę zasługują pola struktury masterkey:
[] iv - wektor inicjalizacyjny wykorzystany do odszyfrowania bloba zapisanego jako [] cipherText.
[] hashAlgo - ponownie liczba wskazująca na użyty algorytm haszujący;
[] cipherAlgo - i tu wracamy do liczby wsazującej na użyty algorytm symetryczny;
[] rounds - liczba określająca liczbę rund użyta przy obliczeniach skrótu z użyciem funkcji pbkdf2.

Jednak najważniejszy element kryje się na samym końcu: guid, który prowadzi nas do kolejnej zagadki: pliku Credhist. Mamy bowiem niemal wszystkie elementy układanki związanej z plikiem masterkey, brakuje nam tylko jednego: klucza deszyfrującego. Bez niego nie jesteśmy w stanie odszyfrować zawartości ciągu cipherText, a więc brniemy dalej.
Zanim jednak to uczynimy, krótka wzmianka o pliku Prefered. DPAPI zapisuje w nim guid związany z plikiem masterkey, który jest 'preferowany', czyli powinien zostać użyty, a także datę, kiedy preferowany plik master powinien zostać zastąpiony kolejnym (Rys Prefered 1, Prefered 2)


Rys Prefered 1. Dane pliku prefered


Rys Prefered 2. Plik Prefered - struktura

Jak widać, datą graniczną dla bieżącego pliku jest 22 kwietnia. Rzucamy okiem na Rys 8. i okazuje się, że DPAPI zamierza wymieniać plik master na nowy po 3 miesiącach od utworzenia poprzedniego. Czego brakuje w pliku Prefered? Jakiegoś HMACa - wystarczy ustawić odpowiednio odległy czas i możemy jechać na jednym pliku master tak długo, jak będziemy chcieli.

Credhist

Już we wstępie do DPAPI napisałem, że plik Credhist zawiera skróty haseł użytkownika, które zostały użyte do zaszyfrowania masterkeys. Myliłby się jednak ten, który sądzi, iż są one zapisane tam w postaci jawnej i tylko czekają na wyciągnięcie. O nie, co to, to nie! Zresztą sami zobaczmy.


Rys 11. Plik Credhist

Hmm… długi ten zrzut jak na wpis na blogu. Ale przynajmniej wszystko widać, jak na dłoni! Plik podzielony jest z grubsza na nagłówek i tablicę elementów typu CredHistEntry, które starałem się pokolorwać w różne odcienie przechodzące między zielenią, a jakimś fioletem. Ostatni, a w istocie pierwszy wpis tej listy, widoczny na dole Rys 11 powinien być najbardziej zielony ze wszystkich, jednak zdjąłem z niego ten kolor i wyróżniłem różnymi kolorami najciekawsze elementy struktury, szczegóły na Rys 12.


Rys 12. Szczegółowy opis pliku Credhist


- hashAlgo, rounds, cipherAlgo, iv - opisywane wcześniej, stanowią parametry funkcji kryptograficznych wyprowadzających klucze oraz biorące udział w deszyfrowaniu ciągu encrypted,
- guid: tu z łatwością odnajdujemy guid zapisany w pliku masterkey (zaznaczony ramką). Zauważmy, że guidy innych wpisów CredHistEntry mają inne guidy (dla porównania rozwinąłem także 3 element listy).

Wszystko fajnie, ale ciągle jeszcze nie wiemy jak wyłuskać interesujący nas klucz deszyfrujący dla naszego pliku masterkey.
W tym momencie przypomina mi się fragment filmu ‘Skarb narodów’, w którym ojciec głównego bohatera stwierdza, iż "a to cię zaprowadzi do kolejnej wskazówki. I zawsze będziesz znajdywał tylko wskazówki.". Mamy bowiem:
- zaszyfrowany fek, do odszyfrowania którego szukamy klucza w
- zaszyfrowanym blobie dpapi w pliku zawierającym prywatny klucz rsa, do odszyfrowania którego potrzebujemy klucza z
- zaszyfrowanego masterkey, do odszfrowania którego potrzebny jest klucz zapisany w
- zaszyfrowanym wpisie w pliku Credhist, do odszyfrowania którego potrzebny jest
- skrót hasła użytkownika.

Ha! :)
Hola, hola! Czyż nie zaskoczyło nikogo to, że pierwszy wpis w pliku Credhist znajduje się na końcu pliku? Okazuje się bowiem, że przy pierwszym dostępie do DPAPI po zmianie hasła przez użytkownika następuje dopisanie bieżącego skrótu na końcu pliku, a poprzedni wpis zostaje zaszyfrowany z użyciem bieżącego skrótu. Aby zatem dostać się do n-tego wpisu, musimy wykonać n-1 operacji odszyfrowania kolejnych skrótów, biorąc wyliczony poprzedni jako klucz do kolejnego. Pierwszym, biorącym udział w całej operacji jest oczywiście bieżący skrót użytkownika.
Wydawałoby się, że plik Credhist jest zatem dosyć dobrym źródłem skrótów haseł i można pokusić się o łamanie ich. Tu okazuje się jednak, że nie ma to większego sensu, albowiem skróty haseł odszyfrowane są następująco:
- na podstawie skrótu SHA1 (rzadziej MD4) hasła użytkownika oraz jego SIDu (zakończonego \0) wyliczany jest HMAC-SHA1 (encKey);
- tak wyliczony encKey trafia do funkcji pbkdf2 wraz z pozostałymi parametrami, w naszym przypadku:
cipherKey = pbkdf2(hashAlgo = 0x800e (SHA512), encryptionKey = encKey, iv = iv(16 bajtów widocznych na Rys 11), rounds = 17400)
- tak wyznaczony klucz (cipherKey) trafia do algorytmu symetrycznego (w naszym przypadku AES-256-CBC), przy czym początkowe 32 bajty stanowią klucz, a pozostałe 16 - wektor inicjujący i po 3 przebiegach uzyskujemy 48 bajtów odszyfrowanych danych.

W ramach odszyfrowanych danych dostajemy 20 bajtów skrótu SHA-1 oraz 16 bajtów skrótu MD4 (NTHash). Poniżej wyniki z badanego przez nas pliku:



>CredhistDecrypt "<tu moje tajne hasło ;)>" %APPDATA%\Microsoft\Protect\CREDHIST
Credhist entries: 16

Entry[0]:
 guid:                 eaa7c4f9-ef65-42cb-9fd4-1713eaa32669
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   0432EF8EA2042B867682B2989ED97CAB
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[1]:
 guid:                 d7808b04-fab3-438e-a89f-5850da47b4cf
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   608AFFAEDEDD7885B5C9A9640CD3BDB0
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[2]:
 guid:                 34dc2512-0dd4-461f-89ed-2874cbb555dd
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   8BCF9332CD96AB0F84B01C82229CA76A
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[3]:
 guid:                 a366d3aa-e2ab-4c32-ad3d-8f708b18d3a1
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   DBBA71569E757A578FF1374DBD53EC04
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[4]:
 guid:                 0ee78b69-bf92-4c7f-bbb4-b13f2001c8c4
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   DF717641C79AB597F9DE2307F78B3B77
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[5]:
 guid:                 cc0f2b05-dd80-4b8c-be1c-63b70e9ac252
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   43249B6FB4C63500EDAB6E9BC36E8BB2
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[6]:
 guid:                 382a65c4-6a8c-40c0-9b9b-d9cf554c499c
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   73067C0035DE8BE2E77037AFD352D9DD
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[7]:
 guid:                 096407ac-6b03-4eb3-b940-9f0bcd697b5f
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   9A87D8CE7C7169A2BBB7C31C2A097EE0
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[8]:
 guid:                 fa0d031d-f413-4f96-a0a7-1b7b4ccf4456
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   6B5DD141228009657C6F3BF50450CCD9
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[9]:
 guid:                 d6f7e7d4-9014-4c98-8d5f-fa08cd74f49f
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   283E18D599A5CF37A91A0AD325CF432A
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[10]:
 guid:                 ac155368-c1f5-414e-958f-873e2409881e
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   2D2863205712AE0790DF0F17A582AFCC
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[11]:
 guid:                 6e452b3d-9f14-4ae2-8ecf-10b2217da8b5
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   AF2BB5D0BA5466FEE19B210B9D155789
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[12]:
 guid:                 abd074f1-8832-4e02-8ae1-8febc15fcc9b
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   7E36201CB0E1FC708ED8B9A7366FD374
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[13]:
 guid:                 cad9ca65-b155-46a6-adf9-81fd787114dd
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   944A03FE54F74768453892EC06E2218D
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73

Entry[14]:
 guid:                 449f6eee-5278-439e-92d6-fe7e70838ccc
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   C269E7A4FADB7E2C4DB02E4767BAA684
 decrypted pwdhash:    0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
 decrypted nthash:     5FA88DF7BF81CCC14C7F75111F4C9C0F

Entry[15]:
 guid:                 47eb2dab-3adc-4d77-9646-6309285b4f06
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 iv:                   272AA056CBB7578EBAE857FF688F0C61
 decrypted pwdhash:    CC2225CC3784FBFEC26F87A511FB7BCCE4718096
 decrypted nthash:     E4F1BA73165D937C5FC709517E604D73


Jak widać, zmieniałem co najmniej kilkanaście razy hasło, przy czym wygląda na to, że używałem na zmianę dwóch :) Z użyciem prostego kalkulatora (który wylicza także skrócik MSDCC2) mogę porównać:

>HashCalc.exe <haslo1> Admin
MD4(NTHash):   5FA88DF7BF81CCC14C7F75111F4C9C0F
SHA1:          0C2078F4B64FA8A76A2204FB5FE56FA1A3499F4D
MSDCC2:        CC0261BBDD0A43517566DA3B997A12B7

>HashCalc.exe <haslo2> Admin
MD4(NTHash):   E4F1BA73165D937C5FC709517E604D73
SHA1:          CC2225CC3784FBFEC26F87A511FB7BCCE4718096
MSDCC2:        75E4DA1B06D6CBFC88568558919ED359


Back to masterkey

Mając skróty dla wpisu o interesującym nas guidzie możemy wrócić do pliku masterkey, gdzie wykonujemy kroki podobne do tych, które wykonywaliśmy przed chwilą:
- rozpoczynamy od wyliczenia skrótu HMAC-SHA1 (encKey) na podstawie skrótu hasła (wyciągniętego przed chwilą) oraz SIDa zakończonego "\0";
- tak wyliczony encKey trafia do funkcji pbkdf2 wraz z pozostałymi parametrami, w naszym przypadku:
cipherKey = pbkdf2(hashAlgo = 0x800e (SHA512), encryptionKey = encKey, iv = iv(16 bajtów widocznych na Rys 10), rounds = 17400)
- tak wyznaczony klucz (cipherKey) trafia do algorytmu symetrycznego (w naszym przypadku AES-256-CBC), przy czym:
(i) pierwsze 16 bajtów to salt, który za chwilkę użyjemy do wyliczenia hmaca;
(ii) kolejne 512(z bitowej długości hasza) / 8 = 64 bajty to hmac, z którym za chwilę porównamy nasz;
(iii) ostatnie 64 bajty wyniku zawierają odszyfrowany klucz masterkey_decrypted.
Do wyliczenia "hmaca" bierzemy encKey, salt, masterkey_decrypted i stosujemy funkcję skrótu hashAlgo (najpierw na encKey + salt), później na wynik tego + masterkey_decrypted.

>MasterKeyDecrypt "S-1-5-21-580747136-2243477503-2994681153-1000" "CC2225CC3784FBFEC26F87A511FB7BCCE4718096" %APPDATA%\Microsoft\Protect\S-1-5-21-580747136-2243477503-2994681153-1000\f36aeda2-00fc-40d3-bac6-41866e959715
Master guid:           f36aeda2-00fc-40d3-bac6-41866e959715
Credhist guid:         eaa7c4f9-ef65-42cb-9fd4-1713eaa32669

MasterKey:
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 rounds:               17400
 decrypted key:        F0A6B3E5053F34A63F1D4D7D2488E523DF0A921432BFC761AAB317C70C3EB0849163F267419478B693738FE212F7A89835CDE50511FB2715FBB1F7E7621D908D
F0 A6 B3 E5 05 3F 34 A6 3F 1D 4D 7D 24 88 E5 23   ?|3a.?4|?.M}$?a#
DF 0A 92 14 32 BF C7 61 AA B3 17 C7 0C 3E B0 84   ß.?.2?Çaa3.Ç.>°?
91 63 F2 67 41 94 78 B6 93 73 8F E2 12 F7 A8 98   ?cogA?x¶?s?â.÷¨?
35 CD E5 05 11 FB 27 15 FB B1 F7 E7 62 1D 90 8D   5Ía..u'.u+÷çb.??


Back to rsafile

Możemy teraz przymierzyć się do odszyfrowania bloba DPAPI. Zaczynamy od rsaFlags.
- zaczynamy od wyliczenia HMAC z haszem wyliczanym zgodnie z algorytmem zapisanym w hashAlgo i długości hashLen, w naszym przypadku - HMAC-SHA512, przy czym jako entropię stosujemy zahardkodowany ciąg ASCII "Hj1diQ6kpUx7VC4m\0";
- wynikowe 64 bajty bierzemy jako klucz deszyfrujący w algorytmie symetrycznym (zgodnie z podanymi parametrami, w naszym przypadku: AES-256;
- dla pewności wyliczamy sign biorąc masterkey, hmac, entropię oraz blob (ciąg bajtów od początku bloba do końca cipherText, a więc bez ciągu sign i jego długości), korzystając z tego samego co w pierwszym punkcie algorytmu i porównujemy z zawartością pola sign. Jak się wszystko zgadza - znaczy, że nikt nic nie majstrował :)
Mając odszyfrowane pole rsaFlags bierzemy wynikowe dane jako entropię do odszyfrowania klucza prywatnego, przy czym masterKey pozostaje bez zmian (co zresztą wynika wprost z guida masterKey dla bloba powiązanego z kluczem prywatnym).
Stosujemy ten sam algorytm, co w przypadku rsaFlags i w wyniku otrzymujemy zestaw parametrów klucza prywatnego (Rys 13)


Rys 13. Odszyfrowany zestaw parametrów klucza RSA

Szczegóły znajdziemy na Rys 14


Rys 14. Parametry klucza RSA

Dla swojej wygody zapisałem parametry zgodnie z notacją, którą możemy znaleźć w implementacji algorytmu RSA Microsoftu w .NET Framework. Jeszcze tylko zrzut wszystkich elementów:

>RSAFileDecrypter F0A6B3E5053F34A63F1D4D7D2488E523DF0A921432BFC761AAB317C70C3EB0849163F267419478B693738
FE212F7A89835CDE50511FB2715FBB1F7E7621D908D 7023b50b1cb2749ef32e108926d13a7d_2f51b5ee-3fb6-43b6-9baa-ba5e4247b0df

Key container:         0d29406b-f9e6-4659-90e4-c407201049d2
Key bit length:        2048

RSA private key:
 mkguid:               f36aeda2-00fc-40d3-bac6-41866e959715
 hashAlgo:             0x800E (SHA512)
 cipherAlgo:           0x6610 (AES-256)
 decrypted blob
52 53 41 32 08 01 00 00 00 08 00 00 FF 00 00 00   RSA2............
01 00 01 00 0F 27 26 AF C6 5C 56 15 1A 20 3D BE   .....'&ÄA\V...=3
AF F2 1C 7B BC 14 17 3E 1D 2D 8F 0C D0 2B 36 36   Äo.{1..>.-?.?+66
5C 8D 69 9E E2 72 D9 78 FF A3 6A 61 2E 5F 4E 9D   \?i?ƒrUx.Lja._N?
03 51 96 D2 76 12 3D 52 54 4A B8 A4 6A D5 71 41   .Q?Ov.=RTJ÷ĎjOqA
6E 60 B7 00 55 F5 51 D9 04 35 58 78 F1 12 B9 BB   n`.UoQU.5Xxn.1Ż
26 58 1D 16 AA C3 5B 1E 85 1F 16 99 C2 4F F2 1D   &X..aA[.?..?¶Oo.
9E E2 3A 81 6F E9 90 23 66 C5 26 6C 2D 6C 9F D7   ?ƒ:?o‚?#fA&l-l?ž
06 78 4B FA D3 B6 90 9C 98 F5 81 71 98 5C 24 F6   .xKŁŕ???o?q?\$"
09 EA B3 AB F4 45 E1 57 DB 87 95 71 2A BC 8B 30   .e3®"E WU??q*1?0
91 25 B0 67 CB 5D D6 B2 E6 1B B3 57 61 96 2D EE   ?%řgÓ]™2a.3Wa?-Ś
4F 03 63 07 DC 6A E1 A5 25 EA 53 7A CD 07 E7 42   O.c.šj Y%eSzÖ.‡B
C9 59 B3 8A 43 DA 02 BA CA 4B 68 C0 FB 2D 0C 0D   Y3?Cé.oEKhAu-..
32 39 4A 2B 31 93 0F A3 FB C7 16 4D 06 F7 B1 EE   29J+1?.Lu€.M.ö+Ś
F2 68 DB D7 B0 2D 99 A9 9F D5 A7 87 93 5B 9B B6   ohUžř-?c?Oő??[?
46 B6 7D B8 1F E5 C9 75 25 74 47 B9 D6 14 C3 E0   F}÷.au%tG1™.Aa
72 9F B8 22 3A 26 FB AD A8 6A 48 94 DC 95 9E A1   r?÷":&uđůjH?š??!
AD 8C D5 9F 00 00 00 00 00 00 00 00 C9 25 F7 C6   đ?O?........%öA
E1 1A D7 C6 83 7C DB 4D 3A AA BA 72 20 90 7A E0    .žA?|UM:aor.?za
67 26 6E B3 EA 6B F7 40 6A 2F 05 E4 B0 96 11 B8   g&n3ekö@j/.„ř?.÷
FE 2F BC E3 F5 EB 09 43 90 F7 30 B2 D2 6A 01 DE   ./1ao‰.C?ö02Oj.?
73 26 03 0F 23 BD C2 99 10 B1 6F BC 36 73 1A D9   s&..#1¶?.+o16s.U
22 88 01 36 39 65 0C 63 1D 7A 15 F3 40 91 E1 AF   "?.69e.c.z.˘@? Ä
85 DA 12 6F 64 F3 65 E4 55 6E EC 2A 4A B1 1E 59   ?é.od˘e„Uni*J+.Y
33 09 F5 2E 9E A0 E3 D8 E3 56 79 E0 6F 2F D3 13   3.o.?˙aOaVyao/ŕ.
1D 05 1C 4C AB 85 04 99 9A 35 16 DA 00 00 00 00   ...L®?.??5.é....
17 B2 4C 47 EC 64 EB 28 9E 09 5A 89 03 B3 29 DD   .2LGid‰(?.Z?.3)í
D6 0F 64 77 28 B3 79 AF FF 82 09 1E D9 C6 D7 3B   ™.dw(3yÄ.?..UAž;
A3 9B 19 9A D1 88 60 54 EA 42 9E 90 BB 6E F4 AA   L?.?N?`TeB??Żn"a
44 07 E5 A0 01 94 4F 29 3B 6C 42 F4 31 4E 1A F0   D.a˙.?O);lB"1N.?
92 C9 FB 1A FC A6 A4 8E 27 C3 95 CF 0C 83 22 CC   ?u.|Ď?'A?I.?"I
20 C1 EB 77 5F 04 1B 48 94 57 4F E5 E0 E0 E8 B1   .µ‰w_..H?WOaaac+
25 FC D0 D3 49 E2 6F 99 78 86 22 BD 71 BB B6 6F   %?ŕIƒo?x?"1qŻo
21 CC 18 D4 D9 67 8A E8 B0 0D D1 2C 1E DA 9E BB   !I.âUg?cř.N,.é?Ż
00 00 00 00 E9 AF 30 90 67 5E 49 B2 30 E3 04 8F   ....‚Ä0?g^I20a.?
C0 67 1D 41 D1 D8 21 D6 D8 B0 5C 11 CB 19 39 5A   Ag.ANO!™Oř\.Ó.9Z
31 55 E4 F1 CA 6B 68 AA D2 F1 9B AF 39 D7 99 20   1U„nEkhaOn?Ä9ž?.
56 2C D7 8F 87 14 27 DE ED B8 13 00 91 85 49 96   V,ž??.'?ˇ÷..??I?
4D 7C B8 37 B8 22 F8 3B E7 52 44 5F 04 17 93 22   M|÷7÷"o;‡RD_..?"
2B 81 4F DA 08 F2 D6 B7 8F 70 5C 2B 77 5B 8E A3   +?Oé.o™?p\+w[?L
52 B3 F8 43 30 83 EF 70 F3 39 0F 84 45 04 51 59   R3oC0?ip˘9.?E.QY
A5 C8 49 96 D8 88 84 E8 FC 7D 5D A6 8A 94 2E F0   YEI?O??c}]|??.?
A9 76 B5 37 00 00 00 00 47 0F 12 0F 56 51 32 6A   cvu7....G...VQ2j
99 47 E1 B9 85 F4 E7 C6 D6 E9 40 05 57 FD FC FE   ?G 1?"‡A™‚@.Wě.
52 AB F2 A2 97 19 72 B0 B7 B4 03 B1 41 D2 D7 7F   R®oc?.rřď.+AOž.
E6 00 9D BF A6 06 E1 3D E0 C5 51 54 BF DB C4 72   a.??|. =aAQT?UŽr
88 1E BA 9E 6E D3 42 84 8B 24 68 82 C4 41 F6 C9   ?.o?nŕB??$h?ŽA"
E7 3B 14 D8 DA C1 13 48 79 15 CF E4 49 F8 8D E5   ‡;.Oéµ.Hy.I„Io?a
3E 11 BC B4 C9 25 56 A1 48 05 7C 01 E7 13 12 B3   >.1ď%V!H.|.‡..3
EB 6D 14 D7 FF C0 3B E2 38 81 0B F1 92 A2 91 34   ‰m.ž.A;ƒ8?.n?c?4
38 F7 27 FB 7E 6D 70 71 00 00 00 00 9D 77 F9 73   8ö'u~mpq....?wus
BF 14 86 5A 4B 52 B5 30 22 C5 9E 18 6C 93 81 BF   ?.?ZKRu0"A?.l???
79 B2 EB C8 18 45 42 AB 42 9A 2B 44 7D BE EE 81   y2‰E.EB®B?+D}3Ś?
6C 22 0C 86 84 74 E9 50 F2 8A C0 6B 2E AA E5 8D   l".??t‚Po?Ak.aa?
55 75 5B 83 C1 E1 24 0D E0 9E 99 CA E0 E6 02 3A   Uu[?µ $.a??Eaa.:
0F C2 36 C5 B8 61 C0 6F 93 AA 30 68 14 40 DA 3E   .¶6A÷aAo?a0h.@é>
4B 67 C4 C5 78 E6 CF FB B6 87 AF 73 98 00 C0 ED   KgŽAxaIu?Äs?.Aˇ
88 4E 0F 87 32 F2 90 E5 E4 5B 34 EA 2E 6C E8 3C   ?N.?2o?a„[4e.lc<
5F 9B DD EC A1 04 03 23 B8 90 CF 43 00 00 00 00   _?íi!..#÷?IC....
71 4E 81 85 E8 C1 8B B4 7D 95 23 DA BB 8A 56 A1   qN??cµ?ď}?#éŻ?V!
D6 34 8B 84 B8 8B 64 60 F2 CB D4 2F 04 14 28 37   ™4??÷?d`oÓâ/..(7
39 67 93 A9 9F C5 E2 06 D6 73 37 09 D1 39 02 7E   9g?c?Aƒ.™s7.N9.~
B3 91 15 30 BE 68 C3 93 B3 0C EE 38 98 26 27 36   3?.03hA?3.Ś8?&'6
52 D6 47 D1 23 43 94 98 06 A5 58 2F CA 51 7B 08   R™GN#C??.YX/EQ{.
2B A2 86 59 1C 2C 83 73 10 F1 B7 3A 2E 24 82 30   +c?Y.,?s.n:.$?0
C1 16 B6 DD 52 E3 EE F9 C6 A2 40 C7 50 74 60 78   µ.íRaŚuAc@€Pt`x
25 89 9D DF 16 E5 28 C1 48 41 B5 41 17 E3 B8 4B   %??á.a(µHAuA.a÷K
51 B7 E9 A9 D0 D8 B6 CF 2A 2E AF 7B 60 D7 80 CF   Q‚c?OI*.Ä{`ž?I
3A DE 9C A1 70 BB A7 42 FE 83 81 8D A2 4B 20 7E   :??!pŻőB.???cK.~
AD 24 76 D4 EE DF F3 88 38 C2 39 EA 20 B3 2A 75   đ$vâŚá˘?8¶9e.3*u
F8 FA CA 7C F5 DD BD 46 04 77 38 43 5E E8 38 2D   oŁE|oí1F.w8C^c8-
B1 64 7E 40 BF 2D D6 58 94 D5 5E 14 A3 43 F9 4F   +d~@?-™X?O^.LCuO
20 8E B1 A2 F6 5F E0 78 2A D7 80 8F 9E 76 97 E1   .?+c"_ax*ž???v?
55 53 68 FE 7F 95 6C 31 26 AD 64 C9 64 0A B2 9B   USh..?l1&đdd.2?
EB 73 DD C1 29 39 82 C9 94 1F D1 70 C3 E5 43 08   ‰síµ)9??.NpAaC.
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 E6 B6 A0 43 99 77 54 4B 04 04 04 04   ....a˙C?wTK....

 RSA XML:
<RSAKeyValue><Modulus>n9WMraGeldyUSGqorfsmOiK4n3LgwxTWuUd0JXXJ5R+4fbZGtptbk4en1Z+pmS2w19to8u6x9wZNFsf7ow+TMStKOTINDC37wGhLyroC2kOKs1nJQucHzXpT6iWl4WrcB2MDT+4tlmFXsxvmstZdy2ewJZEwi7wqcZWH21fhRfSrs+oJ9iRcmHGB9ZickLbT+kt4BtefbC1sJsVmI5Dpb4E64p4d8k/CmRYfhR5bw6oWHVgmu7kS8XhYNQTZUfVVALdgbkFx1WqkuEpUUj0SdtKWUQOdTl8uYWqj/3jZcuKeaY1cNjYr0AyPLR0+FxS8exzyr749IBoVVlzGryYnDw==</Modulus><Exponent>AQAB</Exponent><P>2hY1mpkEhatMHAUdE9Mvb+B5VuPY46CeLvUJM1kesUoq7G5V5GXzZG8S2oWv4ZFA8xV6HWMMZTk2AYgi2RpzNrxvsRCZwr0jDwMmc94BatKyMPeQQwnr9eO8L/64EZaw5AUvakD3a+qzbiZn4HqQIHK6qjpN23yDxtca4cb3Jck=</P><Q>u57aHizRDbDoimfZ1BjMIW+2u3G9IoZ4mW/iSdPQ/CWx6ODg5U9XlEgbBF9368EgzCKDDM+VwyeOpKb8GvvJkvAaTjH0Qmw7KU+UAaDlB0Sq9G67kJ5C6lRgiNGaGZujO9fG2R4Jgv+vebMod2QP1t0pswOJWgmeKOtk7EdMshc=</Q><DP>N7V2qfAulIqmXX386ISI2JZJyKVZUQRFhA8583DvgzBD+LNSo45bdytccI+31vII2k+BKyKTFwRfRFLnO/giuDe4fE2WSYWRABO47d4nFIeP1yxWIJnXOa+b8dKqaGvK8eRVMVo5GcsRXLDY1iHY0UEdZ8CPBOMwskleZ5Awr+k=</DP><DQ>cXBtfvsn9zg0kaKS8QuBOOI7wP/XFG3rsxIT5wF8BUihViXJtLwRPuWN+EnkzxV5SBPB2tgUO+fJ9kHEgmgki4RC026euh6IcsTbv1RRxeA94Qamv50A5n/X0kGxA7S3sHIZl6Lyq1L+/P1XBUDp1sbn9IW54UeZajJRVg8SD0c=</DQ><InverseQ>Q8+QuCMDBKHs3ZtfPOhsLuo0W+TlkPIyhw9OiO3AAJhzr4e2+8/meMXEZ0s+2kAUaDCqk2/AYbjFNsIPOgLm4MqZnuANJOHBg1t1VY3lqi5rwIryUOl0hIYMImyB7r59RCuaQqtCRRjI67J5v4GTbBiexSIwtVJLWoYUv3P5d50=</InverseQ><D>CEPlw3DRH5TJgjkpwd1z65uyCmTJZK0mMWyVf/5oU1Xhl3aej4DXKnjgX/aisY4gT/lDoxRe1ZRY1i2/QH5ksS046F5DOHcERr3d9XzK+vh1KrMg6jnCOIjz3+7UdiStfiBLoo2Bg/5Cp7twoZzeOs+A12B7ry4qz7bY0Knpt1FLuOMXQbVBSMEo5RbfnYkleGB0UMdAosb57uNS3bYWwTCCJC46t/EQc4MsHFmGoisIe1HKL1ilBpiUQyPRR9ZSNicmmDjuDLOTw2i+MBWRs34COdEJN3PWBuLFn6mTZzk3KBQEL9TL8mBki7iEizTWoVaKu9ojlX20i8HohYFOcQ==</D></RSAKeyValue>


Dla tych, którzy nie znają ‘standardu’ rsa xml krótkie wyjaśnienie: bodaj tylko Microsoft korzysta w .NET Framework z takiego zapisu parametrów klucza prywatnego i powyższy ciąg może służyć do wypełnienia pól obiektu klasy RSACryptoServiceProvider, z użyciem metody o wiele mówiącej nazwie: FromXmlString(string xmlString). Ciekawostką jest fakt, że łańcuch base64 zawiera zakodowany odwrócony oryginalny ciąg bajtów danego parametru, nie jest to zresztą jedyne miejsce, gdzie odbywa się odwrócenie.

Kilka uwag implementacyjnych

.NET dostarcza przestrzeń System.Security.Cryptography, w której znajdziemy implementację zarówno funkcji haszujących, jak i algorytmów symetrycznych i asymetrycznych. DPAPI zapisuje używane przez siebie algorytmy w postaci liczby typu ALG_ID, jednak w .NET nie mamy wbudowanej metody fabryki, z której można skorzystać i wyciągać odpowiedni algorytm w oparciu o alg_id. Są za to abstrakcyjne klasy, które udostępniają metodę Create(string name), przy czym name trafia do klasy CryptoConfig, która ma zaszytych trochę algorytmów w postaci tablic haszujących. Najwygodniej wystrugać swoją własną klasę dostarczającą odpowiednie algorytmy + ich parametry, przyjmując alg_id jako parametr.
Kolejna uwaga dotyczy HMAC - na próżno w .NET Framework szukać HMAC opartego o SHA-512, ponieważ klasa HMAC ma zaszytą funkcją skrótu jako SHA1. Tu z pomocą przychodzi rozwiązanie opisane w książce "Security driven .NET", do lektury której gorąco zachęcam, więcej szczegółów na końcu serii.
W kilku miejscach pojawia się funkcja PBKDF2 i prawdopodobnie pierwsza myśl, jaka przychodzi do głowy, to skorzystać z klasy System.Security.Cryptography.Rfc2898DeriveBytes, która implementuje tę funkcję zgodnie ze standardem RFC2898. Niestety, oryginalna implementacja Microsoftu w DPAPI nieco odbiega od standardu i zamiast wyliczania hasza na podstawie oryginalnego hasza, tu wyliczany jest ‘hasz postępujący’, czyli po operacji XOR. Poniżej funkcja wyliczająca wraz z zakomentowanym w pętli ‘zgodnym ze standardem’ rachunkiem:

byte[] Func()

{

byte[] inputBuffer = Int2(this.block);

this.hmac.TransformBlock(this.salt, 0, this.salt.Length, this.salt, 0);

this.hmac.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);

byte[] hash = this.hmac.Hash;

this.hmac.Initialize();

byte[] buffer3 = hash;

for (int i = 2; i <= this.iterations; i++)

{

//hash = this.hmac.ComputeHash(hash);

hash = this.hmac.ComputeHash(buffer3);

for (int j = 0; j < BlockSize; j++)

{

buffer3[j] ^= hash[j];

}

}

this.block++;

return buffer3;

}


Oczywiście przy 1-2 iteracjach problemu nie ma, jednak przy 17400, jak to widzieliśmy w tekście, wyniki byłyby różne.

Ciąg dalszy nastąpi

Wygląda na to, że mamy z czym wracać do naszego zaszyfrowanego EFSem pliku. Mając wszystkie parametry klucza RSA możemy nareszcie zaatakować FEK i podjąć próbę odszyfrowania pliku. Pozostawiam to jednak na kolejny wpis, albowiem niespodzianek nie koniec i zapewne część z Was ulegnie temu samemu ‘ale jak to?! nie… coś chyba nie tak!’, któremu ja uległem swego czasu :)

Opublikowane 30 marca 2015 00:26 przez mgrzeg
Filed under: ,

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

Abc said:

Dzieki za artykuł. Co to za binarny viewer?

marca 30, 2015 09:40
 

mgrzeg said:

Fajoski, nie? :) Przeprosiłem się z nim ostatnio. 010 Editor -> http://www.sweetscape.com/010editor/

marca 30, 2015 10:47
 

Incorrect password in Remote Desktop Connections Manager (with some DPAPI insights) – Low Level Design said:

maja 23, 2016 11:13

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

W oparciu o Community Server (Personal Edition), Telligent Systems