
보안 모니터링을 위한 Go 라이브러리로, 로그 항목에 대해 Sigma 탐지 규칙을 파싱하고 실행하며, 필드 수정자, CIDR 매칭, 사용자 정의 필드 리졸버를 지원합니다.
github.com/runreveal/sigmalitesigmalite 패키지는 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
규칙은 YAML 형식으로 작성되며, 최소한 title과 detection을 포함해야 합니다:
title: My example rule
detection:
keywords:
- foo
- bar
selection:
EventId: 1234
condition: keywords and selection
detection 블록 내의 condition 필드는 detection 블록의 다른 필드 선택자를 결합하는 논리 표현식입니다. 이 예시에서 규칙은 EventId 필드가 정확히 1234이고 메시지에 "foo" 또는 "bar"가 포함된 모든 로그 항목과 일치합니다.
필드는 정규 표현식을 사용하여 일치시킬 수도 있습니다:
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
또한 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
자세한 내용은 공식 Sigma 규칙 문서에서 확인할 수 있습니다.
이 라이브러리는 다음 필드 수정자를 지원합니다:
FieldResolver 인터페이스는 단순한 키/값 쌍을 넘어 복잡한 필드 조회 시나리오를 지원하도록 표준 Sigma 사양을 확장합니다. 이를 통해 다음과 같은 사용자 정의 필드 해석 로직을 구현할 수 있습니다:
event.process.user)process.*.user 또는 network[*].ip와 같은 필드 패턴 지원type FieldResolver interface {
Resolve(fieldName string, entry *LogEntry) []string
}
Resolve 메서드는 Sigma 규칙의 필드 이름을 받아 일치하는 모든 값을 문자열 슬라이스로 반환합니다. 일치하는 항목이 없으면 nil 또는 빈 슬라이스를 반환합니다.
// CustomResolver는 구조화된 로그에 대한 필드 해석을 보여줍니다.
type CustomResolver struct{}
func (r *CustomResolver) Resolve(fieldName string, entry *sigma.LogEntry) []string {
switch fieldName {
case "process.users":
// 여러 소스에서 사용자 필드 집계
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":
// 네트워크 관련 필드에서 모든 IP 주소 추출
var ips []string
for fieldName, value := range entry.Fields {
if strings.Contains(strings.ToLower(fieldName), "ip") {
// 간단한 IP 검증 (실제 사용 시 적절한 검증 사용)
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, // 리졸버를 사용하므로 비워둘 수 있음
}
return detection.Matches(entry, opts)
}
필드 리졸버는 모든 필드 수정자와 원활하게 작동하여 해석된 값에 정규식 패턴, 대소문자 구분 없는 매칭 및 기타 변환을 적용할 수 있습니다.