Skip to content

Instantly share code, notes, and snippets.

@airween
Last active June 2, 2019 16:28
Show Gist options
  • Save airween/f56d2f1348bc95693d1209211919f07c to your computer and use it in GitHub Desktop.
Save airween/f56d2f1348bc95693d1209211919f07c to your computer and use it in GitHub Desktop.
CRS regex checker
#!/usr/bin/python3
import glob
import sys
import os
import secrules_parsing.secrules_parser as secrules_parser
import sre_parse
import sre_constants
import re
class colorize(object):
WARNING = "\033[93m"
FAIL = "\033[91m"
ENDC = "\033[0m"
class ReCheck(object):
def __init__(self):
self.reset()
def reset(self):
self.repeat_vector = []
self.vulnerable = False
# item: a Python sre_parse generated AST, which is a recursive
# embedded list/tuple sequence
# depth: marks how depth are we in the tree
# prev_repeat: marks that the previous level contains any relevant repetation
def walkpattern(self, item, depth = 0, prev_repeat = False):
has_repeat = False
repeat_over10 = False
self.repeat_vector.append(0)
for i in item:
# if the current item is a list, tuple or a SubPattern
# walk it recurse
if type(i) in [list, tuple, sre_parse.SubPattern]:
self.walkpattern(i, depth+1, has_repeat)
# else check the symbol
else:
# if it's a repeat symbol, then set the flag for the recurse call above
if item.index(i) == 0 and i in [sre_constants.MIN_REPEAT, sre_constants.MAX_REPEAT]:
has_repeat = True
# if the previous level contains a repeat symbol, and here the number of repeat is
# infinity (eg: *) or greather that 10 (eg. {n,10}), then set to 1 the current value
# in vector
if item.index(i) == 1 and prev_repeat and (i == sre_constants.MAXREPEAT or i >= 10):
self.repeat_vector[-1] = 1
# if the vector contains more than 1 repeat symbol, set the vulnerable variable to True
if sum(self.repeat_vector) >= 2:
self.vulnerable = True
del(self.repeat_vector[-1])
if len(sys.argv) < 2:
print("Argument missing")
sys.exit(-1)
confdir = sys.argv[1]
# Extract all of our pathing
files = glob.glob("%s/*.conf" % (confdir))
# Pass absolute paths because of module location
files = [os.path.abspath(path) for path in files]
models = secrules_parser.process_rules(files)
# create a regular expression checker instance
rc = ReCheck()
# walk through models
for m in models:
# walk through rules in model
for r in m.rules:
# get regular expressions from rules
exp = secrules_parser.get_rule_regex(r)
if exp is not None:
# exps is a dict, {rule_id1: regex1, rule_id2: regex2, ...}
ekeys = exp.keys()
for k in ekeys:
# k is a rule id
for e in exp[k]:
rc.reset()
# some regex isn't python re compatible
# try to parse it and build the AST
try:
_e = sre_parse.parse(e)
except re.error:
print(colorize.FAIL + "%s: Regex compile error" % (k) + colorize.ENDC)
continue
except:
# okay, what else happened?
print(colorize.FAIL + "Error occured till build AST: '%s'" % (e) + colorize.ENDC)
sys.exit(-1)
# walk the AST
rc.walkpattern(_e)
if rc.vulnerable == True:
#print(colorize.WARNING + "%s: may be vulnerable, need to check (%s)" % (k, e) + colorize.ENDC)
print(colorize.WARNING + "%s: may be vulnerable, need to check" % (k) + colorize.ENDC)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment