NetExec/nxc/modules/bh_owned.py

88 lines
3.5 KiB
Python
Raw Normal View History

# Author:
# Romain Bentz (pixis - @hackanddo)
# Website:
# https://beta.hackndo.com [FR]
# https://en.hackndo.com [EN]
import sys
2023-05-07 04:17:21 +00:00
from neo4j import GraphDatabase
from neo4j.exceptions import AuthError, ServiceUnavailable
class NXCModule:
2023-05-02 15:17:59 +00:00
name = "bh_owned"
description = "Set pwned computer as owned in Bloodhound"
2023-05-02 15:17:59 +00:00
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
2023-03-31 17:49:25 +00:00
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
self.neo4j_pass = None
self.neo4j_user = None
self.neo4j_Port = None
self.neo4j_URI = None
def options(self, context, module_options):
"""
2023-05-02 15:17:59 +00:00
URI URI for Neo4j database (default: 127.0.0.1)
PORT Listening port for Neo4j database (default: 7687)
USER Username for Neo4j database (default: 'neo4j')
PASS Password for Neo4j database (default: 'neo4j')
"""
self.neo4j_URI = "127.0.0.1"
self.neo4j_Port = "7687"
self.neo4j_user = "neo4j"
self.neo4j_pass = "neo4j"
2023-05-02 15:17:59 +00:00
if module_options and "URI" in module_options:
self.neo4j_URI = module_options["URI"]
if module_options and "PORT" in module_options:
self.neo4j_Port = module_options["PORT"]
if module_options and "USER" in module_options:
self.neo4j_user = module_options["USER"]
if module_options and "PASS" in module_options:
self.neo4j_pass = module_options["PASS"]
def on_admin_login(self, context, connection):
domain = connection.conn.getServerDNSDomainName() if context.local_auth else connection.domain
2023-05-07 04:17:21 +00:00
host_fqdn = f"{connection.hostname}.{domain}".upper()
2023-05-07 03:56:33 +00:00
uri = f"bolt://{self.neo4j_URI}:{self.neo4j_Port}"
2023-05-07 04:17:21 +00:00
context.log.debug(f"Neo4j URI: {uri}")
context.log.debug(f"User: {self.neo4j_user}, Password: {self.neo4j_pass}")
try:
2023-05-08 18:39:36 +00:00
driver = GraphDatabase.driver(uri, auth=(self.neo4j_user, self.neo4j_pass), encrypted=False)
2023-05-07 04:17:21 +00:00
except AuthError:
context.log.fail(f"Provided Neo4J credentials ({self.neo4j_user}:{self.neo4j_pass}) are not valid. See --options")
sys.exit()
2023-05-07 04:17:21 +00:00
except ServiceUnavailable:
2023-05-08 18:39:36 +00:00
context.log.fail(f"Neo4J does not seem to be available on {uri}. See --options")
sys.exit()
except Exception as e:
context.log.fail("Unexpected error with Neo4J")
2023-05-07 03:56:33 +00:00
context.log.debug(f"Error {e}: ")
sys.exit()
with driver.session() as session:
try:
with session.begin_transaction() as tx:
result = tx.run(f"MATCH (c:Computer {{name:{host_fqdn}}}) SET c.owned=True RETURN c.name AS name")
record = result.single()
try:
value = record.value()
except AttributeError:
value = []
except ServiceUnavailable as e:
context.log.fail(f"Neo4J does not seem to be available on {uri}. See --options")
context.log.debug(f"Error {e}: ")
driver.close()
sys.exit()
if len(value) > 0:
2023-05-08 18:39:36 +00:00
context.log.success(f"Node {host_fqdn} successfully set as owned in BloodHound")
else:
context.log.fail(f"Node {host_fqdn} does not appear to be in Neo4J database. Have you imported the correct data?")
driver.close()