garyelephant / pygrok

python implementation of jordansissel's grok regular expression library
MIT License
277 stars 74 forks source link

Parsing Cisco Extended Access Control Lists sometimes fails silently #36

Open C0FFEEC0FFEE opened 5 years ago

C0FFEEC0FFEE commented 5 years ago

I've written a grok pattern to parse Cisco Extended ACLs. Mostly this works fine, however for 0.2 % of my ACLs the resulting variable (grok_line = grok.match(line)) is None.

I included my script (parse_cisco_acl.py) as well as some example ACLs which fail to parse (infile.txt).

If you have any pointer how I can debug this myself I'll look into it.

parse_cisco_acl.py:

#!/usr/bin/env python
"""Reads a text-file, uses grok to extract fields from each line."""

from pygrok import Grok
import csv
import os

# Source for the ACL specification:
# Cisco ASA 5500 Series Command Reference, Version 8.2(5)
# https://www.cisco.com/c/en/us/td/docs/security/asa/asa82/command/reference/cmd_ref.pdf
# 
# 1 access-list id [line line-number] [extended] {deny | permit}
# 2 {protocol | object-group protocol_obj_grp_id}
# 3 {src_ip mask | interface ifc_name | host hostname | object-group network_obj_grp_id}
# 4 [object-group service_obj_grp_id | operator port]
# 5 {dst_ip mask | interface ifc_name | host hostname | object-group network_obj_grp_id}
# 6 [object-group service_obj_grp_id | operator port | object-group icmp_type_obj_grp_id]
# 7 [log [[level] [interval secs] | disable | default]]
# 8 [inactive | time-range time_range_name]
# 9 (hitcnt=hitcount) hashcode
#

acl_patterns = {'ANY': '\b(?:any(4)?)\b',
'LOGSTATUS': '\b(?:disable|default)\b',
'RANGE': '(?:%{IPORHOST}|%{POSINT})',
'ACL_LINE1': 'access-list\s%{USERNAME:policy_id}\sline\s\d+\sextended\s%{WORD:action}',
'ACL_LINE2': '((object-group|object)\s%{USERNAME:dst_service}|%{WORD:protocol})',
'ACL_LINE3': '((object-group|object)\s%{USERNAME:src_object_group}|interface\s%{USERNAME:interface}|host\s%{IP:src_ip}|%{ANY:src_host}|%{IP:src_ip}\s%{IP:src_mask})',
'ACL_LINE4': '((object-group|object)\s%{USERNAME:dst_service}|%{WORD:operator}\s%{RANGE:rangestart}(\s%{RANGE:rangeend})?)',
'ACL_LINE5': '((object-group|object)\s%{USERNAME:dst_object_group}|interface\s%{USERNAME:interface}|host\s%{IP:dst_ip}|%{ANY:dst_host}|%{IP:dst_ip}\s%{IP:dst_mask})',
'ACL_LINE6': '((object-group|object)\s%{USERNAME:dst_service}|%{WORD:operator}\s%{RANGE:rangestart}(\s%{RANGE:rangeend})?|%{USERNAME:icmptype})',
'ACL_LINE7': '(log\s((%{INT:loglevel})?(\sinterval\s%{NUMBER:loginterval})?|%{LOGSTATUS:logstatus}))',
'ACL_LINE8': 'inactive|\stime-range\s%{USERNAME:timerange}',
'ACL_LINE9': '\(hitcnt=%{NUMBER:hitcnt}\)\s%{USERNAME:hashcode}((\s|\r|\n)*)?'
}

pattern = '(%{ACL_LINE1:line1}\s%{ACL_LINE2:line2}\s%{ACL_LINE3:line3}(\s%{ACL_LINE4:line4})?\s%{ACL_LINE5:line5}(\s%{ACL_LINE6:line6})?(\s%{ACL_LINE7:line7})?(\s%{ACL_LINE8:line8})?\s%{ACL_LINE9:line9}|%{ACL_LINE1:line1}\s%{ACL_LINE2:line2}\s%{ACL_LINE3:line3}(\s%{ACL_LINE4:line4})?(\s%{ACL_LINE6:line6})?(\s%{ACL_LINE7:line7})?(\s%{ACL_LINE8:line8})?\s%{ACL_LINE9:line9})'

infile="infile.txt"

