pkg/generator/citrix/cef/cef.go (184 lines of code) (raw):
// Package cef implements the generator for Citrix CEF logs.
//
// generator:
// type: citrix:cef
package cef
import (
"bytes"
"encoding/hex"
"fmt"
"math/rand"
"net"
"strconv"
"text/template"
"time"
"github.com/elastic/go-ucfg"
"github.com/elastic/spigot/pkg/generator"
"github.com/elastic/spigot/pkg/random"
)
// Details from https://docs.citrix.com/en-us/citrix-adc/downloads/cef-log-components.pdf,
// https://docs.citrix.com/en-us/citrix-adc/current-release/application-firewall/logs.html
// and https://support.citrix.com/article/CTX136146/common-event-format-cef-logging-support-in-the-application-firewall.
// Name is the name of the generator in the configuration file and registry
const Name = "citrix:cef"
var (
tmpl = `{{.Timestamp.Format .TimeLayout}} <{{.Facility}}.{{.Priority}}> {{.Addr}} CEF:{{.CEFVersion}}|{{.Vendor}}|{{.Product}}|{{.Version}}|{{.Module}}|{{.Violation}}|{{.Severity}}|src={{.SrcAddr}} {{with .Geo}}geolocation={{.}} {{end}}spt={{.SrcPort}} method={{.Method}} request={{.Request}} msg={{.Message}} cn1={{.EventID}} cn2={{.TxID}} cs1={{.Profile}} cs2={{.PPEID}} cs3={{.SessID}} cs4={{.SeverityLabel}} cs5={{.Year}} {{with .ViolationCategory}}cs6={{.}} {{end}}act={{.Action}}`
msgTemplates = []string{
tmpl,
}
timeLayouts = []string{
"Jan 02 15:04:05",
"Jan 2 15:04:05",
}
facilities = []string{
"auth", "authpriv", "cron", "daemon", "kern", "lpr", "mail", "mark", "news", "syslog", "user", "uucp", "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7",
}
priorities = []string{
"debug", "info", "notice", "warning", "warn", "err", "error", "crit", "alert", "emerg", "panic",
}
vendors = []string{
"Citrix",
}
products = []string{
"NetScalar",
}
versions = []string{
"NS10.0",
"NS11.0",
}
modules = []string{
"APPFW",
}
violations = []string{
"APPFW_FIELDCONSISTENCY",
"APPFW_SAFECOMMERCE",
"APPFW_SAFECOMMERCE_XFORM",
"APPFW_SIGNATURE_MATCH",
"APPFW_STARTURL",
}
locations = []string{
"",
"Unknown",
"NorthAmerica.US.Arizona.Tucson.*.*",
"NorthAmerica.US.Arizona.Phoenix.*.*",
"NorthAmerica.US.California.SanFrancisco.*.*",
}
methods = []string{
"GET", "POST",
}
requests = []string{
`http://aaron.stratum8.net/FFC/login.html`,
`http://aaron.stratum8.net/FFC/login.php?login_name=abc&passwd=123456789234&drinking_pref=on&text_area=&loginButton=ClickToLogin&as_sfid=AAAAAAWIahZuYoIFbjBhYMP05mJLTwEfIY0a7AKGMg3jIBaKmwtK4t7M7lNxOgj7Gmd3SZc8KUj6CR6a7W5kIWDRHN8PtK1Zc-txHkHNx1WknuG9DzTuM7t1THhluevXu9I4kp8%3D&as_fid=feeec8758b41740eedeeb6b35b85dfd3d5def30c`,
`http://aaron.stratum8.net/FFC/wwwboard/passwd.txt`,
`http://aaron.stratum8.net/FFC/CreditCardMind.html`,
`http://vpx247.example.net/FFC/CreditCardMind.html`,
`http://vpx247.example.net/FFC/login_post.html?abc\=def`,
`http://vpx247.example.net/FFC/wwwboard/passwd.txt`,
}
messages = []string{
"Signature violation rule ID 807: web-cgi /wwwboard/passwd.txt access",
"Disallow Illegal URL.",
"Transformed (xout) potential credit card numbers seen in server response",
"Maximum number of potential credit card numbers seen",
"Field consistency check failed for field passwd",
}
profiles = []string{
"pr_ffc",
}
severityLabels = []string{
"INFO", "ALERT",
}
violationCategory = []string{
"",
"web-cgi",
"sql-injection",
"phishing",
}
actions = []string{
"blocked", "not blocked", "transformed",
}
)
type CEF struct {
Timestamp time.Time
TimeLayout string
Facility string
Priority string
Addr net.IP
CEFVersion int
Vendor string
Product string
Version string
Module string
Violation string
Severity int
SrcAddr net.IP
Geo string
SrcPort int
Method string
Request string
Message string
EventID int
TxID int
Profile string
PPEID string
SessID string
SeverityLabel string
Year int
ViolationCategory string
Action string
templates []*template.Template
}
func init() {
generator.Register(Name, New)
}
// New returns a new Citrix CEF log line generator.
func New(cfg *ucfg.Config) (generator.Generator, error) {
def := defaultConfig()
if err := cfg.Unpack(&def); err != nil {
return nil, err
}
c := &CEF{}
c.randomize()
for i, v := range msgTemplates {
t, err := template.New(strconv.Itoa(i)).Funcs(generator.FunctionMap).Parse(v)
if err != nil {
return nil, err
}
c.templates = append(c.templates, t)
}
return c, nil
}
// Next produces the next CEF log entry.
func (c *CEF) Next() ([]byte, error) {
var buf bytes.Buffer
err := c.templates[rand.Intn(len(c.templates))].Execute(&buf, c)
if err != nil {
return nil, err
}
c.randomize()
return buf.Bytes(), err
}
func (c *CEF) randomize() {
c.Timestamp = time.Now()
c.TimeLayout = randString(timeLayouts)
c.Facility = randString(facilities)
c.Priority = randString(priorities)
c.Addr = random.IPv4()
c.CEFVersion = rand.Intn(2)
c.Vendor = randString(vendors)
c.Product = randString(products)
c.Version = randString(versions)
c.Module = randString(modules)
c.Violation = randString(violations)
c.Severity = rand.Intn(10) + 1
c.SrcAddr = random.IPv4()
c.Geo = randString(locations)
c.SrcPort = random.Port()
c.Method = randString(methods)
c.Request = randString(requests)
c.Message = randString(messages)
c.EventID = rand.Intn(1000)
c.TxID = rand.Intn(100000)
c.Profile = randString(profiles)
c.PPEID = fmt.Sprintf("PPE%d", rand.Intn(9)+1)
sessID := make([]byte, 16)
rand.Read(sessID)
c.SessID = hex.EncodeToString(sessID)
c.SeverityLabel = randString(severityLabels)
c.Year = c.Timestamp.Year()
c.ViolationCategory = randString(violationCategory)
c.Action = randString(actions)
}
func randString(s []string) string {
return s[rand.Intn(len(s))]
}