YARA Cheatsheet
"Clase de la hoja" id="copy-btn" class="copy-btn" onclick="copyAllCommands()" Copiar todos los comandos de YARA id="pdf-btn" class="pdf-btn" onclick="generatePDF()" Generar YARA Guía PDF ■/div titulada
YARA es un potente motor de juego de patrones diseñado para ayudar a los investigadores de malware a identificar y clasificar muestras de malware. Desarrollado por Victor Alvarez en VirusTotal, YARA le permite crear descripciones de familias de malware basadas en patrones textuales o binarios, lo que lo convierte en una herramienta esencial para la caza de amenazas, respuesta a incidentes y análisis de malware.
Instalación
Instalación de Linux
# Ubuntu/Debian
sudo apt update
sudo apt install yara
# CentOS/RHEL
sudo yum install epel-release
sudo yum install yara
# From source
git clone https://github.com/VirusTotal/yara.git
cd yara
./bootstrap.sh
./configure
make
sudo make install
Instalación de Windows
# Download from GitHub releases
# https://github.com/VirusTotal/yara/releases
# Using Chocolatey
choco install yara
# Using vcpkg
vcpkg install yara
Python Integration
# Install yara-python
pip install yara-python
# Verify installation
python -c "import yara; print(yara.__version__)"
Sintaxis básica y estructura
Estructura
rule RuleName
\\\\{
meta:
description = "Description of what this rule detects"
author = "Your Name"
date = "2024-01-01"
version = "1.0"
strings:
$string1 = "malicious string"
$string2 = \\\\{ 6A 40 68 00 30 00 00 \\\\}
$regex1 = /malware[0-9]\\\\{2,4\\\\}/
condition:
$string1 or $string2 or $regex1
\\\\}
Tipos de cuerda
rule StringTypes
\\\\{
strings:
// Text strings
$text1 = "Hello World"
$text2 = "Case Insensitive" nocase
$text3 = "Wide String" wide
$text4 = "ASCII String" ascii
// Hexadecimal strings
$hex1 = \\\\{ 4D 5A \\\\} // MZ header
$hex2 = \\\\{ 4D 5A [0-100] 50 45 \\\\} // MZ...PE
$hex3 = \\\\{ 4D 5A ?? ?? ?? ?? 50 45 \\\\} // Wildcards
// Regular expressions
$regex1 = /md5:[a-f0-9]\\\\{32\\\\}/
$regex2 = /https?:\/\/[a-zA-Z0-9.-]+/
condition:
any of them
\\\\}
Patrones avanzados de cuerda
Wildcards and Jumps
rule WildcardsAndJumps
\\\\{
strings:
// Single byte wildcard
$pattern1 = \\\\{ 4D 5A ?? ?? 50 45 \\\\}
// Multiple byte wildcards
$pattern2 = \\\\{ 4D 5A ?? ?? ?? ?? 50 45 \\\\}
// Variable length jumps
$pattern3 = \\\\{ 4D 5A [0-100] 50 45 \\\\}
$pattern4 = \\\\{ 4D 5A [10-50] 50 45 \\\\}
// Alternatives
$pattern5 = \\\\{ 4D 5A ( 90|91|92 ) 50 45 \\\\}
condition:
any of them
\\\\}
Modificadores de cuerda
rule StringModifiers
\\\\{
strings:
$case_insensitive = "malware" nocase
$wide_string = "malware" wide
$ascii_string = "malware" ascii
$fullword = "malware" fullword
$xor_string = "malware" xor
$base64_string = "malware" base64
condition:
any of them
\\\\}
Condiciones y lógicas
Condiciones básicas
rule BasicConditions
\\\\{
strings:
$string1 = "malware"
$string2 = "virus"
$string3 = "trojan"
condition:
// Boolean operators
$string1 and $string2
$string1 or $string2
not $string1
// String count
#string1 > 5
#string2 == 1
// Any/All of them
any of them
all of them
2 of them
// String sets
any of ($string*)
all of ($string1, $string2)
\\\\}
Propiedades del archivo
rule FileProperties
\\\\{
condition:
// File size
filesize > 1MB
filesize < 10KB
// Entry point
entrypoint >= 0x1000
// String positions
$string1 at 0
$string2 in (0..100)
// String offsets
@string1[0] ``< 100
@string2[1] >`` 1000
\\\\}
Módulos y funciones
PE Module
import "pe"
rule PEAnalysis
\\\\{
condition:
// PE file detection
pe.is_pe
// Machine type
pe.machine == pe.MACHINE_I386
pe.machine == pe.MACHINE_AMD64
// Characteristics
pe.characteristics & pe.DLL
pe.characteristics & pe.EXECUTABLE_IMAGE
// Sections
pe.number_of_sections > 3
pe.sections[0].name == ".text"
pe.sections[0].characteristics & pe.SECTION_CNT_CODE
// Imports
pe.imports("kernel32.dll", "CreateFileA")
pe.imports("advapi32.dll", "RegSetValueExA")
// Resources
pe.number_of_resources > 0
pe.version_info["CompanyName"] contains "Microsoft"
\\\\}
Módulo Hash
import "hash"
rule HashChecks
\\\\{
condition:
// MD5 hash
hash.md5(0, filesize) == "5d41402abc4b2a76b9719d911017c592"
// SHA1 hash
hash.sha1(0, filesize) == "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
// SHA256 hash
hash.sha256(0, filesize) == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
// Hash of specific sections
hash.md5(pe.sections[0].raw_data_offset, pe.sections[0].raw_data_size) == "hash_value"
\\\\}
Módulo de matemáticas
import "math"
rule MathOperations
\\\\{
condition:
// Entropy calculation
math.entropy(0, filesize) > 7.0
math.entropy(pe.sections[0].raw_data_offset, pe.sections[0].raw_data_size) > 6.5
// Mean calculation
math.mean(0, filesize) > 128
// Standard deviation
math.deviation(0, filesize, math.mean(0, filesize)) > 50
\\\\}
Normas de detección de malware
Generic Malware Patterns
rule Generic_Malware
\\\\{
meta:
description = "Generic malware detection"
author = "Security Analyst"
date = "2024-01-01"
strings:
$api1 = "CreateRemoteThread"
$api2 = "WriteProcessMemory"
$api3 = "VirtualAllocEx"
$api4 = "SetWindowsHookEx"
$string1 = "backdoor"
$string2 = "keylogger"
$string3 = "rootkit"
condition:
2 of ($api*) and any of ($string*)
\\\\}
Detección de ransomware
rule Ransomware_Indicators
\\\\{
meta:
description = "Ransomware behavior indicators"
author = "Security Analyst"
strings:
$encrypt1 = "CryptEncrypt"
$encrypt2 = "CryptGenKey"
$encrypt3 = "CryptAcquireContext"
$file_ext1 = ".encrypted"
$file_ext2 = ".locked"
$file_ext3 = ".crypto"
$ransom_note1 = "your files have been encrypted"
$ransom_note2 = "pay bitcoin"
$ransom_note3 = "decryption key"
condition:
2 of ($encrypt*) and (any of ($file_ext*) or any of ($ransom_note*))
\\\\}
Banking Trojan
rule Banking_Trojan
\\\\{
meta:
description = "Banking trojan detection"
strings:
$bank1 = "online banking"
$bank2 = "credit card"
$bank3 = "account number"
$hook1 = "SetWindowsHookEx"
$hook2 = "GetAsyncKeyState"
$hook3 = "CallNextHookEx"
$network1 = "HttpSendRequest"
$network2 = "InternetConnect"
$network3 = "send"
condition:
any of ($bank*) and any of ($hook*) and any of ($network*)
\\\\}
Técnicas avanzadas
Yara con Pitón
import yara
# Compile rules from file
rules = yara.compile(filepath='malware_rules.yar')
# Compile rules from string
rule_source = '''
rule TestRule \\\\{
strings:
$test = "malware"
condition:
$test
\\\\}
'''
rules = yara.compile(source=rule_source)
# Scan file
matches = rules.match('/path/to/file')
for match in matches:
print(f"Rule: \\\\{match.rule\\\\}")
print(f"Tags: \\\\{match.tags\\\\}")
print(f"Meta: \\\\{match.meta\\\\}")
print(f"Strings: \\\\{match.strings\\\\}")
# Scan data
with open('/path/to/file', 'rb') as f:
data = f.read()
matches = rules.match(data=data)
# Custom callback
def callback(data):
print(f"Match found: \\\\{data\\\\}")
return yara.CALLBACK_CONTINUE
rules.match('/path/to/file', callback=callback)
Optimización del rendimiento
rule OptimizedRule
\\\\{
meta:
description = "Performance optimized rule"
strings:
// Use specific strings first
$specific = \\\\{ 4D 5A 90 00 03 00 00 00 \\\\}
// Avoid expensive regex
$simple_string = "malware" nocase
// Use fullword for exact matches
$exact = "CreateFile" fullword
condition:
// Check file size first
filesize > 1KB and filesize < 10MB and
// Check specific patterns first
$specific at 0 and
// Then check other strings
($simple_string or $exact)
\\\\}
Detección multietapa
rule Multi_Stage_Malware
\\\\{
meta:
description = "Multi-stage malware detection"
strings:
// Stage 1: Dropper
$stage1_1 = "temp.exe"
$stage1_2 = "CreateProcess"
// Stage 2: Payload
$stage2_1 = "payload.dll"
$stage2_2 = "LoadLibrary"
// Stage 3: Persistence
$stage3_1 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
$stage3_2 = "RegSetValueEx"
condition:
(any of ($stage1_*) and any of ($stage2_*)) or
(any of ($stage2_*) and any of ($stage3_*))
\\\\}
Uso de la línea de comandos
Comandos básicos
# Scan single file
yara rules.yar /path/to/file
# Scan directory recursively
yara -r rules.yar /path/to/directory
# Scan with multiple rule files
yara rules1.yar rules2.yar /path/to/file
# Output matching strings
yara -s rules.yar /path/to/file
# Output metadata
yara -m rules.yar /path/to/file
# Set timeout
yara -a 60 rules.yar /path/to/file
# Disable warnings
yara -w rules.yar /path/to/file
Opciones avanzadas
# Define external variables
yara -d filename="malware.exe" rules.yar /path/to/file
# Print tags only
yara -t rules.yar /path/to/file
# Print rule names only
yara -n rules.yar /path/to/file
# Count matches
yara -c rules.yar /path/to/file
# Fast mode (no string matching)
yara -f rules.yar /path/to/file
# Scan process memory (Linux)
yara rules.yar /proc/PID/mem
# Maximum number of strings per rule
yara -l 1000 rules.yar /path/to/file
Ejemplos de integración
Integración de la volatilidad
# Volatility plugin example
import volatility.plugins.common as common
import yara
class YaraScan(common.AbstractWindowsCommand):
def __init__(self, config, *args, **kwargs):
common.AbstractWindowsCommand.__init__(self, config, *args, **kwargs)
self.rules = yara.compile(filepath='malware_rules.yar')
def calculate(self):
addr_space = utils.load_as(self._config)
for proc in tasks.pslist(addr_space):
proc_space = proc.get_process_address_space()
if proc_space:
data = proc_space.read(proc.Peb.ImageBaseAddress, 0x1000)
matches = self.rules.match(data=data)
if matches:
yield proc, matches
Cuckoo Sandbox Integration
# Cuckoo processing module
from lib.cuckoo.common.abstracts import Processing
import yara
class YaraProcessing(Processing):
def run(self):
self.key = "yara"
results = []
rules = yara.compile(filepath='rules/malware.yar')
# Scan dropped files
for file_path in self.results.get("dropped", []):
matches = rules.match(file_path["path"])
if matches:
results.append(\\\\{
"file": file_path["path"],
"matches": [match.rule for match in matches]
\\\\})
return results
Buenas prácticas
Directrices para la redacción de normas
rule BestPracticeExample
\\\\{
meta:
description = "Example of best practices"
author = "Security Team"
date = "2024-01-01"
version = "1.0"
reference = "https://example.com/analysis"
hash = "md5hash"
strings:
// Use descriptive variable names
$mz_header = \\\\{ 4D 5A \\\\}
$pe_header = \\\\{ 50 45 00 00 \\\\}
// Group related strings
$api_process = "CreateProcess"
$api_thread = "CreateThread"
$api_file = "CreateFile"
// Use specific patterns
$specific_string = "unique_malware_string"
condition:
// Check file type first
$mz_header at 0 and
$pe_header and
// Then check specific indicators
$specific_string and
2 of ($api_*)
\\\\}
Consideraciones de la ejecución
rule PerformanceOptimized
\\\\{
strings:
// Anchor strings to specific positions when possible
$header = \\\\{ 4D 5A \\\\} at 0
// Use fullword for API names
$api = "CreateFile" fullword
// Avoid overly broad regex
$url = /https?:\/\/[a-zA-Z0-9.-]\\\\{5,50\\\\}\.[a-z]\\\\{2,4\\\\}/
condition:
// Check file size constraints
filesize > 1KB and filesize < 5MB and
// Use specific checks first
$header and
// Then broader checks
($api or $url)
\\\\}
Manejo de errores
import yara
try:
# Compile rules with error handling
rules = yara.compile(filepath='rules.yar')
except yara.SyntaxError as e:
print(f"Syntax error in rules: \\\\{e\\\\}")
except yara.Error as e:
print(f"YARA error: \\\\{e\\\\}")
try:
# Scan with timeout
matches = rules.match('/path/to/file', timeout=60)
except yara.TimeoutError:
print("Scan timed out")
except yara.Error as e:
print(f"Scan error: \\\\{e\\\\}")
Solución de problemas
Cuestiones comunes
# Rule compilation errors
yara -w rules.yar # Check for warnings
# Memory issues with large files
yara -f rules.yar /large/file # Fast mode
# Timeout issues
yara -a 300 rules.yar /path/to/file # Increase timeout
# String encoding issues
# Use 'wide' modifier for Unicode strings
# Use 'ascii' modifier for ASCII strings
# Performance issues
# Use more specific conditions
# Avoid expensive regex patterns
# Use file size constraints
Normas de depuración
rule DebugRule
\\\\{
meta:
description = "Debug rule with verbose conditions"
strings:
$debug1 = "test string"
$debug2 = \\\\{ 41 42 43 \\\\}
condition:
// Add file size check for debugging
filesize > 0 and
// Check each string individually
($debug1 and #debug1 > 0) or
($debug2 and #debug2 > 0)
\\\\}