Skip to content

Commit

Permalink
initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
DirkDuesentrieb committed Jun 25, 2018
1 parent 80b0afb commit 59954b8
Show file tree
Hide file tree
Showing 6 changed files with 657 additions and 674 deletions.
875 changes: 201 additions & 674 deletions LICENSE

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions asaparser/asaparser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// the parser part for Cisco ASA logs
// dheilema 2018
// 2018 by Nexinto GmbH

package asaparser

import (
"errors"
"regexp"
"strings"
"syslog2faz/faz"
)

type (
// LogFilter contains the necessary infos to parse a log line
LogFilter struct {
pList []string
extra []string
compiled *regexp.Regexp
}
// lfList is an array of all LogFilters of the same message id
lfList []LogFilter
msgList map[string]lfList
)

var (
ml msgList
)

// read file <fname> into msgList.
// Set <runTests> to true to run the regex tests
func New(fname string, runTests bool) error {
ml = make(map[string]lfList)
return readFilterList(fname, runTests)
}

// parse a verbose log line and return faz log structure
func Parse(in string, offset int) (faz.Log, error) {
l := make(map[string]string)
// fix possible offset problem
if len(in) > offset {
in = in[offset:]
} else {
return l, errors.New("offset > len()")
}
// remove CR
if (in[len(in)-1]) == 10 {
in = in[:len(in)-1]
}
// check if the ASA message ID is present
msgid := strings.Split(in[1:13], "-")
if len(msgid) == 3 {
if msgid[0] != "ASA" {
return l, errors.New("Possible offset problem! (" + in[1:13] + ") is not a Message ID (ASA-n-nnnnnn)")
}
} else {
// nothing to parse, stay silent
return l, nil
}
// cut the message part
msg := in[15:]

// see if we can parse this
lfList, exists := ml[msgid[2]]
if !exists {
return l, errors.New("no parser for msgid " + msgid[2])
}

// we might have multiple filter for one message ID
found := false
for _, LogFilter := range lfList {
if LogFilter.compiled.Match([]byte(msg)) {
found = true
matches := LogFilter.compiled.FindStringSubmatch(msg)
if len(LogFilter.pList)+1 == len(matches) {
for i, name := range LogFilter.pList {
l[name] = matches[i+1]
}
} else {
return l, errors.New("error in parser: difference between number of parameters and regexes")
}
// add extras
for _, value := range LogFilter.extra {
kv := strings.Split(value, "=")
if len(kv) == 2 {
l[kv[0]] = kv[1]
}
}
l["level"] = faz.VerboseLogLevel(msgid[1])
}
}
if found == false {
return l, errors.New("error in parser: the filter for " + msgid[2] + " doesn't match")
}
return l, nil
}
83 changes: 83 additions & 0 deletions asaparser/readFilterList.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// dheilema 2018
// 2018 by Nexinto GmbH

package asaparser

import (
"errors"
"fmt"
"io/ioutil"
"regexp"
"strings"
)

// read the filters from a file fname
// runs the test if requested
func readFilterList(fname string, runTests bool) error {
dat, err := ioutil.ReadFile(fname)
if err != nil {
return err
}
lines := strings.Split(string(dat), "\n")
linenr := 0
msgid := ""
step := 0
regex := ""
test := ""
paramList := []string{}
extras := []string{}
for _, line := range lines {
linenr++
if len(line) > 1 {
line = line[0 : len(line)-1]
switch line[0] {
case 35:
// comment
case 9:
// remove tab
line = line[1:]
switch step {
case 0:
// regex
regex = line
case 1:
// paramList
paramList = strings.Split(line, ";")
case 2:
// extras
extras = strings.Split(line, ";")
new := append(ml[msgid], LogFilter{paramList, extras, regexp.MustCompile(regex)})
ml[msgid] = new
case 3:
// test syslog
test = "%ASA-1-" + msgid + ": " + line
case 4:
// test expected parameters
if runTests {
log, err := Parse(test, 0)
if err != nil {
return errors.New("error while testing " + msgid + " line " + fmt.Sprintf("%d", linenr) + ". " + fmt.Sprint(err))
}
expected := strings.Split(line, ";")
for i, key := range paramList {
if log[key] != expected[i] {
out := "error while testing " + msgid + " line " + fmt.Sprintf("%d", linenr) + "\n" + test + "\n"
out = out + "parse result: " + key + "=\"" + log[key] + "\"\n"
out = out + "expected : " + key + "=\"" + expected[i] + "\""
return errors.New(out)
}
}
}
// allow another test / go back to step 2
step = 2
}
step++
default:
// msgid go to step 0
msgid = line
step = 0
}
}
}
return nil
}
82 changes: 82 additions & 0 deletions faz/faz.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// dheilema 2018
// 2018 by Nexinto GmbH
//
// basic functions to create the FAZ compatible log

