Buscando malware en volcados de memoria mediante Volatility y Yara

Aunque prácticamente todos los parámetros de Volatility pueden ayudarnos a encontrar e identificar malware en volcados de memoria, hay algunos que fueron diseñados específicamente para cazar rootkits y código malicioso. Uno de ellos es el plugin "yarascan", que nos puede ayudar a encontrar mediante reglas Yara cualquier secuencia de bytes (como instrucciones de ensamblador con wild cards), expresiones regulares, cadenas ANSI o cadenas Unicode en el modo de usuario o en la memoria del kernel.

Al usar las reglas específicas de Yara, una de las "navajas suizas" de los analistas, se puede detectar la presencia de artefactos relacionados con las familias de malware más comunes en la imagen de memoria analizada.

Para el ejemplo de este post usaremos una muestra de memoria disponible online, como el archivo stuxnet.vmem, que los autores del libro The Malware Analyst Cookbook's hicieron para practicar y que proviene de una máquina virtual infectada con Stuxnet.

Una vez descargada la imagen, lo primero que haremos como siempre será ejecutar una pequeña identificación:
$ volatility -f stuxnet.vmem imageinfo

Volatility Foundation Volatility Framework 2.6
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86)
                     AS Layer1 : IA32PagedMemoryPae (Kernel AS)
                     AS Layer2 : FileAddressSpace (/tools/hunting/stuxnet.vmem)
                      PAE type : PAE
                           DTB : 0x319000L
                          KDBG : 0x80545ae0L
          Number of Processors : 1
     Image Type (Service Pack) : 3
                KPCR for CPU 0 : 0xffdff000L
             KUSER_SHARED_DATA : 0xffdf0000L
           Image date and time : 2011-06-03 04:31:36 UTC+0000
     Image local date and time : 2011-06-03 00:31:36 -0400

Ahora que tenemos el profile tendremos que especificarlo junto con la imagen y la yara o yaras a analizar. Para esto último tendremos varias opciones. La primera de ellas podría ser hacer un "merge" del conjunto de yaras disponible.
Esto lo podemos hacer rápidamente mediante este script en Python de Andrea Fortuna que a su vez se basa en el proyecto de Lucas Soumille:
#!/usr/bin/env python
# encoding: utf-8

import os
import shutil

def get_rules_from_git():
 shutil.rmtree("./rules")
 os.system("git clone https://github.com/Yara-Rules/rules.git")

def list_yara_files():
 all_yara_files = []
 for root, directories, filenames in os.walk("./rules/malware"):
  print ("Processing " + root)
  filenames.sort()
  for file_name in filenames:
   rule_filename, rule_file_extension = os.path.splitext(file_name)
   if rule_file_extension == ".yar" or rule_file_extension == ".yara":
    all_yara_files.append(os.path.join(root, file_name))
 return all_yara_files

def remove_incompatible_imports(files):
 filtered_files = []
 for yara_file in files:
  with open(yara_file, 'r') as fd:
   yara_in_file = fd.read()
   if not (("import \"math\"" in yara_in_file) or ("import \"cuckoo\"" in yara_in_file) or ("import \"hash\"" in yara_in_file) or ("imphash" in yara_in_file)):
    filtered_files.append(yara_file)
 return filtered_files

def fix_duplicated_rules(files):
 filtered_files = []
 first_elf = True
 to_delete = False
 for yara_file in files:
  print ("Processing " + yara_file)
  with open(yara_file, 'r') as fd:
   yara_in_file = fd.readlines()
   for line in yara_in_file:
    if line.strip() == "private rule is__elf {":
     if first_elf:
      first_elf = False
     else:
      to_delete = True
    if not to_delete:
     filtered_files.append(line)
    if (not first_elf) and line.strip() == "}":
     to_delete = False
   filtered_files.append("\n")
 return filtered_files

def merge_rules(all_rules):
 with open("malware_rules.yar", 'w') as fd:
  fd.write(''.join(all_rules))

def main():
 get_rules_from_git()
 all_yara_files = list_yara_files()
 all_yara_filtered_1 = remove_incompatible_imports(all_yara_files)
 all_yara_filtered_2 = fix_duplicated_rules(all_yara_filtered_1)
 merge_rules(all_yara_filtered_2)

# Main body
if __name__ == '__main__':
 main()

Como veis clonaremos el repo de Yara Rules Project y combinaremos todas las reglas de malware en un único fichero yara:

