jeudi 24 mars 2016

Locky: Mieux vaut prévenir...

Bonjour à tous,

Voici un article recopié que vous trouverez en intégralité à cette page... https://www.lexsi.com/securityhub/comment-creer-un-vaccin-contre-le-ransomware-locky/.
Les images n'ont pas été volontairement copiées...

Ainsi, il vaut vous rendre sur le site d’origine afin de copier les données convenablement.

Comment créer un vaccin contre le ransomware Locky

En 2009, nous avions appliqué la notion de vaccin à Conficker afin de protéger les postes contre ce ver se propageant très rapidement sur les parcs informatiques. Voyons si nous pouvons appliquer le même concept au ransomware Locky.

Dans la suite du billet, nous appellerons vaccin toute modification mineure du système ayant pour objet de bloquer, sans intervention utilisateur, tout ou partie des effets néfastes liés à l’exécution d’un programme malveillant. Evidemment, le vaccin doit être administré avant que la maladie n’arrive…

Par modification mineure, on entend par exemple la création d’un mutex ou d’une clé de registre spécifiques, ou bien une modification simple des paramètres n’entraînant pas de désagrément pour l’utilisateur. A titre de contre-exemple, au début de son exécution, Locky vérifie les paramètres de langue du système et n’infecte pas ceux configurés en langue Russe :

On peut donc configurer le système en langue russe pour empêcher l’infection mais cela risque de se révéler assez peu pratique au quotidien

Vaccin n°1 : ACL sur la clé de registre Locky

Suite à la vérification de la langue, Locky tente de créer la clé de registreHKCU\Software\Locky ; si cela échoue pour une quelconque raison, Locky termine immédiatement.

En créant donc cette clé avant Locky avec des ACLs interdisant toute ouverture, on vaccine totalement le système :

Vaccin n°2 : valeur de registre completed

Dans la suite de l’exécution, Locky vérifie au sein de la cléHKCU\Software\Locky l’éventuelle présence des valeurs id (identifiant de la machine infectée), pubkey (clé publique récupérée depuis le serveur, procédure détaillée ci-après), paytext (texte à afficher à la victime, dans sa langue) et completed. Cette dernière valeur indique la fin du processus de chiffrement. Locky vérifie si completed vaut 1 ; le cas échéant et si de plus la valeur id contient l’identifiant correspondant à la machine, il arrête son exécution :

L’algorithme de génération de l’identifiant est simple et donne ceci sur notre machine de test :

GetWindowsDirectoryA() :C:\WINDOWSGetVolumeNameForVolumeMountPointA(C:\WINDOWS) : \\?\Volume{ b17db400-ae8a-11de-9cee-806d6172696f}md5({b17db400-ae8a-11de-9cee-806d6172696f}):1d9076e6fd853ab665d25de4330fee06conversion en ASCII, passage en majuscules et troncature aux 16 premiers caractères :1D9076E6FD853AB6

La création de ces deux clés de registre, dont l’une dépend du système, permet donc d’empêcher le chiffrement des fichiers par Locky :

Vaccin n°3 : clé RSA corrompue

Avant de chiffrer les fichiers, Locky contacte son C&C via une requête HTTP POST avec comme données en clair dans notre exemple :

(gdb) hexdump 0x923770 0x65 88 09 0c da 46 fd 2c de 1d e8 e4 45 89 18 ae 46 |....F.,....E...F|69 64 3d 31 44 39 30 37 36 45 36 46 44 38 35 33 |id=1D9076E6FD853| 41 42 36 26 61 63 74 3d 67 65 74 6b 65 79 26 61|AB6&act=getkey&a| 66 66 69 64 3d 33 26 6c 61 6e 67 3d 66 72 26 63 |ffid=3〈=fr&c| 6f72 70 3d 30 26 73 65 72 76 3d 30 26 6f 73 3d |orp=0&serv=0&os=| 57 69 6e 64 6f 77 73 2b58 50 26 73 70 3d 32 26 |Windows+XP&sp=2&| 78 36 34 3d 30 |x64=0