package faz

import "time"

type (
Log map[string]string
)

// create formatted string from map
func (l Log) String() string {
now := time.Now().String()
l["date"] = string(now[:10])
l["time"] = string(now[11:19])

out := ""
for name, value := range l {
if out != "" {
out += " "
}
if needsQuoting(name) {
value = "\"" + value + "\""
}
if name == "proto" {
value = fixProto(value)
}
out += name + "=" + value
}
return out
}

// convert syslog severity as number (as string) to it's verbose name
func VerboseLogLevel(in string) (out string) {
switch in {
case "1":
out = "emerg"
case "2":
out = "alert"
case "3":
out = "crit"
case "4":
out = "err"
case "5":
out = "warning"
case "6":
out = "notice"
case "7":
out = "info"
case "8":
out = "debug"
}
return
}

// some values need quotes
func needsQuoting(name string) bool {
switch name {
case "msg", "srcintf", "dstintf":
return true
default:
return false
}
}

// some proto needs sanitizing
func fixProto(name string) string {
switch name {
case "tcp", "TCP":
return "6"
case "udp", "UDP":
return "17"
case "icmp", "ICMP":
return "1"
case "ipv6-icmp", "IPv6-ICMP":
return "58"
}
return name
}
104 changes: 104 additions & 0 deletions filter.list
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# list of syslog filter
#
# file format:
# <message id>
# TAB<regex>
# TAB<parameter list>
# TAB<extra parameters as k=v>
# TAB<test syslog>
# TAB<test expected parsed values>
# optional: more test log and value lines...
#
106023
^Deny (tcp|udp) src (.*):(.*)/(.*) dst (.*):(.*)/(.*) by access-group ".*" .*
proto;srcintf;srcip;srcport;dstintf;dstip;dstport
action=deny;type=traffic;subtype=forward
Deny udp src inside:10.10.10.10/12345 dst outside:2.2.2.2/80 by access-group "global" [0x0, 0x0]
udp;inside;10.10.10.10;12345;outside;2.2.2.2;80

106023
^Deny (icmp) src ([^:]*):(.*) dst ([^:]*):(.*) \(type (.*), code (.*)\) by access-group ".*" .*
proto;srcintf;srcip;dstintf;dstip;icmptype;icmpcode
action=deny;type=traffic;subtype=forward
Deny icmp src inside:10.10.10.10 dst outside:2.2.2.2 (type 8, code 0) by access-group "inside-in" [0x0, 0x0]
icmp;inside;10.10.10.10;outside;2.2.2.2;8;0
Deny icmp src inside:2a01:111:222:333::2 dst outside:2a00:111:222:333:444:555:666:777 (type 1, code 3) by access-group "outside-in" [0x0, 0x0]
icmp;inside;2a01:111:222:333::2;outside;2a00:111:222:333:444:555:666:777;1;3

106023
^Deny protocol ([^ ]+) src (.*):(.*) dst (.*):(.*) by access-group ".*" .*
proto;srcintf;srcip;dstintf;dstip
action=deny;type=traffic;subtype=forward
Deny protocol 50 src outside:2.2.2.2 dst inside:10.10.10.10 by access-group "outside-in" [0x0, 0x0]
50;outside;2.2.2.2;inside;10.10.10.10

106006
^Deny inbound (TCP|UDP) from ([^ ]*)\/([^ ]*) to ([^ ]*)\/([^ ]*) on interface ([^ ]*)
proto;srcip;srcport;dstip;dstport;srcintf
action=deny;type=traffic;subtype=forward
Deny inbound UDP from 10.10.10.10/12345 to 2.2.2.2/80 on interface inside
UDP;10.10.10.10;12345;2.2.2.2;80;inside