$ ./malware_yara_rules.py
Cloning into 'rules'...
remote: Counting objects: 6166, done.
remote: Total 6166 (delta 0), reused 0 (delta 0), pack-reused 6166
Ricezione degli oggetti: 100% (6166/6166), 3.77 MiB | 2.15 MiB/s, done.
Risoluzione dei delta: 100% (3806/3806), done.
Processing ./rules/malware
Processing ./rules/malware/Operation_Blockbuster
Processing ./rules/malware/000_common_rules.yar
Processing ./rules/malware/APT_APT1.yar
Processing ./rules/malware/APT_APT10.yar
Processing ./rules/malware/APT_APT15.yar
....
....

Solo falta especificarlo en el comando de Volatility y ya lo tenemos:
$ volatility -f stuxnet.vmem --profile=WinXPSP2x86 yarascan -y malware_rules.yar

Volatility Foundation Volatility Framework 2.6

Rule: StuxNet_Malware_1
Owner: Process lsass.exe Pid 868
0x01002723 8b 45 08 35 dd 79 19 ae 33 c9 8b 55 08 89 02 89 .E.5.y..3..U....
0x01002733 4a 04 8b 45 08 c7 40 0c 77 35 00 01 33 c0 5e c9 J..E..@.w5..3.^.
0x01002743 c3 55 8b ec 83 ec 2c 83 65 e8 00 83 65 f4 00 83 .U....,.e...e...
0x01002753 65 e4 00 8b 45 20 8b 4d 14 8d 84 01 98 00 00 00 e...E..M........
0x01002763 89 45 f0 8d 45 f4 50 8d 45 e8 50 8d 45 d8 50 ff .E..E.P.E.P.E.P.
0x01002773 75 f0 ff 75 08 e8 14 fe ff ff 83 c4 14 89 45 fc u..u..........E.
0x01002783 83 7d fc 00 74 08 8b 45 fc e9 fd 00 00 00 8b 45 .}..t..E.......E
0x01002793 e8 89 45 f8 8b 45 e8 05 98 00 00 00 89 45 e8 c7 ..E..E.......E..
0x010027a3 45 e4 98 00 00 00 ff 75 20 ff 75 1c 8b 45 f8 05 E......u..u..E..
0x010027b3 84 00 00 00 50 8d 45 e4 50 ff 75 f4 8d 45 e8 50 ....P.E.P.u..E.P
0x010027c3 e8 79 fe ff ff 83 c4 18 8b 45 e8 89 45 dc ff 75 .y.......E..E..u
0x010027d3 14 ff 75 10 8b 45 f8 05 8c 00 00 00 50 8d 45 e4 ..u..E......P.E.
0x010027e3 50 ff 75 f4 8d 45 e8 50 e8 51 fe ff ff 83 c4 18 P.u..E.P.Q......
0x010027f3 8b 45 dc 89 45 ec 81 7d 14 00 10 00 00 72 47 8b .E..E..}.....rG.
0x01002803 45 ec 0f b7 00 3d 4d 5a 00 00 75 3a 8b 45 ec 8b E....=MZ..u:.E..
0x01002813 40 3c 05 f8 00 00 00 3b 45 14 73 2a 8b 45 ec 8b @<.....;E.s*.E..

