Skip to content

runreveal/sigmalite

Repository files navigation

github.com/runreveal/sigmalite

Package sigmalite provides a parser and an execution engine for the Sigma detection format.

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)

Install

go get github.com/runreveal/sigmalite

Rules

Rules are written in YAML format and, at a minimum, must include a title and a detection:

title: My example rule
detection:
  keywords:
    - foo
    - bar
  selection:
    EventId: 1234
  condition: keywords and selection

The condition field in the detection block is a logical expression that joins other field selectors in the detection block. In this example, this rule will match any log entry that has an EventId field that is exactly 1234 and has "foo" or "bar" in its message.

Fields can also be matched using regular expressions:

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

As well as CIDRs:

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

More information can be found in the official Sigma rules documentation.

Field Modifiers

This library supports the following field modifiers:

Field Resolver

The FieldResolver interface extends the standard Sigma specification to support complex field lookup scenarios that go beyond simple key/value pairs. This allows you to implement custom field resolution logic for:

  • Nested JSON structures: Access deeply nested fields using dot notation (e.g., event.process.user)
  • Array handling: Extract values from arrays or lists within log entries
  • Wildcard matching: Support field patterns like process.*.user or network[*].ip
  • Multiple field aggregation: Combine values from multiple related fields
  • Case normalization: Handle field name variations and case sensitivity
  • Complex data transformations: Apply custom logic before field matching
  • External datasource lookups: Lookup field values from an external datasource.

Interface Definition

type FieldResolver interface {
    Resolve(fieldName string, entry *LogEntry) []string
}

The Resolve method takes a field name from your Sigma rule and returns all matching values as a string slice. If no matches are found, return nil or an empty slice.

Basic Usage Example

// 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)
}

Field Resolvers work seamlessly with all field modifiers, allowing you to apply regex patterns, case-insensitive matching, and other transformations to the resolved values.

License

Apache 2.0

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages