Wykrywanie wspomagane sztuczną inteligencją: LLM do generowania reguł Sigma
Integracja modeli wielkojęzycznych z inżynierią wykrywania stanowi jedną z najbardziej radykalnych zmian w krajobrazie SOC w ostatnich latach. Nie chodzi po prostu o automatyzację powtarzalnego zadania: użycie LLM do wygenerowania reguł Sigma oznacza skompresowanie procesu do sekund, które ekspert-analityk zajmuje to kilka godzin – od przeczytania raportu o zagrożeniach do napisania przetestowanej reguły gotowej do wdrożenia.
Frameworki takie jak SigmaGen, zaprezentowane na konferencji MITER ATT&CK APAC 2025, pokazują, w jaki sposób precyzyjnie dostrojone modele mogą wykorzystywać raporty dotyczące analizę zagrożeń, wyodrębnianie technik ATT&CK i tworzenie mapowanych reguł Sigmy z dużą precyzją. Jednocześnie narzędzia open source i Przepływy pracy oparte na n8n umożliwiają mniejszym zespołom tworzenie potoków wspomaganych sztuczną inteligencją bez inwestycji przedsiębiorstw.
W tym artykule omówiono architekturę systemu wspomaganego sztuczną inteligencją do generowania reguł wykrywania: od poziomu zachęty inżynieryjnej, do automatycznej walidacji, testowania z logami syntetycznymi, do integracji z istniejącym rurociągiem CI/CD.
Czego się nauczysz
- Jak LLM myślą o formacie Sigma i dlaczego dają lepszą moc wyjściową niż bezpośrednie SPL
- Specyficzne techniki inżynieryjne umożliwiające generowanie reguł wykrywania
- Architektura kompleksowego potoku wspomaganego sztuczną inteligencją
- Automatyczna walidacja i testowanie wygenerowanych reguł
- Integracja z przepływem pracy SigmaGen, pySigma i CI/CD
- Antywzorce, których należy unikać i rzeczywiste ograniczenia LLM w kontekście bezpieczeństwa
dlaczego LLM doskonale radzą sobie z generowaniem reguł Sigma
Jedną z najciekawszych obserwacji, jakie wyłoniły się z badań stosowanych (i potwierdzonych w praktyce), jest to, że LLM dają produkty wysokiej jakości znacznie wyższe, gdy generują Sigmy w porównaniu do bezpośrednich zapytań SPL lub KQL. Powód jest strukturalny.
Format YAML firmy Sigma narzuca wyraźny podział pomiędzy:
- tytuł i opis: Model musi jasno określić, co wykrywa i dlaczego
- źródło dziennika: określa źródło danych (kategoria, produkt, usługa)
- wykrywanie: logika dopasowywania logicznego
- stan: Jak łączyć selektory
- wyniki fałszywie pozytywne: Wyraźne rozumowanie w przypadkach Edge
Struktura ta zmusza model do „myślenia” sekwencyjnego i deklaratywnego, redukując błędy logiczne powstające podczas bezpośrednio żąda danych wyjściowych w języku zapytań specyficznym dla platformy. W praktyce Sigma działa jak ukryty ciąg myślowy dla LLM stosowanych do wykrywania.
Dane porównawcze
Naukowcy z projektu LLMCloudHunter (2024) wykazali, że ogólne LLM, takie jak GPT-4, generują reguły Sigma, które są ważne w 73% przypadków w przypadku ustrukturyzowanych raportów CTI w porównaniu z 41% w przypadku pytań o bezpośrednie wyniki SPL. Po dostrojeniu zbiorów danych odsetek ten wzrasta do 89%. specyfikacje bezpieczeństwa.
Architektura rurociągu wspomaganego sztuczną inteligencją
Proces generowania reguł wykrywania wspomagany sztuczną inteligencją składa się z pięciu odrębnych etapów:
- Przyjmowanie pokarmu: przetwarzanie raportów o zagrożeniach, postów na blogu CTI, porad CVE
- Ekstrakcja: Ekstrakcja IOC, techniki ATT&CK, opisane zachowania
- Generacja: generowanie reguły Sigma poprzez LLM
- Walidacja: automatyczna walidacja syntaktyczna i semantyczna
- Testowanie: Testowanie z logami syntetycznymi i integracją CI/CD
# 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 []
Szybka inżynieria w celu uzyskania wysokiej jakości zasad Sigma
Jakość wyników zależy w dużym stopniu od struktury podpowiedzi. Istnieją trzy podstawowe wzorce, które dają rezultaty polegająca na wygenerowaniu reguł Sigma:
Wzorzec 1: Podpowiedź systemu strukturalnego
Podpowiedź systemowa musi zawierać dokładnie metainformacje potrzebne modelowi do wygenerowania prawidłowych sigm:
struktura YAML, prawidłowe wartości category e product, najlepsze praktyki na
falsepositives oraz dopuszczalne poziomy dotkliwości.
# 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."""
Wzór 2: Kilka strzałów z przykładami jakości
Dołączenie 2-3 przykładów reguł wysokiej jakości do zachęty (kilka strzałów) radykalnie poprawia spójność wyników, szczególnie w przypadku nietypowych źródeł logów lub złożonych warunków.
# 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
"""
Wzorzec 3: Wyraźny łańcuch myśli
W przypadku złożonych technik wymaganie od modelu rozumowania przed napisaniem reguły daje dokładniejsze wyniki. Takie podejście zwiększa opóźnienia, ale znacznie zmniejsza liczbę potrzebnych iteracji.
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
)
Automatyczna walidacja wygenerowanych reguł
LLM może wygenerować poprawny składniowo, ale niepoprawny semantycznie YAML: nieistniejące źródło dziennika, pole misnamed, warunek, który nie odwołuje się poprawnie do selektorów. Automatyczna walidacja i bramę krytyczną, zanim reguła trafi do repozytorium.
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
Anty-wzorzec: ślepe zaufanie wynikom LLM
Częstym błędem zespołów wdrażających wykrywanie wspomagane sztuczną inteligencją jest wdrażanie wygenerowanych reguł bez walidacji. LLM popełniają konkretne i powtarzalne błędy w generacji Sigmy:
- Użyj pól
ProcessNamezamiastImage(Sysmon) - Zapisz warunki odwołujące się do nieistniejących selektorów
- Wymyśl niestandardowe kategorie źródeł logów
- Używać
containsw polach, które nie obsługują symboli wieloznacznych w docelowym źródle dziennika
Automatyczna weryfikacja i testowanie z użyciem prawdziwych dzienników NIE są OPCJONALNE.
Automatyczne testowanie z użyciem kłód syntetycznych
Po sprawdzeniu składni każdą regułę należy przetestować w dziennikach symulujących oba zachowania oczekiwany złośliwy ruch (test prawdziwie pozytywny) niż normalny ruch (test fałszywie pozytywny). To podejście, zadzwonił testowanie jednostkowe regułyoraz praktyka odróżniająca dojrzały potok od a eksperyment.
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: platforma typu open source do wykrywania wspomaganego sztuczną inteligencją
SigmaGen, zaprezentowany na targach MITER ATT&CK APAC 2025, reprezentuje najnowocześniejsze rozwiązania w zakresie ram open source do generowania reguł wykrywania przez sztuczną inteligencję. Projekt łączy w sobie dostrajanie wybranych zbiorów danych z architektura potokowa obejmująca cały cykl życia reguły.
# 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
Integracja z rurociągiem CI/CD
Wygenerowane i zatwierdzone reguły nie trafiają automatycznie do produkcji: muszą przejść przez ten proces przeglądu ręcznego i bramek CI/CD w potoku wykrywania jako kodu. Zalecany przepływ to AI wygeneruj żądanie ściągnięcia, a nie bezpośrednie połączenie.
# 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/"))
Alternatywne modele i względy kosztowe
Nie wszystkie organizacje mogą lub chcą wysyłać wrażliwe dane CTI do interfejsów API w chmurze. Stosowanie szablonów lokal przez Ollama o vLLM oraz konkretną alternatywę dla środowiska z wymogami dotyczącymi przechowywania danych.
| Model | Jakość Sigmy | Koszt za 100 reguł | Średnie opóźnienie | Data pobytu |
|---|---|---|---|---|
| GPT-4o | Wysoka (87% wartości prawidłowych) | ~2,50 dolara | 3-8 s | Chmura (OpenAI) |
| GPT-4o-mini | Dobry (71% ważny) | ~0,15 USD | 1-3 s | Chmura (OpenAI) |
| Claude 3,5 Sonety | Wysoka (84% wartości prawidłowych) | ~3,00 $ | 3-6 s | Chmura (antropiczna) |
| Lama 3.1 70B (lokalnie) | Dostateczny (58% wartości prawidłowy) | ~0 $ (poniżej) | 15-45 s | Na miejscu |
| Mistral 7B dostrojony | Dobry (69% ważny) | ~0 $ (poniżej) | 5-15 s | Na miejscu |
Strategia opłacalna
Używaj GPT-4o-mini do początkowej generacji i ponawiania iteracji (niski koszt, dobra jakość), i GPT-4o tylko w przypadkach, gdy mini kończy się niepowodzeniem po 2 próbach. Dzięki temu hybrydowemu podejściu średni koszt spada do 30% w porównaniu do wyłącznego stosowania GPT-4o przy zachowaniu porównywalnej jakości.
Rzeczywiste granice i anty-wzorce
Uczciwość jest podstawą oceny tej technologii. LLM nie są nieomylni tworzenia reguł wykrywania, a znajomość ich ograniczeń jest równie ważna, jak ich wykorzystanie mocne strony.
Udokumentowane ograniczenia LLM w inżynierii wykrywania
-
Halucynacje pól: Model może wymyślić nazwy pól, które nie istnieją
w prawdziwych logach (np.
ProcessHashzamiastHashesw Sysmonie). - Nadmierne dopasowanie raportu: Wygenerowane reguły mogą być zbyt szczegółowe (w oparciu o IOC) zamiast rejestrować ogólne zachowanie.
- Nierealistyczne fałszywe alarmy: „fałszywie pozytywne” generowane przez LLM są często ogólne i nie reprezentują rzeczywistych przypadków w konkretnym kontekście organizacji.
- Ciemne techniki: W przypadku rzadkich lub bardzo niedawnych (po odcięciu) technik ATT&CK, jakość ulega znacznemu pogorszeniu bez zwiększonego odzyskiwania.
- Brak kontekstu SIEM: Model nie zna konkretnej normalizacji Twojego SIEM (np. jak Splunk normalizuje pola Windows w porównaniu z Elastic ECS).
RAG dla SIEM kontekstowo
Funkcja Retrieval Augmented Generation (RAG) umożliwia wstrzyknięcie kontekstu specyficznego dla organizacji do podpowiedzi: normalizacja pól SIEM, istniejące zasady, fałszywie dodatnie dane kalibracyjne. Takie podejście znacznie zmniejsza liczbę błędów związanych z brakiem kontekstu.
# 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
Wnioski i dalsze kroki
Inżynieria wykrywania wspomagana sztuczną inteligencją nie jest trendem: jest koniecznością operacyjną dla zespołów, które tego potrzebują nadążaj za szybkością pojawiania się nowych technik ataku. Połączenie LLM do generowania, pozwala na rygorystyczną automatyczną walidację i testowanie za pomocą logów syntetycznych w nowo opublikowanym raporcie o zagrożeniach skróć czas wykrycia z dni do godzin.
Kluczowe dania na wynos
- Dzięki strukturze YAML LLM generują reguły Sigma o wyższej jakości niż bezpośrednie zapytania SPL
- Szybka inżynieria (ustrukturyzowane podpowiedzi systemowe, kilka strzałów, łańcuch myślowy) ma kluczowe znaczenie dla jakości
- Automatyczna weryfikacja syntaktyczna i semantyczna nie jest opcjonalna
- Testowanie z wykorzystaniem logów syntetycznych generowanych przez sztuczną inteligencję zamyka pętlę jakości
- Wygenerowane reguły muszą przejść kontrolę PR przez człowieka, a nie automatyczne scalanie
- Kontekstowy RAG SIEM redukuje błędy terenowe i fałszywe alarmy
- Modele lokalne (dostrojone Lama, Mistral) stanowią ważną alternatywę dla przechowywania danych
Powiązane artykuły
- Reguły Sigma: uniwersalna logika detekcji i konwersja SIEM
- Potok wykrywania jako kodu z Git i CI/CD
- Testowanie reguł wykrywania: testowanie jednostkowe logiki bezpieczeństwa
- Pozyskiwanie informacji o zagrożeniach: procesor kanałów STIX/TAXII