Rule: StuxNet_Malware_1
Owner: Process lsass.exe Pid 868
0x01002eb5 74 36 8b 7f 08 83 ff 00 74 2e 0f b7 1f 8b 7f 04 t6......t.......
0x01002ec5 8d 5c 1f 02 8d 5b fe 3b df 7e 1d 66 83 7b fe 5c .\...[.;.~.f.{.\
0x01002ed5 75 f2 52 53 8d 5a 10 53 e8 bf ff ff ff ff 52 08 u.RS.Z.S......R.
0x01002ee5 5a 85 c0 75 03 40 eb 02 33 c0 5f 5a 59 5b c3 50 Z..u.@..3._ZY[.P
0x01002ef5 51 52 e8 a5 ff ff ff c7 42 04 00 00 00 00 ff 32 QR......B......2
0x01002f05 ff 52 14 59 85 c0 0f 84 b7 00 00 00 50 51 50 54 .R.Y........PQPT
0x01002f15 68 80 00 00 00 6a 18 50 e8 7f ff ff ff ff 52 10 h....j.P......R.
0x01002f25 5a 8b d0 59 58 85 d2 0f 84 96 00 00 00 80 38 b8 Z..YX.........8.
0x01002f35 0f 85 8d 00 00 00 80 78 05 ba 74 70 81 78 05 8d .......x..tp.x..
0x01002f45 54 24 04 75 1b 81 78 08 04 cd 2e c2 75 75 2b c8 T$.u..x.....uu+.
0x01002f55 83 e9 0a 89 48 06 c6 40 05 e8 c6 40 0a 90 eb 63 ....H..@...@...c
0x01002f65 81 78 07 8d 54 24 04 75 5a 81 78 0b 64 ff 15 c0 .x..T$.uZ.x.d...
0x01002f75 75 51 81 78 0f 00 00 00 c2 75 48 52 e8 1b ff ff uQ.x.....uHR....
0x01002f85 ff c7 42 04 01 00 00 00 5a 56 50 53 51 52 8b f0 ..B.....ZVPSQR..
0x01002f95 8b 46 0a 8b 56 0e 2b ce 83 e9 12 bb 04 90 90 e8 .F..V.+.........
0x01002fa5 f0 0f c7 4e 0a 5a 59 5b 58 5e eb 17 66 81 78 0a ...N.ZY[X^..f.x.

Rule: StuxNet_Malware_1
Owner: Process lsass.exe Pid 868
0x01002f3f 74 70 81 78 05 8d 54 24 04 75 1b 81 78 08 04 cd tp.x..T$.u..x...
0x01002f4f 2e c2 75 75 2b c8 83 e9 0a 89 48 06 c6 40 05 e8 ..uu+.....H..@..
0x01002f5f c6 40 0a 90 eb 63 81 78 07 8d 54 24 04 75 5a 81 .@...c.x..T$.uZ.
0x01002f6f 78 0b 64 ff 15 c0 75 51 81 78 0f 00 00 00 c2 75 x.d...uQ.x.....u
0x01002f7f 48 52 e8 1b ff ff ff c7 42 04 01 00 00 00 5a 56 HR......B.....ZV
0x01002f8f 50 53 51 52 8b f0 8b 46 0a 8b 56 0e 2b ce 83 e9 PSQR...F..V.+...
0x01002f9f 12 bb 04 90 90 e8 f0 0f c7 4e 0a 5a 59 5b 58 5e .........N.ZY[X^
0x01002faf eb 17 66 81 78 0a ff d2 74 0c 66 81 78 0a ff 12 ..f.x...t.f.x...
0x01002fbf 75 07 c6 40 0b d2 89 48 06 58 c3 00 00 90 7c 00 u..@...H.X....|.
0x01002fcf 00 00 00 26 aa 80 7c 61 ba 80 7c d4 1a 80 7c 30 ...&..|a..|...|0
0x01002fdf ae 80 7c 95 b9 80 7c 04 ba 80 7c d4 55 83 7c db ..|...|...|.U.|.
0x01002fef ae 80 7c 6e ac 80 7c 60 d1 90 7c 00 d5 90 7c c7 ..|n..|`..|...|.
0x01002fff 06 81 7c 30 25 80 7c 1d 14 82 7c d0 cf 90 7c 8b ..|0%.|...|...|.
0x0100300f 44 24 04 85 c0 75 08 8b 44 24 08 c6 00 00 c3 8b D$...u..D$......
0x0100301f 4c 24 08 eb 03 40 40 41 8a 10 80 f2 12 88 11 75 L$...@@A.......u
0x0100302f f4 c3 8b 4c 24 04 85 c9 75 0a 8b 4c 24 08 33 c0 ...L$...u..L$.3.
....
....

Si queremos usar varias yaras podemos hacerlo también simplemente especificando los nombres de archivo separados por comas:

volatility -f stuxnet.vmem --profile=WinXPSP2x86 yarascan --yara-file=stuxnet.yar,edd.yar,worm.yar

O si queremos usar todas las yaras de un directorio/subdirectorios podemos tirar de un one-liner en bash:

for f in *.yara ; do volatility -f stuxnet.vmem --profile=WinXPSP2x86 yarascan --yara-file="$f" ; done

Otra opción podría ser usar un 'index_rules.yar' del tipo:

/*
Generated by Yara-Rules
On 23-10-2017
*/
include "./malware/APT_APT1.yar"
include "./malware/APT_APT10.yar"
include "./malware/APT_APT17.yar"
include "./malware/APT_APT29_Grizzly_Steppe.yar"
include "./malware/APT_APT3102.yar"
include "./malware/APT_APT9002.yar"
include "./malware/APT_Backspace.yar"
include "./malware/APT_Bestia.yar"
...

O también compilar las reglas con yarac para ganar rendimiento:

yarac rule1.yar rule2.yar rule3.yar compiled_output.yar

Fuentes:
- Finding malware on memory dumps using Volatility and Yara rules
- Using Yara rules with Volatility
- Detección de código malicioso con YARA (II)
- Update Yarascan to Support Compiled Yara Rules 

Comentarios