Skip to content

Instantly share code, notes, and snippets.

@mpgn
Created November 26, 2019 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpgn/0e73d59ade8e9ea7433f0029414422fc to your computer and use it in GitHub Desktop.
Save mpgn/0e73d59ade8e9ea7433f0029414422fc to your computer and use it in GitHub Desktop.
CrackMapExec module to set as "owned" on BloodHound every target owned by the attacker

Installation

  • Copy bloodhound_owned.py in cme/modules and reinstall CrackMapExec python setup.py install
  • pip install neo4j

Usage

cme smb 10.10.0.0/24 -d adsec.local -u jsnow -p Winter_is_coming_\! -M bloodhound_owned

You can check available options using

cme smb 10.10.0.0/24 -d adsec.local -u jsnow -p Winter_is_coming_\! -M bloodhound_owned --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')

Options can be set using

cme smb dc01.adsec.local -d adsec.local -u jsnow -p Winter_is_coming_\! -M bloodhound_owned -o NEO4JURI='127.0.0.1' NEO4JPORT='7687' NEO4JUSER='neo4j' NEO4JPASS='bloodhound'

Have fun

# 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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment