La semaine dernière, nous avons proposé une série de vaccins afin d’empêcher le ransomware Locky de chiffrer les fichiers ou de nous permettre de les déchiffrer en forçant la clé RSA. Le malware a depuis muté et n’utilise plus une clé de registre statique et ces vaccins ne sont plus efficaces. Il reste cependant toujours possible de créer un vaccin contre cette nouvelle variante de Locky.

Le vaccin n°1 présenté dans le billet précédent avait l’avantage de la simplicité : une clé de registre HKCU\Software\Locky présente avec des ACLs restrictives permettait de bloquer sa création par le malware lui-même et empêchait donc une bonne exécution. Sur les variantes les plus récentes, Locky n’utilise plus cette clé statique :

locky2_reg

Comme Locky utilise cette clé pour stocker des informations dans le but de les retrouver ultérieurement, on suppose que cette clé n’est pas aléatoire mais issue d’un algorithme utilisant des paramètres propres au système en cours d’infection. En analysant le code, une nouvelle fonction est en effet apparue avant l’appel à RegCreateKeyExA(), nommée myGenerateKeyName() dans la capture ci-dessous :

locky2_reg2

myGenerateKeyName() commence par appeler une fonction sur les valeurs 0x1D9076E6 et 0xFD853AB6. On reconnait l’identifiant Locky de notre machine de test dont le calcul a été donné dans le billet précédent, basé sur le GUID de la partition Windows (vaccin n°2). Cette fonction, que nous nommerons myCrypt() dans la suite, contient quelques opérations cryptographiques simples dans une boucle :

lock2_mycrypt
Par la suite, la fonction myCrypt() est appelée deux fois à l’intérieur d’une boucle, à chaque fois sur le résultat fourni par l’appel précédent, et en itérant sur un troisième paramètre. En fin de boucle, une valeur est ajoutée à 0x41, 0x61 ou 0x30 afin de créer respectivement un caractère majuscule, minuscule ou un chiffre, en fonction du reste d’une division euclidienne par 26 ou 10 :

lock2_mycrypt2

La boucle est exécutée un nombre de fois déterminé par la variable esp+0x48+ var_1C dont le contenu provient de quelques opérations élémentaires appliquées au résultat du premier appel à myCrypt() :

lock2_mycrypt3

Le script Python suivant permet de générer le nom de la clé de registre désormais utilisée par Locky :

#! /usr/bin/env python

# Locky registry name generator
# Sylvain SARMEJEANNE, CERT-LEXSI 03/2016

from sys import argv

# Fonctions generales
def v32(val):
  return val & 0xffffffff

def shrd(dst, src, cnt):
  return v32(((src << 32) + dst) >> cnt)

def shld(dst, src, cnt):
  out = ((src << 32) + dst) << cnt
  out |= (src >> 32-cnt)
  return v32(out)

def add(a, b):
  out = a + b
  c = out > (2**32-1)
  return v32(out), c

rol = lambda val, r_bits: \
 (val << r_bits%32) & (2**32-1) | \
 ((val & (2**32-1)) >> (32-(r_bits%32)))

# Fonction myCrypt() de Locky
def mycrypt(h, l, idx):
  for i in range(7):
    eax = shrd(l, h, 0x19)
    edx = v32(l<<7) 
    eax = eax^edx
 
    ebx = shld(h, l, 7)
    ecx = h>>0x19
    ecx = ecx^ebx

    esi, c = add(rol(i, 7), eax)
    edi = v32(ecx+c)
 
    esi, c = add(esi, v32(idx<<i))
    edi = v32(edi+c)
 
    esi, c = add(esi, 0x4E456DEF)
    edi = v32(edi+c+0x58749DF5)
 
    l, c = add(l, esi)
    h = v32(h+edi+c)

  return h, l

botid = argv[1]

h = int(botid[:8], 16)
l = int(botid[8:], 16)
name = ""

h, l = mycrypt(h, l, 0)
size = 8 + (shrd(l, h, 5) & 7)

for i in range(size):
  h, l = mycrypt(h, l, i)
  l_save = (l & 0xff) - 1

  h, l = mycrypt(h, l, i)
  eax = l & 0xff
 
  if l_save%3 == 0:
    edx = (eax%26) + ord('A')
  elif l_save%3 == 1:
    edx = (eax%26) + ord('a')
  else:
    edx = (eax%10) + ord('0')

  name += chr(edx)

print name

En fournissant à ce script notre identifiant Locky, on retrouve bien le nom de la clé créée par le ransomware sur la première capture de ce billet :

$ ./locky_reg.py 1D9076E6FD853AB6
BP9d9j6l

Conclusion

Locky a été récemment mis à jour et n’utilise plus la clé de registre statique HKCU\Software\Locky. L’analyse d’une nouvelle souche montre que le ransomware utilise désormais une clé de registre dont le nom dépend de l’identifiant de la machine, lui-même calculé à partir du GUID de la partition Windows. Le principe d’une vaccination contre Locky est toujours valable et effective sur cette nouvelle variante, en utilisant cette fois-ci un vaccin dynamique.

Les auteurs de Locky sont très réactifs et le vaccin présenté ici ne durera probablement pas très longtemps… Ce billet avait principalement pour objectif de montrer qu’un vaccin est réalisable même si les éléments utilisés ne sont pas statiques ; il suffit en effet qu’ils soient prévisibles.