La première ligne correspond au condensé MD5 du reste du buffer. Ces données sont encodées basiquement avant envoi :

Le décodage des données reçues en réponse utilise un algorithme similaire :

Ces deux algorithmes s’implémentent en quelques lignes de Python :

def encode(buff): buff = md5(buff).digest() + buff out = "" key = 0xcd43ef19 for index in range(len(buff)): ebx = ord(buff[index]) ecx = (ror(key, 5) - rol(index, 0x0d)) ^ ebx out += chr(ecx & 0xff) edx = (rol(ebx, index & 0x1f) + ror(key, 1)) & 0xffffffff ecx = (ror(index, 0x17) + 0x53702f68) & 0xffffffff key = edx ^ ecx return outdef decode(buff): out = "" key = 0xaff49754 for index in range(len(buff)): eax = (ord(buff[index]) - index - rol(key, 3)) & 0xff out += chr(eax) key += ((ror(eax, 0xb) ^ rol(key, 5) ^ index) + 0xb834f2d1) & 0xffffffff return out

Les données décodées sont les suivantes :

00000000: 3af6 b4e2 83b1 6405 0758 854f b971 a80a :.....d..X.O.q.. 00000010: 0602 0000 00a4 0000 5253 4131 0008 0000 ........RSA1....00000020: 0100 0100 2160 3262 90cb 7be6 9b94 d54a ....!`2b..{....J 00000030: 45e0 b6c3 f624 1ec5 3f28 7d06 c868 ca45 E....\..?(}..h.E00000040: c374 250f 9ed9 91d3 3bd2 b20f b843 f9a3 .t%.....;....C.. 00000050: 1150 5af5 4478 4e90 0af9 1e89 66d2 9860 .PZ.DxN.....f..` 00000060: 4b60 a289 1a16 c258 3754 5be6 7ae3 a75a K`.....X7T[.z..Z00000070: 0be4 0783 9f18 46e4 80f7 8195 be65 078e ......F......e.. 00000080: de62 3793 2fa6 cead d661 e7e4 2b40 c92b .b7./....a..+@.+ 00000090: 23c9 4ab3 c3aa b560 2258 849c b9fc b1a7 #.J....`"X...... 000000a0: b03f d9b1 e5ee 278c bf75 040b 5f48 9501 .?....'..u.._H.. 000000b0: 80f6 0cbf 2bb4 04eb a4b5 7e8d 30ad f4d4 ....+.....~.0... 000000c0: 70ba f8fb ddae 7270 9103 d385 359a 5a91 p.....rp....5.Z. 000000d0: 4995 9996 3620 3a12 168e f113 1753 d18b I...6 :......S.. 000000e0: fdac 1eed 25a1 fa5c 0d54 6d9c dcbd 9cb7 ....%..\.Tm..... 000000f0: 4b8e 1228 8b70 be13 2bfd face f91a 8481 K..(.p..+.......00000100: dc33 185e b181 8b0f ccbd f89d 67d3 afa8 .3.^........g... 00000110: c680 17d80100 6438 4eba a7b7 04b1 d00f ......d8N.......00000120: c4fc 94ba ....

Les 16 premiers octets sont le MD5 du reste. A partir de l’offset 0x10, on reconnaît une structureBLOB_HEADER :

type 0x06 =PUBLICKEYBLOBversion 0x022 octets réservésALG_ID 0xa400 =CALG_RSA_KEYX

Il s’agit d’une clé publique RSA, la suite est donc une structureRSAPUBKEY :

magic RSA1 = clé publiquetaille de la clé : 0x800 = 2048 bitsexposant 0x10001 = 65537module 2160…94ba

