def register_sensitivity(bpcls, pkttype): "Register that class 'cls' wants to see packet of type 'pkttype'" if pkttype not in BestPractices.wantedpackets: BestPractices.wantedpackets.append(pkttype) Drone.add_json_processor(BestPractices) if pkttype not in BestPractices.evaluators: BestPractices.evaluators[pkttype] = [] if bpcls not in BestPractices.evaluators[pkttype]: BestPractices.evaluators[pkttype].append(bpcls)
def register_sensitivity(bpcls, pkttype): "Register that class 'bpcls' wants to see packet of type 'pkttype'" #print >> sys.stderr, '%s is looking for packet of type %s' % (bpcls, pkttype) if pkttype not in BestPractices.wantedpackets: BestPractices.wantedpackets.append(pkttype) Drone.add_json_processor(BestPractices) if pkttype not in BestPractices.eval_classes: BestPractices.eval_classes[pkttype] = [] if bpcls not in BestPractices.eval_classes[pkttype]: BestPractices.eval_classes[pkttype].append(bpcls)
def decorator(cls): '''Register our class with the packet types given to 'register' above. Return value: Class that we registered. ''' for pkttype in pkttypes: if pkttype not in BestPractices.wantedpackets: BestPractices.wantedpackets.append(pkttype) Drone.add_json_processor(BestPractices) if pkttype not in BestPractices.evaluators: BestPractices.evaluators[pkttype] = [] if cls not in BestPractices.evaluators[pkttype]: BestPractices.evaluators[pkttype].append(cls) return cls
def log_rule_results(self, results, drone, _srcaddr, discoveryobj, discovertype, rulesobj): '''Log the results of this set of rule evaluations''' status_name = Drone.bp_discoverytype_result_attrname(discovertype) if hasattr(drone, status_name): oldstats = pyConfigContext(getattr(drone, status_name)) else: oldstats = {'pass': [], 'fail': [], 'ignore': [], 'NA': [], 'score': 0.0} for stat in ('pass', 'fail', 'ignore', 'NA'): logmethod = self.log.info if stat == 'pass' else self.log.warning for ruleid in results[stat]: oldstat = None for statold in ('pass', 'fail', 'ignore', 'NA'): if ruleid in oldstats[statold]: oldstat = statold break if oldstat == stat or stat == 'NA': # No change continue BestPractices.send_rule_event(oldstat, stat, drone, ruleid, rulesobj) thisrule = rulesobj[ruleid] rulecategory = thisrule['category'] logmethod('%s %sED %s rule %s: %s [%s]' % (drone, stat.upper(), rulecategory, ruleid, self.url(drone, ruleid, rulesobj[ruleid]), thisrule['rule'])) self.compute_score_updates(discoveryobj, drone, rulesobj, results, oldstats) setattr(drone, status_name, str(results))
def auditadrone(self, droneid): designation = dronedesignation(droneid) droneip = droneipaddress(droneid) droneipstr = str(droneip) # Did the drone get put in the Drone table? drone = Drone.find(designation) self.assertTrue(drone is not None) # Did the drone's list of addresses get updated? ipnodes = drone.get_owned_ips() ipnodes = [ip for ip in ipnodes] self.assertEqual(len(ipnodes), 1) ipnode = ipnodes[0] ipnodeaddr = pyNetAddr(ipnode.ipaddr) json = drone.JSON_netconfig jsobj = pyConfigContext(init=json) jsdata = jsobj['data'] eth0obj = jsdata['eth0'] eth0addrcidr = eth0obj['ipaddrs'].keys()[0] eth0addrstr, cidrmask = eth0addrcidr.split('/') eth0addr = pyNetAddr(eth0addrstr) self.assertTrue(eth0addr == ipnodeaddr) # Do we know that eth0 is the default gateway? self.assertEqual(eth0obj['default_gw'], True) # the JSON should have exactly 5 top-level keys self.assertEqual(len(jsobj.keys()), 5) # Was the JSON host name saved away correctly? self.assertEqual(jsobj['host'], designation)
def auditadrone(self, droneid): designation = dronedesignation(droneid) droneip = droneipaddress(droneid) droneipstr = str(droneip) # Did the drone get put in the Drone table? drone=Drone.find(designation) self.assertTrue(drone is not None) # Did the drone's list of addresses get updated? ipnodes = drone.get_owned_ips() ipnodes = [ip for ip in ipnodes] self.assertEqual(len(ipnodes), 1) ipnode = ipnodes[0] ipnodeaddr = pyNetAddr(ipnode.ipaddr) json = drone['netconfig'] jsobj = pyConfigContext(init=json) jsdata = jsobj['data'] eth0obj = jsdata['eth0'] eth0addrcidr = eth0obj['ipaddrs'].keys()[0] eth0addrstr, cidrmask = eth0addrcidr.split('/') eth0addr = pyNetAddr(eth0addrstr) self.assertTrue(eth0addr == ipnodeaddr) # Do we know that eth0 is the default gateway? self.assertEqual(eth0obj['default_gw'], True) # the JSON should have exactly 6 top-level keys self.assertEqual(len(jsobj.keys()), 6) # Was the JSON host name saved away correctly? self.assertEqual(jsobj['host'], designation) assert drone.get_active_nic_count() == 1
def maintest(): 'test main program' from cmainit import CMAinit from droneinfo import Drone from systemnode import SystemNode print >> sys.stderr, 'Starting' CMAinit(None, cleanoutdb=True, debug=True) if CMAdb.store.transaction_pending: print 'Transaction pending in:', CMAdb.store print 'Results:', CMAdb.store.commit() print ProcessNode.__meta_labels__() print SystemNode.__meta_labels__() print Drone.__meta_labels__() print 'keys:', Drone.__meta_keyattrs__() print >> sys.stderr, 'Init done' return 0
def compute_score_updates(discovery_json, drone, rulesobj, newstats, oldstats): '''We compute the score updates for the rules and results we've been given. The drone is a Drone (or host), the 'rulesobj' contains the rules and their categories. Statuses contains the results of evaluating the rules. Our job is to compute the scores for each of the categories of rules in the statuses, issue events for score changes, and update the category scores in the host. We're storing the successes, failures, etc, for this discovery object for this drone. Note that this can fail if we change our algorithm - because we don't know the values the old algorithm gave us, only what the current algorithm gives us on the old results. @TODO: We eventually want to update the scores for the domain to which this drone belongs. ''' _, oldcatscores, _ = BestPractices.compute_scores(drone, rulesobj, oldstats) _, newcatscores, _ = BestPractices.compute_scores(drone, rulesobj, newstats) keys = set(newcatscores) keys |= set(oldcatscores) # I have no idea why "keys = set(newcatscores) | set(oldcatscores)" did not work... # It worked fine in an interactive python session... diffs = {} for category in keys: newscore = newcatscores.get(category, 0.0) oldscore = oldcatscores.get(category, 0.0) catattr = Drone.bp_category_score_attrname(category) # I just compare two floating point numbers without a lot of formality. # This should be OK because they're both computed by the same algorithm # And at this level algorithms mostly produce integers # This is not a numerical analysis problem ;-) if newscore != oldscore: diff = newscore - oldscore if category in diffs: diffs[category] += diff else: diffs[category] = diff eventtype = AssimEvent.OBJWARN if newscore > oldscore else AssimEvent.OBJUNWARN extrainfo = {'category': category, 'oldscore': str(oldscore), 'newscore': str(newscore), 'discovery_type': discovery_json['discovertype'], 'discovery_description': discovery_json['description'] } # POTENTIALCONCURRENCY # As long as no one else is updating this attribute for this drone # we shouldn't have concurrency problems. oldval = getattr(drone, catattr) if hasattr(drone, catattr) else 0.0 setattr(drone, catattr, oldval + diff) print >> sys.stderr, 'Setting %s.%s to %d' % (drone, catattr, oldval+diff) AssimEvent(drone, eventtype, extrainfo=extrainfo) return newcatscores, diffs
def grab_category_scores(store, categories=None, debug=False): '''Program to create and return some python Dicts with security scores and totals by category and totals by drone/category Categories is None or a list of desired categories. ''' cypher = '''START drone=node:Drone('*:*') RETURN drone''' BestPractices(CMAdb.io.config, CMAdb.io, store, CMAdb.log, debug=debug) dtype_totals = {} # scores organized by (category, discovery-type) drone_totals = {} # scores organized by (category, discovery-type, drone) rule_totals = {} # scores organized by (category, discovery-type, rule) for drone in store.load_cypher_nodes(cypher, Drone): designation = drone.designation discoverytypes = drone.bp_discoverytypes_list() for dtype in discoverytypes: dattr = Drone.bp_discoverytype_result_attrname(dtype) statuses = getattr(drone, dattr) for rule_obj in BestPractices.eval_objects[dtype]: rulesobj = rule_obj.fetch_rules(drone, None, dtype) _, scores, rulescores = BestPractices.compute_scores(drone, rulesobj, statuses) for category in scores: if category not in categories and categories: continue # Accumulate scores by (category, discovery_type) setup_dict2(dtype_totals, category, dtype) dtype_totals[category][dtype] += scores[category] # Accumulate scores by (category, discovery_type, drone) setup_dict3(drone_totals, category, dtype, designation) drone_totals[category][dtype][designation] += scores[category] # Accumulate scores by (category, discovery_type, ruleid) for ruleid in rulescores[category]: setup_dict3(rule_totals, category, dtype, ruleid) rule_totals[category][dtype][ruleid] += rulescores[category][ruleid] return dtype_totals, drone_totals, rule_totals
'Iterate over self.keys() - giving the names of all our *top level* attributes.' for key in self.keys(): yield key def __contains__(self, key): return key in self.map() def __len__(self): return len(self.map()) @staticmethod def __meta_keyattrs__(): 'Return our key attributes in order of significance' return ['jhash'] if __name__ == '__main__': from cmainit import CMAinit print >> sys.stderr, 'Starting' CMAinit(None, cleanoutdb=True, debug=True) if CMAdb.store.transaction_pending: print 'Transaction pending in:', CMAdb.store print 'Results:', CMAdb.store.commit() print CMAclass.__meta_labels__() print ProcessNode.__meta_labels__() print SystemNode.__meta_labels__() from droneinfo import Drone print Drone.__meta_labels__() print 'keys:', Drone.__meta_keyattrs__() print >> sys.stderr, 'Init done'
'Delete a role from our GraphNode' if isinstance(roles, tuple) or isinstance(roles, list): for role in roles: self.delrole(role) return self.roles assert isinstance(roles, str) or isinstance(roles, unicode) if roles in self.roles: self.roles.remove(roles) return self.roles @staticmethod def __meta_keyattrs__(): 'Return our key attributes in order of significance' return ['processname', 'domain'] if __name__ == '__main__': from cmainit import CMAinit from cmadb import CMAdb print >> sys.stderr, 'Starting' CMAinit(None, cleanoutdb=True, debug=True) if CMAdb.store.transaction_pending: print 'Transaction pending in:', CMAdb.store print 'Results:', CMAdb.store.commit() print CMAclass.__meta_labels__() print ProcessNode.__meta_labels__() print SystemNode.__meta_labels__() from droneinfo import Drone print Drone.__meta_labels__() print 'keys:', Drone.__meta_keyattrs__() print >> sys.stderr, 'Init done'
yield key def __contains__(self, key): return key in self.map() def __len__(self): return len(self.map()) @staticmethod def __meta_keyattrs__(): "Return our key attributes in order of significance" return ["jhash"] if __name__ == "__main__": from cmainit import CMAinit print >> sys.stderr, "Starting" CMAinit(None, cleanoutdb=True, debug=True) if CMAdb.store.transaction_pending: print "Transaction pending in:", CMAdb.store print "Results:", CMAdb.store.commit() print CMAclass.__meta_labels__() print ProcessNode.__meta_labels__() print SystemNode.__meta_labels__() from droneinfo import Drone print Drone.__meta_labels__() print "keys:", Drone.__meta_keyattrs__() print >> sys.stderr, "Init done"