-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
DirkDuesentrieb
committed
Jun 25, 2018
1 parent
80b0afb
commit 59954b8
Showing
6 changed files
with
657 additions
and
674 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
Oops, something went wrong.