def main():
  grok = Grok(pattern, custom_patterns=acl_patterns)
  infilept = open(infile, "r")
  gpf=0

  """Parse all lines of input file with grok"""
  for line in infilept:
    if "line" in line and "remark" not in line:
      grok_line = grok.match(line)
      if grok_line is None:
        print("Grok parse failure:\n"+line)
        gpf+=1
        continue
  print("Finished parsing file, number of grok parse failures: "+str(gpf))

if __name__ == "__main__":
    main()

infile.txt:

access-list vlan123-in line 335 extended permit tcp 1.2.3.4 255.255.0.0 1.2.1.1 255.255.255.128 range 2217 2223 log disable (hitcnt=1583) 0x60a9c03b
access-list vlan123-in line 403 extended permit ip any4 1.5.6.0 255.255.255.0 (hitcnt=185048) 0xdc331198
access-list vlan123-in line 404 extended permit tcp any4 object-group foo eq 5723 log disable (hitcnt=0) 0x86f049d0
access-list vlan123-in line 404 extended permit tcp any4 host 1.2.1.6 eq 5723 log disable (hitcnt=0) 0xadc8cd80
access-list vlan123-in line 405 extended permit tcp any4 host 1.2.1.7 eq www (hitcnt=0) 0x14fd6d81
access-list vlan123-in line 517 extended permit icmp any4 any4 (hitcnt=85402033) 0x0674f896
access-list vlan123-in line 726 extended permit tcp any4 object-group foo eq 2003 (hitcnt=4616243) 0x75d35eaf
access-list vlan123-in line 932 extended permit tcp 1.2.1.0 255.255.128.0 host 1.5.6.4 eq netbios-ssn log default (hitcnt=0) 0x8337e616
access-list vlan123-in line 1008 extended deny ip any4 object foobar (hitcnt=134) 0x985e0953
access-list vlan123-in line 1008 extended deny ip any4 host 1.5.6.2 (hitcnt=134) 0x985e0953
access-list vlan123-in line 1162 extended permit ip any4 object-group foo log disable (hitcnt=17503) 0x06dabb44
access-list vlan22-in line 6 extended deny tcp any4 object bar eq 4786 (hitcnt=0) 0x22500030
access-list vlan22-in line 6 extended deny tcp any4 1.2.2.0 255.255.254.0 eq 4786 (hitcnt=0) 0x22500030
access-list vlan22-in line 35 extended deny tcp any4 host 1.2.1.6 eq https (hitcnt=0) 0x24ad7386
access-list vlan22-in line 36 extended deny tcp any4 host 1.2.1.6 eq https (hitcnt=530) 0x0f90e0f2
access-list vlan22-in line 330 extended permit tcp any4 host 1.2.6.2 eq www (hitcnt=0) 0xe5729237
access-list vlan22-in line 331 extended permit tcp any4 host 1.2.6.1 eq https (hitcnt=0) 0x6d7e0e31
access-list vlan22-in line 385 extended permit ip any4 1.4.5.0 255.255.254.0 (hitcnt=235) 0x37911bb7
access-list foo-in line 16 extended permit tcp host 1.2.1.8 1.5.8.0 255.255.128.0 range 48000 48010 log disable (hitcnt=0) 0x8be36362
access-list foo-in line 42 extended deny ip any4 object-group foo (hitcnt=434091) 0x72e5d595
access-list foo-in line 42 extended deny ip any4 9.2.4.0 255.255.254.0 (hitcnt=0) 0x94e6be14
access-list foo-in line 193 extended permit ip any4 object-group bar (hitcnt=11383) 0x0a04d092
access-list foo-in line 393 extended permit object icmp-echo any4 any4 (hitcnt=205452616) 0x8536e84b
access-list foo-in line 393 extended permit icmp any4 any4 echo (hitcnt=205452616) 0x8536e84b
access-list foo-in line 395 extended permit object icmp-time-exceeded any4 any4 (hitcnt=577) 0xd8718f72
access-list vlan66-in line 34 extended permit icmp any4 any4 (hitcnt=192) 0xc66ea5c5 
goldstar611 commented 4 years ago

Were you ever able to figure out your issue? I have a PyQt gui to help debug grok patterns that may help if you're still stuck on this.

daniel-afo commented 4 years ago

Were you ever able to figure out your issue? I have a PyQt gui to help debug grok patterns that may help if you're still stuck on this.

no, it is still not working.

But you can check that our grok patterns are valid with the provided log lines (infile.txt) and our patterns (acl_patterns). We tested it as well with the https://grokconstructor.appspot.com/