Comme mentionné précédemment, cette structure est stockée telle quelle (hors MD5) dans la valeur pubkey. Si cette valeur existe mais contient une valeur invalide, les fichiers ne sont ni renommés, ni chiffrés par Locky. La capture ci-dessous montre une machine de test possédant une valeur pubkey contenant un unique octet nul. On voit que Locky s’est exécuté sur la machine mais qu’il n’a pas altéré le fichier monfichier.txt présent sur le bureau bien que son extension fasse partie des cibles :

On remarque aussi que si la valeur pubkey contient une clé RSA 1024, le fichier sera renommé mais pas chiffré :

Vaccin n°4 : clé privée RSA connue

Locky possède un autre problème de design intéressant : si la valeur pubkey existe déjà, elle est utilisée sans aucune forme de vérification lors du chiffrement des fichiers, ce qui permet de forcer l’utilisation d’une clé publique RSA sous notre contrôle et pour laquelle nous disposons de la clé privée associée.

Le code C suivant permet de générer une bi-clé RSA 2048 au format BLOB_HEADER utilisé par Locky dans la valeur pubkey :

#define RSA2048BIT_KEY 0x8000000CryptAcquireContext(&hCryptProv, "LEXSI", NULL, PROV_RSA_FULL, 0); CryptGenKey(hCryptProv, AT_KEYEXCHANGE, RSA2048BIT_KEY|CRYPT_EXPORTABLE, &hKey);// Clé publique CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwPublicKeyLen); pbPublicKey = (BYTE *)malloc(dwPublicKeyLen); CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, pbPublicKey, &dwPublicKeyLen); hPublicKeyFile = CreateFile("public.key", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hPublicKeyFile, (LPCVOID)pbPublicKey, dwPublicKeyLen, &lpNumberOfBytesWritten, NULL);// Clé privée CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPrivateKeyLen); pbPrivateKey = (BYTE *)malloc(dwPrivateKeyLen); CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pbPrivateKey, &dwPrivateKeyLen); hPrivateKeyFile = CreateFile("private.key", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hPrivateKeyFile, (LPCVOID)pbPrivateKey, dwPrivateKeyLen, &lpNumberOfBytesWritten, NULL);

Quelques lignes de Python plus tard, on dispose d’un fichier .reg qu’on peut insérer en base de registre afin de forcer l’utilisation de notre clé publique.

Observons précisément comment chaque fichier est chiffré. Après avoir obtenu un handle vers le CSP (Cryptographic Service Provider) PROV_RSA_AES via un appel àCryptAcquireContext(), Locky importe avec CryptImportKey()le blob contenant la clé publique, issu de la valeur de registre pubkey. Il renomme le fichier ciblé sous la forme .locky. Via la fonction CryptGenRandom(), il génère ensuite 16 autres octets aléatoires :

(gdb) hexdump 0x009ef8a0 16 9d 86 d3 42 48 3a 45 04 1a cb 95 1c 77 90 8f 7c

Ces octets sont copiés à la suite d’une structure BLOB_HEADER importée avec CryptImportKey():

(gdb) hexdump 0x009ef784 0x1c 08 02 00 00 0e 66 00 00 10 00 00 00 9d 86 d3 42 48 3a 45 04 1a cb 95 1c 77 90 8f 7ctype 0x08 =PLAINTEXTKEYBLOBversion 0x022 octets réservésALG_ID = 0x660e =CALG_AES_128taille de la clé = 0x10 octets

Il s’agit donc d’une clé AES-128. La fonction GetSetKeyParam() est ensuite appelée pour préciser l’utilisation future de la clé :

(gdb) x/w $esp+4 0x9ef830: 0x00000004 (gdb) x/w *(int*)($esp+4+4) 0x9ef858: 0x00000002

La valeur 4 pour le deuxième argument signifie KP_MODE et permet de spécifier le mode d’opération utilisé : la valeur 2 pour le troisième argument signifie CRYPT_ MODE_ECB.

Par la suite, la fonction CryptEncrypt() est appelée afin de chiffrer cette clé AES par la clé publique RSA. On obtient le résultat suivant :

