From d2f6c9db10f397fc79d5349cb11f08e923d32812 Mon Sep 17 00:00:00 2001 From: TheToddLuci0 Date: Thu, 7 Sep 2023 11:08:51 -0500 Subject: [PATCH 1/3] Packaging for PyPi Now we can `pipx install` this good boy --- .gitignore | 160 ++++++++++++++++++++++++++++++++++++++++ max-bh/__init__.py | 0 max.py => max-bh/max.py | 0 pyproject.toml | 21 ++++++ 4 files changed, 181 insertions(+) create mode 100644 .gitignore create mode 100644 max-bh/__init__.py rename max.py => max-bh/max.py (100%) create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6769e21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/max-bh/__init__.py b/max-bh/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/max.py b/max-bh/max.py similarity index 100% rename from max.py rename to max-bh/max.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..58dceab --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["setuptools", "setuptools_scm"] +build-backend = "setuptools.build_meta" + +[project] +name = "max-bh" +readme ="README.md" +description = "Maximizing Bloodhound" +requires-python = ">=3.7" +dependencies = [ + "requests" +] +dynamic = ['version'] + +[project.scripts] +max = "max.max:main" + +# [tool.setuptools.packages.find] +# include = ['max-bh'] + +[tool.setuptools_scm] \ No newline at end of file From a7ba4db64beb0b6785806c5b72a5917787674d28 Mon Sep 17 00:00:00 2001 From: TheToddLuci0 Date: Thu, 7 Sep 2023 12:56:16 -0500 Subject: [PATCH 2/3] Small tweaks so pypi will take it --- .github/workflows/publish-to-pypi.yml | 43 +++++++++++++++++++++++++++ pyproject.toml | 8 +++-- 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish-to-pypi.yml diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml new file mode 100644 index 0000000..fd1d1b9 --- /dev/null +++ b/.github/workflows/publish-to-pypi.yml @@ -0,0 +1,43 @@ +name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI + +on: + push: + branches: + - master + - main +jobs: + build-n-publish: + name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI + runs-on: ubuntu-latest + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: >- + python3 -m + build + --sdist + --wheel + --outdir dist/ + . + # - name: Publish distribution 📦 to Test PyPI + # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # # We don't _really_ care if there are dupes on pypi + # skip-existing: true + # repository-url: https://test.pypi.org/legacy/ + - name: Publish distribution 📦 to PyPI + # if: startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 58dceab..63665c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,9 @@ dynamic = ['version'] [project.scripts] max = "max.max:main" -# [tool.setuptools.packages.find] -# include = ['max-bh'] +[tool.setuptools.packages.find] +include = ['max-bh'] -[tool.setuptools_scm] \ No newline at end of file +[tool.setuptools_scm] +# This is so pypi will actually accept the package +local_scheme = "no-local-version" \ No newline at end of file From 919002f7518490558df4714090752db8044c6a30 Mon Sep 17 00:00:00 2001 From: TheToddLuci0 Date: Tue, 26 Sep 2023 20:28:55 -0500 Subject: [PATCH 3/3] Update README.md with packaging --- README.md | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 455b690..755531c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ A new potential attack primitive was added to this tool during my research, see ### Installation +Now available on PyPi! + +`pipx install max-bh` + +#### Manual Ideally there shouldn't be much to install, but I've included a requirements.txt file just in case. Tested on Kali Linux & Windows 10, all functionality should work for both linux and Windows operating systems. `pip3 install -r requirements.txt` @@ -37,16 +42,16 @@ Neo4j credentials can be hardcoded at the beginning of the script, they can be p ```bash export NEO4J_PASSWORD='bloodhound' # Notice whitespace before 'export' -python3 max.py {module} {args} +max {module} {args} ``` ``` -python3 max.py -u neo4j -p neo4j {module} {args} +max -u neo4j -p neo4j {module} {args} ``` ``` -python3 max.py {module} {args} +max {module} {args} Neo4j Username: neo4j Neo4j Password: ``` @@ -55,20 +60,20 @@ Neo4j Password: Getting help in general, and module specific ``` -python3 max.py -h -python3 max.py {module} -h +max -h +max {module} -h ``` Importing owned objects into BH ``` -python3 max.py mark-owned -f owned.txt -python3 max.py mark-owned -f owned.txt --add-note "Owned by repeated local admin" +max mark-owned -f owned.txt +max mark-owned -f owned.txt --add-note "Owned by repeated local admin" ``` Get list of users ``` -python3 max.py get-info --users -python3 max.py get-info --users --enabled +max get-info --users +max get-info --users --enabled USER01@DOMAIN.LOCAL USER02@DOMAIN.LOCAL @@ -77,43 +82,43 @@ USER02@DOMAIN.LOCAL Get list of objects in a target group ``` -python3 max.py get-info --group-members "domain controllers@domain.local" +max get-info --group-members "domain controllers@domain.local" ``` Get a list of computers that a user has administrative rights to ``` -python3 max.py get-info --adminto USER01@DOMAIN.LOCAL +max get-info --adminto USER01@DOMAIN.LOCAL ``` Get a list of owned objects with the notes for each ``` -python3 max.py get-info --owned --get-note +max get-info --owned --get-note ``` Running a query - return a list of all users with a path to DA ``` -python3 max.py query -q "MATCH (n:User),(m:Group {name:'DOMAIN ADMINS@DOMAIN.LOCAL'}) MATCH (n)-[*1..]->(m) RETURN DISTINCT(n.name)" +max query -q "MATCH (n:User),(m:Group {name:'DOMAIN ADMINS@DOMAIN.LOCAL'}) MATCH (n)-[*1..]->(m) RETURN DISTINCT(n.name)" ``` Delete an edge from the database ``` -python3 max.py del-edge CanRDP +max del-edge CanRDP ``` Add HasSPNConfigured relationship using the information stored within BloodHound, or with a GetUserSPNs impacket file ``` -python3 max.py add-spns -b -python3 max.py add-spns -i getuserspns-raw-output.txt +max add-spns -b +max add-spns -i getuserspns-raw-output.txt ``` DPAT ``` -python3 max.py dpat -n ~/client/ntds.dit -c ~/.hashcat/hashcat.potfile -o ouputdir --html --sanitize +max dpat -n ~/client/ntds.dit -c ~/.hashcat/hashcat.potfile -o ouputdir --html --sanitize ``` Pet max ``` -python3 max.py pet-max +max pet-max ``` #### Object Files & Specification