|
# bloodhound_owned module for CME python2 |
|
# author: Pixis (https://twitter.com/HackAndDo) |
|
# v0.1 |
|
|
|
import sys |
|
from neo4j.v1 import GraphDatabase |
|
from neo4j.exceptions import AuthError, ServiceUnavailable |
|
|
|
class CMEModule: |
|
name = 'bloodhound_owned' |
|
description = "Set owned attribute in BloodHound for compromised targets" |
|
supported_protocols = ['smb'] |
|
opsec_safe = True |
|
multiple_hosts = True |
|
|
|
def options(self, context, module_options): |
|
''' |
|
NEO4JURI URI for Neo4j database (defaults to 127.0.0.1) |
|
NEO4JPORT Listeninfg port for Neo4j database (defaults to 7687) |
|
NEO4JUSER Username for Neo4j database (defaults to 'neo4j') |
|
NEO4JPASS Password for Neo4j database (defaults to 'neo4j') |
|
''' |
|
|
|
self.neo4j_URI = "127.0.0.1" |
|
self.neo4j_Port = "7687" |
|
self.neo4j_user = "neo4j" |
|
self.neo4j_pass = "neo4j" |
|
|
|
if module_options and 'NEO4JURI' in module_options: |
|
self.neo4j_URI = module_options['NEO4JURI'] |
|
if module_options and 'NEO4JPORT' in module_options: |
|
self.neo4j_Port = module_options['NEO4JPORT'] |
|
if module_options and 'NEO4JUSER' in module_options: |
|
self.neo4j_user = module_options['NEO4JUSER'] |
|
if module_options and 'NEO4JPASS' in module_options: |
|
self.neo4j_pass = module_options['NEO4JPASS'] |
|
|
|
def on_admin_login(self, context, connection): |
|
hostFQDN = (connection.hostname + "." + connection.domain).upper() |
|
uri = "bolt://{}:{}".format(self.neo4j_URI, self.neo4j_Port) |
|
|
|
try: |
|
driver = GraphDatabase.driver(uri, auth=(self.neo4j_user, self.neo4j_pass)) |
|
except AuthError as e: |
|
context.log.error("Provided credentials ({}:{}) are not valid. See --options".format(self.neo4j_user, self.neo4j_pass)) |
|
sys.exit() |
|
except ServiceUnavailable as e: |
|
context.log.error("Neo4J does not seem to be available on {}. See --options".format(uri)) |
|
sys.exit() |
|
except Exception as e: |
|
context.log.error("Unexpected error : {}".format(e)) |
|
sys.exit() |
|
|
|
with driver.session() as session: |
|
with session.begin_transaction() as tx: |
|
result = tx.run("MATCH (c:Computer {{name:\"{}\"}}) SET c.owned=True RETURN c.name AS name".format(hostFQDN)) |
|
if (len(result.value()) > 0): |
|
context.log.success("Node {} successfully set as owned in BloodHound".format(hostFQDN)) |
|
else: |
|
context.log.error("Node {} does not appear to be in Neo4J database. Have you imported correct data ?".format(hostFQDN)) |
|
driver.close() |