Skip to content

Commit

Permalink
Make ruleset config more robust
Browse files Browse the repository at this point in the history
Make rule functions check and possibly warn if their config doesn't
exist. Alternatively they can choose to fall back on defaults.

Make PeekabooRulesetConfiguration actually provide some helpful
abstraction of the ruleset configuration.
  • Loading branch information
michaelweiser committed Sep 6, 2018
1 parent 4a5cb94 commit 673fd06
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 22 deletions.
18 changes: 14 additions & 4 deletions peekaboo/config.py
Expand Up @@ -172,8 +172,6 @@ class PeekabooRulesetConfiguration(object):
def __init__(self, config_file):
self.config_file = config_file
self.ruleset_config = {}

def parse(self):
config = SafeConfigParser()
try:
config.read(self.config_file)
Expand All @@ -193,8 +191,20 @@ def parse(self):
except NoOptionError as e:
logger.exception(e)

def get_config(self):
return self.ruleset_config
def rule_config(self, rule):
# potentially do some validity checks here

# arbitrary interface definition: return an empty hash if no rule
# config exists as empty rule config so the rule func can rely on it
# and does not need to do any type checking
return self.ruleset_config.get(rule, {})

# rule is enabled as long as:
# - no config section for that rule is present
# - enabled keyword is not present in that section or
# - enabled is not equal to 'no'
def rule_enabled(self, rule):
return (self.rule_config(rule).get('enabled', 'yes') != 'no')

def __str__(self):
return '<PeekabooRulesetConfiguration(filepath="%s")>' % self.config_file
Expand Down
3 changes: 0 additions & 3 deletions peekaboo/daemon.py
Expand Up @@ -283,9 +283,6 @@ def run():
# workers of the job queue need the ruleset configuration to create the
# ruleset engine with it
ruleset_config = PeekabooRulesetConfiguration(config.ruleset_config)
ruleset_config.parse()
ruleset_config = ruleset_config.get_config()

job_queue = JobQueue(worker_count = config.worker_count,
ruleset_config = ruleset_config)
connection_map = ConnectionMap()
Expand Down
11 changes: 6 additions & 5 deletions peekaboo/ruleset/engine.py
Expand Up @@ -86,15 +86,16 @@ def __exec_rule(self, config, sample, rule_function):

try:
# skip disabled rules.
if rule_name in config.keys() and \
'enabled' in config[rule_name].keys() and \
config[rule_name]['enabled'] == 'no':
if config.rule_enabled(rule_name):
# guaranteed to be a hash, albeit empty if no rule config
# exists
rule_config = config.rule_config(rule_name)
result = rule_function(rule_config, sample)
else:
logger.debug("Rule '%s' is disabled." % rule_name)
result = RuleResult(rule_name, result=Result.unchecked,
reason="Regel '%s' ist deaktiviert." % rule_name,
further_analysis=True)
else:
result = rule_function(config, sample)
sample.add_rule_result(result)
except CuckooReportPendingException as e:
# in case the Sample is requesting the Cuckoo report
Expand Down
22 changes: 16 additions & 6 deletions peekaboo/ruleset/rules.py
Expand Up @@ -56,7 +56,8 @@ def file_larger_than(config, s):
tb = tb[-1]
position = "%s:%s" % (tb[2], tb[1])

size = int(config['file_larger_than']['bytes'])
size = int(config.get('bytes', 5))

if s.file_size > size:
return RuleResult(position,
result=Result.unknown,
Expand All @@ -76,7 +77,9 @@ def file_type_on_whitelist(config, s):
tb = tb[-1]
position = "%s:%s" % (tb[2], tb[1])

whitelist = config['file_type_on_whitelist']['whitelist']
whitelist = config.get('whitelist', ())
if len(whitelist) == 0:
logger.warn("Empty whitelist, check ruleset config.")

if set(s.mimetypes).issubset(set(whitelist)):
return RuleResult(position,
Expand All @@ -95,7 +98,9 @@ def file_type_on_greylist(config, s):
tb = tb[-1]
position = "%s:%s" % (tb[2], tb[1])

greylist = config['file_type_on_greylist']['greylist']
greylist = config.get('greylist', ())
if len(greylist) == 0:
logger.warn("Empty greylist, check ruleset config.")

if set(s.mimetypes).issubset(set(greylist)):
return RuleResult(position,
Expand All @@ -118,7 +123,9 @@ def cuckoo_evil_sig(config, s):
# signatures that if matched mark a sample as bad
# list all installed signatures
# grep -o "description.*" -R . ~/cuckoo2.0/modules/signatures/
bad_sigs = config['cuckoo_evil_sig']['signature']
bad_sigs = config.get('signature', ())
if len(bad_sigs) == 0:
logger.warn("Empty bad signature list, check ruleset config.")

sigs = []

Expand Down Expand Up @@ -152,7 +159,8 @@ def cuckoo_score(config, s):
tb = tb[-1]
position = "%s:%s" % (tb[2], tb[1])

threshold = float(config['cuckoo_score']['higher_than'])
threshold = float(config.get('higher_than', 4.0))

if s.cuckoo_report.score >= threshold:
return RuleResult(position,
result=Result.bad,
Expand Down Expand Up @@ -189,7 +197,9 @@ def requests_evil_domain(config, s):
tb = tb[-1]
position = "%s:%s" % (tb[2], tb[1])

evil_domains = config['requests_evil_domain']['domain']
evil_domains = config.get('domain', ())
if len(evil_domains) == 0:
logger.warn("Empty evil domain list, check ruleset config.")

for d in s.requested_domains:
if d in evil_domains:
Expand Down
10 changes: 6 additions & 4 deletions ruleset.conf.sample
Expand Up @@ -11,8 +11,9 @@
# if not specified the default is enabled : yes
enabled : yes

[file_larger_than]
bytes : 5
#[file_larger_than]
# defaults:
#bytes : 5

[file_type_on_whitelist]
whitelist.1 : text/plain
Expand Down Expand Up @@ -107,8 +108,9 @@ signature.41 : Tries to detect analysis programs from within the browser
signature.42 : Tries to locate whether any sniffers are installed
signature.43 : Wscript.exe initiated network communications indicative of a script based payload download

[cuckoo_score]
higher_than : 4.0
#[cuckoo_score]
# defaults:
#higher_than : 4.0

[requests_evil_domain]
enabled : no
Expand Down

0 comments on commit 673fd06

Please sign in to comment.