AI-ondersteunde detectie: LLM voor het genereren van Sigma-regels
De integratie van grote taalmodellen in detectie-engineering vertegenwoordigt een van de meest radicale veranderingen in het SOC-landschap van de afgelopen jaren. Het is niet simpelweg een kwestie van het automatiseren van een repetitieve taak: het gebruik van een LLM om Sigma-regels te genereren betekent het comprimeren van een proces in seconden die een deskundige analist is binnen enkele uren klaar, van het lezen van een dreigingsrapport tot het schrijven van een geteste regel die gereed is voor implementatie.
Kaders zoals SigmaGen, gepresenteerd op MITRE ATT&CK APAC 2025, laten zien hoe verfijnde modellen rapporten kunnen verwerken van informatie over bedreigingen, extractie van ATT&CK-technieken en het produceren van zeer nauwkeurig in kaart gebrachte Sigma-regels. Tegelijkertijd zijn er open source-tools en Op n8n gebaseerde workflows stellen kleinere teams in staat AI-ondersteunde pijplijnen te bouwen zonder bedrijfsinvesteringen.
Dit artikel begeleidt u door de architectuur van een AI-ondersteund systeem voor het genereren van detectieregels: vanaf de technische prompt, tot automatische validatie, testen met synthetische logs, tot integratie in een bestaande CI/CD-pijplijn.
Wat je gaat leren
- Hoe LLM's denken over het Sigma-formaat en waarom ze betere output produceren dan directe SPL
- Specifieke prompt engineering-technieken voor het genereren van detectieregels
- Architectuur van een end-to-end AI-ondersteunde pijplijn
- Automatische validatie en testen van de gegenereerde regels
- Integratie met SigmaGen, pySigma en CI/CD-workflow
- Antipatronen die moeten worden vermeden en echte beperkingen van LLM's in beveiligingscontexten
waarom LLM's uitblinken in het genereren van Sigma-regels
Een van de meest interessante observaties die uit toegepast onderzoek naar voren is gekomen (en door de praktijk wordt bevestigd) is dat LLM’s kwaliteitsoutput produceren aanzienlijk hoger wanneer ze genereren Sigma vergeleken met directe SPL- of KQL-query's. De reden is structureel.
Sigma's YAML-formaat legt een duidelijke scheiding op tussen:
- titel en beschrijving: Het model moet verwoorden wat het detecteert en waarom
- logbron: specificeert de gegevensbron (categorie, product, dienst)
- detectie: de Booleaanse matchinglogica
- voorwaarde: Selectors combineren
- valse positieven: Expliciete redenering over randgevallen
Deze structuur dwingt het model om sequentieel en declaratief te ‘denken’, waardoor de logische fouten die daarbij optreden worden verminderd vraagt rechtstreeks uitvoer aan in een platformspecifieke querytaal. In de praktijk werkt Sigma als een impliciete gedachteketen voor LLM's toegepast op detectie.
Benchmarkgegevens
Onderzoekers van het LLMCloudHunter-project (2024) hebben aangetoond dat generalistische LLM's zoals GPT-4 Sigma-regels genereren die in 73% van de gevallen geldig zijn op gestructureerde CTI-rapporten, tegenover 41% bij het vragen om directe SPL-output. Het percentage stijgt naar 89% met verfijning van datasets veiligheidsspecificaties.
Architectuur van een AI-ondersteunde pijplijn
Een AI-ondersteunde pijplijn voor het genereren van detectieregels bestaat uit vijf verschillende fasen:
- Inslikken: opname van dreigingsrapporten, CTI-blogposts, CVE-advies
- Extractie: IOC-extractie, ATT&CK-technieken, beschreven gedrag
- Generatie: generatie van de Sigma-regel via LLM
- Geldigmaking: automatische syntactische en semantische validatie
- Testen: Testen met synthetische logs en CI/CD-integratie
# Architettura base della pipeline AI-assisted
# File: ai_sigma_pipeline.py
import openai
import yaml
import subprocess
from pathlib import Path
from dataclasses import dataclass
from typing import Optional
@dataclass
class ThreatReport:
content: str
source_url: str
report_type: str # 'cti_blog', 'advisory', 'malware_analysis'
@dataclass
class GeneratedRule:
sigma_yaml: str
mitre_techniques: list[str]
confidence: float
validation_passed: bool
test_results: Optional[dict] = None
class AISigmaPipeline:
def __init__(self, openai_api_key: str, rules_output_dir: str):
self.client = openai.OpenAI(api_key=openai_api_key)
self.output_dir = Path(rules_output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
def process_report(self, report: ThreatReport) -> list[GeneratedRule]:
"""Pipeline completa da report a regole validate."""
# Stage 1: Extraction
techniques = self._extract_attack_techniques(report)
behaviors = self._extract_behaviors(report)
# Stage 2: Generation
rules = []
for technique in techniques:
rule = self._generate_sigma_rule(
report=report,
technique=technique,
behaviors=behaviors
)
if rule:
rules.append(rule)
# Stage 3: Validation + Testing
return [self._validate_and_test(r) for r in rules]
def _extract_attack_techniques(self, report: ThreatReport) -> list[str]:
"""Estrae tecniche ATT&CK dal report tramite LLM."""
response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": (
"Sei un analista di threat intelligence esperto in MITRE ATT&CK. "
"Estrai SOLO le tecniche ATT&CK (formato T1234 o T1234.001) "
"esplicitamente descritte nel testo. Rispondi solo con una lista JSON."
)
},
{
"role": "user",
"content": f"Report:\n{report.content[:4000]}"
}
],
temperature=0.1 # Bassa temperatura per output deterministico
)
import json
try:
return json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
return []
Snelle engineering voor kwaliteit Sigma-regels
De kwaliteit van de output hangt in belangrijke mate af van de promptstructuur. Er zijn drie basispatronen die resultaten opleveren bestaande uit het genereren van Sigma-regels:
Patroon 1: Gestructureerde systeemprompt
De systeemprompt moet precies de meta-informatie bevatten die het model nodig heeft om geldige Sigma's te genereren:
de YAML-structuur, de geldige waarden voor category e product, beste praktijken op
falsepositives en de toegestane ernstniveaus.
# Prompt di sistema ottimizzato per generazione Sigma rules
SIGMA_SYSTEM_PROMPT = """
Sei un Detection Engineer esperto nella scrittura di Sigma rules.
Quando generi una Sigma rule, rispetta SEMPRE questa struttura YAML:
title: [titolo descrittivo, max 80 char]
id: [UUID v4]
status: experimental
description: [descrizione dettagliata del comportamento rilevato]
references:
- [URL del report originale se disponibile]
author: AI-Assisted Detection
date: [data odierna in formato YYYY-MM-DD]
tags:
- attack.[tattica]
- attack.[tecnica]
logsource:
category: [process_creation | network_connection | file_event | registry_event]
product: [windows | linux | macos]
detection:
[nome_selettore]:
[campo]: [valore o lista valori]
condition: [nome_selettore]
falsepositives:
- [casi legittimi plausibili]
level: [informational | low | medium | high | critical]
REGOLE CRITICHE:
- Usa SEMPRE wildcards (*) nei valori stringa per evitare match esatti fragili
- Preferisci campi con alta disponibilità (Image, CommandLine, ParentImage)
- Indica sempre almeno un falso positivo realistico
- Il campo 'condition' deve essere semplice e leggibile
- Non usare regex complesse se un approccio con keywords e sufficiente
"""
def build_generation_prompt(technique_id: str, behaviors: list[str],
logsource_hint: str, report_excerpt: str) -> str:
return f"""Genera una Sigma rule per rilevare la tecnica MITRE ATT&CK {technique_id}.
Comportamenti osservati nel report:
{chr(10).join(f'- {b}' for b in behaviors[:5])}
Tipo di log suggerito: {logsource_hint}
Estratto del report originale:
{report_excerpt[:1500]}
Genera UNA SOLA Sigma rule in formato YAML valido. Non aggiungere spiegazioni fuori dal YAML."""
Patroon 2: Few-Shot met kwaliteitsvoorbeelden
Het opnemen van 2-3 regelvoorbeelden van hoge kwaliteit in de prompt (paar shots) verbetert de consistentie van de uitvoer dramatisch, vooral voor ongebruikelijke logbronnen of complexe omstandigheden.
# Few-shot: esempio di regola di qualità inclusa nel prompt
FEW_SHOT_EXAMPLE = """
Esempio di regola di alta qualità per ispirazione:
title: Suspicious PowerShell Encoded Command Execution
id: 5b4f6d89-1234-4321-ab12-fedcba987654
status: stable
description: >
Rileva l'esecuzione di PowerShell con parametri di encoding (-enc, -EncodedCommand)
frequentemente usati da malware per offuscare payload malevoli.
references:
- https://attack.mitre.org/techniques/T1059/001/
author: SigmaHQ Community
date: 2025-01-15
tags:
- attack.execution
- attack.t1059.001
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith:
- '\\\\powershell.exe'
- '\\\\pwsh.exe'
CommandLine|contains:
- ' -enc '
- ' -EncodedCommand '
- ' -ec '
condition: selection
falsepositives:
- Software legittimo che usa PowerShell con encoding per configurazioni complesse
- Script di deployment enterprise
level: medium
"""
Patroon 3: Expliciete gedachteketen
Voor complexe technieken levert het vereisen van het model om te redeneren voordat de regel wordt geschreven, nauwkeurigere resultaten op. Deze aanpak voegt latentie toe, maar vermindert het aantal benodigde iteraties aanzienlijk.
def generate_with_cot(self, technique_id: str, report: ThreatReport) -> GeneratedRule:
"""Generazione con Chain-of-Thought esplicito."""
# Step 1: Chiedi al modello di ragionare
reasoning_response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SIGMA_SYSTEM_PROMPT},
{
"role": "user",
"content": f"""Prima di scrivere la regola per {technique_id}, analizza:
1. Quali artefatti forensi questa tecnica lascia nei log?
2. Qual è il logsource più appropriato?
3. Quali campi hanno la maggiore discriminazione signal/noise?
4. Quali sono i falsi positivi più comuni?
Report: {report.content[:2000]}"""
}
],
temperature=0.3
)
reasoning = reasoning_response.choices[0].message.content
# Step 2: Usa il ragionamento per guidare la generazione
rule_response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SIGMA_SYSTEM_PROMPT},
{"role": "user", "content": f"Analisi tecnica:\n{reasoning}"},
{
"role": "assistant",
"content": "Basandomi su questa analisi, genero la Sigma rule ottimale:"
},
{"role": "user", "content": "Procedi con la generazione YAML."}
],
temperature=0.1
)
return GeneratedRule(
sigma_yaml=rule_response.choices[0].message.content,
mitre_techniques=[technique_id],
confidence=0.0, # Calcolata nella validazione
validation_passed=False
)
Automatische validatie van gegenereerde regels
Een LLM kan syntactisch geldige maar semantisch incorrecte YAML produceren: een niet-bestaande logbron, veld verkeerd genoemd, een voorwaarde die niet correct naar selectors verwijst. Automatische validatie en de kritische poort voordat een regel de repository binnengaat.
import yaml
from sigma.rule import SigmaRule
from sigma.exceptions import SigmaError
import re
import uuid
class SigmaRuleValidator:
# Logsource validi più comuni
VALID_CATEGORIES = {
'process_creation', 'network_connection', 'file_event',
'registry_event', 'registry_add', 'registry_set',
'dns_query', 'image_load', 'pipe_created', 'raw_access_read'
}
VALID_LEVELS = {'informational', 'low', 'medium', 'high', 'critical'}
VALID_STATUSES = {'stable', 'test', 'experimental', 'deprecated', 'unsupported'}
def validate(self, sigma_yaml: str) -> tuple[bool, list[str]]:
"""Valida una Sigma rule. Restituisce (valida, lista errori)."""
errors = []
# 1. Validazione YAML sintattico
try:
rule_dict = yaml.safe_load(sigma_yaml)
except yaml.YAMLError as e:
return False, [f"YAML invalido: {str(e)}"]
# 2. Campi obbligatori
required_fields = ['title', 'description', 'logsource', 'detection']
for field in required_fields:
if field not in rule_dict:
errors.append(f"Campo obbligatorio mancante: {field}")
if errors:
return False, errors
# 3. Validazione logsource
logsource = rule_dict.get('logsource', {})
if 'category' in logsource:
if logsource['category'] not in self.VALID_CATEGORIES:
errors.append(
f"Categoria logsource non valida: {logsource['category']}. "
f"Valide: {', '.join(self.VALID_CATEGORIES)}"
)
# 4. Validazione detection
detection = rule_dict.get('detection', {})
if 'condition' not in detection:
errors.append("Campo 'condition' mancante in detection")
else:
condition = detection['condition']
# Verifica che i selettori nella condition esistano
selectors = [k for k in detection.keys() if k != 'condition']
# Parse base della condition per trovare riferimenti
referenced = re.findall(r'\b([a-zA-Z_][a-zA-Z0-9_]*)\b', condition)
for ref in referenced:
if ref not in ['and', 'or', 'not', '1', 'of', 'all', 'them', 'filter']:
if ref not in selectors:
errors.append(
f"Condition referenzia '{ref}' che non esiste nei selettori: {selectors}"
)
# 5. Validazione level
level = rule_dict.get('level', '')
if level and level not in self.VALID_LEVELS:
errors.append(f"Level non valido: {level}. Validi: {self.VALID_LEVELS}")
# 6. UUID check
rule_id = rule_dict.get('id', '')
if rule_id:
try:
uuid.UUID(str(rule_id))
except ValueError:
errors.append(f"ID non e un UUID valido: {rule_id}")
else:
errors.append("Campo 'id' mancante - genera un UUID v4")
# 7. Validazione pySigma (se disponibile)
try:
SigmaRule.from_yaml(sigma_yaml)
except SigmaError as e:
errors.append(f"Errore pySigma: {str(e)}")
return len(errors) == 0, errors
Antipatroon: blindelings vertrouwen op de LLM-uitvoer
Een veelgemaakte fout bij teams die AI-ondersteunde detectie implementeren, is het inzetten van gegenereerde regels zonder validatie. LLM's maken specifieke en herhaalbare fouten bij het genereren van Sigma:
- Gebruik velden
ProcessNamein plaats vanImage(Sysmon) - Schrijf voorwaarden die verwijzen naar niet-bestaande selectors
- Bedenk niet-standaard logbroncategorieën
- Gebruik
containsop velden die geen jokertekens ondersteunen in de doellogboekbron
Automatische validatie en testen met echte logs zijn NIET OPTIONEEL.
Geautomatiseerd testen met synthetische logboeken
Na syntactische validatie moet elke regel worden getest op logboeken die beide gedragingen simuleren verwacht kwaadaardig verkeer (true positive test) dan normaal verkeer (false positive test). Deze aanpak, gebeld testen van regeleenheden, en de praktijk die een volwassen pijplijn onderscheidt van een experimenteren.
import json
from sigma.collection import SigmaCollection
from sigma.backends.test import TextQueryTestBackend
from typing import Any
class SigmaRuleTester:
def __init__(self):
self.backend = TextQueryTestBackend()
def generate_test_events(self, sigma_yaml: str,
llm_client) -> dict[str, list[dict]]:
"""Genera eventi di test tramite LLM basandosi sulla regola."""
rule_dict = yaml.safe_load(sigma_yaml)
prompt = f"""Data questa Sigma rule:
{sigma_yaml}
Genera in formato JSON due liste di eventi di log:
1. "true_positives": 3 eventi che DEVONO triggherare la regola
2. "false_positives": 3 eventi legittimi che NON devono triggherare la regola
Ogni evento deve avere i campi esatti che la regola usa per il matching.
Formato richiesto:
{
"true_positives": [
{"Image": "C:\\\\Windows\\\\System32\\\\cmd.exe", "CommandLine": "...", ...}
],
"false_positives": [
{"Image": "C:\\\\Program Files\\\\...", "CommandLine": "...", ...}
]
}"""
response = llm_client.chat.completions.create(
model="gpt-4o-mini", # Modello più economico per i test
messages=[{"role": "user", "content": prompt}],
temperature=0.2
)
try:
return json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
return {"true_positives": [], "false_positives": []}
def run_tests(self, sigma_yaml: str, test_events: dict) -> dict[str, Any]:
"""Esegue i test e restituisce risultati dettagliati."""
results = {
"tp_tests": {"passed": 0, "failed": 0, "details": []},
"fp_tests": {"passed": 0, "failed": 0, "details": []},
"overall_pass": False
}
# Nota: questa e una simulazione del meccanismo di test.
# In produzione si usano tool come sigma-test o un SIEM sandbox.
rule_dict = yaml.safe_load(sigma_yaml)
detection = rule_dict.get('detection', {})
for event in test_events.get('true_positives', []):
matched = self._simulate_match(event, detection)
if matched:
results["tp_tests"]["passed"] += 1
results["tp_tests"]["details"].append({"event": event, "result": "PASS"})
else:
results["tp_tests"]["failed"] += 1
results["tp_tests"]["details"].append({"event": event, "result": "FAIL - non matchato"})
for event in test_events.get('false_positives', []):
matched = self._simulate_match(event, detection)
if not matched:
results["fp_tests"]["passed"] += 1
results["fp_tests"]["details"].append({"event": event, "result": "PASS"})
else:
results["fp_tests"]["failed"] += 1
results["fp_tests"]["details"].append({"event": event, "result": "FAIL - falso positivo"})
tp_ok = results["tp_tests"]["failed"] == 0
fp_ok = results["fp_tests"]["failed"] == 0
results["overall_pass"] = tp_ok and fp_ok
return results
def _simulate_match(self, event: dict, detection: dict) -> bool:
"""Simulazione semplificata del match. Per produzione: usa sigma-test."""
# Logica di matching semplificata per demo
for selector_name, selector_criteria in detection.items():
if selector_name == 'condition':
continue
if not isinstance(selector_criteria, dict):
continue
for field, value in selector_criteria.items():
actual_field = field.split('|')[0]
modifier = field.split('|')[1] if '|' in field else 'exact'
event_value = event.get(actual_field, '')
if isinstance(value, list):
for v in value:
if self._apply_modifier(str(event_value), str(v), modifier):
return True
else:
if self._apply_modifier(str(event_value), str(value), modifier):
return True
return False
def _apply_modifier(self, event_val: str, pattern: str, modifier: str) -> bool:
pattern_clean = pattern.replace('*', '')
if modifier == 'contains':
return pattern_clean.lower() in event_val.lower()
elif modifier == 'endswith':
return event_val.lower().endswith(pattern_clean.lower())
elif modifier == 'startswith':
return event_val.lower().startswith(pattern_clean.lower())
return event_val.lower() == pattern_clean.lower()
SigmaGen: het open source-framework voor AI-ondersteunde detectie
SigmaGen, gepresenteerd op MITRE ATT&CK APAC 2025, vertegenwoordigt de stand van zaken op het gebied van raamwerken open-source voor het genereren van detectieregels door AI. Het project combineert verfijning van gecureerde datasets met een pijplijnarchitectuur die de gehele levenscyclus van de regel bestrijkt.
# Integrazione con SigmaGen (workflow concettuale)
# SigmaGen usa un approccio in tre fasi:
# 1. Ingestion di CTI (blog, advisory, STIX feeds)
# 2. Extraction di tecniche ATT&CK tramite NER specializzato
# 3. Generazione Sigma tramite modello fine-tuned
# Workflow alternativo con n8n e LLM generici:
# n8n Workflow JSON (estratto concettuale)
N8N_WORKFLOW_STRUCTURE = {
"nodes": [
{
"name": "RSS_CTI_Feed",
"type": "n8n-nodes-base.rssFeedRead",
"parameters": {
"url": "https://example-cti-blog.com/feed.xml"
}
},
{
"name": "Extract_Techniques",
"type": "n8n-nodes-base.openAi",
"parameters": {
"model": "gpt-4o",
"prompt": "Estrai tecniche ATT&CK da: {{$json.content}}",
"system_prompt": "Sei un analista CTI esperto..."
}
},
{
"name": "Generate_Sigma",
"type": "n8n-nodes-base.openAi",
"parameters": {
"model": "gpt-4o",
"prompt": "Genera Sigma rule per: {{$json.techniques}}",
"system_prompt": SIGMA_SYSTEM_PROMPT
}
},
{
"name": "Validate_Rule",
"type": "n8n-nodes-base.code",
"parameters": {
"code": "// Chiama API di validazione Python"
}
},
{
"name": "GitHub_PR",
"type": "n8n-nodes-base.github",
"parameters": {
"operation": "createPullRequest",
"repository": "org/detection-rules"
}
}
]
}
# Pipeline Python completa con gestione errori
class FullAISigmaPipeline:
def __init__(self, config: dict):
self.llm_client = openai.OpenAI(api_key=config['openai_key'])
self.validator = SigmaRuleValidator()
self.tester = SigmaRuleTester()
self.max_retries = config.get('max_retries', 3)
def generate_validated_rule(self, technique_id: str,
report: ThreatReport) -> Optional[GeneratedRule]:
"""Genera, valida e testa una regola con retry automatico."""
errors_history = []
for attempt in range(self.max_retries):
# Genera la regola (con errori precedenti nel prompt se disponibili)
sigma_yaml = self._generate_with_error_feedback(
technique_id, report, errors_history
)
# Valida
is_valid, errors = self.validator.validate(sigma_yaml)
if not is_valid:
errors_history.extend(errors)
continue
# Test con eventi sintetici
test_events = self.tester.generate_test_events(sigma_yaml, self.llm_client)
test_results = self.tester.run_tests(sigma_yaml, test_events)
if test_results['overall_pass']:
return GeneratedRule(
sigma_yaml=sigma_yaml,
mitre_techniques=[technique_id],
confidence=self._calculate_confidence(test_results),
validation_passed=True,
test_results=test_results
)
else:
errors_history.append(f"Test falliti: {test_results}")
return None # Non e riuscito a generare una regola valida
def _generate_with_error_feedback(self, technique_id: str,
report: ThreatReport,
errors: list[str]) -> str:
"""Genera con feedback sugli errori precedenti."""
error_context = ""
if errors:
error_context = f"\n\nTentativo precedente fallito con errori:\n" + \
"\n".join(f"- {e}" for e in errors[-3:]) # Ultimi 3 errori
prompt = build_generation_prompt(
technique_id=technique_id,
behaviors=[],
logsource_hint="process_creation",
report_excerpt=report.content[:2000] + error_context
)
response = self.llm_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SIGMA_SYSTEM_PROMPT},
{"role": "user", "content": prompt}
],
temperature=0.1
)
return response.choices[0].message.content
def _calculate_confidence(self, test_results: dict) -> float:
"""Calcola un confidence score basato sui test."""
tp = test_results["tp_tests"]
fp = test_results["fp_tests"]
total_tp = tp["passed"] + tp["failed"]
total_fp = fp["passed"] + fp["failed"]
if total_tp == 0 or total_fp == 0:
return 0.5
tp_rate = tp["passed"] / total_tp
fp_ok_rate = fp["passed"] / total_fp
return (tp_rate + fp_ok_rate) / 2
Integratie in de CI/CD-pijplijn
Gegenereerde en gevalideerde regels gaan niet automatisch in productie: ze moeten het proces doorlopen van menselijke beoordeling en de CI/CD-poorten van de Detection-as-Code-pijplijn. De aanbevolen stroom is die AI genereer een Pull Request, geen directe merge.
# GitHub Actions workflow per AI-generated rules
# File: .github/workflows/ai-sigma-generation.yml
"""
name: AI Sigma Rule Generation
on:
schedule:
- cron: '0 6 * * *' # Ogni giorno alle 6:00 UTC
workflow_dispatch:
inputs:
cti_url:
description: 'URL del CTI report da processare'
required: false
jobs:
generate-rules:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install openai pySigma pySigma-backend-splunk pyyaml
- name: Run AI pipeline
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: python scripts/ai_sigma_pipeline.py
- name: Validate generated rules
run: python scripts/validate_all_rules.py rules/ai-generated/
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
title: '[AI-Generated] Detection rules da CTI feed'
body: |
## Regole generate automaticamente da AI
Tecniche ATT&CK rilevate e tradotte in Sigma rules.
**REVIEW OBBLIGATORIA** - Verificare prima del merge:
- [ ] Logsource corretto per il SIEM target
- [ ] Condition logicamente corretta
- [ ] Falsi positivi accettabili
- [ ] Test su ambiente staging completato
labels: 'ai-generated,needs-review'
branch: 'ai-generated-rules'
"""
# Script di validazione bulk
# File: scripts/validate_all_rules.py
import sys
from pathlib import Path
def validate_directory(rules_dir: str) -> int:
"""Valida tutte le regole in una directory. Restituisce exit code."""
validator = SigmaRuleValidator()
rules_path = Path(rules_dir)
failed = []
for rule_file in rules_path.glob("**/*.yml"):
content = rule_file.read_text()
is_valid, errors = validator.validate(content)
if not is_valid:
failed.append((rule_file.name, errors))
print(f"FAIL: {rule_file.name}")
for e in errors:
print(f" - {e}")
else:
print(f"OK: {rule_file.name}")
print(f"\nRisultati: {len(failed)} fallite su {len(list(rules_path.glob('**/*.yml')))} totali")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(validate_directory(sys.argv[1] if len(sys.argv) > 1 else "rules/"))
Alternatieve modellen en kostenoverwegingen
Niet alle organisaties kunnen of willen gevoelige CTI-gegevens naar cloud-API's sturen. Het gebruik van sjablonen pand via Ollama o vLLM en een concreet alternatief voor omgevingen met eisen inzake gegevensresidentie.
| Model | Sigma-kwaliteit | Kosten per 100 regels | Gemiddelde latentie | Datum van verblijf |
|---|---|---|---|---|
| GPT-4o | Hoog (87% geldig) | ~ $ 2,50 | 3-8s | Wolk (OpenAI) |
| GPT-4o-mini | Goed (71% geldig) | ~ $ 0,15 | 1-3s | Wolk (OpenAI) |
| Claude 3.5 Sonnetten | Hoog (84% geldig) | ~ $ 3,00 | 3-6s | Wolk (antropisch) |
| Lama 3.1 70B (lokaal) | Redelijk (58% geldig) | ~$0 (onder) | 15-45s | Op locatie |
| Mistral 7B verfijnd | Goed (69% geldig) | ~$0 (onder) | 5-15s | Op locatie |
Kosteneffectieve strategie
Gebruik GPT-4o-mini voor initiële generatie en iteraties voor nieuwe pogingen (lage kosten, goede kwaliteit), en GPT-4o alleen voor gevallen waarin mini na 2 pogingen mislukt. Met deze hybride aanpak de gemiddelde kosten dalen tot 30% vergeleken met het exclusieve gebruik van GPT-4o met behoud van vergelijkbare kwaliteit.
Echte grenzen en antipatronen
Eerlijkheid is van fundamenteel belang bij de evaluatie van deze technologie. LLM's zijn niet onfeilbaar in het genereren van detectieregels en het kennen van hun beperkingen is net zo belangrijk als het exploiteren ervan de sterke punten.
Gedocumenteerde beperkingen van LLM's voor detectietechniek
-
Hallucinatie van velden: Het model kan veldnamen verzinnen die niet bestaan
in echte logboeken (bijv.
ProcessHashin plaats vanHashesin Sysmon). - Het rapport overdrijven: gegenereerde regels zijn mogelijk te specifiek (IOC-gebaseerd) in plaats van algemeen gedrag vast te leggen.
- Onrealistische valse positieven: De "false positives" gegenereerd door LLM's zijn vaak generiek en vertegenwoordigen geen echte gevallen in de specifieke context van de organisatie.
- Donkere technieken: Voor zeldzame of zeer recente (post-cutoff) ATT&CK-technieken, de kwaliteit gaat aanzienlijk achteruit zonder dat er meer wordt opgehaald.
- Gebrek aan SIEM-context: Het model kent de specifieke normalisatie niet van uw SIEM (bijvoorbeeld hoe Splunk Windows-velden normaliseert in vergelijking met Elastic ECS).
RAG voor SIEM contextspecifiek
Met Retrieval Augmented Generation (RAG) kunt u organisatiespecifieke context in de prompt injecteren: de normalisatie van de SIEM-velden, de bestaande regels, de vals-positieve kalibratiegegevens. Deze aanpak vermindert aanzienlijk het aantal fouten dat verband houdt met een gebrek aan context.
# RAG per generazione Sigma contestualizzata
from chromadb import Client
from chromadb.utils import embedding_functions
class RAGSigmaGenerator:
def __init__(self, chroma_persist_dir: str, openai_key: str):
self.chroma_client = Client()
self.embed_fn = embedding_functions.OpenAIEmbeddingFunction(
api_key=openai_key,
model_name="text-embedding-3-small"
)
# Collection di regole esistenti per few-shot contestuale
self.rules_collection = self.chroma_client.get_or_create_collection(
name="sigma_rules",
embedding_function=self.embed_fn
)
# Collection di field mappings SIEM-specifici
self.field_mappings_collection = self.chroma_client.get_or_create_collection(
name="siem_field_mappings",
embedding_function=self.embed_fn
)
def index_existing_rules(self, rules_dir: str) -> None:
"""Indicizza le regole esistenti per few-shot retrieval."""
for rule_file in Path(rules_dir).glob("**/*.yml"):
content = rule_file.read_text()
rule_dict = yaml.safe_load(content)
self.rules_collection.add(
documents=[content],
metadatas=[{
"title": rule_dict.get('title', ''),
"category": rule_dict.get('logsource', {}).get('category', ''),
"tags": str(rule_dict.get('tags', []))
}],
ids=[str(rule_file)]
)
def generate_with_rag(self, technique_id: str, report: ThreatReport) -> str:
"""Genera Sigma rule con contesto recuperato dal RAG."""
# Recupera regole simili come few-shot examples
similar_rules = self.rules_collection.query(
query_texts=[report.content[:500]],
n_results=3
)
# Recupera field mappings SIEM-specifici
field_mappings = self.field_mappings_collection.query(
query_texts=[f"process_creation windows {technique_id}"],
n_results=2
)
# Costruisce prompt arricchito con contesto RAG
context = "\n\n".join(similar_rules['documents'][0][:2])
mappings_context = "\n".join(field_mappings['documents'][0])
enhanced_prompt = f"""
Regole simili esistenti nel nostro repository (usa come ispirazione):
{context}
Field mappings specifici del nostro SIEM:
{mappings_context}
Ora genera una nuova regola per la tecnica {technique_id}
basandoti sul seguente report: {report.content[:2000]}
"""
# Continua con la generazione standard...
return enhanced_prompt
Conclusies en volgende stappen
AI-ondersteunde detectie-engineering is geen trend: het is een operationele noodzaak voor teams die dat nodig hebben gelijke tred houden met de snelheid waarmee nieuwe aanvalstechnieken ontstaan. De combinatie van LLM voor generatie, rigoureuze automatische validatie en testen met synthetische logs maakt dit mogelijk verkort de tijd tot detectie van dagen naar uren voor een nieuw gepubliceerd dreigingsrapport.
Belangrijkste afhaalrestaurants
- LLM's produceren Sigma-regels van hogere kwaliteit dan directe SPL-query's dankzij de YAML-structuur
- Snelle engineering (gestructureerde systeemprompt, weinig-shots, gedachteketen) is cruciaal voor kwaliteit
- Automatische syntactische en semantische validatie is niet optioneel
- Testen met door AI gegenereerde synthetische logs sluit de kwaliteitslus
- De gegenereerde regels moeten door een menselijke PR-beoordeling gaan, en niet door een automatische samenvoeging
- SIEM-contextspecifieke RAG vermindert veldfouten en valse positieven
- Lokale modellen (Llama, Mistral verfijnd) zijn een geldig alternatief voor dataresidentie
Gerelateerde artikelen
- Sigma-regels: universele detectielogica en SIEM-conversie
- Pipeline voor detectie als code met Git en CI/CD
- Detectieregels testen: testen van eenheden voor beveiligingslogica
- Inname van bedreigingsinformatie: STIX/TAXII-feedprocessor