106021
^Deny ([^ ]*) reverse path check from ([^ ]*) to ([^ ]*) on interface ([^ ]*)
proto;srcip;dstip;srcintf
action=deny;type=traffic;subtype=forward
Deny IPv6-ICMP reverse path check from :: to ff02::16 on interface inside
IPv6-ICMP;::;ff02::16;inside

106100
^access-list [^ ]* permitted (tcp|udp) ([^ ]*)\/([^ ]*)\(([^ ]*)\) -> ([^ ]*)\/([^ ]*)\(([^ ]*)\) hit-cnt .*
proto;srcintf;srcip;srcport;dstintf;dstip;dstport
action=allow;type=traffic;subtype=forward
access-list inside-in permitted tcp inside/10.10.10.10(12345) -> outside/2.2.2.2(80) hit-cnt 1 first hit [0x12345678, 0x00000000]
tcp;inside;10.10.10.10;12345;outside;2.2.2.2;80

305006
^regular translation creation failed for (icmp) src ([^:]*):([^ ]*) dst ([^:]*):([^ ]*) \(type (.*), code (.*)\)
proto;srcintf;srcip;dstintf;dstip;icmptype;icmpcode
action=deny;type=traffic;subtype=forward
regular translation creation failed for icmp src inside:10.10.10.10 dst outside:2.2.2.2 (type 3, code 3)
icmp;inside;10.10.10.10;outside;2.2.2.2;3;3

313005
^No matching connection for ICMP error message: (icmp) src ([^:]*):([^ ]*) dst ([^:]*):([^ ]*) \(type (.*), code (.*)\) on [^ ]* interface. (.*)
proto;srcintf;srcip;dstintf;dstip;icmptype;icmpcode;msg
action=deny;type=traffic;subtype=forward
No matching connection for ICMP error message: icmp src inside:10.10.10.10 dst outside:2.2.2.2 (type 3, code 3) on inside interface. Original IP payload: udp src 2.2.2.2/80 dst 10.10.10.10/12345.
icmp;inside;10.10.10.10;outside;2.2.2.2;3;3;Original IP payload: udp src 2.2.2.2/80 dst 10.10.10.10/12345.

313008
^Denied ([^ ]*) type=(.*), code=(.*) from ([^ ]*) on interface ([^ ]*)
proto;icmptype;icmpcode;srpip;srcintf
action=deny;type=traffic;subtype=forward
Denied IPv6-ICMP type=135, code=0 from 2a01:111:222:333::2 on interface inside
IPv6-ICMP;135;0;2a01:111:222:333::2;inside

710003
^(TCP|UDP) access denied by ACL from (.*)/(.*) to (.*):(.*)/(.*)
proto;srcip;srcport;dstintf;dstip;dstport
action=deny;type=traffic;subtype=forward
TCP access denied by ACL from 10.10.10.10/12345 to outside:2.2.2.2/80
TCP;10.10.10.10;12345;outside;2.2.2.2;80

733100
^\[ ([^ ]*)\] ([^;]*);.*
attack;attackcontext
action=deny;type=ips;subtype=signature
[ Scanning] drop rate-1 exceeded. Current burst rate is 26 per second, max configured rate is 10; Current average rate is 88 per second, max configured rate is 5; Cumulative total count is 53225
Scanning;drop rate-1 exceeded. Current burst rate is 26 per second, max configured rate is 10

733100
^\[[ ]+Port-.* (.*)\] ([^;]*);.*
dstport;attackcontext
action=deny;type=ips;subtype=signature;attack=scan port;proto=6
[ Port-5247 5247] drop rate-1 exceeded. Current burst rate is 40 per second, max configured rate is 40; Current average rate is 19 per second, max configured rate is 20; Cumulative total count is 11950
5247;drop rate-1 exceeded. Current burst rate is 40 per second, max configured rate is 40

733100
^\[[ ]+Port-.*\] ([^;]*);.*
attackcontext
action=deny;type=ips;subtype=signature;attack=scan portrange;proto=6
[ Port-8191-65535] drop rate-1 exceeded. Current burst rate is 40 per second, max configured rate is 40; Current average rate is 30 per second, max configured rate is 20; Cumulative total count is 18297
drop rate-1 exceeded. Current burst rate is 40 per second, max configured rate is 40

Loading

0 comments on commit 59954b8

Please sign in to comment.