
Bibliothèque Go pour analyser et exécuter des règles de détection Sigma sur des entrées de logs, prenant en charge les modificateurs de champs, la correspondance CIDR et les résolveurs de champs personnalisés pour la surveillance de sécurité.
github.com/runreveal/sigmaliteLe paquet sigmalite fournit un analyseur syntaxique et un moteur d'exécution pour le format de détection Sigma.
rule, err := sigmalite.ParseRule([]byte(`
title: My example rule
detection:
keywords:
- foo
- bar
selection:
EventId: 1234
condition: keywords and selection
`))
if err != nil {
return err
}
entry := &sigmalite.LogEntry{
Message: "Hello foo",
Fields: map[string]string{
"EventId": "1234",
},
}
isMatch := rule.Detection.Matches(entry, nil)
go get github.com/runreveal/sigmalite
Les règles sont écrites au format YAML et doivent, au minimum, inclure un title et une :
detectiontitle: My example rule
detection:
keywords:
- foo
- bar
selection:
EventId: 1234
condition: keywords and selection
Le champ condition dans le bloc detection est une expression logique qui joint d'autres sélecteurs de champs dans le bloc detection. Dans cet exemple, cette règle correspondra à toute entrée de journal qui a un champ EventId exactement égal à 1234 et contient "foo" ou "bar" dans son message.
Les champs peuvent également être mis en correspondance à l'aide d'expressions régulières :
title: My example rule with a timestamp
detection:
selection:
Timestamp|re: ^2024-06-01T(01|02|03):[0-5][0-9]:[0-5][0-9]$
condition: selection
Ainsi que des CIDR :
title: My example rule with IP addresses
detection:
local:
DestinationIp|cidr:
- "127.0.0.0/8"
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "169.254.0.0/16"
- "::1/128" # IPv6 loopback
- "fe80::/10" # IPv6 link-local addresses
- "fc00::/7" # IPv6 private addresses
condition: not local
Plus d'informations sont disponibles dans la documentation officielle des règles Sigma.
Cette bibliothèque prend en charge les modificateurs de champ suivants :
L'interface FieldResolver étend la spécification Sigma standard pour prendre en charge des scénarios de recherche de champ complexes allant au-delà des simples paires clé/valeur. Cela vous permet d'implémenter une logique de résolution de champ personnalisée pour :
event.process.user).process.*.user ou network[*].ip.type FieldResolver interface {
Resolve(fieldName string, entry *LogEntry) []string
}
La méthode Resolve prend un nom de champ de votre règle Sigma et renvoie toutes les valeurs correspondantes sous forme de tranche de chaînes. Si aucune correspondance n'est trouvée, renvoyez nil ou une tranche vide.
// CustomResolver demonstrates field resolution for structured logs
type CustomResolver struct{}
func (r *CustomResolver) Resolve(fieldName string, entry *sigma.LogEntry) []string {
switch fieldName {
case "process.users":
// Aggregate user fields from multiple sources
var users []string
if user, ok := entry.Fields["Event.Process.User"]; ok {
users = append(users, user)
}
if user, ok := entry.Fields["Event.Login.User"]; ok {
users = append(users, user)
}
if user, ok := entry.Fields["Event.Session.User"]; ok {
users = append(users, user)
}
return users
case "network.internal_ips":
// Extract all IP addresses from network-related fields
var ips []string
for fieldName, value := range entry.Fields {
if strings.Contains(strings.ToLower(fieldName), "ip") {
// Simple IP validation (in real usage, use proper validation)
if strings.Contains(value, ".") {
ips = append(ips, value)
}
}
}
return ips
default:
return nil
}
}
func matches(detection *sigmalite.Detection) bool {
opts := &sigmalite.MatchOptions{
FieldResolver: CustomResolver{},
},
entry := &sigmalite.LogEntry{
Message: string("Message Text"),
Fields: nil, // Using resolver so this can be empty
}
return detection.Matches(entry, opts)
}
Les résolveurs de champ fonctionnent harmonieusement avec tous les modificateurs de champ, vous permettant d'appliquer des motifs regex, une correspondance insensible à la casse et d'autres transformations aux valeurs résolues.