-
Notifications
You must be signed in to change notification settings - Fork 0
/
snort_rules_sampler.py
executable file
·161 lines (133 loc) · 4.53 KB
/
snort_rules_sampler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/python
#This release does not work on flowbits over default group.
#Authors: Sabin G., Radu L.
#Release: 0.75 / June 2017
import sys, getopt, os
import re
import random
from datetime import date
#sys.path.append("../")
#from utils import *
GREEN = "\033[0;32m"
YELLOW = "\033[0;93m"
RESET = "\033[0;0m"
rpath = "/etc/snort/rules/"
ofile = "sample.rules"
rdb = {}
rtotal = 0
rsamples = []
def getrulestates(rule):
#state = re.match('.*flowbits\s*:\s*(isset|isnotset|set|setx|unset|toggle|reset|noalert)\s*[,;]\s*'\
# '(all|any|bit[0-9]\s*[\|&])*([a-zA-Z0-9_\.]+\s*;)?.*', line)
flowbits = re.findall('flowbits\s*:\s*(isset|isnotset|set|setx|unset|toggle|reset|noalert)'\
'(\s*,\s*all|\s*,\s*any)?(\s*[,]?\s*bit[0-9]\s*[\|&])*(\s*,\s*[a-zA-Z0-9_\.]+)?\s*;', rule)
if flowbits:
return set([flowbits[i][3][1:] for i in xrange(len(flowbits))])
return set()
try:
opts, args = getopt.getopt(sys.argv[1:], "hf:n:o:")
except getopt.GetoptError:
print "Usage:", sys.argv[0], "{-h, -f <path to the rules files folder>/, -n <#rules>, -o <output>}\n"
sys.exit(1)
for opt, arg in opts:
if opt == "-h":
print "Usage:",sys.argv[0],"{-h, -f <path to the rules files folder>/, -n <#rules>, -o <output>}\n"
sys.exit(1)
elif opt == "-f":
rpath = arg
elif opt == "-n":
rtotal = int(arg)
elif opt == "-o":
ofile = arg
if rtotal == 0:
print "Nothing to do here. Please retry with -n arg.\n"
sys.exit(1)
#open given directory and preprocess ALL rules files
for root, dirs, files in os.walk(rpath):
for file in files:
if file.endswith(".rules"):
print "check out:", file, "file ..."
with open(rpath+"/"+file) as input:
cnt = 0
for line in input:
if not re.match('\s*[#]+.*\r?\n', line) and not re.match('\s*\r?\n', line):
cnt = cnt + 1
#print line
else:
print "\tempty or commented out line omitted."
print "\n\t", cnt, "active rules found."
rdb[rpath+"/"+file] = cnt
rsamples.append([])
#check out whether enough rules in database(folder)
if rtotal > sum(rdb.values()):
print "Couldn't sample", rtotal, "rules from database(only", sum(rdb.values()), "rules).\n"
sys.exit(1)
print "\nstart sampling from:", sum(rdb.values()), "rules..."
print "\trdb content is:", rdb, "\n"
with open(ofile, 'w') as output:
output.write("#This file is automatically generated by snort rules sampler application.\n")
output.write("#Date: "+str(date.today())+"\n\n")
total = 0
while total < rtotal:
#choose random file from dict
file = random.choice(rdb.keys())
#randomly choose a file iff there are still rules, left
if len(range(1,rdb[file]+1)) == len(rsamples[rdb.keys().index(file)]):
continue
#choose random rule from file, except the ones already selected
index = random.choice(list(set(range(1,rdb[file]+1)) -set(rsamples[rdb.keys().index(file)])) )
#rsamples[rdb.keys().index(file)].append(index)
sys.stdout.write(GREEN)
print "\tfrom file", file, ": selected the rule no. ", index, "out of", rdb[file],"rules"
sys.stdout.write(RESET)
#goto selected rule
with open(file) as input:
cnt = 0
states = set()
mlr = 0
rules = ""
while True:
for line in input:
if not re.match('\s*[#]+.*\r?\n', line) and not re.match('\s*\r?\n', line):
cnt = cnt + 1
else:
continue
if cnt not in rsamples[rdb.keys().index(file)]:
if cnt == index:
rules = rules + line
total = total + 1
rsamples[rdb.keys().index(file)].append(cnt)
if getrulestates(line):
states = states.union(getrulestates(line))
states.discard('')
print "multiple-lines rule found(states=", states, ").Looking for correlated rules ..."
mlr = 1
continue
mlr = 0
break
if getrulestates(line):
if getrulestates(line).intersection(states):
rules = rules + line
total = total + 1
rsamples[rdb.keys().index(file)].append(cnt)
states = states.union(getrulestates(line))
states.discard('')
mlr = 1
print "\t+correlated rule added(states=", states, " progress=%.1f" % round(100*float(cnt)/rdb[file], 2), "%)."
if mlr:
input.seek(0, 0)
cnt = 0
mlr = 0
sys.stdout.write(YELLOW)
print "rewind and check out for more rules w/ related flowbits."
sys.stdout.write(RESET)
else:
break
print rules
output.write(rules)
print "\trules sel'd from this file:", rsamples[rdb.keys().index(file)]
print "\ttotal rules sel'd:", total, "\n"
del states
print "sample size:", total
if __name__ == "__main__":
pass