(gdb) hexdump 0x9ef8a0 256 64 ab 20 75 75 56 ae f4 af 20 7f 38 81 d7 d6 56 |d. uuV... .8...V| 22 89 92 6e 30 e0 61 d2 24 f0 a1 d6 2a 20 7f 6c |"..n0.a.\...* .l| e0 10 cc ab 26 62 33 66 71 8d 93 4c 04 61 8a 9a |....&b3fq..L.a..| 86 e7 f4 75 58 ae 8a 68 96 1f a8 69 15 aa 2f e7 |...uX..h...i../.| 8b cd ca 2e b0 7b e1 89 5f 3e 65 61 4c 0b 43 5e |.....{.._>eaL.C^| 60 3b 17 48 0e d2 08 80 bd 4d e2 38 5b 51 c9 82 |`;.H.....M.8[Q..| 26 bf 94 8a 45 40 82 62 1e 88 42 aa 35 2a 3e 58 |&...E@.b..B.5*>X| d2 7d 03 4d cd d4 e6 3b 7d 44 e9 5f dc 4d 1c 4b |.}.M...;}D._.M.K| 27 a9 39 0c 74 ed 46 97 60 af 3a 97 3f 89 33 28 |'.9.t.F.`.:.?.3(| bf 27 67 57 f8 c5 4e 03 72 45 60 88 03 e5 11 98 |.'gW..N.rE`.....| 6f 49 af 92 72 69 db ec b7 c7 51 9a 05 f2 34 e0 |oI..ri....Q...4.| 17 e4 1b 7e c5 97 ff 3d 42 5d ff a5 69 a4 58 f8 |...~...=B]..i.X.| 3b bd 9f 84 6e a5 c7 81 4e 0e aa 5d 40 ff 06 01 |;...n...N..]@...| e9 ee 3c e5 0f b2 b4 80 af 56 c5 b8 25 af 11 2e |..76 98 46 2e db 6c 76 bb |"....P..v.F..lv.| b5 1e 70 44 41
e2 15 31 f9 02 7d 92 7a e5 73 17 |..pDA..1..}.z.s.|

Ce buffer est recopié tel quel dans le fichier .locky.

Puis Locky construit un buffer de taille 0x800 constitué de zéros, sauf à la fin de chaque ligne où un compteur est incrémenté :

(gdb) hexdump 0x00926598 0x800 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 01 |................| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 |................| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 |................| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 |................| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 |................| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 |................| [...] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7a |...............z| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7b |...............{| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7c |...............|| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7d |...............}| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7e |...............~| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7f |................|

Ces données sont chiffrées en AES-128-ECB via CryptEncrypt()avec la clé générée ci-dessus pour obtenir le buffer K suivant :

0x00926598: fc d3 bb 90 ac 1e 1e 6e 76 88 09 52 66 76 71 fc 0x009265a8: d5 e2 07 fd a5 0c 02 50 d0 83 4e 9b 95 1c 0b 60 0x009265b8: 3f c5 49 e5 df b2 05 56 bd ce eb f6 0d 70 9f 62 0x009265c8: 98 f1 e8 b7 e2 8e d8 97 7f a1 83 14 2b db 82 98 0x009265d8: 5b 4a 94 f7 fb 60 81 cd bb c7 a2 33 60 b1 c0 c7 0x009265e8: 1c c5 c7 40 af 7c ea 4b e2 74 b0 32 c2 37 5e fa 0x009265f8: cf 40 69 9b 81 92 b8 f1 77 79 83 97 32 19 75 a6 [...] 0x009267c8: 96 9a 1d bd 9b 03 33 2f d5 e7 a7 fc ac fc 09 c9 0x009267d8: f6 bd c5 73 ce 9e ce bc fd e4 ef 6f 06 dd 7d 15 0x009267e8: 7d 95 e6 18 78 87 46 ba 75 5e 58 2e f8 ba 5c 14 0x009267f8: 3d a9 f3 d3 af ef 0b 39 00 ae 0c 32 2b fd 37 eb 0x00926808: 3f 3a 68 11 b8 d1 ae e7 28 40 0a20 33 31 8f 7e 0x00926818: c3 8f 55 2a 5f b531 26 02 41 d7 e3 84 c5 79 9b [...]

