def allow(target, actuator, modifier): cybox_address_obs = Observable.from_json(json.dumps(target["specifiers"])) address = str(cybox_address_obs.object_.properties.address_value) result_message = {} if "specifiers" in actuator: # Handling for specific devices - lookup on name or id if "name" in actuator["specifiers"]: actuator = Actuator.objects.get(name=actuator["specifiers"]["name"]) result_message[actuator.name] = allow_address(address,actuator) elif "id" in actuator["specifiers"]: actuator = Actuator.objects.get(pk=actuator["specifiers"]["id"]) result_message[actuator.name] = allow_address(address,actuator) else: for actuator in Actuator.objects.filter(openc2_type="network-ips"): result_message[actuator.name] = allow_address(address,actuator) if "respond-to" in modifier: if "command-ref" in modifier: ref=modifier["command-ref"] else: ref=None respond_message(make_response_message(ref, "simple", {"address":address,"result":result_message}), modifier["respond-to"]) return True
def scan(target, actuator, modifier): cybox_address_obs = Observable.from_json(json.dumps(target["specifiers"])) address = str(cybox_address_obs.object_.properties.address_value) result = icmp_ping(address) if "respond-to" in modifier: if "command-ref" in modifier: ref = modifier["command-ref"] else: ref = None respond_message( make_response_message(ref, "simple", { "address": address, "ping": result }), modifier["respond-to"]) return True
def locate(target, actuator, modifier): cybox_address_obs = Observable.from_json(json.dumps(target["specifiers"])) address = str(cybox_address_obs.object_.properties.address_value) if is_public(address): country = geo_lookup(address) print country # Handle response if country and "respond-to" in modifier: if "command-ref" in modifier: ref = modifier["command-ref"] else: ref = None respond_message(make_response_message(ref, "simple", {"country":country}),modifier["respond-to"]) return True
def notify(target, actuator, modifier): cybox_address_obs = Observable.from_json(json.dumps(target["specifiers"])) send_from = str(cybox_address_obs.object_.properties.from_.address_value) # send_to only sends to the first email address send_to = str(cybox_address_obs.object_.properties.to[0]) subject = str(cybox_address_obs.object_.properties.subject) message = str(cybox_address_obs.object_.properties.raw_body) result = send_mail(send_from, send_to, subject, message) if "respond-to" in modifier: if "command-ref" in modifier: ref = modifier["command-ref"] else: ref = None respond_message( make_response_message(ref, "simple", { "subject": subject, "sent": result }), modifier["respond-to"]) return True
def dispatch(self,message,user): """ Name: dispatch Desc: Dispatch is called by the main /openc2/ api view. It actions which downstream host to send a received command to. It creates the job locally so it can be tracker and re-dresses the respond-to feilds so it can intercept command success/fail on downstream relays/actuators. """ logger.debug("Dispatcher called") capable_handlers = [] # Check action / target type if message["action"] == 'query' and message["target"]["type"] == 'openc2:openc2': return HttpResponse(self.capabilities(),status=200) # If the message is a down stream response if message["action"].lower() == "response": response.response(message["target"], message.get("actuator"), message.get("modifiers")) return HttpResponse(status=200) # This is an action destined for a downstream host message['action'] = message['action'].lower() # Work out which downstreams are capable of this action capable = False if "specifiers" in message["actuator"]: # If the end user is targetting a specific actuator if "id" in message["actuator"]["specifiers"]: capable = Capability.objects.filter(actuator=message["actuator"]["type"],action=message["action"],requires__identifier=message["target"]["type"],remote_id=message["actuator"]["specifiers"]["id"],active=True) elif "name" in message["actuator"]["specifiers"]: capable = Capability.objects.filter(actuator=message["actuator"]["type"],action=message["action"],requires__identifier=message["target"]["type"],remote_name=message["actuator"]["specifiers"]["name"],active=True) else: capable = Capability.objects.filter(actuator=message["actuator"]["type"],action=message["action"],requires__identifier=message["target"]["type"],active=True) if capable: # Someone is capable of dealing with this message # Odds of the target being in our database is low - so will make a new one anyway # TODO: Expand this to handle other types (Network Connection) # False / Object target = False # Address Handling if message["target"]["type"] == "cybox:AddressObjectType": cybox_address_obs = Observable.from_json(json.dumps(message["target"]["specifiers"])) address = str(cybox_address_obs.object_.properties.address_value) target = Target(name="Auto Target - %s" % address, cybox_type=CybOXType.objects.get(identifier=message["target"]["type"]), raw_message=json.dumps(message["target"]["specifiers"])) logger.info("Target %s Created" % address) target.save() elif message["target"]["type"] == "cybox:NetworkConnectionObjectType": # TODO: Handler pass # If we have been able to assign a valid target if target: for capability in capable: new_job = Job(capability=capability, target=target, raw_message="Pending", status=JobStatus.objects.get(status="Pending"), created_by = user) new_job.save() command = { "action": capability.action, "actuator": { "specifiers": { "id":capability.remote_id, "name":capability.remote_name, }, "type": capability.actuator }, "modifiers": { "respond-to": getattr(settings, "OPENC2_RESPONSE_URL", None) }, "target": { "specifiers": json.loads(target.raw_message), "type": capability.requires.identifier } } command["modifiers"]["command-ref"] = new_job.id logger.info("Job Created - Command - %s" % (json.dumps(command))) # Handle upstream respond to - send the copy back to us and pass it on to an upstream if "respond-to" in message["modifiers"]: new_job.upstream_respond_to = message["modifiers"]["respond-to"] new_job.upstream_command_ref = message["modifiers"]["command-ref"] new_job.raw_message = json.dumps(command,sort_keys=True,indent=4).replace("\t", u'\xa0\xa0\xa0\xa0\xa0') new_job.save() return HttpResponse(status=200) else: logger.error("Failed to identify target") return HttpResponse(status=501) else: return HttpResponse(status=501)