diff --git a/.gitignore b/.gitignore index 595392e7..92203703 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ AD_Miner/sources/modules/temporary* *node_modules* /tests /test - +evolution_data/ # Byte-compiled / optimized / DLL files __pycache__/ @@ -170,6 +170,3 @@ cython_debug/ # 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/ - -# VS Code -.vscode/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..1217178f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11-slim + +# Set the working directory in the container +WORKDIR /tmp + +# Install necessary system dependencies for Git +RUN apt-get update && apt-get install -y git \ + && rm -rf /var/lib/apt/lists/* + +# Install AD-Miner from the Git repository +RUN pip install --no-cache-dir 'git+https://github.com/AD-Security/AD_Miner.git' diff --git a/README.md b/README.md index 53ab9935..537cfb89 100755 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ To run AD Miner, you first need a neo4j database which contains the Active Direc The easier way is to do the following command using `pipx`: ```shell -pipx install 'git+https://github.com/Mazars-Tech/AD_Miner.git' +pipx install 'git+https://github.com/AD-Security/AD_Miner.git' ``` ADMiner is also available on some Linux distributions: @@ -92,6 +92,26 @@ ADMiner is also available on some Linux distributions: - BlackArch: `pacman -S ad-miner` - NixOS: `nix-env -iA nixos.ad-miner` +A Docker image is available to build. Build the image with the following commmand: + +```sh +docker build -t ad-miner . +``` + +To run this on Windows with the BloodHound Community Edition data, use the commands below: + +```sh +docker run -v ${PWD}:/tmp ad-miner AD-miner -b bolt://host.docker.internal:7687 -u neo4j -p mypassword -cf YOUR_PREFIX +``` + +To run this on Linux with the BloodHound Community Edition data, use the commands below: + +```sh +docker run -v ${PWD}:/tmp --network host ad-miner AD-miner -b bolt://localhost:7687 -u neo4j -p mypassword -cf YOUR_PREFIX +``` + +Note that mounting the volume with `-v` is critical to get the output of the data. This assumes that the BHCE server is running on the Docker host with default settings. + ## Usage ## Run the tool: @@ -154,13 +174,15 @@ In the graph pages, you can right-click on the graph nodes to cluster them or to If you have multiple AD-Miner reports over time, you can easily track the evolution with the `--evolution` argument: each AD-Miner report generates a JSON data file alongside the `index.html` file. You just need to gather these different JSON files into a single folder and specify the path to that folder after the `--evolution` argument. -A tab called 'Evolution over time' then appears on the main page. + AD-miner -c -cf My_Report -b bolt://server:7687 -u neo4j -p mypassword -r 180 --evolution evolution_folder/ + +An 'Evolution over time' tab appears on the main page, providing evolution graphs for each category (Permissions, Passwords, Kerberos, and Misc).

-Also, views by categories 'permissions,' 'passwords,' 'kerberos' also allow you to track changes over time. +Detailed evolution for each control is also available and can be accessed via the “Show evolution” button for each category. A logarithmic scale is available to better highlight subtle variations over time.

diff --git a/ad_miner/__main__.py b/ad_miner/__main__.py index 456bc361..7d6baa6c 100644 --- a/ad_miner/__main__.py +++ b/ad_miner/__main__.py @@ -8,6 +8,9 @@ import traceback import signal import sys +import subprocess +import requests +from importlib.metadata import version, PackageNotFoundError # Local library imports from ad_miner.sources.modules import logger, utils, generic_formating, main_page @@ -142,6 +145,48 @@ def prepare_render(arguments) -> None: shutil.copy2(js_file, folder_name / "js") +def get_version_and_commit(): + # Either using pip(x) you get the version number or in dev environment the git commit + try: + ver = version("ad-miner") + except PackageNotFoundError: + ver = "unknown" + + commit = "" + try: + root = Path(__file__).resolve().parent + commit = subprocess.check_output( + ["git", "rev-parse", "--short", "HEAD"], cwd=root, stderr=subprocess.DEVNULL, text=True + ).strip() + except Exception: + commit = "unknown" + return ver, commit + + +def get_last_version(): + try: + r = requests.get("https://www.ad-miner.com/version.json", timeout=0.5) + data = r.json() + return data["lastversion"] + except Exception: + return "unreachable" + + +def check_version(lastversion, currentversion): + try: + last = tuple(map(int, lastversion.lstrip("v").split("."))) + current = tuple(map(int, currentversion.lstrip("v").split("."))) + + if last > current: + logger.print_error(f"New AD Miner version {lastversion} available.") + logger.print_error( + "Update with pipx or manually on https://github.com/AD-Security/AD_Miner" + ) + return + except Exception: + return + + def main() -> None: """Main execution function for the script.""" start = time.time() @@ -163,6 +208,12 @@ def main() -> None: prepare_render(arguments) + AD_miner_version, AD_miner_commit = get_version_and_commit() + arguments.version = AD_miner_version + arguments.commit = AD_miner_commit + + check_version(get_last_version(), AD_miner_version) + neo4j_version, extract_date, total_objects, number_relations, boolean_azure = pre_request( arguments ) diff --git a/ad_miner/sources/html/bootstrap/css/custom.css b/ad_miner/sources/html/bootstrap/css/custom.css index 8338397a..7e407995 100755 --- a/ad_miner/sources/html/bootstrap/css/custom.css +++ b/ad_miner/sources/html/bootstrap/css/custom.css @@ -389,4 +389,9 @@ a:hover{ .percentage-evolution { font-size: small; font-weight: 800; +} + +.ag-cell-value i.bi { + margin-right: 4px; + vertical-align: middle; } \ No newline at end of file diff --git a/ad_miner/sources/html/components/grid/grid_template.html b/ad_miner/sources/html/components/grid/grid_template.html index 4945fb76..4719b92f 100755 --- a/ad_miner/sources/html/components/grid/grid_template.html +++ b/ad_miner/sources/html/components/grid/grid_template.html @@ -99,10 +99,18 @@ rowData2.push(new_dico); } } + else if (window.location.href.includes('computers_with_administrators_details')) { + if (rowData[i]['Computer'] == parameter) { + var new_dico = {}; + new_dico['Users'] = rowData[i]['Users']; + new_dico['Distinguished Name'] = rowData[i]['Distinguished Name']; + rowData2.push(new_dico); + } + } else if (window.location.href.includes('users_rdp_access') || window.location.href.includes('computers_list_of_rdp_users')) { if (rowData[i][keys[0]].includes(parameter)) { - const startSubstring = "

"; + const startSubstring = "

"; const endSubstring = "

"; const startIndex = rowData[i][keys[1]].indexOf(startSubstring) + startSubstring.length; @@ -130,7 +138,12 @@ } } } - columnDefs2 = [{field: parameter}]; + if (window.location.href.includes('computers_with_administrators_details')) { + columnDefs2 = [{field: 'Users'},{field: 'Distinguished Name'}] + } + else { + columnDefs2 = [{field: parameter}]; + } return [rowData2, columnDefs2]; } diff --git a/ad_miner/sources/html/templates/main_header.html b/ad_miner/sources/html/templates/main_header.html index 9257e76a..489fc9ec 100644 --- a/ad_miner/sources/html/templates/main_header.html +++ b/ad_miner/sources/html/templates/main_header.html @@ -125,7 +125,7 @@