Le premier élément à être chiffré est le nom du fichier. Locky réserve pour cela un buffer de taille 0x230 rempli initialement de zéros et y copie le nom du fichier avant de la XORer avec le buffer K qui est donc utilisé comme flux de clé. Par exemple, pour les octets 0 à 3 :

(gdb) p/x \edx // flux de clé \3 = 0x90bbd3fc(gdb) hexdump \edi 64 //avant XOR 2a a1 1b d4 6d 00 6f 00 6e 00 66 00 69 00 63 00 |*...m.o.n.f.i.c.| 68 00 69 00 65 00 72 00 2e 00 74 00 78 00 74 00 |h.i.e.r...t.x.t.| 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 |................|(gdb) hexdump \edi 64 //après XOR 1 d6 72 a0 44 6d 00 6f 00 6e00 66 00 69 00 63 00 |.r.Dm.o.n.f.i.c.| 68 00 69 00 65 00 72 00 2e 00 74 00 78 00 74 00|h.i.e.r...t.x.t.| 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 |................|

Pour les octets 4 à 7 :

(gdb) p/x \eax // flux de clé \4 = 0x6e1e1eac(gdb) hexdump \edi 64 //après XOR 2 d6 72 a0 44 c1 1e 71 6e 6e 00 66 00 69 00 63 00 |.r.D..qnn.f.i.c.| 68 00 69 00 65 00 72 00 2e 00 74 00 78 00 74 00 |h.i.e.r...t.x.t.| 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 |................|

Et ainsi de suite. Le buffer résultant est recopié tel quel dans le fichier .locky à la suite de la clé AES chiffrée en RSA.

Locky chiffre ensuite le contenu du fichier de la même façon que le nom mais en utilisant le flux de clé à partir de l’offset 0x230 (adresse 0x009267c8 dans notre cas). On imagine que ce choix n’est pas dû au hasard car si les développeurs de Locky avaient utilisé le même flux de clé pour les deux éléments, le déchiffrement du contenu aurait été trivial… En effet, partant du principe que sur les 0x230 octets réservés pour le nom, l’immense majorité sera constituée de zéros, le XOR de ces octets nuls, qu’on retrouve dans le fichier.locky, aurait directement fourni une grande partie du flux de clé sans connaissance de la clé secrète AES correspondante.

Le contenu du fichier est ainsi XORé avec le flux de clé à partir de l’offset 0x230 :

(gdb) p/x \edx \5 = 0xbd1d9a96 // flux de clé à l'offset 0x230 (0x009267c8)(gdb) hexdump \edi 64 //avant XOR 63 65 63 69 20 65 73 74 20 75 6e 20 73 65 63 72 |ceci est un secr| 65 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |et..............|(gdb) hexdump \edi 64 //après XOR 1 f5 ff 7e d4 20 65 73 74 20 75 6e 20 73 65 63 72 |..~. est un secr| 65 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |et..............|

Le résultat complet du XOR du contenu est recopié tel quel au début du fichier .locky.

Si la taille du fichier dépasse la taille du buffer incrémental initial, Locky chiffre d’autres buffers du même type avec CryptEncrypt()en continuant à incrémenter le compteur :

(gdb) hexdump *(int*)($esp+4+4+4+4) 128 0x009255e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 0x009255f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 81 0x00925600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 [...](gdb) hexdump *(int*)($esp+4+4+4+4) 128 0x009255e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 0x009255f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 0x00925600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 [...]

Au final, un fichier .locky a donc le format suivant :

Les étapes du déchiffrement d’un fichier .locky sont les suivantes :

