added markOwnedNodesInNeo4j.py

This commit is contained in:
mgeeky 2020-03-05 13:21:59 +01:00
parent 0daff1b3d8
commit edb128d4e0
2 changed files with 143 additions and 0 deletions

View File

@ -259,6 +259,24 @@ PS E:\PowerSploit\Recon> Get-DomainOU | Get-DomainOUTree
- **`malleable_redirector`** - A [proxy2](https://github.com/mgeeky/proxy2) plugin for resilient, evasive C2 infrastructures covering your redirectors from AV/EDR/Sandbox/IR lurking eyes based on the CobaltStrike's Malleable C2 Profile specified. Combines advantages of classic evasion techniques such as Apache2 Mod_Rewrite/`.htaccess` and deep c2-profile-drive HTTP/HTTPS request inspection
- **`markOwnedNodesInNeo4j.py`** - This script takes an input file containing Node names to be marked in Neo4j database as owned = True. The strategy for working with neo4j and Bloodhound becomes fruitful during complex Active Directory Security Review assessments or Red Teams. Imagine you've kerberoasted a number of accounts, access set of workstations or even cracked userPassword hashes. Using this script you can quickly instruct Neo4j to mark that principals as owned, which will enrich your future use of BloodHound.
```
$ ./markOwnedNodesInNeo4j.py kerberoasted.txt
[.] Connected to neo4j instance.
[.] Marking nodes (0..10) ...
[+] Marked 10 nodes in 4.617 seconds. Finish ETA: in 16.622 seconds.
[.] Marking nodes (10..20) ...
[+] Marked 10 nodes in 4.663 seconds. Finish ETA: in 12.064 seconds.
[.] Marking nodes (20..30) ...
[+] Marked 10 nodes in 4.157 seconds. Finish ETA: in 7.167 seconds.
[.] Marking nodes (30..40) ...
[+] Marked 10 nodes in 4.365 seconds. Finish ETA: in 2.670 seconds.
[.] Marking nodes (40..46) ...
[+] Marked 6 nodes in 2.324 seconds. Finish ETA: in 0 seconds.
[+] Nodes marked as owned successfully in 20.246 seconds.
```
- **`msbuild-powershell-msgbox.xml`** - Example of Powershell execution via MSBuild inline task XML file. On a simple Message-Box script.
([gist](https://gist.github.com/mgeeky/617c54a23f0c4e99e6f475e6af070810))

View File

@ -0,0 +1,125 @@
#!/usr/bin/python3
#
# This script takes an input file containing Node names to be marked in Neo4j database as
# owned = True. The strategy for working with neo4j and Bloodhound becomes fruitful during
# complex Active Directory Security Review assessments or Red Teams. Imagine you've kerberoasted
# a number of accounts, access set of workstations or even cracked userPassword hashes. Using this
# script you can quickly instruct Neo4j to mark that principals as owned, which will enrich your
# future use of BloodHound.
#
# Mariusz B. / mgeeky
#
import sys
import os
import time
try:
from neo4j import GraphDatabase
except ImportError:
print('[!] "neo4j >= 1.7.0" required. Install it with: python3 -m pip install neo4j')
#
# ===========================================
#
# Specify neo4j connection details
NEO4J_CONNECTION_DETAILS = \
{
'Host': '127.0.0.1', # neo4j listening address.
'Port': 7687, # Bolt port
'User': 'neo4j',
'Pass': 'neo4j1'
}
#
# ===========================================
#
#
# Construct a MATCH ... SET owned=TRUE query of not more than this number of nodes.
# This number impacts single query execution time. If it is more than 1000, neo4j may complain
# about running out of heap memory space (java...).
#
numberOfNodesToAddPerStep = 500
def markNodes(tx, nodes):
query = ''
for i in range(len(nodes)):
n = nodes[i]
query += 'MATCH (n {name: "' + n + '"}) SET n.owned = TRUE '
if i < len(nodes) - 1: query += 'UNION '
tx.run(query)
def main(argv):
if len(argv) != 2:
print('''
Takes a file containing node names on input and marks them as Owned in specified neo4j database.
Usage: ./markOwnedNodesInNeo4j.py <nodes-file>
''')
return False
nodesFile = argv[1]
programStart = time.time()
if not os.path.isfile(nodesFile):
print(f'[!] Input file containing nodes does not exist: "{nodesFile}"!')
return False
nodes = []
with open(nodesFile) as f: nodes = [x.strip() for x in f.readlines()]
try:
driver = GraphDatabase.driver(
f"bolt://{NEO4J_CONNECTION_DETAILS['Host']}:{NEO4J_CONNECTION_DETAILS['Port']}",
auth = (NEO4J_CONNECTION_DETAILS['User'], NEO4J_CONNECTION_DETAILS['Pass']),
encrypted = False,
connection_timeout = 10,
max_retry_time = 5,
keep_alive = True
)
except Exception as e:
print(f'[-] Could not connect to the neo4j database. Reason: {str(e)}')
return False
print('[.] Connected to neo4j instance.')
if len(nodes) >= 200:
print('[*] Warning: Working with a large number of nodes may be time-consuming in large databases.')
print('\te.g. setting 1000 nodes as owned can take up to 10 minutes easily.')
print()
finishEta = 0.0
totalTime = 0.0
runs = 0
try:
with driver.session() as session:
for a in range(0, len(nodes), numberOfNodesToAddPerStep):
b = a + min(numberOfNodesToAddPerStep, len(nodes) - a)
print(f'[.] Marking nodes ({a}..{b}) ...')
start = time.time()
session.write_transaction(markNodes, nodes[a:b])
stop = time.time()
totalTime += (stop - start)
runs += 1
finishEta = ((len(nodes) / numberOfNodesToAddPerStep) - runs) * (totalTime / float(runs))
if finishEta < 0: finishEta = 0
print(f'[+] Marked {b-a} nodes in {stop - start:.3f} seconds. Finish ETA: in {finishEta:.3f} seconds.')
except KeyboardInterrupt:
print('[.] User interruption.')
driver.close()
return False
driver.close()
programStop = time.time()
print(f'\n[+] Nodes marked as owned successfully in {programStop - programStart:.3f} seconds.')
if __name__ == '__main__':
main(sys.argv)