déchiffrement du buffer RSA avec notre clé privée pour obtenir 16 octets utilisation de ces 16 octets comme clé AES-128-ECB pour chiffrer un buffer constant constituant un compteur utilisation des 0x230 premiers octets du résultat comme flux de clé pour XORer le nom du fichier utilisation des octets à partir de l’offset 0x230 comme flux de clé pour XORer son contenu

Le code C suivant implémente la première étape :

// Import de la clé privée RSA hPrivateKeyFile = CreateFile("private.key", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); dwPrivateKeyLen = GetFileSize(hPrivateKeyFile, NULL); pbPrivateKey = (BYTE *)malloc(dwPrivateKeyLen); ReadFile(hPrivateKeyFile, pbPrivateKey, dwPrivateKeyLen, &dwPrivateKeyLen, NULL); CryptImportKey(hCryptProv, pbPrivateKey, dwPrivateKeyLen, 0, 0, &hKey);// Lecture du buffer RSA hEncryptedFile = CreateFile("encrypted.rsa", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); dwEncryptedDataLen = GetFileSize(hEncryptedFile, NULL); pbEncryptedFile = (BYTE *)malloc(dwEncryptedDataLen); ReadFile(hEncryptedFile, pbEncryptedFile, dwEncryptedDataLen, &dwEncryptedDataLen, NULL);// Déchiffrement de la clé AES CryptDecrypt(hKey, NULL, TRUE, 0, pbEncryptedFile, &dwEncryptedDataLen); hClearFile = CreateFile("aeskey.raw", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hClearFile, (LPCVOID)pbEncryptedFile, dwEncryptedDataLen, &lpNumberOfBytesWritten, NULL);

On récupère bien la clé AES générée ci-dessus :

$ xxd aeskey.raw 9d86 d342 483a 4504 1acb 951c 7790 8f7c

Le script Python suivant permet de déchiffrer le nom du fichier et son contenu à partir de cette clé :

#! /usr/bin/env pythonfrom Crypto.Cipher import AESprint "UnLocky - Locky decryption tool, CERT-LEXSI 2016key = "9d86d342483a45041acb951c77908f7c".decode("hex")# NB : ici petits fichiers seulement counter = "" for i in range(0x80): counter += "\x00"*15 + chr(i)keystream = AES.new(key, AES.MODE_ECB).encrypt(counter)data = open("1D9076E6FD853AB6C931AFE2B33C3AF9.locky").read() enc_size = len(data) - 0x230 - 0x100 - 0x14enc_filename = data[-0x230:] enc_content = data[:enc_size]clear_filename = "" for i in range(0x230): clear_filename += chr(ord(enc_filename[i]) ^ ord(keystream[i]))print "[+] Nom du fichier :" print clear_filenameclear_content = "" for i in range(enc_size): clear_content += chr(ord(enc_content[i]) ^ ord(keystream[0x230+i]))print "[+] Contenu :" print clear_content

Voyons si tout fonctionne :

\ ./unlocky.py UnLocky - Locky decryption tool, CERT-LEXSI 2016[+] Nom du fichier : monfichier.txt [+] Contenu : ceci est un secret

Conclusion

Locky fait des ravages dans le monde entier depuis de nombreuses semaines mais il existe des moyens très simples pour se protéger de la perte de ses fichiers, sans antivirus ni autre outil de sécurité, à condition de se préparer avant l’infection. L’un des 4 vaccins différents présentés dans ce billet utilise par exemple le fait de pouvoir forcer la clé publique RSA avec laquelle sont chiffrées les clés AES.

Concernant l’aspect cryptographique, l’analyse menée ci-dessus montre que les fichiers ne sont pas directement chiffrés en AES-128-ECB. Locky construit un buffer constant de forme incrémentale qu’il chiffre en AES-128-ECB et le résultat est utilisé comme deux flux de clé pour XORer respectivement le nom du fichier et son contenu, ce qui s’apparente plus au mode CTR.

https://www.lexsi.com/securityhub/comment-creer-un-vaccin-contre-le-ransomware-locky/

Bonne soirée.
Patrice.