├── pytests ├── __init__.py └── test_flask.py ├── log └── README ├── bulkdownload └── README ├── static ├── favicon.ico ├── fonts │ ├── .DS_Store │ ├── ._webfonts │ ├── ._.DS_Store │ ├── Bold │ │ ├── OpenSans-Bold.woff │ │ ├── OpenSans-Bold.woff2 │ │ └── SourceCodePro-Bold.ttf │ ├── Light │ │ ├── OpenSans-Light.woff │ │ ├── OpenSans-Light.woff2 │ │ └── SourceCodePro-Light.ttf │ ├── webfonts │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.ttf │ │ ├── ._fa-solid-900.eot │ │ ├── ._fa-solid-900.svg │ │ ├── ._fa-solid-900.ttf │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.ttf │ │ ├── fa-brands-400.woff │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.ttf │ │ ├── fa-solid-900.woff │ │ ├── fa-solid-900.woff2 │ │ ├── ._fa-brands-400.eot │ │ ├── ._fa-brands-400.svg │ │ ├── ._fa-brands-400.ttf │ │ ├── ._fa-brands-400.woff │ │ ├── ._fa-brands-400.woff2 │ │ ├── ._fa-regular-400.eot │ │ ├── ._fa-regular-400.svg │ │ ├── ._fa-regular-400.ttf │ │ ├── ._fa-regular-400.woff │ │ ├── ._fa-solid-900.woff │ │ ├── ._fa-solid-900.woff2 │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ └── ._fa-regular-400.woff2 │ ├── Italic │ │ ├── OpenSans-Italic.woff │ │ └── OpenSans-Italic.woff2 │ ├── Regular │ │ ├── OpenSans-Regular.woff │ │ ├── OpenSans-Regular.woff2 │ │ └── SourceCodePro-Regular.ttf │ ├── Semibold │ │ ├── OpenSans-Semibold.woff │ │ ├── OpenSans-Semibold.woff2 │ │ └── SourceCodePro-Semibold.ttf │ ├── BoldItalic │ │ ├── OpenSans-BoldItalic.woff │ │ └── OpenSans-BoldItalic.woff2 │ ├── ExtraBold │ │ ├── OpenSans-ExtraBold.woff │ │ └── OpenSans-ExtraBold.woff2 │ ├── LightItalic │ │ ├── OpenSans-LightItalic.woff │ │ └── OpenSans-LightItalic.woff2 │ ├── ExtraBoldItalic │ │ ├── OpenSans-ExtraBoldItalic.woff │ │ └── OpenSans-ExtraBoldItalic.woff2 │ ├── SemiboldItalic │ │ ├── OpenSans-SemiboldItalic.woff │ │ └── OpenSans-SemiboldItalic.woff2 │ └── bootstrap │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 ├── vlines │ ├── node.png │ ├── vline.png │ └── lastnode.png ├── fireeye-2-color.png ├── img │ └── datatables │ │ ├── sort_asc.png │ │ ├── sort_both.png │ │ ├── sort_desc.png │ │ ├── details_open.png │ │ ├── details_close.png │ │ ├── sort_asc_disabled.png │ │ └── sort_desc_disabled.png ├── fontawesome-free-5.7.2-web │ ├── ._css │ ├── .DS_Store │ ├── ._.DS_Store │ ├── ._webfonts │ ├── ._LICENSE.txt │ ├── css │ │ ├── ._all.css │ │ ├── ._brands.css │ │ ├── ._solid.css │ │ ├── ._all.min.css │ │ ├── ._regular.css │ │ ├── ._solid.min.css │ │ ├── ._v4-shims.css │ │ ├── ._brands.min.css │ │ ├── ._fontawesome.css │ │ ├── ._regular.min.css │ │ ├── ._svg-with-js.css │ │ ├── ._v4-shims.min.css │ │ ├── ._fontawesome.min.css │ │ ├── ._svg-with-js.min.css │ │ ├── brands.min.css │ │ ├── solid.min.css │ │ ├── regular.min.css │ │ ├── brands.css │ │ ├── solid.css │ │ ├── regular.css │ │ └── svg-with-js.min.css │ ├── webfonts │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.ttf │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ ├── ._fa-brands-400.eot │ │ ├── ._fa-brands-400.svg │ │ ├── ._fa-brands-400.ttf │ │ ├── ._fa-brands-400.woff │ │ ├── ._fa-regular-400.eot │ │ ├── ._fa-regular-400.svg │ │ ├── ._fa-regular-400.ttf │ │ ├── ._fa-solid-900.eot │ │ ├── ._fa-solid-900.svg │ │ ├── ._fa-solid-900.ttf │ │ ├── ._fa-solid-900.woff │ │ ├── ._fa-solid-900.woff2 │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.woff2 │ │ ├── ._fa-brands-400.woff2 │ │ ├── ._fa-regular-400.woff │ │ └── ._fa-regular-400.woff2 │ └── LICENSE.txt ├── css │ ├── colReorder.dataTables.min.css │ ├── scroller.dataTables.min.css │ └── buttons.jqueryui.min.css ├── hxtool-css │ ├── hxtool-chartjs.css │ ├── hxtool-login.css │ ├── hxtool-typography.css │ ├── hxtool-top-nav.css │ ├── hxtool-panel.css │ ├── hxtool-rtioc.css │ ├── hxtool-datatables.css │ ├── hxtool-scriptbuilder.css │ ├── hxtool-grid.css │ ├── hxtool-host.css │ └── hxtool-table.css ├── progress.js ├── ico │ ├── windows.svg │ └── apple.svg ├── js │ ├── buttons.jqueryui.min.js │ └── buttons.print.min.js ├── ChartJS │ └── LICENSE.md ├── alert_types.json ├── hxtool-js │ ├── hxtool-widgets.js │ ├── hxtool-generic.js │ └── hxtool-doc-ready.js ├── multi-select.css ├── spinner.svg └── fireeye.svg ├── requirements.txt ├── scripts ├── ports.json ├── processes-api.json ├── w32drivers-modulelist.xml ├── files_listing_template.json ├── services-md5.xml ├── w32mbr.xml ├── w32tasks.xml ├── w32drivers-signature.xml └── w32processes-memory.xml ├── .dockerignore ├── hxtool_db.py ├── hxtool_vars.py ├── docker-entrypoint.sh ├── README.DOCKER ├── hxtool_global.py ├── templates ├── ht_noaccess.html ├── widget-radio.html ├── widget-input.html ├── widget-textarea.html ├── widget-panel-noheader.html ├── widget-panel.html ├── ht_settings.html ├── widget-modal.html ├── widget-dropdown.html ├── ht_sysinfo.html ├── voltron_data.html ├── ht_hostsearch.html ├── widget-schedule.html ├── ht_search_dd.html ├── ht_auditmanager.html ├── ht_stacking_analyze.html ├── ht_scheduler.html └── ht_categories.html ├── Dockerfile ├── gunicorn_container.py ├── hxtool_task_modules ├── __init__.py ├── task_api_session_module.py ├── file_listing_task_module.py ├── mongodb_ingest_task_module.py ├── task_module.py ├── file_acquisition_task_module.py ├── enterprise_search_task_module.py ├── stacking_task_module.py ├── file_write_task_module.py ├── streaming_task_module.py ├── helix_task_module.py └── x15_postgres_task_module.py ├── hxtool_logging.py ├── data ├── conf.json ├── hxtool.crt └── hxtool.key ├── hxtool_x15_db.py ├── tests └── test_scheduler.py ├── tools └── xagentinput_parser.py ├── LICENSE ├── README.md ├── hxtool_config.py ├── hxtool_session.py └── README.CONFIG /pytests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /log/README: -------------------------------------------------------------------------------- 1 | THIS IS WHERE HXTool logs end up 2 | -------------------------------------------------------------------------------- /bulkdownload/README: -------------------------------------------------------------------------------- 1 | This directory holds your downloaded bulk acquisitions 2 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/favicon.ico -------------------------------------------------------------------------------- /static/fonts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/.DS_Store -------------------------------------------------------------------------------- /static/fonts/._webfonts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/._webfonts -------------------------------------------------------------------------------- /static/vlines/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/vlines/node.png -------------------------------------------------------------------------------- /static/vlines/vline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/vlines/vline.png -------------------------------------------------------------------------------- /static/fonts/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/._.DS_Store -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask>=2.0.0 2 | requests 3 | pycryptodomex 4 | tinydb>=3.15.2 5 | pandas 6 | keyring 7 | -------------------------------------------------------------------------------- /static/fireeye-2-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fireeye-2-color.png -------------------------------------------------------------------------------- /static/vlines/lastnode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/vlines/lastnode.png -------------------------------------------------------------------------------- /scripts/ports.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": [ 3 | { 4 | "name": "ports" 5 | } 6 | ] 7 | } -------------------------------------------------------------------------------- /static/img/datatables/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/sort_asc.png -------------------------------------------------------------------------------- /static/img/datatables/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/sort_both.png -------------------------------------------------------------------------------- /static/img/datatables/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/sort_desc.png -------------------------------------------------------------------------------- /static/fonts/Bold/OpenSans-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Bold/OpenSans-Bold.woff -------------------------------------------------------------------------------- /static/fonts/Bold/OpenSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Bold/OpenSans-Bold.woff2 -------------------------------------------------------------------------------- /static/fonts/Light/OpenSans-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Light/OpenSans-Light.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /static/img/datatables/details_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/details_open.png -------------------------------------------------------------------------------- /scripts/processes-api.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": [ 3 | { 4 | "name": "processes-api" 5 | } 6 | ] 7 | } -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/._css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/._css -------------------------------------------------------------------------------- /static/fonts/Bold/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Bold/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /static/fonts/Italic/OpenSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Italic/OpenSans-Italic.woff -------------------------------------------------------------------------------- /static/fonts/Light/OpenSans-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Light/OpenSans-Light.woff2 -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-solid-900.eot -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-solid-900.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-solid-900.svg -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-solid-900.ttf -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /static/img/datatables/details_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/details_close.png -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.git 2 | **/__pycache__ 3 | **/*.pyc 4 | *.db 5 | log/* 6 | !log/README 7 | bulkdownload/* 8 | !bulkdownload/README 9 | -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/.DS_Store -------------------------------------------------------------------------------- /static/fonts/Italic/OpenSans-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Italic/OpenSans-Italic.woff2 -------------------------------------------------------------------------------- /static/fonts/Light/SourceCodePro-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Light/SourceCodePro-Light.ttf -------------------------------------------------------------------------------- /static/fonts/Regular/OpenSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Regular/OpenSans-Regular.woff -------------------------------------------------------------------------------- /static/fonts/Regular/OpenSans-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Regular/OpenSans-Regular.woff2 -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-brands-400.eot -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-brands-400.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-brands-400.svg -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-brands-400.ttf -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-brands-400.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-brands-400.woff2 -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-regular-400.eot -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-regular-400.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-regular-400.svg -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-regular-400.ttf -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-regular-400.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-solid-900.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-solid-900.woff2 -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /static/fonts/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /static/img/datatables/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/sort_asc_disabled.png -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/._.DS_Store -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/._webfonts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/._webfonts -------------------------------------------------------------------------------- /static/fonts/Semibold/OpenSans-Semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Semibold/OpenSans-Semibold.woff -------------------------------------------------------------------------------- /static/fonts/Semibold/OpenSans-Semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Semibold/OpenSans-Semibold.woff2 -------------------------------------------------------------------------------- /static/fonts/webfonts/._fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/webfonts/._fa-regular-400.woff2 -------------------------------------------------------------------------------- /static/img/datatables/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/img/datatables/sort_desc_disabled.png -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/._LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/._LICENSE.txt -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._all.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._all.css -------------------------------------------------------------------------------- /static/fonts/BoldItalic/OpenSans-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/BoldItalic/OpenSans-BoldItalic.woff -------------------------------------------------------------------------------- /static/fonts/ExtraBold/OpenSans-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/ExtraBold/OpenSans-ExtraBold.woff -------------------------------------------------------------------------------- /static/fonts/ExtraBold/OpenSans-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/ExtraBold/OpenSans-ExtraBold.woff2 -------------------------------------------------------------------------------- /static/fonts/Regular/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Regular/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /static/fonts/Semibold/SourceCodePro-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/Semibold/SourceCodePro-Semibold.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._brands.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._brands.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._solid.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._solid.css -------------------------------------------------------------------------------- /static/fonts/BoldItalic/OpenSans-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/BoldItalic/OpenSans-BoldItalic.woff2 -------------------------------------------------------------------------------- /static/fonts/LightItalic/OpenSans-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/LightItalic/OpenSans-LightItalic.woff -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._all.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._all.min.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._regular.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._regular.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._solid.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._solid.min.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._v4-shims.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._v4-shims.css -------------------------------------------------------------------------------- /static/fonts/LightItalic/OpenSans-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/LightItalic/OpenSans-LightItalic.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._brands.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._brands.min.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._fontawesome.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._fontawesome.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._regular.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._regular.min.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._svg-with-js.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._svg-with-js.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._v4-shims.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._v4-shims.min.css -------------------------------------------------------------------------------- /static/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff -------------------------------------------------------------------------------- /static/fonts/SemiboldItalic/OpenSans-SemiboldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/SemiboldItalic/OpenSans-SemiboldItalic.woff -------------------------------------------------------------------------------- /static/fonts/SemiboldItalic/OpenSans-SemiboldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/SemiboldItalic/OpenSans-SemiboldItalic.woff2 -------------------------------------------------------------------------------- /static/fonts/bootstrap/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/bootstrap/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/fonts/bootstrap/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/bootstrap/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._fontawesome.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._fontawesome.min.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/._svg-with-js.min.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/css/._svg-with-js.min.css -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /static/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.eot -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.svg -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.woff -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.eot -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.svg -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.eot -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.svg -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.woff -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-solid-900.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-brands-400.woff2 -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.woff -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/HXTool/master/static/fontawesome-free-5.7.2-web/webfonts/._fa-regular-400.woff2 -------------------------------------------------------------------------------- /static/css/colReorder.dataTables.min.css: -------------------------------------------------------------------------------- 1 | table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201} 2 | -------------------------------------------------------------------------------- /hxtool_db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | class hxtool_db: 5 | def __init__(self): 6 | pass 7 | 8 | @property 9 | def database_engine(self): 10 | raise NotImplementedError("You must override this in your database class.") -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-chartjs.css: -------------------------------------------------------------------------------- 1 | .hxtool_chartjs_canvas { 2 | padding: 24px; 3 | padding-bottom: 6px; 4 | padding-top: 6px; 5 | } 6 | 7 | .hxtool_chartjs_host_canvas { 8 | padding: 12px; 9 | padding-bottom: 6px; 10 | padding-top: 6px; 11 | height: 90px; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /hxtool_vars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Global variables 5 | 6 | default_encoding = 'utf-8' 7 | HXTOOL_API_VERSION = 1 8 | __version__ = "4.8-pre" 9 | hxtool_schema_version = 40 10 | data_path = "data" 11 | log_path = "log" 12 | 13 | global app_instance_path 14 | -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-login.css: -------------------------------------------------------------------------------- 1 | .hxtool_login_main { 2 | position: absolute; 3 | left: 50%; 4 | top: 20%; 5 | margin-left: -250px; 6 | } 7 | 8 | .hxtool_login_profile { 9 | list-style-type: none; 10 | } 11 | 12 | .hxtool_login_profile li { 13 | font-size: 14px; 14 | margin-bottom: 12px; 15 | } -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PASSWORD_FILE=/opt/hxtool/data/.keyring_password 3 | if [ ! -f "$PASSWORD_FILE" ]; then 4 | dd if=/dev/urandom of=$PASSWORD_FILE bs=1 count=32 5 | fi 6 | /usr/bin/dbus-run-session -- bash -r << EOF 7 | cat $PASSWORD_FILE | gnome-keyring-daemon --unlock 8 | python3 hxtool.py 9 | EOF 10 | -------------------------------------------------------------------------------- /README.DOCKER: -------------------------------------------------------------------------------- 1 | To build a Docker image from the HXTool source, execute the following: 2 | docker build --pull -t hxtool:latest . 3 | 4 | To run HXTool once the image build process is complete, execute the following: 5 | docker run -p 8080:8080/tcp -d --cap-add=IPC_LOCK --name hxtool hxtool:latest 6 | 7 | IPC_LOCK is needed for the GNOME keyring daemon -------------------------------------------------------------------------------- /hxtool_global.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # The sole purpose of this module is to store global variables and functions 5 | 6 | def initialize(): 7 | global apicache 8 | apicache = {} 9 | 10 | global hxtool_db 11 | global hxtool_config 12 | global hxtool_scheduler 13 | global hxtool_x15_object 14 | global hx_alert_types 15 | -------------------------------------------------------------------------------- /static/css/scroller.dataTables.min.css: -------------------------------------------------------------------------------- 1 | div.DTS{display:block !important}div.DTS tbody th,div.DTS tbody td{white-space:nowrap}div.DTS div.DTS_Loading{z-index:1}div.DTS div.dataTables_scrollBody{background:repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, #fff 10px, #fff 20px)}div.DTS div.dataTables_scrollBody table{z-index:2}div.DTS div.dataTables_paginate,div.DTS div.dataTables_length{display:none} 2 | -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-typography.css: -------------------------------------------------------------------------------- 1 | .hxtool_typography_h3 { 2 | margin-bottom: 8px; 3 | margin-top: 8px; 4 | } 5 | 6 | .hxtool_typography_h4 { 7 | margin-bottom: 8px; 8 | margin-top: 8px; 9 | } 10 | 11 | .hxtool_typography_h5 { 12 | margin-bottom: 8px; 13 | margin-top: 8px; 14 | } 15 | 16 | .hxtool_typography_underline { 17 | border-bottom: 0.5px solid rgba(15, 184, 220, 0.3); 18 | padding-bottom: 2px; 19 | } -------------------------------------------------------------------------------- /templates/ht_noaccess.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Access denied{% endblock %} 3 | {% block navlocation %}Access denied{% endblock %} 4 | {% block content %} 5 | 6 | {{ htPanel.widgetHeader("HXTool message", panelIcon="fa-ban") }} 7 | Access to this feature is denied. Check your account role in the FireEye HX appliance some features requires "API Administrator" access. 8 | {{ htPanel.widgetFooter() }} 9 | 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/brands.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"} -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/solid.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900} -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/regular.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400} -------------------------------------------------------------------------------- /static/progress.js: -------------------------------------------------------------------------------- 1 | (function ( $ ) { 2 | $.fn.progress = function() { 3 | var percent = this.data("percent"); 4 | this.html("
"+percent+"%
"); 5 | this.find("div").animate({ width: percent+"%" }); 6 | }; 7 | }( jQuery )); 8 | 9 | (function ( $ ) { 10 | $.fn.progressNoAnimate = function() { 11 | var percent = this.data("percent"); 12 | this.html("
"+percent+"%
"); 13 | }; 14 | }( jQuery )); 15 | -------------------------------------------------------------------------------- /templates/widget-radio.html: -------------------------------------------------------------------------------- 1 | {% macro widgetHeader(elementTitle, elementValue, elementId, elementName, elementChecked="false") -%} 2 |
3 | 4 | 5 | 6 | 7 |
8 | {% endmacro %} -------------------------------------------------------------------------------- /templates/widget-input.html: -------------------------------------------------------------------------------- 1 | {% macro widget(elementPlaceholder, elementTitle="", elementHint="", elementId="", elementWidth="") -%} 2 | {% if elementTitle != "" %} 3 |

{{elementTitle}}

4 | {% endif %} 5 | 6 | {% if elementHint != "" %} 7 | {{elementHint}} 8 | {% endif %} 9 | {% endmacro %} -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6-slim 2 | LABEL maintainer="Elazar Broad " 3 | WORKDIR /opt/hxtool 4 | # TODO: should be converted to a script 5 | COPY requirements.txt ./ 6 | RUN apt-get update && apt-get install -y dbus gnome-keyring \ 7 | && pip install --no-cache-dir pymongo psycopg2-binary pydbus \ 8 | && pip install --no-cache-dir -r requirements.txt \ 9 | && rm -rf /root/.cache 10 | COPY . /opt/hxtool 11 | VOLUME /opt/hxtool/data /opt/hxtool/bulkdownload /opt/hxtool/log 12 | EXPOSE 8080/tcp 13 | ENTRYPOINT ["/bin/sh", "docker-entrypoint.sh"] 14 | -------------------------------------------------------------------------------- /templates/widget-textarea.html: -------------------------------------------------------------------------------- 1 | {% macro widget(elementPlaceholder, elementTitle="", elementHint="", elementId="", elementWidth="") -%} 2 | {% if elementTitle != "" %} 3 |

{{elementTitle}}

4 | {% endif %} 5 | 6 | {% if elementHint != "" %} 7 | {{elementHint}} 8 | {% endif %} 9 | {% endmacro %} -------------------------------------------------------------------------------- /templates/widget-panel-noheader.html: -------------------------------------------------------------------------------- 1 | {% macro widgetHeader(panelId="", panelDisplay="block", panelWidth="", elementAdditionalClass="", elementAdditionalBodyClass="") -%} 2 |
3 |
4 | {% endmacro %} 5 | 6 | {% macro widgetFooter() -%} 7 |
8 |
9 | {% endmacro %} -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/brands.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Font Awesome 5 Brands'; 3 | font-style: normal; 4 | font-weight: normal; 5 | font-display: auto; 6 | src: url("../webfonts/fa-brands-400.eot"); 7 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); } 8 | 9 | .fab { 10 | font-family: 'Font Awesome 5 Brands'; } 11 | -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/solid.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Font Awesome 5 Free'; 3 | font-style: normal; 4 | font-weight: 900; 5 | font-display: auto; 6 | src: url("../webfonts/fa-solid-900.eot"); 7 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } 8 | 9 | .fa, 10 | .fas { 11 | font-family: 'Font Awesome 5 Free'; 12 | font-weight: 900; } 13 | -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/regular.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Font Awesome 5 Free'; 3 | font-style: normal; 4 | font-weight: 400; 5 | font-display: auto; 6 | src: url("../webfonts/fa-regular-400.eot"); 7 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); } 8 | 9 | .far { 10 | font-family: 'Font Awesome 5 Free'; 11 | font-weight: 400; } 12 | -------------------------------------------------------------------------------- /gunicorn_container.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from gunicorn.app.base import Application 5 | 6 | class GunicornContainerApplication(Application): 7 | def __init__(self, app, options = {}): 8 | self.application = app 9 | self.options = options 10 | super(GunicornContainerApplication, self).__init__() 11 | 12 | def load_config(self): 13 | config = dict([(key, value) for key, value in self.options.items() 14 | if key in self.cfg.settings and value is not None]) 15 | for key, value in config.items(): 16 | self.cfg.set(key.lower(), value) 17 | 18 | def load(self): 19 | return self.application 20 | -------------------------------------------------------------------------------- /hxtool_task_modules/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Base module 5 | from .task_module import * 6 | 7 | # HXTool packages modules here 8 | from .task_api_session_module import * 9 | from .bulk_acquisition_task_module import * 10 | from .bulk_download_monitor_task_module import * 11 | from .bulk_download_task_module import * 12 | from .enterprise_search_task_module import * 13 | from .stacking_task_module import * 14 | from .file_listing_task_module import * 15 | from .file_acquisition_task_module import * 16 | from .streaming_task_module import * 17 | from .file_write_task_module import * 18 | from .helix_task_module import * 19 | from .x15_postgres_task_module import * 20 | from .mongodb_ingest_task_module import * 21 | 22 | # Customer modules here 23 | -------------------------------------------------------------------------------- /static/ico/windows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /templates/widget-panel.html: -------------------------------------------------------------------------------- 1 | {% macro widgetHeader(panelTitle, panelId="", panelDisplay="block", panelWidth="", elementAdditionalClass="", elementAdditionalBodyClass="", panelIcon="") -%} 2 |
3 |
4 |
{% if panelIcon != "" %}{% endif %}{{panelTitle}}
5 |
6 |
7 | {% endmacro %} 8 | 9 | {% macro widgetFooter() -%} 10 |
11 |
12 | {% endmacro %} -------------------------------------------------------------------------------- /templates/ht_settings.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Settings{% endblock %} 3 | {% block navlocation %}Settings{% endblock %} 4 | {% block content %} 5 | 6 | 17 | 18 | {{ htPanel.widgetHeader("Background processing", panelIcon="fa-table") }} 19 |
Enter HX API credentials to use for background processing. This feature is used to post-process acquisitions as they come in (when you are not logged into HXTool). PLEASE NOTE: These credentials are stored in the database encrypted with a static key.
20 | {% if bgcreds %} {{ bgcreds|safe }} {% endif %} 21 | 22 | {{ htPanel.widgetFooter() }} 23 | 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /hxtool_logging.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import threading 5 | import logging 6 | from multiprocessing import Queue, RLock 7 | 8 | 9 | root_logger_name = "hxtool" 10 | 11 | def setLoggerClass(): 12 | logging.setLoggerClass(hxtool_logger) 13 | 14 | def getLoggerName(name): 15 | return "{}.{}".format(root_logger_name, name) 16 | 17 | def getLogger(name = None): 18 | _name = root_logger_name 19 | if name is not None: 20 | _name = getLoggerName(name) 21 | 22 | return logging.getLogger(_name) 23 | 24 | class hxtool_logger(logging.Logger): 25 | def __init__(self, name, level=logging.NOTSET): 26 | super(hxtool_logger, self).__init__(name, level=level) 27 | 28 | def callHandlers(self, record): 29 | with RLock(): 30 | _thread = threading.Thread(target=super(hxtool_logger, self).callHandlers(record)) 31 | _thread.start() 32 | _thread.join() 33 | 34 | -------------------------------------------------------------------------------- /templates/widget-modal.html: -------------------------------------------------------------------------------- 1 | {% macro widgetHeader(modalTitle, modalId="", modalSize="medium", modalOverflow="false") -%} 2 | 26 | {% endmacro %} -------------------------------------------------------------------------------- /static/js/buttons.jqueryui.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | jQuery UI integration for DataTables' Buttons 3 | ©2016 SpryMedia Ltd - datatables.net/license 4 | */ 5 | (function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-jqui","datatables.net-buttons"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);if(!b||!b.fn.dataTable)b=require("datatables.net-jqui")(a,b).$;b.fn.dataTable.Buttons||require("datatables.net-buttons")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c){var a=c.fn.dataTable;c.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons ui-buttonset"}, 6 | button:{className:"dt-button ui-button ui-state-default ui-button-text-only",disabled:"ui-state-disabled",active:"ui-state-active"},buttonLiner:{tag:"span",className:"ui-button-text"}}});a.ext.buttons.collection.text=function(a){return a.i18n("buttons.collection",'Collection ')};return a.Buttons}); 7 | -------------------------------------------------------------------------------- /static/ChartJS/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Chart.js Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /scripts/w32drivers-modulelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | application/vnd.mandiant.host+xml 5 | 6 | 7 | application/vnd.mandiant.auditresult+xml 8 | 9 | 25 | -------------------------------------------------------------------------------- /scripts/files_listing_template.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": [{ 3 | "name": "files-api", 4 | "parameters": [{ 5 | "name": "Prevent Hibernation", 6 | "value": true 7 | }, { 8 | "name": "Depth", 9 | "value": -1 10 | }, { 11 | "name": "MD5", 12 | "value": true 13 | }, { 14 | "name": "SHA1", 15 | "value": false 16 | }, { 17 | "name": "SHA256", 18 | "value": true 19 | },{ 20 | "name": "Strings", 21 | "value": false 22 | }, { 23 | "name": "AND Operator", 24 | "value": false 25 | }, { 26 | "name": "Include Files", 27 | "value": true 28 | }, { 29 | "name": "Include Directories", 30 | "value": true 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /static/alert_types.json: -------------------------------------------------------------------------------- 1 | { 2 | "IOC": { 3 | "label": "Realtime IOC Detection", 4 | "threat_key": "indicator.display_name" 5 | }, 6 | "EXD": { 7 | "label": "Exploit Guard", 8 | "threat_key": "event_values.process_name" 9 | }, 10 | "MAL": { 11 | "label": "Malware Protection", 12 | "threat_key": "event_values.detections.detection.#0.infection.infection-name" 13 | }, 14 | "PROCESS_TRACKER": { 15 | "label": "Process Tracker", 16 | "threat_key": "event_values.#0.name" 17 | }, 18 | "PROCGUARD": { 19 | "label": "Process Guard", 20 | "threat_key": "event_values.#0.name" 21 | }, 22 | "LTALERT": { 23 | "label": "Logon Tracker", 24 | "threat_key": "event_values.#0.name" 25 | }, 26 | "UACPROTECT": { 27 | "label": "UAC Protect", 28 | "threat_key": "event_values.#0.name" 29 | }, 30 | "AMSI": { 31 | "label": "AMSI", 32 | "threat_key": "event_values.#0.name" 33 | }, 34 | "TP": { 35 | "label": "Tamper Protection", 36 | "threat_key": "event_values.#0.name" 37 | }, 38 | "DL": { 39 | "label": "Deny List", 40 | "threat_key": "event_values.#0.name" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-top-nav.css: -------------------------------------------------------------------------------- 1 | /* HXTool Top Navigation bar */ 2 | 3 | .hxtool_topnav_dropdown { 4 | background: rgba(0, 0, 0, 0.6) !important; 5 | position: absolute; 6 | box-shadow: 0 0.5px 5px 0 rgba(0, 0, 0, 0.25); 7 | display: none; 8 | z-index: 50 !important; 9 | } 10 | 11 | .hxtool_topnav_dropdown_child { 12 | width: 100%; 13 | color: #0fb8dc; 14 | text-align: left; 15 | background: transparent; 16 | border: 0; 17 | } 18 | 19 | .hxtool_topnav_dropdown_child:hover { 20 | background: rgba(0, 0, 0, 0.6); 21 | color: #66ebff !important; 22 | } 23 | 24 | .hxtool_topnav_left_container-left { 25 | position: absolute; 26 | display: none; 27 | margin-left: 24px; 28 | } 29 | 30 | .hxtool_topnav_right_container-right { 31 | float: right; 32 | text-align: right; 33 | } 34 | 35 | .hxtool_topnav_dropdown_divider { 36 | width: 100%; 37 | margin-right: 0px; 38 | border-top: 1px solid; 39 | height: 16px; 40 | padding-bottom: 0px; 41 | padding-left: 8px; 42 | font-size: 10px; 43 | color: #b3cacf; 44 | } 45 | 46 | .hxtool_topnav_mainbutton { 47 | background: transparent; 48 | color: #0fb8dc; 49 | border: 0; 50 | } 51 | 52 | button.hxtool_topnav_mainbutton:hover { 53 | background: rgba(0, 0, 0, 0.6); 54 | color: #66ebff !important; 55 | } -------------------------------------------------------------------------------- /static/ico/apple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 17 | 18 | -------------------------------------------------------------------------------- /data/conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "log_handlers": { 3 | "rotating_file_handler": { 4 | "file": "log/hxtool.log", 5 | "max_bytes": 5000000, 6 | "backup_count": 5, 7 | "level": "info", 8 | "format": "[%(asctime)s] {%(module)s} {%(threadName)s} %(levelname)s - %(message)s" 9 | } 10 | }, 11 | "network": { 12 | "ssl": "enabled", 13 | "port": 8080, 14 | "listen_address": "0.0.0.0", 15 | "session_timeout": 30 16 | }, 17 | "ssl": { 18 | "cert": "hxtool.crt", 19 | "key": "hxtool.key" 20 | }, 21 | "scheduler": { 22 | "thread_count" : null, 23 | "defer_interval" : 30 24 | }, 25 | "apicache": { 26 | "enabled": false, 27 | "types": ["host", "alert", "triage", "file", "live"], 28 | "intervals": { 29 | "host": { 30 | "fetcher_interval": 60, 31 | "objects_per_poll": 3, 32 | "refresh_interval": 60 33 | }, 34 | "alert": { 35 | "fetcher_interval": 15, 36 | "objects_per_poll": 300, 37 | "refresh_interval": 15 38 | }, 39 | "triage": { 40 | "fetcher_interval": 10, 41 | "objects_per_poll": 10, 42 | "refresh_interval": 30 43 | }, 44 | "file": { 45 | "fetcher_interval": 10, 46 | "objects_per_poll": 5, 47 | "refresh_interval": 25 48 | }, 49 | "live": { 50 | "fetcher_interval": 10, 51 | "objects_per_poll": 50, 52 | "refresh_interval": 35 53 | } 54 | } 55 | }, 56 | "headers": {}, 57 | "cookies": {} 58 | } -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-panel.css: -------------------------------------------------------------------------------- 1 | .hxtool_panel_wrapper { 2 | margin-bottom: 24px; 3 | margin-top: 16px; 4 | margin-left: 12px; 5 | } 6 | 7 | .hxtool-panel-toggle { 8 | outline: 0; 9 | } 10 | 11 | .hxtool_panel_float { 12 | position: fixed; 13 | display: none; 14 | left: 50%; 15 | top: 50%; 16 | transform: translate(-50%, -50%); 17 | z-index: 5; 18 | } 19 | 20 | .hxtool_panel_body_popup { 21 | padding: 24px; 22 | } 23 | 24 | .hxtool_panel_dashboard { 25 | height: 100%; 26 | display: flex; 27 | flex-direction: column; 28 | position: relative; 29 | } 30 | 31 | .hxtool_panel_dashboard_child { 32 | flex: 1; 33 | } 34 | 35 | .hxtool_panel_top_right { 36 | position: absolute; 37 | right: 0; 38 | padding-left: 6px; 39 | margin-top: 4px; 40 | } 41 | 42 | .hxtool_panel_top_right_alert { 43 | position: absolute; 44 | right: 12px; 45 | padding-left: 6px; 46 | margin-top: -32px; 47 | } 48 | 49 | .hxtool_panel_scriptbuilder { 50 | width: 1536px; 51 | height: calc(100vh - 190px); 52 | overflow-y: visible; 53 | } 54 | 55 | .hxtool_panel_stackinganalyze { 56 | max-height: calc(100vh - 190px); 57 | overflow-y: auto; 58 | } 59 | 60 | .hxtool_panel_multi_flist { 61 | max-height: calc(50vh - 125px); 62 | overflow-y: auto; 63 | } 64 | 65 | .hxtool_panel_multi_macq { 66 | max-height: calc(50vh - 125px); 67 | overflow-y: auto; 68 | } 69 | 70 | .hxtool_panel_dashboard_lastalerts { 71 | overflow-y: auto; 72 | } -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-rtioc.css: -------------------------------------------------------------------------------- 1 | .hxtool_rtioc_table_header_condition { 2 | text-align: left !important; 3 | border-right: none !important; 4 | border-left: none; 5 | font-weight: bold; 6 | font-size: 14px; 7 | background: rgba(0,0,0,0.2); 8 | padding-top: 12px !important; 9 | padding-bottom: 12px !important; 10 | vertical-align: middle; 11 | } 12 | 13 | .hxtool_rtioc_table_header_condition_right { 14 | text-align: center !important; 15 | border-right: none; 16 | border-left: none; 17 | background: rgba(0,0,0,0.2); 18 | padding-top: 12px; 19 | } 20 | 21 | .hxtool_rtioc_input { 22 | padding: 3px; 23 | } 24 | 25 | .hxtool_rtioc_table tbody tr:nth-child(odd) { 26 | background: transparent !important; 27 | } 28 | 29 | 30 | .hxtool_rtioc_table tbody td:nth-child(1) { 31 | text-align: center; 32 | width: 230px; 33 | } 34 | 35 | .hxtool_rtioc_table tbody td:nth-child(2) { 36 | text-align: center; 37 | width: 200px; 38 | } 39 | 40 | .hxtool_rtioc_table tbody td:nth-child(3) { 41 | text-align: center; 42 | width: 130px; 43 | } 44 | 45 | .hxtool_rtioc_table tbody td:nth-child(4) { 46 | text-align: center; 47 | width: 100px; 48 | } 49 | 50 | .hxtool_rtioc_table tbody td:nth-child(5) { 51 | text-align: center; 52 | width: 100px; 53 | } 54 | 55 | .hxtool_rtioc_table tbody td:nth-child(7) { 56 | text-align: center; 57 | width: 40px; 58 | } 59 | 60 | .hxtool_rtioc_table tbody td:nth-child(8) { 61 | text-align: center; 62 | width: 100px; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /hxtool_x15_db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | try: 5 | import psycopg2 6 | import psycopg2.extras 7 | except ImportError: 8 | print("HXTool with X15 integration requires the psycopg2 library please install it") 9 | exit(1) 10 | 11 | import hxtool_global 12 | 13 | class hxtool_x15: 14 | def __init__(self, x15conf = hxtool_global.hxtool_config['x15']): 15 | 16 | connect_string = "host={} dbname={} user={} port={} password={}".format(x15conf['host'], x15conf['db'], x15conf['user'], x15conf['port'], x15conf['password']) 17 | self.conn = psycopg2.connect(connect_string) 18 | self.cur = self.conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) 19 | 20 | def getAudits(self): 21 | self.cur.execute("SELECT bulk_acquisition_id, min(timestamps[1]['time']) as starttime, max(timestamps[1]['time']) as stoptime, count(*) as events FROM eventdata GROUP BY bulk_acquisition_id") 22 | return(self.cur.fetchall()) 23 | 24 | def getAuditModules(self, bulk_list): 25 | self.cur.execute("SELECT generator, count(*) as events FROM eventdata WHERE bulk_acquisition_id IN %s GROUP BY generator", (tuple(bulk_list),)) 26 | return(self.cur.fetchall()) 27 | 28 | def getAuditData(self, generators, bulk_list): 29 | self.cur.execute("SELECT eventitem::string as eventitem FROM eventdata WHERE bulk_acquisition_id IN %(bulkids)s AND generator IN %(generators)s LIMIT 1", {"bulkids": tuple(bulk_list), "generators": tuple(generators)}) 30 | return(self.cur.fetchall()) 31 | -------------------------------------------------------------------------------- /tests/test_scheduler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import random 6 | from time import sleep 7 | import logging 8 | 9 | sys.path.append('../') 10 | 11 | from hxtool_scheduler import * 12 | from hxtool_scheduler_task import hxtool_scheduler_task 13 | import hxtool_global 14 | 15 | class test_scheduler: 16 | 17 | def __init__(self): 18 | self.ht_scheduler = hxtool_scheduler() 19 | self.ht_scheduler.logger.addHandler(logging.StreamHandler(sys.stdout)) 20 | self.ht_scheduler.logger.setLevel(logging.DEBUG) 21 | 22 | hxtool_global.hxtool_scheduler = self.ht_scheduler 23 | 24 | def run_test(self): 25 | print("Testing hxtool_scheduler...") 26 | self.ht_scheduler.start() 27 | for i in range(1, 500): 28 | ht_task = hxtool_scheduler_task('System', 'Test Task {}'.format(i), immutable = True, logger = self.ht_scheduler.logger) 29 | r = random.randint(1, 100) 30 | if r > 50: 31 | ht_task.set_schedule(minutes = random.randint(1, 5)) 32 | ht_task.add_step(self, "test_scheduler_function", args = (random.randint(1, 60),)) 33 | self.ht_scheduler.add(ht_task, should_store = False) 34 | ht_task = None 35 | 36 | try: 37 | while True: 38 | sleep(.1) 39 | except (KeyboardInterrupt, SystemExit): 40 | self.ht_scheduler.stop() 41 | 42 | def test_scheduler_function(self, n): 43 | print("Random number is: {}".format(n * random.randint(0, 500))) 44 | return True 45 | 46 | t = test_scheduler() 47 | t.run_test() -------------------------------------------------------------------------------- /scripts/services-md5.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tools/xagentinput_parser.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | myjson = {} 4 | 5 | with open('../../xagtinput.json') as f: 6 | data = json.load(f) 7 | 8 | for key in ['modules-audits', 'modules-acquisitions']: 9 | for module in data[key]: 10 | 11 | for mymodule, val in module.items(): 12 | 13 | myjson[val['module name']] = {} 14 | myjson[val['module name']]['description'] = val['usage'] 15 | myjson[val['module name']]['platforms'] = val['platform'] 16 | myjson[val['module name']]['parameters'] = [] 17 | 18 | for parameter in val['parameters']: 19 | 20 | myparam = parameter 21 | myparam['platforms'] = ["win", "osx", "linux"] 22 | 23 | textlist = ["String", "ByteSize", "FilePath", "Numeric", "PID", "RegistryPath", "dateTime"] 24 | 25 | if parameter['required'] == "true": 26 | myparam['required'] = True 27 | elif parameter['required'] == "false": 28 | myparam['required'] = False 29 | 30 | if parameter['repeatable'] == "true": 31 | myparam['repeatable'] = True 32 | elif parameter['repeatable'] == "false": 33 | myparam['repeatable'] = False 34 | 35 | if parameter['type'] in textlist: 36 | myparam['type'] = "text" 37 | elif parameter['type'] == "Bool": 38 | myparam['type'] = "dropdown" 39 | myparam['values'] = ['true', 'false'] 40 | elif parameter['type'] == "ArrayOfString": 41 | myparam['type'] = "textarea" 42 | 43 | myjson[val['module name']]['parameters'].append(myparam) 44 | 45 | 46 | print(json.dumps(myjson, indent=4, sort_keys=True)) -------------------------------------------------------------------------------- /scripts/w32mbr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | application/vnd.mandiant.host+xml 5 | 6 | 7 | application/vnd.mandiant.auditresult+xml 8 | 9 | 36 | -------------------------------------------------------------------------------- /templates/widget-dropdown.html: -------------------------------------------------------------------------------- 1 | {% macro widgetHeader(elementValue, elementId, elementDefault, elementAdditionalClass="") -%} 2 |
3 | 4 |
5 | 26 |
27 |
28 |
29 | {% if elementLabel != "" %} 30 | {{elementLabel}}
31 | {% endif %} 32 | {% endmacro %} -------------------------------------------------------------------------------- /templates/ht_sysinfo.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - System information{% endblock %} 3 | {% block content %} 4 | 5 | 34 | 35 | {{ htPanel.widgetHeader("System information", panelIcon="fa-info") }} 36 |

FireEye Endpoint Security Controller

37 |
38 | 39 |

HXTool

40 |
41 | 42 | {{ htPanel.widgetFooter() }} 43 | 44 | {{ htPanel.widgetHeader("API Cache", panelIcon="fa-info") }} 45 |

Cache statistics

46 |
47 | 48 | {{ htPanel.widgetFooter() }} 49 | 50 | {% endblock %} -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font Awesome Free License 2 | ------------------------- 3 | 4 | Font Awesome Free is free, open source, and GPL friendly. You can use it for 5 | commercial projects, open source projects, or really almost whatever you want. 6 | Full Font Awesome Free license: https://fontawesome.com/license/free. 7 | 8 | # Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) 9 | In the Font Awesome Free download, the CC BY 4.0 license applies to all icons 10 | packaged as SVG and JS file types. 11 | 12 | # Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) 13 | In the Font Awesome Free download, the SIL OFL license applies to all icons 14 | packaged as web and desktop font files. 15 | 16 | # Code: MIT License (https://opensource.org/licenses/MIT) 17 | In the Font Awesome Free download, the MIT license applies to all non-font and 18 | non-icon files. 19 | 20 | # Attribution 21 | Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font 22 | Awesome Free files already contain embedded comments with sufficient 23 | attribution, so you shouldn't need to do anything additional when using these 24 | files normally. 25 | 26 | We've kept attribution comments terse, so we ask that you do not actively work 27 | to remove them from files, especially code. They're a great way for folks to 28 | learn about Font Awesome. 29 | 30 | # Brand Icons 31 | All brand icons are trademarks of their respective owners. The use of these 32 | trademarks does not indicate endorsement of the trademark holder by Font 33 | Awesome, nor vice versa. **Please do not use brand logos for any purpose except 34 | to represent the company, product, or service to which they refer.** 35 | -------------------------------------------------------------------------------- /templates/voltron_data.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Analysis data{% endblock %} 3 | {% block navlocation %}Analysis data{% endblock %} 4 | {% block content %} 5 | 6 | 47 | 48 | {{ htPanel.widgetHeader("Analysis data", panelIcon="fa-desktop") }} 49 |
50 | {{ htPanel.widgetFooter() }} 51 | 52 | 53 | {% endblock %} 54 | -------------------------------------------------------------------------------- /scripts/w32tasks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | application/vnd.mandiant.host+xml 5 | 6 | 7 | application/vnd.mandiant.auditresult+xml 8 | 9 | 43 | 44 | -------------------------------------------------------------------------------- /hxtool_task_modules/task_api_session_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is a system task module that performs the API logins needed by the task scheduler. 5 | 6 | from .task_module import * 7 | from hx_lib import * 8 | 9 | class task_api_session_module(task_module): 10 | def __init__(self, parent_task): 11 | super(type(self), self).__init__(parent_task) 12 | 13 | @staticmethod 14 | def input_args(): 15 | return [ 16 | { 17 | 'name' : 'profile_id', 18 | 'type' : str, 19 | 'required' : True, 20 | 'user_supplied' : True, 21 | 'description' : "The profile ID of the HXTool profile." 22 | }, 23 | { 24 | 'name' : 'username', 25 | 'type' : str, 26 | 'required' : True, 27 | 'user_supplied' : True, 28 | 'description' : "The HX API username." 29 | }, 30 | { 31 | 'name' : 'password', 32 | 'type' : str, 33 | 'required' : True, 34 | 'user_supplied' : True, 35 | 'description' : "The HX API password." 36 | } 37 | ] 38 | 39 | @staticmethod 40 | def output_args(): 41 | return [] 42 | 43 | def run(self, profile_id = None, username = None, password = None): 44 | ret = False 45 | hx_api_object = self.parent_task.scheduler.task_hx_api_sessions.get(profile_id, None) 46 | if hx_api_object is not None: 47 | (ret, response_code, response_data) = hx_api_object.restLogin(username, password, auto_renew_token = True) 48 | if ret: 49 | self.logger.info("Successfully initialized task API session for host {} ({})".format(hx_api_object.hx_host, profile_id)) 50 | else: 51 | self.logger.warn("Failed to initialize task API session for host {} ({}). Response code: {}, response data: {}".format(hx_api_object.hx_host, profile_id, response_code, response_data)) 52 | del self.parent_task.scheduler.task_hx_api_sessions[profile_id] 53 | password = None 54 | hx_api_object = None 55 | return ret -------------------------------------------------------------------------------- /static/js/buttons.print.min.js: -------------------------------------------------------------------------------- 1 | (function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(f){return d(f,window,document)}):"object"===typeof exports?module.exports=function(f,b){f||(f=window);if(!b||!b.fn.dataTable)b=require("datatables.net")(f,b).$;b.fn.dataTable.Buttons||require("datatables.net-buttons")(f,b);return d(b,f,f.document)}:d(jQuery,window,document)})(function(d,f,b){var i=d.fn.dataTable,h=b.createElement("a"),m=function(a){h.href=a;a=h.host;-1===a.indexOf("/")&& 2 | 0!==h.pathname.indexOf("/")&&(a+="/");return h.protocol+"//"+a+h.pathname+h.search};i.ext.buttons.print={className:"buttons-print",text:function(a){return a.i18n("buttons.print","Print")},action:function(a,b,h,e){var c=b.buttons.exportData(e.exportOptions),k=function(a,c){for(var b="",d=0,e=a.length;d"+a[d]+"";return b+""},a='';e.header&&(a+=""+k(c.header,"th")+"");for(var a=a+"",l=0,i=c.body.length;l< 3 | i;l++)a+=k(c.body[l],"td");a+="";e.footer&&c.footer&&(a+=""+k(c.footer,"th")+"");var g=f.open("",""),c=e.title;"function"===typeof c&&(c=c());-1!==c.indexOf("*")&&(c=c.replace("*",d("title").text()));g.document.close();var j=""+c+"";d("style, link").each(function(){var a=j,b=d(this).clone()[0];"link"===b.nodeName.toLowerCase()&&(b.href=m(b.href));j=a+b.outerHTML});try{g.document.head.innerHTML=j}catch(n){d(g.document.head).html(j)}g.document.body.innerHTML="

"+ 4 | c+"

"+("function"===typeof e.message?e.message(b,h,e):e.message)+"
"+a;d(g.document.body).addClass("dt-print-view");d("img",g.document.body).each(function(a,b){b.setAttribute("src",m(b.getAttribute("src")))});e.customize&&e.customize(g);setTimeout(function(){e.autoPrint&&(g.print(),g.close())},250)},title:"*",message:"",exportOptions:{},header:!0,footer:!1,autoPrint:!0,customize:null};return i.Buttons}); 5 | -------------------------------------------------------------------------------- /static/hxtool-js/hxtool-widgets.js: -------------------------------------------------------------------------------- 1 | function hxtoolAddInput(title, name, id, placeholder, hint) { 2 | 3 | html = '
'; 4 | html += ''; 5 | html += ''; 6 | html += '' + hint + ''; 7 | html += '
'; 8 | 9 | return(html); 10 | } 11 | 12 | function generateDropDown(elementValue, elementId, elementDefault, entries=[{}], elementAdditionalClass, elementLabel) { 13 | var r = ""; 14 | 15 | // Header 16 | r += "
"; 19 | r += ''; 20 | r += '
'; 21 | r += '"; 37 | r += "
"; 38 | r += "
"; 39 | 40 | // Label 41 | if (elementLabel != false) { 42 | r += "
" + elementLabel + "
"; 43 | } 44 | 45 | r += "
"; 46 | 47 | return(r); 48 | } -------------------------------------------------------------------------------- /data/hxtool.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIF6TCCA9GgAwIBAgIJAKodHBtwAe/tMA0GCSqGSIb3DQEBCwUAMIGKMQswCQYD 3 | VQQGEwJTRTEQMA4GA1UECAwHSGFsbGFuZDEPMA0GA1UEBwwGT25zYWxhMRAwDgYD 4 | VQQKDAdGaXJlRXllMQswCQYDVQQLDAJIWDEPMA0GA1UEAwwGSFhUT09MMSgwJgYJ 5 | KoZIhvcNAQkBFhloZW5yaWsub2xzc29uQGZpcmVleWUuY29tMB4XDTE3MDIyMTEy 6 | NTY0OVoXDTQ0MDcwODEyNTY0OVowgYoxCzAJBgNVBAYTAlNFMRAwDgYDVQQIDAdI 7 | YWxsYW5kMQ8wDQYDVQQHDAZPbnNhbGExEDAOBgNVBAoMB0ZpcmVFeWUxCzAJBgNV 8 | BAsMAkhYMQ8wDQYDVQQDDAZIWFRPT0wxKDAmBgkqhkiG9w0BCQEWGWhlbnJpay5v 9 | bHNzb25AZmlyZWV5ZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC 10 | AQDFTAPsfC7RVJn18fgU+XuaplfgcYFKF1OaFkJKfuuwyejhm+v738tn/h1+RGPL 11 | KMqlJI9l+6IXshau+IQHmq7chZEbWw373BYVsBbnSELLUgQ4TvZbLyvw7eewwF4S 12 | J9aRLzNiXGBEzwt0SuyGLF199ZkTQFnFtC5QK5GZXZ1LuJKryzgoq5L15IkrNatG 13 | dhJYQc6WWz2yBP4ZA+KAMvkn5rV0QCE3w9uQumzMm+Qw5v5LGzyX+wgCdYn1rMZp 14 | ipN5pmSA3QRVQlcfFBTbv9LQGNNuM0ZgetXBpuH7Otq6Us9eXWzZx+Z4hpKNX2Ri 15 | T7aj29XNf3iMAKsNjxA1ey3EqGursoGR0UzlUaXwPccblKaUnFIawVZVneO1Hcoe 16 | jbwbqESGHgMEeiZfEWInsJ8Vd/L8DxJPTjoths8OGb1/o8bNFe9ZvuOLXxZt5VpZ 17 | 1/y4YMRg8FWn8pR9+EyszLQzDPnnC5Q7Z5fhX957M7O5XxgbKoBnbH21MXptSAfv 18 | ++w94GSopQNXU4EmlT3C3bcMYwlE+ryovWt/ySM4vOHt3XAH6Yc25MIxpIwZA/JT 19 | X7Yk6jIlt3x4V2vPE7AqbB8eg0d4/uzCrxkw+OGgP3jZtdo/SWJGT/8j4i9145gg 20 | Ff/tCH3trf5+nWSLhEln2hLxGmUtPuNlEQ64X9qOm4uxFQIDAQABo1AwTjAdBgNV 21 | HQ4EFgQUDxKDVBW9F8mKWV91HeHU/zqvHoIwHwYDVR0jBBgwFoAUDxKDVBW9F8mK 22 | WV91HeHU/zqvHoIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAwvOB 23 | cNMJcqfHhk1zUhMKkMBpFpjmlz/YinrxddseOKgv2kwGSq9zm//J8sNJcmJbOPW4 24 | w0H2D+7Y/5aioRWpRz23fc5ycstQHT/Srw8yTKSASeu2yrpbCTKV+o3EwTWfu5YR 25 | 9JYJe3Po1cFr5qsAu80IFJRQnu5+xr8lhP7rbWcFiiCnbnvksU47GeYBnQ+y1Ka+ 26 | OPlZkg6av2cutBEhDOqCB/w5+uqM1D8IT392dzJvRPefKAlPzppcOzrGgV4HuA80 27 | fjVVeuvXr7HhLR8yzq6y4cTYFQ3VxEEnUKOwkEiyTeAMjPjxGVhgPHtcw0S8k7v/ 28 | W7Y2qrmBoHMI7LAEq7L72ivhH9cvwbie3zBVg3HF5Etq/M8s7DZCBGzdvVhSQ0wT 29 | 2mTGYlC/ANqyvis/MKw4RJ+OsLHXYeBYTqMUPi99mtln6A+r49VeZ/7cU+/tFO6c 30 | yh2SQ0nT9xgqR2yPzcFDlmmKO/JcreSzRqxQq18VD3WrAIJV7qWF4OBaqS7wThy9 31 | O0f/xd0cLfHaADr9lWpU2F5uV1ZkjG8TXKNLPUIC6D9SqENB93ks7dYs01DManOn 32 | jvUcB/+kK28qeiA17z2TlPllglLr2T9MDa6O3F2crbwDWjwuWp6cus8BNerbdUrj 33 | /n2gCnpF8KMxxHN1w3B1L7h1zg2DwjlBtqA80Nc= 34 | -----END CERTIFICATE----- 35 | -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-datatables.css: -------------------------------------------------------------------------------- 1 | .hxtool_datatables_buttons { 2 | position: absolute; 3 | right: 0; 4 | margin-top: -45px; 5 | margin-right: 12px; 6 | } 7 | 8 | .hxtool_datatables_popup_buttons { 9 | position: absolute; 10 | right: 0; 11 | margin-top: -42px; 12 | } 13 | 14 | 15 | .dt-button { 16 | font-size: 12px; 17 | font-weight: bold; 18 | line-height: 100%; 19 | text-transform: uppercase; 20 | background: rgba(255, 255, 255, 0.2) !important; 21 | color: rgba(255, 255, 255, 0.9) !important; 22 | border-color: #0000 !important; 23 | border-radius: 0 !important; 24 | padding: 5px !important; 25 | } 26 | 27 | .dt-button:hover, .dt-button:focus, .dt-button.focus { 28 | background-color: rgba(255, 255, 255, 0.5) !important; 29 | color: rgba(255, 255, 255, 1.0) !important; 30 | border-color: rgba(255, 255, 255, 0.1) !important; 31 | } 32 | 33 | .dt-button-info { 34 | background: rgb(31, 31, 31) !important; 35 | color: rgba(255, 255, 255, 0.9) !important; 36 | border: 1px solid rgba(255, 255, 255, 0.2) !important; 37 | } 38 | 39 | .dt-button-info h2 { 40 | background: #000000 !important; 41 | color: rgba(255, 255, 255, 0.9) !important; 42 | } 43 | 44 | .dataTables_filter { 45 | position: absolute; 46 | right: 0; 47 | margin-top: -47px; 48 | margin-right: 218px; 49 | font-family: 'Open Sans' 50 | font-size: 12px; 51 | font-weight: bold; 52 | } 53 | 54 | .dataTables_filter input { 55 | padding: 4px; 56 | font-weight: bold; 57 | display: inline-block; 58 | width: 120px; 59 | margin-left: 6px; 60 | } 61 | 62 | .dataTables_filter label { 63 | font-size: 12px; 64 | } 65 | 66 | .dataTables_paginate { 67 | text-align: right; 68 | font-family: 'Open Sans'; 69 | margin-top: 12px; 70 | margin-bottom: 12px; 71 | } 72 | 73 | .paginate_button { 74 | line-height: 100%; 75 | font-size: 10px; 76 | font-weight: bold; 77 | text-transform: uppercase; 78 | background: rgba(255, 255, 255, 0.2) !important; 79 | border-color: #0000 !important; 80 | border-radius: 0 !important; 81 | padding: 5px !important; 82 | margin-right: 6px; 83 | } 84 | 85 | .disabled { 86 | color: rgba(255, 255, 255, 0.3) !important; 87 | } 88 | 89 | .paginate_button:hover { 90 | cursor: pointer; 91 | } 92 | -------------------------------------------------------------------------------- /scripts/w32drivers-signature.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | application/vnd.mandiant.host+xml 5 | 6 | 7 | application/vnd.mandiant.auditresult+xml 8 | 9 | 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | HXTool™ Software License 2.0 2 | 3 | 4 | Copyright © 2017 - 2020 by FireEye, Inc. All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files made available with this software (the "Software") to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | • The above copyright notice, this permission notice, and the following provisions shall be included in all copies or substantial portions of the Software. 9 | • You agree to be bound to any and all license provisions applicable to third-party software, if any, contained in the Software. 10 | • You give the authors, copyright holder, and others the right to freely use any of your ideas, comments, suggestions, or modifications pertaining to the Software or its use that you choose to disclose. 11 | • You shall not use the trade names, trademarks, service marks, or product names of the Licensor (including, without limitation, HXTool), except HXTool may be used (i) as required for reasonable and customary use in describing the origin of the Software, and (ii) in connection with or referring to the original Software that is not modified by you. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, TITLE, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY SUPPORT OR MAINTENANCE OF THE SOFTWARE, ITS INTEGRATION OR COMPATIBILITY WITH OTHER PRODUCTS, ANY ERROR, DEFECT OR VULNERABILITY IN THE SOFTWARE, OR ANY CLAIM, DAMAGES (INCLUDING BUT NOT LIMITED TO DIRECT, INDIRECT, SPECIAL, EXEMPLARY, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER), OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF, INABILITY TO USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF ADVISED OF THE POSSBILITY OF SUCH DAMAGES. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR DEALING IN THE SOFTWARE, AND ASSUME ANY RISKS ASSOCIATED WITH YOUR EXERCISE OF PERMISSIONS UNDER THIS LICENSE. -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-scriptbuilder.css: -------------------------------------------------------------------------------- 1 | .hxtool_scriptbuilder_scriptarea { 2 | height: calc(100vh - 580px); 3 | overflow-y: auto; 4 | padding-right: 12px; 5 | padding-top: 6px; 6 | } 7 | 8 | .auditParameterPlaceholder { 9 | margin-top: 12px; 10 | } 11 | 12 | .auditParameterTitleOptional { 13 | font-family: "Open Sans"; 14 | font-size: 14px; 15 | font-weight: 700; 16 | -webkit-font-smoothing: antialiased; 17 | margin-bottom: 4px; 18 | } 19 | 20 | .auditParameterTitle { 21 | font-family: "Open Sans"; 22 | font-size: 14px; 23 | font-weight: 700; 24 | -webkit-font-smoothing: antialiased; 25 | margin-bottom: 4px; 26 | } 27 | 28 | .auditDescription { 29 | font-family: "Open Sans"; 30 | font-size: 12px; 31 | font-weight: 400; 32 | -webkit-font-smoothing: antialiased; 33 | } 34 | 35 | .auditName { 36 | font-family: "Open Sans"; 37 | font-size: 16px; 38 | text-transform: capitalize; 39 | font-weight: 700; 40 | -webkit-font-smoothing: antialiased; 41 | margin-bottom: 12px; 42 | border-bottom: 1px solid rgba(255, 255, 255, 0.2); 43 | } 44 | 45 | .auditNameUUID { 46 | font-family: "Open Sans"; 47 | font-size: 12px; 48 | font-weight: 600; 49 | -webkit-font-smoothing: antialiased; 50 | margin-bottom: 12px; 51 | display: none; 52 | } 53 | 54 | .tabMenu { 55 | padding: 0; 56 | } 57 | 58 | .tabMenu li { 59 | border: 0.5px solid rgba(255, 255, 255, 0.1); 60 | color: rgba(255, 255, 255, 0.8); 61 | background: rgba(255, 255, 255, 0.2); 62 | padding: 3px; 63 | margin-bottom: 4px; 64 | font-family: "Open Sans"; 65 | font-size: 12px; 66 | font-weight: 700; 67 | -webkit-font-smoothing: antialiased; 68 | text-transform: uppercase; 69 | } 70 | 71 | .tabMenu li:hover { 72 | background: rgba(255, 255, 255, 0.5); 73 | cursor: pointer; 74 | } 75 | 76 | .auditContent { 77 | padding-left: 8px; 78 | } 79 | 80 | .auditRemove { 81 | float: right; 82 | margin-top: -40px; 83 | margin-bottom: 4px; 84 | } 85 | 86 | .auditRemove:hover { 87 | background: rgba(255, 255, 255, 0.5); 88 | cursor: pointer; 89 | } 90 | 91 | .auditParameterRemove { 92 | margin-left: 6px; 93 | font-size: 10px; 94 | line-height: 12px; 95 | height: 16px; 96 | float: right; 97 | } 98 | 99 | .auditParameterRemove:hover { 100 | color: #b20032; 101 | cursor: pointer; 102 | } 103 | 104 | .auditParameterPlaceholder { 105 | margin-top: 12px; 106 | } 107 | 108 | 109 | -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-grid.css: -------------------------------------------------------------------------------- 1 | .dash-grid-container { 2 | display: grid; 3 | height: 90vh; 4 | grid-template-columns: 1fr; 5 | grid-template-rows: 1fr 1fr 1fr; 6 | margin: 12px; 7 | } 8 | 9 | .top { 10 | display: grid; 11 | grid-area: 1 / 1 / 2 / 2; 12 | grid-template-columns: 1fr 1fr 1fr; 13 | grid-template-rows: 1fr; 14 | grid-gap: 0 12px; 15 | padding-bottom: 12px; 16 | } 17 | 18 | .cell1 { 19 | grid-area: 1 / 1 / 2 / 2; 20 | } 21 | 22 | .cell2 { 23 | grid-area: 1 / 2 / 2 / 3; 24 | } 25 | 26 | .cell3 { 27 | grid-area: 1 / 3 / 2 / 4; 28 | } 29 | 30 | .middle { 31 | display: grid; 32 | grid-area: 2 / 1 / 3 / 2; 33 | grid-template-columns: 2fr 1fr; 34 | grid-template-rows: 1fr; 35 | grid-gap: 0 12px; 36 | padding-bottom: 12px; 37 | } 38 | 39 | .cell4 { 40 | grid-area: 1 / 1 / 2 / 2; 41 | } 42 | 43 | .cell5 { 44 | padding-left: 4px; 45 | grid-area: 1 / 2 / 2 / 3; 46 | } 47 | 48 | .cell6 { 49 | grid-area: 3 / 1 / 4 / 2; 50 | } 51 | 52 | 53 | /* AV dashboard */ 54 | 55 | .avdash-grid-container { 56 | display: grid; 57 | grid-template-columns: 1fr 1fr 1fr; 58 | grid-template-rows: 0.7fr 1fr; 59 | grid-template-areas: "avcell1 avcell2 avcell3" "avtable avtable avtable"; 60 | margin: 12px; 61 | height: 90vh; 62 | } 63 | 64 | .avtable { grid-area: avtable; padding-top: 12px; } 65 | 66 | .avcell1 { grid-area: avcell1; padding-right: 12px;} 67 | 68 | .avcell2 { grid-area: avcell2; padding-right: 12px;} 69 | 70 | .avcell3 { grid-area: avcell3; } 71 | 72 | /* Agent dashboard */ 73 | 74 | .agentdash-grid-container { 75 | display: grid; 76 | grid-template-columns: 1fr 1fr 1fr; 77 | grid-template-rows: 1fr 1fr 1fr; 78 | grid-template-areas: "agentcell1 agentcell2 agentcell3" "agentcell4 agentcell5 agentcell6" "agentcell7 agentcell8 agentcell8"; 79 | margin: 12px; 80 | height: 90vh; 81 | } 82 | 83 | .agentcell1 { grid-area: agentcell1; padding-right: 12px;} 84 | 85 | .agentcell2 { grid-area: agentcell2; padding-right: 12px;} 86 | 87 | .agentcell3 { grid-area: agentcell3; } 88 | 89 | .agentcell4 { grid-area: agentcell4; padding-right: 12px; padding-top: 12px;} 90 | 91 | .agentcell5 { grid-area: agentcell5; padding-right: 12px; padding-top: 12px;} 92 | 93 | .agentcell6 { grid-area: agentcell6; padding-top: 12px;} 94 | 95 | .agentcell7 { grid-area: agentcell7; padding-right: 12px; padding-top: 12px;} 96 | 97 | .agentcell8 { grid-area: agentcell8; padding-top: 12px;} 98 | 99 | 100 | -------------------------------------------------------------------------------- /hxtool_task_modules/file_listing_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | import hxtool_global 7 | from .task_module import * 8 | from hxtool_data_models import * 9 | from hx_audit import * 10 | 11 | class file_listing_task_module(task_module): 12 | def __init__(self, parent_task): 13 | super(type(self), self).__init__(parent_task) 14 | 15 | @staticmethod 16 | def input_args(): 17 | return [ 18 | { 19 | 'name' : 'bulk_download_eid', 20 | 'type' : int, 21 | 'required' : True, 22 | 'user_supplied' : False, 23 | 'description' : "The document ID of the bulk download job." 24 | }, 25 | { 26 | 'name' : 'host_name', 27 | 'type' : str, 28 | 'required' : True, 29 | 'user_supplied' : False, 30 | 'description' : "The host name of this bulk acquisition package." 31 | }, 32 | { 33 | 'name' : 'bulk_download_path', 34 | 'type' : str, 35 | 'required' : True, 36 | 'user_supplied' : False, 37 | 'description' : "The fully qualified path to the bulk acquisition package." 38 | }, 39 | { 40 | 'name' : 'delete_bulk_download', 41 | 'type' : bool, 42 | 'required' : False, 43 | 'user_supplied' : True, 44 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 45 | } 46 | ] 47 | 48 | @staticmethod 49 | def output_args(): 50 | return [] 51 | 52 | 53 | def run(self, bulk_download_eid = None, host_name = None, bulk_download_path = None, delete_bulk_download = False): 54 | ret = False 55 | result = {} 56 | try: 57 | file_listing = hxtool_global.hxtool_db.fileListingGetByBulkId(self.parent_task.profile_id, bulk_download_eid) 58 | generator = 'files-raw' 59 | if file_listing and 'api_mode' in file_listing['cfg'] and file_listing['cfg']['api_mode']: 60 | generator = 'files-api' 61 | with AuditPackage(bulk_download_path) as audit_pkg: 62 | audit_data = audit_pkg.get_audit(generator = generator, open_only=True) 63 | if audit_data: 64 | files = get_audit_records(audit_data, generator, 'FileItem', hostname=host_name) 65 | if files: 66 | hxtool_global.hxtool_db.fileListingAddResult(self.parent_task.profile_id, bulk_download_eid, files) 67 | self.logger.debug("File Listing added to the database. bulk job: {0} host: {1}".format(bulk_download_eid, host_name)) 68 | ret = True 69 | else: 70 | self.logger.warn("File Listing: No audit data for {} from bulk download job {}".format(host_name, bulk_download_eid)) 71 | audit_data.close() 72 | 73 | except Exception as e: 74 | self.logger.error(pretty_exceptions(e)) 75 | finally: 76 | return(ret, result) -------------------------------------------------------------------------------- /hxtool_task_modules/mongodb_ingest_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import json 6 | 7 | import hxtool_global 8 | from .task_module import * 9 | from hx_audit import * 10 | from hxtool_util import * 11 | 12 | class mongodb_ingest_task_module(task_module): 13 | def __init__(self, parent_task): 14 | super(type(self), self).__init__(parent_task) 15 | 16 | @staticmethod 17 | def input_args(): 18 | return [ 19 | { 20 | 'name' : 'host_name', 21 | 'type' : str, 22 | 'required' : True, 23 | 'user_supplied' : False, 24 | 'description' : "The host name belonging to the bulk acquisition package." 25 | }, 26 | { 27 | 'name' : 'agent_id', 28 | 'type' : str, 29 | 'required' : False, 30 | 'user_supplied' : False, 31 | 'description' : "The host/agent ID of the bulk acquisition to download." 32 | }, 33 | { 34 | 'name' : 'bulk_download_path', 35 | 'type' : str, 36 | 'required' : True, 37 | 'user_supplied' : False, 38 | 'description' : "The fully qualified path to the bulk acquisition package." 39 | }, 40 | { 41 | 'name' : 'bulk_acquisition_id', 42 | 'type' : int, 43 | 'required' : True, 44 | 'description' : "The bulk acquisition ID assigned to the bulk acquisition job by the controller." 45 | }, 46 | { 47 | 'name' : 'batch_mode', 48 | 'type' : bool, 49 | 'required' : False, 50 | 'user_supplied' : True, 51 | 'description' : "Flag whether to batch each audit as single JSON object versus sending each record as a separate object. Defaults to False" 52 | }, 53 | { 54 | 'name' : 'delete_bulk_download', 55 | 'type' : bool, 56 | 'required' : False, 57 | 'user_supplied' : True, 58 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 59 | } 60 | ] 61 | 62 | @staticmethod 63 | def output_args(): 64 | return [] 65 | 66 | def run(self, host_name = None, agent_id = None, bulk_download_path = None, bulk_acquisition_id = None, batch_mode = False, delete_bulk_download = False): 67 | ret = False 68 | result = {} 69 | try: 70 | if bulk_download_path: 71 | for audit_object in self.yield_audit_results(bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = bulk_acquisition_id): 72 | hxtool_global.hxtool_db.auditInsert(audit_object) 73 | ret = True 74 | if ret and delete_bulk_download: 75 | os.remove(os.path.realpath(bulk_download_path)) 76 | 77 | else: 78 | self.logger.error("bulk_download_path is empty!") 79 | except Exception as e: 80 | self.logger.error(pretty_exceptions(e)) 81 | finally: 82 | return(ret, result) -------------------------------------------------------------------------------- /static/multi-select.css: -------------------------------------------------------------------------------- 1 | .ms-container{ 2 | background: transparent url('../img/switch.png') no-repeat 50% 50%; 3 | width: 370px; 4 | } 5 | 6 | .ms-container:after{ 7 | content: "."; 8 | display: block; 9 | height: 0; 10 | line-height: 0; 11 | font-size: 0; 12 | clear: both; 13 | min-height: 0; 14 | visibility: hidden; 15 | } 16 | 17 | .ms-container .ms-selectable, .ms-container .ms-selection{ 18 | background: #fff; 19 | color: #555555; 20 | float: left; 21 | width: 45%; 22 | } 23 | .ms-container .ms-selection{ 24 | float: right; 25 | } 26 | 27 | .ms-container .ms-list{ 28 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 29 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 30 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 31 | -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; 32 | -moz-transition: border linear 0.2s, box-shadow linear 0.2s; 33 | -ms-transition: border linear 0.2s, box-shadow linear 0.2s; 34 | -o-transition: border linear 0.2s, box-shadow linear 0.2s; 35 | transition: border linear 0.2s, box-shadow linear 0.2s; 36 | border: 1px solid #ccc; 37 | -webkit-border-radius: 0px; 38 | -moz-border-radius: 0px; 39 | border-radius: 0px; 40 | position: relative; 41 | height: 200px; 42 | padding: 0; 43 | overflow-y: auto; 44 | } 45 | 46 | .ms-container .ms-list.ms-focus{ 47 | border-color: rgba(82, 168, 236, 0.8); 48 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 49 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 50 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 51 | outline: 0; 52 | outline: thin dotted \9; 53 | } 54 | 55 | .ms-container ul{ 56 | margin: 0; 57 | list-style-type: none; 58 | padding: 0; 59 | } 60 | 61 | .ms-container .ms-optgroup-container{ 62 | width: 100%; 63 | } 64 | 65 | .ms-container .ms-optgroup-label{ 66 | margin: 0; 67 | padding: 5px 0px 0px 5px; 68 | cursor: pointer; 69 | color: #999; 70 | } 71 | 72 | .ms-container .ms-selectable li.ms-elem-selectable, 73 | .ms-container .ms-selection li.ms-elem-selection{ 74 | border-bottom: 1px #eee solid; 75 | padding: 2px 10px; 76 | color: #555; 77 | font-size: 14px; 78 | } 79 | 80 | .ms-container .ms-selectable li.ms-hover, 81 | .ms-container .ms-selection li.ms-hover{ 82 | cursor: pointer; 83 | color: #fff; 84 | text-decoration: none; 85 | background-color: #08c; 86 | } 87 | 88 | .ms-container .ms-selectable li.disabled, 89 | .ms-container .ms-selection li.disabled{ 90 | background-color: #eee; 91 | color: #aaa; 92 | cursor: text; 93 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HXTool 2 | 3 | ## Summary 4 | HXTool is a web-based, standalone tool that can be used with Trellix Endpoint Security (HX). 5 | 6 | HXTool provides additional features not directly available in the product by leveraging Trellix Endpoint Security (HX)'s rich API. 7 | 8 | ### Version 9 | 4.8-pre 10 | 11 | ## Installation 12 | To install HXTool: 13 | 1. Ensure that you have a working Python installation, see the [Dependencies](#dependencies) section below for version requirements. 14 | 2. Unzip the distribution archive; Or, if you have code repository access, fetch the repo and place the files in a directory. 15 | 2. Install HXTool's dependencies by running `pip install -r requirements.txt` from your operating system's command shell. 16 | - On Windows systems, `pip.exe` can be found in the "scripts" folder under your Python installation directory. 17 | 3. After installing the dependencies, run `python hxtool.py` from your operating system's command shell and the server will start listening to tcp port 8080 (HTTPS). 18 | - Alternatively, on Windows, you should be able to double-click on the `hxtool.py` file. 19 | 4. Access the web user interface via a browser: https://127.0.0.1:8080 (tested with Google Chrome and Mozilla Firefox) 20 | 5. You will need an account on the Endpoint Security (HX) controller that has either the `api_admin` or `api_analyst` role. 21 | 6. Don't forget to set the Background Processing credentials under Admin --> HXTool Settings. These credentials are used by the scheduler, and can be the same as what you have logged in with, or a separate set. 22 | 23 | ### Dependencies 24 | Python 3.6+ 25 | 26 | Full dependency list available in [requirements.txt](requirements.txt). 27 | 28 | Optionally, the [pymongo](https://pypi.org/project/pymongo/) library may be installed for additional database functionality. 29 | 30 | ### Configuration 31 | Configuration for HXTool is held in the `conf.json` file, documentation is in [README.CONFIG](README.CONFIG). 32 | 33 | ### Docker 34 | To build a Docker image from the HXTool source, execute the following: 35 | ```bash 36 | docker build --pull -t hxtool:latest . 37 | ``` 38 | 39 | To run HXTool once the image build process is complete, execute the following: 40 | ```bash 41 | docker run -p 8080:8080/tcp -d --cap-add=IPC_LOCK --name hxtool hxtool:latest 42 | ``` 43 | IPC_LOCK is needed for the GNOME keyring daemon. See [README.DOCKER](README.DOCKER) 44 | 45 | ## Contribution 46 | 47 | ### Guidelines 48 | None so far 49 | 50 | ### Who do I talk to? 51 | * [Henrik Olsson](mailto:henrik.olsson@trellix.com) 52 | 53 | ### Contributors 54 | * [Elazar Broad](mailto:elazar.broad@trellix.com) 55 | * [Matthew Briggs](mailto:matthew.briggs@trellix.com) 56 | * [Martin Holste](mailto:martin.holste@trellix.com) 57 | -------------------------------------------------------------------------------- /pytests/test_flask.py: -------------------------------------------------------------------------------- 1 | from hxtool import app, hxtool_run_main, app_init_1, hxtool_global 2 | import unittest 3 | 4 | class FlaskSimpleTests(unittest.TestCase): 5 | 6 | client = None 7 | profileName = 'unit_TEST_profile' 8 | hx_host = '10.61.152.126' 9 | profile_id = None 10 | 11 | @classmethod 12 | def setUpClass(cls): 13 | # Flask initialization 14 | app.testing = True 15 | cls.client = app.test_client() 16 | # special HXTool initialization 17 | app_init_1(True) 18 | # clean up any dirt from prior tests 19 | cls.removeProfile() 20 | 21 | @classmethod 22 | def tearDownClass(cls): 23 | cls.removeProfile() 24 | 25 | def setUp(self): 26 | pass 27 | 28 | def tearDown(self): 29 | pass 30 | 31 | def test_verifyAccessToHomePage(self): 32 | assert FlaskSimpleTests.client != None 33 | response = FlaskSimpleTests.client.get('/', follow_redirects=True) 34 | self.assertEqual(response.status_code, 200) 35 | 36 | def test_verifyUnitTestControllerProfileCreate(self): 37 | FlaskSimpleTests.createProfile() 38 | self.assertIsNotNone(FlaskSimpleTests.profile_id) 39 | 40 | def test_verifyLogin(self): 41 | FlaskSimpleTests.createProfile() 42 | response = FlaskSimpleTests.client.post( 43 | '/login', 44 | data=dict( 45 | ht_user='api_admin', 46 | ht_pass='dev3rd25!', 47 | controllerProfileDropdown=FlaskSimpleTests.profile_id 48 | ), 49 | follow_redirects=True 50 | ) 51 | self.assertEqual(response.status_code, 200) 52 | 53 | 54 | @classmethod 55 | def createProfile(cls): 56 | if not FlaskSimpleTests.profile_id: 57 | #create the controller profile for unit testing 58 | hxtool_global.hxtool_db.profileCreate( 59 | hx_name=FlaskSimpleTests.profileName, 60 | hx_host=FlaskSimpleTests.hx_host, 61 | hx_port='3000') 62 | cls.profile_id = cls.getProfileId() 63 | 64 | @classmethod 65 | def removeProfile(cls): 66 | if hxtool_global.hxtool_db: 67 | # remove all instances of the unit test profile from the db 68 | for profile in hxtool_global.hxtool_db.profileList(): 69 | if profile['hx_name'] == cls.profileName: 70 | hxtool_global.hxtool_db.profileDelete(profile_id=profile['profile_id']) 71 | 72 | @classmethod 73 | # Return the profile_id of our unit test profile 74 | def getProfileId(cls): 75 | for profile in hxtool_global.hxtool_db.profileList(): 76 | if profile['hx_name'] == cls.profileName: 77 | return profile['profile_id'] 78 | return None 79 | -------------------------------------------------------------------------------- /hxtool_task_modules/task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import hxtool_logging 5 | from hx_lib import * 6 | from hx_audit import * 7 | from hxtool_util import * 8 | 9 | class task_module(object): 10 | MAX_RETRY = 10 11 | 12 | # TODO: parent_task should probably be renamed to just task, as modules are associated with tasks 13 | # and this confuses the parent/child task relationship. 14 | def __init__(self, task): 15 | self.parent_task = task 16 | self.logger = hxtool_logging.getLogger(__name__) 17 | self.enabled = True 18 | self.retry_count = 0 19 | 20 | def get_task_api_object(self): 21 | s = self.parent_task.scheduler.task_hx_api_sessions.get(self.parent_task.profile_id, None) 22 | if s is not None and s.restIsSessionValid(): 23 | return s 24 | else: 25 | self.logger.error("There is no valid background task API session for profile {}".format(self.parent_task.profile_id)) 26 | return None 27 | 28 | def can_retry(self, err): 29 | return('connection' in str(type(err)).lower() and self.retry_count < task_module.MAX_RETRY) 30 | 31 | def yield_audit_results(self, bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = None): 32 | hx_host = None 33 | api_object = self.get_task_api_object() 34 | if api_object: 35 | hx_host = api_object.hx_host 36 | api_object = None 37 | 38 | with AuditPackage(bulk_download_path) as audit_package: 39 | for audit in audit_package.audits: 40 | try: 41 | for audit_object in audit_package.audit_to_dict(audit, host_name, agent_id = agent_id, batch_mode = batch_mode): 42 | audit_object.update({ 43 | 'hx_host' : hx_host, 44 | 'bulk_acquisition_id' : bulk_acquisition_id 45 | }) 46 | yield audit_object 47 | except EmptyAuditException as e: 48 | self.logger.warning(e) 49 | 50 | # Input and output args are a list of dictionary objects containing the following five keys: name, type, required user_supplied, and description 51 | # these define the modules inputs and outputs, for example: 52 | # @staticmethod 53 | # def input_args(): 54 | # return [ {'name' : 'foo', 'type' : str, 'required' : True, 'user_supplied' : True, 'description' : "Foo argument"} ] 55 | # 56 | @staticmethod 57 | def input_args(): 58 | raise NotImplementedError("You must define a list of arguments that your module's run() function requires!") 59 | 60 | @staticmethod 61 | def output_args(): 62 | raise NotImplementedError("You must define a list of arguments that your module will output!") 63 | 64 | # Note: function return must be a tuple of (boolean, result) 65 | def run(self, **kwargs): 66 | raise NotImplementedError("You must override run() in your task module.") 67 | 68 | # Used by the task scheduler to signal that we are an HXTool Task Module 69 | @staticmethod 70 | def hxtool_task_module(): 71 | return True -------------------------------------------------------------------------------- /static/hxtool-js/hxtool-generic.js: -------------------------------------------------------------------------------- 1 | function hxtool_ajax_post_request(endpoint, mydata, successCallback, contentType=false) { 2 | $.ajax 3 | ({ 4 | type: "POST", 5 | url: endpoint, 6 | dataType: 'json', 7 | contentType: contentType, 8 | processData: false, 9 | data: mydata, 10 | success: successCallback, 11 | error: hxtoolActionFail 12 | }) 13 | } 14 | 15 | function hxtool_ajax_get_request(endpoint, myargs, successCallback) { 16 | $.ajax 17 | ({ 18 | url: endpoint, 19 | dataType: 'json', 20 | contentType: 'application/json', 21 | data: myargs, 22 | success: successCallback, 23 | error: hxtoolActionFail 24 | }) 25 | } 26 | 27 | function hxtoolActionFail(xhr,status,error) { 28 | $("#hxtoolMessageBody").html(JSON.stringify(xhr['responseText'])); 29 | $("#hxtoolMessage").show(); 30 | } 31 | 32 | 33 | function getHistoricDate(days) { 34 | var historicDate = new Date(); 35 | historicDate.setDate(historicDate.getDate() - days); 36 | return(historicDate.toISOString().substr(0, 10)) 37 | } 38 | 39 | function updateChartJS(name, url) { 40 | var jsonData = $.ajax({ 41 | url: url, 42 | dataType: 'json', 43 | }).done(function (myChartData) { 44 | name.data = myChartData; 45 | name.options.animation.duration = 0; 46 | name.update(); 47 | }); 48 | } 49 | 50 | var getUrlParameter = function getUrlParameter(sParam) { 51 | var sPageURL = window.location.search.substring(1), 52 | sURLVariables = sPageURL.split('&'), 53 | sParameterName, 54 | i; 55 | 56 | for (i = 0; i < sURLVariables.length; i++) { 57 | sParameterName = sURLVariables[i].split('='); 58 | 59 | if (sParameterName[0] === sParam) { 60 | return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); 61 | } 62 | } 63 | }; 64 | 65 | function hxtoolGenerateNestedTable(myData) { 66 | var r = "
"; 67 | r += ""; 68 | $.each( myData, function( index, value ) { 69 | r += ""; 70 | r += ""; 71 | r += ""; 79 | r += ""; 80 | }); 81 | r += ""; 82 | r += "
" + index + ""; 72 | if (isObject(value)) { 73 | r += hxtoolGenerateNestedTable(value); 74 | } 75 | else { 76 | r += value; 77 | } 78 | r += "
"; 83 | return(r); 84 | } 85 | 86 | function hxtoolGenerateNestedObjectView(myData) { 87 | var r = ""; 88 | console.log(myData); 89 | $.each( myData, function( index, value ) { 90 | r += "
"; 91 | r += index + ": "; 92 | if (isObject(value)) { 93 | hxtoolGenerateNestedObjectView(value); 94 | } 95 | else { 96 | r += value; 97 | } 98 | r += "
"; 99 | }); 100 | } 101 | 102 | function isObject(obj) { 103 | return obj === Object(obj); 104 | } 105 | -------------------------------------------------------------------------------- /hxtool_task_modules/file_acquisition_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import time 6 | 7 | import hxtool_global 8 | from .task_module import * 9 | from hxtool_util import * 10 | 11 | class file_acquisition_task_module(task_module): 12 | def __init__(self, parent_task): 13 | super(type(self), self).__init__(parent_task) 14 | 15 | @staticmethod 16 | def input_args(): 17 | return [ 18 | { 19 | 'name' : 'multi_file_eid', 20 | 'type' : int, 21 | 'required' : True, 22 | 'user_supplied' : False, 23 | 'description' : "The document ID of the multi-file download job." 24 | }, 25 | { 26 | 'name' : 'file_acquisition_id', 27 | 'type' : int, 28 | 'required' : True, 29 | 'user_supplied' : False, 30 | 'description' : "The ID assigned to the file acquisition by the controller." 31 | }, 32 | { 33 | 'name' : 'host_name', 34 | 'type' : str, 35 | 'required' : True, 36 | 'user_supplied' : False, 37 | 'description' : "The host name of this file acquisition package." 38 | } 39 | ] 40 | 41 | @staticmethod 42 | def output_args(): 43 | return [] 44 | 45 | def run(self, multi_file_eid = None, file_acquisition_id = None, host_name = None): 46 | ret = False 47 | result = {} 48 | try: 49 | hx_api_object = self.get_task_api_object() 50 | if hx_api_object: 51 | self.logger.debug("Processing multi file acquisition job: {0}.".format(multi_file_eid)) 52 | download_directory = make_download_directory(hx_api_object.hx_host, multi_file_eid, job_type = 'multi_file') 53 | (ret, response_code, response_data) = hx_api_object.restFileAcquisitionById(file_acquisition_id) 54 | if ret and response_data and response_data['data']['state'] == "COMPLETE" and response_data['data']['url']: 55 | self.logger.debug("Processing multi file acquisition host: {0}".format(host_name)) 56 | full_path = os.path.join(download_directory, get_download_filename(host_name, file_acquisition_id)) 57 | (ret, response_code, response_data) = hx_api_object.restDownloadFile('{}.zip'.format(response_data['data']['url']), full_path) 58 | if ret: 59 | hxtool_global.hxtool_db.multiFileUpdateFile(self.parent_task.profile_id, multi_file_eid, file_acquisition_id) 60 | self.logger.info("File Acquisition download complete. Acquisition ID: {0}, Batch: {1}".format(file_acquisition_id, multi_file_eid)) 61 | elif response_code == 404: 62 | self.logger.error("File acquisition ID: {} not found on the controller.".format(file_acquisition_id)) 63 | self.parent_task.stop() 64 | else: 65 | self.logger.debug("Deferring file acquisition for: {}".format(host_name)) 66 | self.parent_task.defer() 67 | else: 68 | self.logger.warn("No task API session for profile: {}".format(self.parent_task.profile_id)) 69 | except Exception as e: 70 | self.logger.error(e) 71 | finally: 72 | return(ret, result) -------------------------------------------------------------------------------- /hxtool_task_modules/enterprise_search_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import hxtool_global 5 | from .task_module import * 6 | from hx_lib import * 7 | 8 | class enterprise_search_task_module(task_module): 9 | def __init__(self, parent_task): 10 | super(type(self), self).__init__(parent_task) 11 | 12 | @staticmethod 13 | def input_args(): 14 | return [ 15 | { 16 | 'name' : 'script', 17 | 'type' : str, 18 | 'required' : True, 19 | 'user_supplied' : True, 20 | 'description' : "The OpenIOC 1.1 formatted script to utilize." 21 | }, 22 | { 23 | 'name' : 'hostset_id', 24 | 'type' : int, 25 | 'required' : True, 26 | 'user_supplied' : True, 27 | 'description' : "The ID of the host set to execute the script against." 28 | }, 29 | { 30 | 'name' : 'ignore_unsupported_items', 31 | 'type' : bool, 32 | 'required' : False, 33 | 'user_supplied' : True, 34 | 'description' : "Specifies whether to instruct the HX controller to ignore unsupported items in the script. Defaults to False" 35 | }, 36 | { 37 | 'name' : 'skip_base64', 38 | 'type' : bool, 39 | 'required' : False, 40 | 'user_supplied' : True, 41 | 'description' : "Specifies whether the contents of the script argument are already base64 encoded. Defaults to False" 42 | }, 43 | { 44 | 'name' : 'displayname', 45 | 'type' : str, 46 | 'required' : False, 47 | 'user_supplied' : True, 48 | 'description' : "Specifies the display name of the search. Defaults to False" 49 | } 50 | ] 51 | 52 | @staticmethod 53 | def output_args(): 54 | return [ 55 | { 56 | 'name' : 'enterprise_search_id', 57 | 'type' : int, 58 | 'required' : True, 59 | 'description' : "The Enterprise Search ID assigned to the search job by the controller." 60 | } 61 | ] 62 | 63 | def run(self, script = None, hostset_id = None, ignore_unsupported_items = False, skip_base64 = False, displayname = False): 64 | ret = False 65 | result = {} 66 | if script: 67 | hx_api_object = self.get_task_api_object() 68 | if hx_api_object and hx_api_object.restIsSessionValid(): 69 | (ret, response_code, response_data) = hx_api_object.restSubmitSweep(script, hostset_id, ignore_unsupported_items = ignore_unsupported_items, skip_base64 = skip_base64, displayname = displayname) 70 | if ret: 71 | result['enterprise_search_id'] = response_data['data']['_id'] 72 | self.parent_task.name = "Enterprise Search ID: {}".format(response_data['data']['_id']) 73 | self.logger.info("Enterprise Search ID: {} successfully submitted.".format(result['enterprise_search_id'])) 74 | else: 75 | self.logger.error("Enterprise Search submission failed. Response code: {}, response data: {}".format(response_code, response_data)) 76 | else: 77 | self.logger.warn("No task API session for profile: {}".format(self.parent_task.profile_id)) 78 | return(ret, result) -------------------------------------------------------------------------------- /static/spinner.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/ht_hostsearch.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Find a host{% endblock %} 3 | {% block navlocation %}Find a host{% endblock %} 4 | {% block content %} 5 | 6 | 73 | 74 | {{ htPanel.widgetHeader("Matching hosts", panelIcon="fa-desktop") }} 75 |
76 | {{ htPanel.widgetFooter() }} 77 | 78 | 79 | {% endblock %} 80 | -------------------------------------------------------------------------------- /hxtool_task_modules/stacking_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | import hxtool_global 7 | from .task_module import * 8 | from hxtool_data_models import * 9 | from hx_audit import * 10 | 11 | class stacking_task_module(task_module): 12 | def __init__(self, parent_task): 13 | super(type(self), self).__init__(parent_task) 14 | 15 | @staticmethod 16 | def input_args(): 17 | return [ 18 | { 19 | 'name' : 'bulk_download_eid', 20 | 'type' : int, 21 | 'required' : True, 22 | 'user_supplied' : False, 23 | 'description' : "The document ID of the bulk download job." 24 | }, 25 | { 26 | 'name' : 'host_name', 27 | 'type' : str, 28 | 'required' : True, 29 | 'user_supplied' : False, 30 | 'description' : "The host name of this bulk acquisition package." 31 | }, 32 | { 33 | 'name' : 'bulk_download_path', 34 | 'type' : str, 35 | 'required' : True, 36 | 'user_supplied' : False, 37 | 'description' : "The fully qualified path to the bulk acquisition package." 38 | }, 39 | { 40 | 'name' : 'delete_bulk_download', 41 | 'type' : bool, 42 | 'required' : False, 43 | 'user_supplied' : True, 44 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 45 | } 46 | ] 47 | 48 | @staticmethod 49 | def output_args(): 50 | return [] 51 | 52 | def run(self, bulk_download_eid = None, host_name = None, bulk_download_path = None, delete_bulk_download = False): 53 | try: 54 | ret = False 55 | if bulk_download_path: 56 | stack_job = hxtool_global.hxtool_db.stackJobGet(profile_id = self.parent_task.profile_id, bulk_download_eid = bulk_download_eid) 57 | stack_model = hxtool_data_models(stack_job['stack_type']).stack_type 58 | with AuditPackage(bulk_download_path) as audit_pkg: 59 | audit_data = audit_pkg.get_audit(generator=stack_model['audit_module'], open_only=True) 60 | if audit_data: 61 | records = get_audit_records(audit_data, stack_model['audit_module'], stack_model['item_name'], fields=stack_model['fields'], post_process=stack_model['post_process'], hostname=host_name) 62 | if records: 63 | hxtool_global.hxtool_db.stackJobAddResult(self.parent_task.profile_id, bulk_download_eid, host_name, records) 64 | self.logger.debug("Stacking records added to the database for host {}".format(host_name)) 65 | ret = True 66 | else: 67 | self.logger.warn("Stacking: No audit data for {}".format(host_name)) 68 | 69 | # Explicitly close 70 | audit_data.close() 71 | 72 | if ret and delete_bulk_download: 73 | try: 74 | os.remove(os.path.realpath(bulk_download_path)) 75 | except: 76 | self.logger.warn("Failed to remove {}".format(os.path.realpath(bulk_download_path))) 77 | 78 | else: 79 | self.logger.error("bulk_download_path is empty!") 80 | 81 | return(ret, None) 82 | except Exception as e: 83 | self.logger.error(pretty_exceptions(e)) 84 | return(False, None) -------------------------------------------------------------------------------- /scripts/w32processes-memory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | application/vnd.mandiant.host+xml 5 | 6 | 7 | application/vnd.mandiant.auditresult+xml 8 | 9 | 72 | -------------------------------------------------------------------------------- /templates/widget-schedule.html: -------------------------------------------------------------------------------- 1 | {% import 'widget-radio.html' as htRadio %} 2 | {% import 'widget-dropdown.html' as htDropdown %} 3 | {% import 'widget-input.html' as htInput %} 4 | 5 | {% macro widgetHeader() -%} 6 | 37 |

Schedule

38 |
39 | {{ htRadio.widgetHeader("Run now", "run_now", "schedule", "schedule", elementChecked="true") }} 40 |
41 | {{ htRadio.widgetHeader("Run at a specific date/time", "run_at", "schedule", "schedule", elementChecked="false") }} 42 |
43 |
44 | {{ htInput.widget("", elementId="run_at_value") }} 45 |
46 | {{ htRadio.widgetHeader("Run on an interval", "run_interval", "schedule", "schedule", elementChecked="false") }} 47 |
48 |
49 | {{ htInput.widget("Every", elementId="interval_value") }} 50 |
51 |
52 | {{ htDropdown.widgetHeader("Select an interval unit", "interval_unit", "false") }} 53 | {{ htDropdown.widgetItem("Second(s)", "second") }} 54 | {{ htDropdown.widgetItem("Minute(s)", "minute") }} 55 | {{ htDropdown.widgetItem("Hour(s)", "hour") }} 56 | {{ htDropdown.widgetItem("Week(s)", "week") }} 57 | {{ htDropdown.widgetItem("Month(s)", "month") }} 58 | {{ htDropdown.widgetFooter(elementLabel="") }} 59 |
60 |
61 |

Starting

62 |
63 | {{ htRadio.widgetHeader("Now", "interval_start_now", "interval_start", "interval_start", elementChecked="true") }} 64 |
65 | {{ htRadio.widgetHeader("At a specific date/time", "interval_start_at", "interval_start", "interval_start", elementChecked="false") }} 66 |
67 |
68 | {{ htInput.widget("", elementId="interval_start_value") }} 69 |
70 |
71 |
72 |
73 | {% endmacro %} -------------------------------------------------------------------------------- /templates/ht_search_dd.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Enterprise Search{% endblock %} 3 | {% block navlocation %}Enterprise Search - Drilldown{% endblock %} 4 | {% block content %} 5 | 6 | 68 | 69 | {{ htPanelNoHeader.widgetHeader(panelDisplay="inline-block") }} 70 | 71 | {{ htPanelNoHeader.widgetFooter() }} 72 | 73 | 74 |
75 | 76 | 77 | {% endblock %} 78 | -------------------------------------------------------------------------------- /hxtool_task_modules/file_write_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import json 6 | 7 | import hxtool_global 8 | from .task_module import * 9 | from hx_audit import * 10 | from hxtool_util import * 11 | 12 | class file_write_task_module(task_module): 13 | def __init__(self, parent_task): 14 | super(type(self), self).__init__(parent_task) 15 | 16 | @staticmethod 17 | def input_args(): 18 | return [ 19 | { 20 | 'name' : 'host_name', 21 | 'type' : str, 22 | 'required' : True, 23 | 'user_supplied' : False, 24 | 'description' : "The host name belonging to the bulk acquisition package." 25 | }, 26 | { 27 | 'name' : 'agent_id', 28 | 'type' : str, 29 | 'required' : False, 30 | 'user_supplied' : False, 31 | 'description' : "The host/agent ID of the bulk acquisition to download." 32 | }, 33 | { 34 | 'name' : 'bulk_download_path', 35 | 'type' : str, 36 | 'required' : True, 37 | 'user_supplied' : False, 38 | 'description' : "The fully qualified path to the bulk acquisition package." 39 | }, 40 | { 41 | 'name' : 'bulk_acquisition_id', 42 | 'type' : int, 43 | 'required' : True, 44 | 'description' : "The bulk acquisition ID assigned to the bulk acquisition job by the controller." 45 | }, 46 | { 47 | 'name' : 'batch_mode', 48 | 'type' : bool, 49 | 'required' : False, 50 | 'user_supplied' : True, 51 | 'description' : "Flag whether to batch each audit as single JSON object versus sending each record as a separate object. Defaults to False" 52 | }, 53 | { 54 | 'name' : 'delete_bulk_download', 55 | 'type' : bool, 56 | 'required' : False, 57 | 'user_supplied' : True, 58 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 59 | }, 60 | { 61 | 'name' : 'file_name', 62 | 'type' : str, 63 | 'required' : True, 64 | 'user_supplied' : True, 65 | 'description' : "The fully qualified path of the file to write to." 66 | } 67 | ] 68 | 69 | @staticmethod 70 | def output_args(): 71 | return [] 72 | 73 | def run(self, host_name = None, agent_id = None, bulk_download_path = None, bulk_acquisition_id = None, batch_mode = False, delete_bulk_download = False, file_name = None): 74 | ret = False 75 | result = {} 76 | try: 77 | if bulk_download_path: 78 | # TODO: Ultimately, this should be converted to utilizing the Python rotating log handler. 79 | with TemporaryFileLock(os.path.dirname(file_name), file_name = "{}.lock".format(os.path.basename(file_name))): 80 | with open(file_name, 'a') as f: 81 | for audit_object in self.yield_audit_results(bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = bulk_acquisition_id): 82 | json.dump(audit_object, f, sort_keys = False) 83 | f.write('\n') 84 | f.close() 85 | ret = True 86 | if ret and delete_bulk_download: 87 | os.remove(os.path.realpath(bulk_download_path)) 88 | 89 | else: 90 | self.logger.error("bulk_download_path is empty!") 91 | except Exception as e: 92 | self.logger.error(pretty_exceptions(e)) 93 | finally: 94 | return(ret, result) -------------------------------------------------------------------------------- /templates/ht_auditmanager.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Audit Manager{% endblock %} 3 | {% block navlocation %}Audit Manager{% endblock %} 4 | {% block content %} 5 | 6 | 83 | 84 | {{ htPanel.widgetHeader("Collected acquisitions and audits", panelIcon="fa-table") }} 85 |
86 | {{ htPanel.widgetFooter() }} 87 | 88 | {% endblock %} 89 | -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-host.css: -------------------------------------------------------------------------------- 1 | .host-grid-container { 2 | display: grid; 3 | grid-template-columns: 0.5fr 1fr 0.4fr; 4 | grid-template-rows: 160px; 5 | grid-template-areas: "top top top" "alerts content acquisitions"; 6 | height: calc(100vh - 160px); 7 | } 8 | 9 | .host-top { 10 | grid-area: top; 11 | } 12 | 13 | .host-alerts { 14 | grid-area: alerts; 15 | } 16 | 17 | .host-content { 18 | grid-area: content; 19 | padding-left: 12px; 20 | padding-right: 12px; 21 | } 22 | 23 | .host-acquisitions { 24 | grid-area: acquisitions; 25 | } 26 | 27 | .hxtool_host_panel_read_more { 28 | background: #0d1a2b; 29 | padding: 3px; 30 | padding-left: 24px; 31 | padding-right: 24px; 32 | font-size: 10px; 33 | font-weight: bold; 34 | border-top: 1px solid rgba(15, 184, 220, 0.4); 35 | } 36 | 37 | .hxtool_host_panel_read_more:hover { 38 | background: rgba(255, 255, 255, 0.2); 39 | cursor: pointer; 40 | } 41 | 42 | .panelHostClass { 43 | } 44 | 45 | .panelAlertsClass { 46 | overflow: auto; 47 | height: calc(100vh - 290px); 48 | } 49 | 50 | .panelContentClass { 51 | overflow: auto; 52 | height: calc(100vh - 290px); 53 | } 54 | 55 | .panelAcqClass { 56 | overflow: auto; 57 | height: calc(100vh - 290px); 58 | } 59 | 60 | .hxtool_host_alert_table tbody tr:hover { 61 | background: rgba(255,255,255,0.1); 62 | cursor: pointer; 63 | } 64 | 65 | .hxtool_host_acq_table tbody tr:hover { 66 | background: rgba(255,255,255,0.1); 67 | cursor: pointer; 68 | } 69 | 70 | .hxtool_host_ul { 71 | list-style-type: none; 72 | background: url(/static/vlines/vline.png) repeat-y; 73 | margin-left: 40px; 74 | padding: 0; 75 | } 76 | 77 | .hxtool_host_ul li { 78 | margin: 0; 79 | padding: 0px 12px; 80 | line-height: 34px; 81 | background: url(/static/vlines/node.png) no-repeat; 82 | } 83 | 84 | .hxtool_host_ul li:last-child { 85 | background: url(/static/vlines/lastnode.png) no-repeat; 86 | } 87 | 88 | .hxtool_host_table { 89 | width: 100%; 90 | } 91 | 92 | .hxtool_host_table tbody td:nth-child(1) { 93 | width: 150px; 94 | } 95 | 96 | .hxtool_host_table tbody tr:nth-child(odd) { 97 | background: transparent; 98 | } 99 | 100 | .hxtool_host_table tbody td { 101 | border-right: 0; 102 | } 103 | 104 | .hxtool_host_table tbody tr { 105 | border-bottom: 0; 106 | } 107 | 108 | .product { 109 | text-align: center; 110 | } 111 | 112 | .hxtool_host_info_cell { 113 | background: rgba(0,0,0,0.2); 114 | width: 120px; 115 | font-weight: bold; 116 | } 117 | 118 | .hxtool_table_host_alert { 119 | width: 100%; 120 | margin-bottom: 24px; 121 | } 122 | 123 | .hxtool_table_host_alert tbody tr:nth-child(odd) { 124 | background: transparent; 125 | } 126 | 127 | .hxtool_alert_header { 128 | margin-block-start: 6px; 129 | margin-block-end: 0; 130 | border-bottom: 1px solid rgba(15, 184, 220, 0.4); 131 | font-size: 14px; 132 | padding-bottom: 3px; 133 | padding-left: 2px; 134 | } 135 | 136 | .hxtool_alert_json_item { 137 | font-weight: bold; 138 | border: 1px solid #10455B; 139 | padding: 3px; 140 | border-radius: 2px; 141 | background: #0A0F18; 142 | 143 | } 144 | 145 | .hxtool_host_alert_goLink { 146 | margin-right: 6px; 147 | } 148 | 149 | .acqRemove { 150 | margin-left: 6px; 151 | } 152 | 153 | .allAcqDetailsButton { 154 | display: block; 155 | margin-top: 24px; 156 | } 157 | -------------------------------------------------------------------------------- /data/hxtool.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDFTAPsfC7RVJn1 3 | 8fgU+XuaplfgcYFKF1OaFkJKfuuwyejhm+v738tn/h1+RGPLKMqlJI9l+6IXshau 4 | +IQHmq7chZEbWw373BYVsBbnSELLUgQ4TvZbLyvw7eewwF4SJ9aRLzNiXGBEzwt0 5 | SuyGLF199ZkTQFnFtC5QK5GZXZ1LuJKryzgoq5L15IkrNatGdhJYQc6WWz2yBP4Z 6 | A+KAMvkn5rV0QCE3w9uQumzMm+Qw5v5LGzyX+wgCdYn1rMZpipN5pmSA3QRVQlcf 7 | FBTbv9LQGNNuM0ZgetXBpuH7Otq6Us9eXWzZx+Z4hpKNX2RiT7aj29XNf3iMAKsN 8 | jxA1ey3EqGursoGR0UzlUaXwPccblKaUnFIawVZVneO1HcoejbwbqESGHgMEeiZf 9 | EWInsJ8Vd/L8DxJPTjoths8OGb1/o8bNFe9ZvuOLXxZt5VpZ1/y4YMRg8FWn8pR9 10 | +EyszLQzDPnnC5Q7Z5fhX957M7O5XxgbKoBnbH21MXptSAfv++w94GSopQNXU4Em 11 | lT3C3bcMYwlE+ryovWt/ySM4vOHt3XAH6Yc25MIxpIwZA/JTX7Yk6jIlt3x4V2vP 12 | E7AqbB8eg0d4/uzCrxkw+OGgP3jZtdo/SWJGT/8j4i9145ggFf/tCH3trf5+nWSL 13 | hEln2hLxGmUtPuNlEQ64X9qOm4uxFQIDAQABAoICAHBz9UCTP3Qczmw6cHY0BNmO 14 | ukO5LkH2rbYDveEMGnZ3fv8oigbT9fHeCx1vCZpAM9CQ2BL+q9LptLgh+c8DwWr7 15 | zktTSNMnDIdsCIHm0/tjUfhuOUibyGXYk9hQrM2YW1oBFz6W/F/7ysGL+ug23Urv 16 | 80Hfycs/+a3ER4asrvz7xM2aVPYJZQg2LGCuhGLy5V3clE1qz+1pnxLO/gioBQ9T 17 | FlWeP9CzF7CUMXMl35hn8MUKTy0o7dXI/MtEoQqC66/IwTwZvWCDIXkbTxA5c4Uc 18 | wVXsb86J9NAduGwjjYvpqzxT77jpkVldCqb9mg/W83jN0j0AzMqvjs95nXl+LgUI 19 | 40HOjFIWWfu6zXxwg7OchyYwI/5VaP12rhhxKlxBhAP8yfKwvP+yTRxzdf0DCQUh 20 | ImwWqxi+IJ3ndzuA+aV2Iq13q+FILX37LVrLYu0aklNXF1novTAxcJ6jeBvCyr33 21 | PXEVGoV5oYiG5mC6oqTFHPMD6iLzNnu61wkt1/hRH+is4tQAzk/zC0THo/tvTGc+ 22 | Bv6Xub1rzsM4XvwlHkbGe/oU7NLgRSiQXLV2svfjVd/0uDolj1IB+dVWmqEZHuaX 23 | uekNJhQcZMw5bX7mdeb/xBRPHU9Uy87u8niOFBj/2VXyZCzWv1tjN6vo2ImpMdY/ 24 | /q7xkXq2sDwX8ySpFTwBAoIBAQD/CejN7UuiAulZ5fg7So5S6fguSGH8361y4t6K 25 | eZGYQrjWhIBgLQkdisdTEtgUN+nOvkDASbQL4ZJUMytPSfrl3VpqUiqqLNHNKtIl 26 | AmLWPdC2omWoNMo4pSOsKbp3ogo9HLyqFqKsmOsb/qGQcxYhQqsP5ChE0uIkpFY3 27 | 4l4CGE00+0Jq7vL63SIRbFoa6rEHLtf7obd3H496xCVH649ppYooTD40nI4p5aOD 28 | 2aGdV2aKZe6/ApsOqLkPz1ufPB5lJfgnDoMP1gaB3pglkeVNfJDQbWO27FdH6M1I 29 | 8pU62ehtOLH4NJOtYGRq9/DZFLMi6U+z6sQxlkQndOFg90+VAoIBAQDGCmPaGz1a 30 | XmEXJMJjnHlMWq98rOyVNRsBRPdr+I692bvaP6mrQHBW6fnoJ0G7leVDJiOtQXnn 31 | AlKGMsM5DnE9G+6zK72hU1KkTjpxQgRf0ZZ4WGPrBmRgaTRpVyIfE6l2kaAvp+C3 32 | jHSDukvcxST2oR5Z7WluTUGLYo5jNxYWVhYqaF1/iwSti5tyZD3gqpDvcgD/Glvj 33 | bdCKOiWJCjCHl42ieuMbMjOwyHBn0aYGNMdSE3hMVlbvnWIxqKPKWdprg/QDa5jZ 34 | d+6zv4Ye8NPGONZg0lrcGubYha93piNbbVzdprFxv1JPPjvm8WsmQFpvy3sujsiJ 35 | +bBnt8oQ8HuBAoIBAQDQmOdMPxFEcsMv31O4ExPzpyBxooxaywxP0lWYxzQZaEFM 36 | W9WwVEWHXzIGtXv8lXrruVq2q9HSge4wZiW/VVAcYH8KRShWRhBXkfWNhbUXbDng 37 | l1U0TfE0gYV61CqKnQNo1q9NIvRs3So3nH3C6w6np6LIfaGeISoMNEm8ra6cYgoM 38 | EpJRah1cqC+sNoZAS8L9kAfh7XRkv3CYRgQEHhwPmfE1Yp7iY0Y36HZkakWwroLV 39 | IegzXMs8Iy4ySzSyOfbWXkbokwsJkdGCuXCSEhGN3huIDmCnhgkhbL0zNA5wszhS 40 | 1TNjQoWjIhsgDql0tGSMYm3pR1SvBiu6ZfPNXpo9AoIBAQCO2zHaRGoGhSxOUJL0 41 | 3gvV21jZe7gRjcRULxa3yQ3Wv3i139SZlxsyZweBwse09FT0ElAMC75OuKsk6PtQ 42 | bi2bYknW70eUVxG3OkMILhIPuJVtbH1vLSY9Mca/8j3H4xwMTtIZbmU4olXuK/XL 43 | ZF7cla7aOdsi2RHd5RNHWJZTOHg20SAZAAQ42AsjAlJsfT2drEQxwSblsPKMs5Md 44 | /r6xIM7nlPO8S4NkE8KZ8W5s7aeWejr9/g4qPQJ3ReoY7qYThpT/3p7cyJnlCdRK 45 | /3gUdi2WnEc0nSdGq3C+w5afvg0OSs+XeOZ8CS2W0zFy31sdZ9AM7qyUcwwgVUCq 46 | 5X6BAoIBAQDxaX4VflY3VppXNAtBNhJKUR2b3on/3vsbFWdJT4gg/9bPGBTakkA+ 47 | yjtSVWeMRwavFPG21VctCoo7l1GcvL8vhG1napBMcV14iVADy3FU5r0Hku52ccHp 48 | w1mvS01FXK64UAPwMld7T+ORsuWEciuIsfEtVU46XPqX2/OqqgcEPBqNRcBqVGo1 49 | A6cWPQ0m4sVWDVewX2I6JOzoUhG+ipwhJpffH/kazXnnJwwAq1VBSHMHU2jq57ly 50 | CBLC/FUnfsWqCXWi/hPVWPqjRlxZUy2gcHLPFpMThpMhQKsOD3FFrMbjoA70imqB 51 | cG9cTrUzc+/QoXPcKlacyHhYdT8wrgr1 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /static/fireeye.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 10 | 13 | 15 | 17 | 20 | 22 | 25 | 27 | 30 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /templates/ht_stacking_analyze.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Stacking analysis{% endblock %} 3 | {% block navlocation %}Stacking analysis{% endblock %} 4 | {% block content %} 5 | 6 | 76 | 77 | {{ htPanelNoHeader.widgetHeader(panelDisplay="inline-block") }} 78 | 79 | {{ htPanelNoHeader.widgetFooter() }} 80 | 81 | {{ htPanel.widgetHeader("Stacking results", panelId="iocTableContainer", panelIcon="fa-table", elementAdditionalBodyClass="hxtool_panel_stackinganalyze") }} 82 |
83 | {{ htPanel.widgetFooter() }} 84 | 85 | {{ htModal.widgetHeader("Matching endpoints", modalId="endpointViewPopup", modalSize="medium") }} 86 | {{ htModal.widgetMiddle() }} 87 | 88 | {{ htModal.widgetFooter() }} 89 | 90 | {% endblock %} -------------------------------------------------------------------------------- /static/hxtool-css/hxtool-table.css: -------------------------------------------------------------------------------- 1 | /* Generic datatables table */ 2 | 3 | .hxtool_table { 4 | border-collapse: collapse; 5 | font-weight: 400; 6 | } 7 | 8 | .hxtool_table td, .hxtool_table tr, .hxtool_table th { 9 | 10 | } 11 | 12 | .hxtool_table thead td, .hxtool_table thead th { 13 | padding: 2px; 14 | padding-top: 4px; 15 | padding-bottom: 4px; 16 | font-size: 11px; 17 | border-right: 1px solid rgba(15, 184, 220, 0.4);; 18 | border-bottom: 1px solid rgba(15, 184, 220, 0.4);; 19 | vertical-align: bottom; 20 | } 21 | 22 | .hxtool_table thead td:last-child, .hxtool_table thead th:last-child { 23 | border-right: none; 24 | } 25 | 26 | 27 | .hxtool_table tbody td { 28 | padding: 2px; 29 | padding-top: 4px; 30 | padding-bottom: 4px; 31 | border-right: 1px solid rgba(15, 184, 220, 0.4); 32 | font-size: 11px; 33 | vertical-align: middle; 34 | } 35 | 36 | .hxtool_table tbody td:last-child { 37 | border-right: none; 38 | } 39 | 40 | .hxtool_table tbody tr { 41 | border-bottom: 1px solid rgba(15, 184, 220, 0.1); 42 | } 43 | 44 | .hxtool_table tbody tr:hover { 45 | background: rgba(255,255,255,0.1); 46 | } 47 | 48 | /* Zebra striping? 49 | .hxtool_table tbody tr:nth-child(odd) { 50 | background: rgba(0,0,0,0.2); 51 | } 52 | */ 53 | 54 | .hxtool_table tbody tr:last-child { 55 | border-bottom: none; 56 | } 57 | 58 | .hxtool_table a:link, a:visited { 59 | font-size: 12px; 60 | font-weight: bold; 61 | color: rgba(255, 255, 255, 0.8); 62 | } 63 | 64 | .hxtool_table a:hover { 65 | color: #0fb8dc; 66 | } 67 | 68 | .streaming_ioc_id { 69 | font-size: xx-small; 70 | color: #006b8c 71 | } 72 | 73 | .streaming_condition_id { 74 | font-size: xx-small; 75 | color: #0fb8dc 76 | } 77 | 78 | /* Generic datatables Exceptions */ 79 | 80 | .hxtool_table_cell_center { 81 | text-align: center; 82 | } 83 | 84 | .hxtool_table_cell_vertical { 85 | transform: rotate(-65deg); 86 | transform-origin: top left; 87 | text-align: left; 88 | padding: 0; 89 | position: absolute; 90 | margin-top: -10px; 91 | } 92 | 93 | .hxtool_table_header_es thead th:nth-child(n+12):nth-last-child(n+3) { 94 | padding: 0; 95 | height: 80px; 96 | min-width: 40px; 97 | max-width: 40px; 98 | } 99 | 100 | .hxtool_table_header_es thead th:nth-child(3) { 101 | text-align: left; 102 | padding-left: 5px; 103 | } 104 | 105 | .hxtool_alerts_filter th, td { 106 | padding-left: 6px; 107 | padding-right: 6px; 108 | text-align: left; 109 | } 110 | 111 | .hxtool_alerts_filter th:nth-child(1) { 112 | width: 300px; 113 | } 114 | 115 | .hxtool_alerts_filter th:nth-child(2) { 116 | width: 300px; 117 | } 118 | 119 | .hxtool_alerts_filter th:nth-child(3) { 120 | width: 400px; 121 | } 122 | 123 | .hxtool_alerts_filter th:nth-child(4) { 124 | width: 150px; 125 | } 126 | 127 | .hxtool_alerts_filter th:nth-child(5) { 128 | width: 150px; 129 | } 130 | 131 | 132 | /* Dashboard grid table */ 133 | 134 | .hxtool_table_dashboard { 135 | width: 100%; 136 | } 137 | 138 | .hxtool_table_dashboard td { 139 | padding: 5px; 140 | vertical-align: top; 141 | } 142 | 143 | .auditFilter:hover { 144 | background: rgba(255, 255, 255, 0.2); 145 | cursor: pointer; 146 | } 147 | 148 | .auditFilterContainer { 149 | width: 200px; 150 | margin-top: 4px; 151 | z-index: 999; 152 | padding: 10px; 153 | position: absolute; 154 | display: none; 155 | background: #49515d; 156 | border: 1px solid #31363d; 157 | border-radius: 3px; 158 | } 159 | 160 | .auditFilterDropdownChild { 161 | width: 100%; 162 | display: block; 163 | color: #0fb8dc; 164 | text-align: left; 165 | background: #49515d; 166 | border: 0; 167 | padding-bottom: 10px; 168 | padding-top: 10px; 169 | } 170 | 171 | .auditFilterDropdownChild:hover { 172 | background: rgba(0, 0, 0, 0.6); 173 | color: #66ebff !important; 174 | } -------------------------------------------------------------------------------- /hxtool_task_modules/streaming_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import socket 5 | import os 6 | import json 7 | 8 | import hxtool_global 9 | from .task_module import * 10 | from hx_audit import * 11 | 12 | class streaming_task_module(task_module): 13 | def __init__(self, parent_task): 14 | super(type(self), self).__init__(parent_task) 15 | 16 | @staticmethod 17 | def input_args(): 18 | return [ 19 | { 20 | 'name' : 'host_name', 21 | 'type' : str, 22 | 'required' : True, 23 | 'user_supplied' : False, 24 | 'description' : "The host name belonging to the bulk acquisition package." 25 | }, 26 | { 27 | 'name' : 'agent_id', 28 | 'type' : str, 29 | 'required' : False, 30 | 'user_supplied' : False, 31 | 'description' : "The host/agent ID of the bulk acquisition to download." 32 | }, 33 | { 34 | 'name' : 'bulk_download_path', 35 | 'type' : str, 36 | 'required' : True, 37 | 'user_supplied' : False, 38 | 'description' : "The fully qualified path to the bulk acquisition package." 39 | }, 40 | { 41 | 'name' : 'bulk_acquisition_id', 42 | 'type' : int, 43 | 'required' : True, 44 | 'description' : "The bulk acquisition ID assigned to the bulk acquisition job by the controller." 45 | }, 46 | { 47 | 'name' : 'batch_mode', 48 | 'type' : bool, 49 | 'required' : False, 50 | 'user_supplied' : True, 51 | 'description' : "Flag whether to batch each audit as single JSON object versus sending each record as a separate object. Defaults to False" 52 | }, 53 | { 54 | 'name' : 'delete_bulk_download', 55 | 'type' : bool, 56 | 'required' : False, 57 | 'user_supplied' : True, 58 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 59 | }, 60 | { 61 | 'name' : 'stream_protocol', 62 | 'type' : str, 63 | 'required' : False, 64 | 'user_supplied' : True, 65 | 'description' : "The protocol to use when streaming. Defaults to TCP" 66 | }, 67 | { 68 | 'name' : 'stream_host', 69 | 'type' : str, 70 | 'required' : True, 71 | 'user_supplied' : True, 72 | 'description' : "The FQDN or IP address of the host to stream to." 73 | }, 74 | { 75 | 'name' : 'stream_port', 76 | 'type' : int, 77 | 'required' : True, 78 | 'user_supplied' : True, 79 | 'description' : "The port on which to stream to." 80 | } 81 | 82 | ] 83 | 84 | @staticmethod 85 | def output_args(): 86 | return [] 87 | 88 | def run(self, host_name = None, agent_id = None, bulk_download_path = None, bulk_acquisition_id = None, batch_mode = False, delete_bulk_download = False, stream_host = None, stream_port = None, stream_protocol = 'tcp'): 89 | try: 90 | ret = False 91 | if bulk_download_path: 92 | 93 | socket_type = socket.SOCK_STREAM 94 | if stream_protocol == 'udp': 95 | socket_type = socket.SOCK_DGRAM 96 | 97 | for res in socket.getaddrinfo(stream_host, int(stream_port), socket.AF_UNSPEC, socket_type): 98 | address_family, socktype, proto, canonname, sockaddr = res 99 | 100 | stream_socket = socket.socket(address_family, socktype, proto) 101 | 102 | stream_socket.connect(sockaddr) 103 | 104 | for audit_object in self.yield_audit_results(bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = bulk_acquisition_id): 105 | stream_socket.sendall(json.dumps(audit_object, sort_keys = False).encode('utf-8') + '\n'.encode('utf-8')) 106 | 107 | stream_socket.close() 108 | 109 | ret = True 110 | 111 | if ret and delete_bulk_download: 112 | os.remove(os.path.realpath(bulk_download_path)) 113 | 114 | else: 115 | self.logger.error("bulk_download_path is empty!") 116 | 117 | return(ret, None) 118 | except Exception as e: 119 | self.logger.error(pretty_exceptions(e)) 120 | return(False, None) -------------------------------------------------------------------------------- /hxtool_task_modules/helix_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import socket 5 | import os 6 | import json 7 | import time 8 | import tempfile 9 | import gzip 10 | 11 | import requests 12 | 13 | import hxtool_global 14 | from .task_module import * 15 | from hx_audit import * 16 | 17 | class helix_task_module(task_module): 18 | def __init__(self, parent_task): 19 | super(type(self), self).__init__(parent_task) 20 | 21 | @staticmethod 22 | def input_args(): 23 | return [ 24 | { 25 | 'name' : 'host_name', 26 | 'type' : str, 27 | 'required' : True, 28 | 'user_supplied' : False, 29 | 'description' : "The host name belonging to the bulk acquisition package." 30 | }, 31 | { 32 | 'name' : 'agent_id', 33 | 'type' : str, 34 | 'required' : False, 35 | 'user_supplied' : False, 36 | 'description' : "The host/agent ID of the bulk acquisition to download." 37 | }, 38 | { 39 | 'name' : 'bulk_download_path', 40 | 'type' : str, 41 | 'required' : True, 42 | 'user_supplied' : False, 43 | 'description' : "The fully qualified path to the bulk acquisition package." 44 | }, 45 | { 46 | 'name' : 'bulk_acquisition_id', 47 | 'type' : int, 48 | 'required' : True, 49 | 'description' : "The bulk acquisition ID assigned to the bulk acquisition job by the controller." 50 | }, 51 | { 52 | 'name' : 'delete_bulk_download', 53 | 'type' : bool, 54 | 'required' : False, 55 | 'user_supplied' : True, 56 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 57 | }, 58 | { 59 | 'name' : 'apikey', 60 | 'type' : str, 61 | 'required' : True, 62 | 'user_supplied' : True, 63 | 'description' : "The API key for uploading" 64 | }, 65 | { 66 | 'name' : 'url', 67 | 'type' : str, 68 | 'required' : True, 69 | 'user_supplied' : True, 70 | 'description' : "The URL to which the upload is sent" 71 | } 72 | 73 | ] 74 | 75 | @staticmethod 76 | def output_args(): 77 | return [] 78 | 79 | def _write_fh(self, gz_fh, bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id=None): 80 | gz = gzip.GzipFile(fileobj=gz_fh, mode='wb') 81 | for audit_object in self.yield_audit_results(bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = bulk_acquisition_id): 82 | gz.write(json.dumps(audit_object, sort_keys = False).encode('utf-8') + '\n'.encode('utf-8')) 83 | gz.close() 84 | gz_fh.seek(0) 85 | 86 | def run(self, host_name = None, agent_id = None, bulk_download_path = None, bulk_acquisition_id = None, batch_mode = False, delete_bulk_download = False, apikey = None, url = None): 87 | try: 88 | if not bulk_download_path: 89 | self.logger.error("bulk_download_path is empty!") 90 | return (False, None) 91 | 92 | resp = requests.post(url, headers={"x-api-key": apikey}, data={"host_name": host_name, "agent_id": agent_id, "bulk_acquisition_id": bulk_acquisition_id}) 93 | if not resp: 94 | raise Exception("Unable to get upload link from URL {}: {}".format(url, resp)) 95 | resp = resp.json() 96 | self.logger.debug("Uploading id {} from {} to {}".format(bulk_acquisition_id, bulk_download_path, resp["url"])) 97 | 98 | start = time.time() 99 | with tempfile.TemporaryFile(mode='r+b') as gz_fh: 100 | self._write_fh(gz_fh, bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = bulk_acquisition_id) 101 | resp = requests.post(resp["url"], data=resp["fields"], files={"file": (str(time.time()), gz_fh)}) 102 | if not resp: 103 | raise Exception("Unable to upload: {} {}".format(resp, resp.text)) 104 | self.logger.info("Uploaded id {} in {}".format(bulk_acquisition_id, (time.time() - start))) 105 | if delete_bulk_download: 106 | os.remove(os.path.realpath(bulk_download_path)) 107 | return(True, None) 108 | except Exception as e: 109 | self.logger.error(pretty_exceptions(e)) 110 | return(False, None) -------------------------------------------------------------------------------- /static/css/buttons.jqueryui.min.css: -------------------------------------------------------------------------------- 1 | @keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dt-buttons{position:relative;float:left}div.dt-buttons .dt-button{margin-right:0}div.dt-buttons .dt-button span.ui-icon{display:inline-block;vertical-align:middle;margin-top:-2px}div.dt-buttons .dt-button:active{outline:none}div.dt-buttons .dt-button:hover>span{background-color:rgba(0,0,0,0.05)}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:#f3f3f3;background-color:rgba(255,255,255,0.3);overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,0.3);z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px;-webkit-column-gap:0;-moz-column-gap:0;-ms-column-gap:0;-o-column-gap:0;column-gap:0}div.dt-button-collection .dt-button{position:relative;left:0;right:0;display:block;float:none;margin-right:0}div.dt-button-collection .dt-button:last-child{margin-bottom:4px}div.dt-button-collection .dt-button:hover>span{background-color:rgba(0,0,0,0.05)}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-150px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0,0,0,0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:' ';border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear} 2 | -------------------------------------------------------------------------------- /templates/ht_scheduler.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Scheduler{% endblock %} 3 | {% block navlocation %}Scheduler{% endblock %} 4 | {% block content %} 5 | 6 | 107 | 108 | {{ htPanelNoHeader.widgetHeader(panelDisplay="inline-block") }} 109 |

110 | {{ htPanelNoHeader.widgetFooter() }} 111 | 112 | {{ htPanel.widgetHeader("Scheduler tasks", panelIcon="fa-table") }} 113 |
114 | {{ htPanel.widgetFooter() }} 115 | 116 | {% endblock %} 117 | -------------------------------------------------------------------------------- /static/fontawesome-free-5.7.2-web/css/svg-with-js.min.css: -------------------------------------------------------------------------------- 1 | .svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;transform:scale(.25);transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;transform:scale(.25);transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;transform:scale(.25);transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto} -------------------------------------------------------------------------------- /hxtool_task_modules/x15_postgres_task_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | try: 6 | from io import StringIO 7 | except ModuleNotFoundError: 8 | from cStringIO import StringIO 9 | 10 | import hxtool_global 11 | from .task_module import * 12 | from hx_audit import * 13 | from hxtool_util import * 14 | 15 | class x15_postgres_task_module(task_module): 16 | def __init__(self, parent_task): 17 | super(type(self), self).__init__(parent_task) 18 | 19 | @staticmethod 20 | def input_args(): 21 | return [ 22 | { 23 | 'name' : 'host_name', 24 | 'type' : str, 25 | 'required' : True, 26 | 'user_supplied' : False, 27 | 'description' : "The host name belonging to the bulk acquisition package." 28 | }, 29 | { 30 | 'name' : 'agent_id', 31 | 'type' : str, 32 | 'required' : False, 33 | 'user_supplied' : False, 34 | 'description' : "The host/agent ID of the bulk acquisition to download." 35 | }, 36 | { 37 | 'name' : 'bulk_download_path', 38 | 'type' : str, 39 | 'required' : True, 40 | 'user_supplied' : False, 41 | 'description' : "The fully qualified path to the bulk acquisition package." 42 | }, 43 | { 44 | 'name' : 'bulk_acquisition_id', 45 | 'type' : int, 46 | 'required' : True, 47 | 'description' : "The bulk acquisition ID assigned to the bulk acquisition job by the controller." 48 | }, 49 | { 50 | 'name' : 'batch_mode', 51 | 'type' : bool, 52 | 'required' : False, 53 | 'user_supplied' : True, 54 | 'description' : "Flag whether to batch each audit as single JSON object versus sending each record as a separate object. Defaults to False" 55 | }, 56 | { 57 | 'name' : 'delete_bulk_download', 58 | 'type' : bool, 59 | 'required' : False, 60 | 'user_supplied' : True, 61 | 'description' : "Flag whether to delete the bulk acquisition package locally once complete. Defaults to False" 62 | }, 63 | { 64 | 'name' : 'x15_host', 65 | 'type' : str, 66 | 'required' : True, 67 | 'user_supplied' : True, 68 | 'description' : "The IP address or fully qualified domain name of the X15 server." 69 | }, 70 | { 71 | 'name' : 'x15_port', 72 | 'type' : int, 73 | 'required' : True, 74 | 'user_supplied' : True, 75 | 'description' : "The Postgres port on the X15 server." 76 | }, 77 | { 78 | 'name' : 'x15_user', 79 | 'type' : str, 80 | 'required' : True, 81 | 'user_supplied' : True, 82 | 'description' : "The username with which to authenticate to the X15 server." 83 | }, 84 | { 85 | 'name' : 'x15_password', 86 | 'type' : str, 87 | 'required' : True, 88 | 'user_supplied' : True, 89 | 'description' : "The password with which to authenticate to the X15 server." 90 | }, 91 | { 92 | 'name' : 'x15_database', 93 | 'type' : str, 94 | 'required' : True, 95 | 'user_supplied' : True, 96 | 'description' : "The database to utilize on the X15 server." 97 | }, 98 | { 99 | 'name' : 'x15_table', 100 | 'type' : str, 101 | 'required' : True, 102 | 'user_supplied' : True, 103 | 'description' : "The table in the database to utilize." 104 | } 105 | ] 106 | 107 | @staticmethod 108 | def output_args(): 109 | return [] 110 | 111 | def run(self, host_name = None, agent_id = None, bulk_download_path = None, bulk_acquisition_id = None, batch_mode = False, delete_bulk_download = False, x15_host = None, x15_port = None, x15_user = None, x15_password = None, x15_database = None, x15_table = None): 112 | 113 | ret = False 114 | result = {} 115 | try: 116 | import psycopg2 117 | 118 | if bulk_download_path: 119 | x15_connection_string = "host={} port={} dbname={} user={} password={}".format(x15_host, x15_port, x15_database, x15_user, x15_password) 120 | x15_connection = psycopg2.connect(x15_connection_string) 121 | x15_cursor = x15_connection.cursor() 122 | x15_query = "COPY {} from stdin".format(x15_table) 123 | 124 | for audit_object in self.yield_audit_results(bulk_download_path, batch_mode, host_name, agent_id, bulk_acquisition_id = bulk_acquisition_id): 125 | buffer = StringIO() 126 | json.dump(audit_object, buffer) 127 | buffer.seek(0) 128 | x15_cursor.copy_expert(x15_query, buffer, size=16384) 129 | 130 | x15_connection.commit() 131 | x15_connection.close() 132 | 133 | ret = True 134 | if ret and delete_bulk_download: 135 | os.remove(os.path.realpath(bulk_download_path)) 136 | 137 | else: 138 | self.logger.error("bulk_download_path is empty!") 139 | except Exception as e: 140 | self.logger.error(pretty_exceptions(e)) 141 | finally: 142 | return(ret, result) -------------------------------------------------------------------------------- /hxtool_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | import logging 6 | from os import path 7 | import sys, logging, logging.handlers, socket 8 | 9 | import hxtool_logging 10 | from hxtool_util import combine_app_path 11 | 12 | logger = hxtool_logging.getLogger(__name__) 13 | 14 | class hxtool_config: 15 | """ 16 | Default hard coded config 17 | """ 18 | DEFAULT_CONFIG = { 19 | 'log_handlers' : { 20 | 'rotating_file_handler' : { 21 | 'file' : 'log/hxtool.log', 22 | 'max_bytes' : 5000000, 23 | 'backup_count' : 5, 24 | 'level' : 'info', 25 | 'format' : '[%(asctime)s] {%(module)s} {%(threadName)s} %(levelname)s - %(message)s' 26 | } 27 | }, 28 | 'network' : { 29 | 'ssl' : 'enabled', 30 | 'port' : 8080, 31 | 'listen_address' : '0.0.0.0', 32 | 'session_timeout' : 30 33 | }, 34 | 'ssl' : { 35 | 'cert' : 'hxtool.crt', 36 | 'key' : 'hxtool.key' 37 | }, 38 | 'scheduler' : { 39 | 'thread_count' : None, 40 | 'defer_interval' : 30 41 | }, 42 | 'headers' : { 43 | }, 44 | 'cookies' : { 45 | } 46 | } 47 | 48 | LOG_LEVELS = { 49 | 'debug' : logging.DEBUG, 50 | 'info' : logging.INFO, 51 | 'warning' : logging.WARNING, 52 | 'error' : logging.ERROR, 53 | 'critical' : logging.CRITICAL 54 | } 55 | 56 | def __init__(self, config_file): 57 | 58 | logger.info('Reading configuration file %s', config_file) 59 | if path.isfile(config_file): 60 | with open(config_file, 'r') as config_file_handle: 61 | self._config = json.load(config_file_handle) 62 | logger.info('Checking configuration file %s', config_file) 63 | if not {'log_handlers', 'network', 'ssl', 'scheduler'} <= set(self._config.keys()): 64 | raise ValueError('Configuration file is missing key elements!') 65 | else: 66 | logger.info('Configuration file %s is OK.', config_file) 67 | 68 | if 'proxies' in self._config['network']: 69 | if len(list(filter(lambda x: x == 'http' or x == 'https' or x == 'use_pac' or x == 'pac_url', self._config['network']['proxies']))) == 0: 70 | logger.warning("Ignoring invalid proxy configuration! Please see http://docs.python-requests.org/en/master/user/advanced/") 71 | del self._config['network']['proxies'] 72 | else: 73 | logger.warning('Unable to open config file: %s, loading default config.', config_file) 74 | self._config = self.DEFAULT_CONFIG 75 | 76 | def __getitem__(self, key, default = None): 77 | v = self._config.get(key) 78 | if not v: 79 | v = default 80 | return v 81 | 82 | def get_child_item(self, parent_key, child_key, default = None): 83 | try: 84 | if self[parent_key] is not None: 85 | return self[parent_key].get(child_key, default) 86 | except TypeError: 87 | return default 88 | 89 | def get_config(self): 90 | return self._config 91 | 92 | def log_handlers(self): 93 | for handler_name in self._config['log_handlers']: 94 | if handler_name == 'rotating_file_handler': 95 | handler_config = self._config['log_handlers'][handler_name] 96 | if 'file' in handler_config: 97 | h = logging.handlers.RotatingFileHandler(combine_app_path(handler_config['file'])) 98 | 99 | if 'max_bytes' in handler_config: 100 | h.maxBytes = handler_config['max_bytes'] 101 | if 'backup_count' in handler_config: 102 | h.backupCount = handler_config['backup_count'] 103 | 104 | self._set_level_and_format(handler_config, h) 105 | yield(h) 106 | 107 | elif handler_name == 'syslog_handler': 108 | handler_config = self._config['log_handlers'][handler_name] 109 | 110 | syslog_address = '127.0.0.1' 111 | syslog_port = logging.handlers.SYSLOG_UDP_PORT 112 | if 'address' in handler_config: 113 | syslog_address = handler_config['address'] 114 | if 'port' in handler_config and 0 < handler_config['port'] < 65535: 115 | syslog_port = handler_config['port'] 116 | 117 | facility = logging.handlers.SysLogHandler.LOG_USER 118 | if 'facility' in handler_config: 119 | facility = logging.handlers.SysLogHandler.facility_names.get(handler_config['facility']) 120 | 121 | socket_type = socket.SOCK_DGRAM 122 | if 'protocol' in handler_config and handler_config['protocol'].lower() == 'tcp': 123 | socket_type = socket.SOCK_STREAM 124 | 125 | h = logging.handlers.SysLogHandler(address = (syslog_address, syslog_port), facility = facility, socktype = socket_type) 126 | 127 | self._set_level_and_format(handler_config, h) 128 | yield(h) 129 | 130 | def _set_level_and_format(self, handler_config, handler): 131 | level = logging.WARNING 132 | if 'level' in handler_config: 133 | level = self.LOG_LEVELS.get(handler_config['level'].lower()) 134 | 135 | handler.setLevel(level) 136 | 137 | if 'format' in handler_config: 138 | handler.setFormatter(logging.Formatter(handler_config['format'])) 139 | -------------------------------------------------------------------------------- /hxtool_session.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from werkzeug.datastructures import CallbackDict 5 | from flask.sessions import SessionInterface, SessionMixin 6 | import os 7 | import hmac 8 | import hashlib 9 | import threading 10 | import datetime 11 | 12 | import hxtool_global 13 | import hxtool_logging 14 | from hx_lib import * 15 | from hxtool_scheduler_task import hxtool_scheduler_task 16 | 17 | logger = hxtool_logging.getLogger(__name__) 18 | 19 | class hxtool_session(CallbackDict, SessionMixin): 20 | def __init__(self, app_secret): 21 | def on_update(self): 22 | if self.accessed == False: 23 | self.modified = True 24 | 25 | self.secret = app_secret 26 | self.id = None 27 | self.new = True 28 | self.accessed = False 29 | self.modified = False 30 | self.permanent = True 31 | CallbackDict.__init__(self, on_update=on_update) 32 | 33 | def create(self): 34 | self.id = str(hmac.new(self.secret, os.urandom(32), digestmod=hashlib.sha256).hexdigest()) 35 | 36 | def load(self, id, session_record): 37 | if session_record is not None: 38 | logger.debug("Loading saved session data.") 39 | # Set accessed to True for set/update so we don't loop into on_update() 40 | self.accessed = True 41 | # Explicitly set modified to False 42 | self.modified = False 43 | self.id = id 44 | self.update(session_record['session_data']) 45 | self.accessed = False 46 | 47 | # expiration_delta is in minutes 48 | class hxtool_session_interface(SessionInterface): 49 | def __init__(self, app, expiration_delta=30): 50 | self.session_cache = {} 51 | self.expiration_delta = expiration_delta 52 | 53 | # Schedule session_reaper 54 | session_reaper_task = hxtool_scheduler_task("System", "Session Reaper", immutable=True) 55 | session_reaper_task.set_schedule(minutes=30) 56 | session_reaper_task.add_step(self, "session_reaper", args = (app,)) 57 | hxtool_global.hxtool_scheduler.add(session_reaper_task) 58 | 59 | def get_expiration_time(self, app, session): 60 | delta = datetime.timedelta(minutes=self.expiration_delta) 61 | if session.permanent: 62 | delta = app.permanent_session_lifetime 63 | return datetime.datetime.utcnow() + delta 64 | 65 | def open_session(self, app, request): 66 | session = hxtool_session(app.secret_key) 67 | 68 | session_id = request.cookies.get(app.config['SESSION_COOKIE_NAME']) 69 | if session_id: 70 | cached_session = self.session_cache.get(session_id) 71 | if not cached_session: 72 | session_record = hxtool_global.hxtool_db.sessionGet(session_id) 73 | if session_record is not None: 74 | session.load(session_id, session_record) 75 | logger.debug("We have an existing database session with id: {0}".format(session.id)) 76 | else: 77 | session = cached_session 78 | logger.debug("We have an existing cached session with id: {0}".format(session.id)) 79 | 80 | 81 | return session 82 | 83 | def save_session(self, app, session, response): 84 | cookie_domain = self.get_cookie_domain(app) 85 | if not session: 86 | if not session.new: 87 | self.delete_session(app, session.id) 88 | if session.modified: 89 | response.delete_cookie(app.config['SESSION_COOKIE_NAME'], domain=cookie_domain) 90 | return 91 | 92 | if not self.should_set_cookie(app, session): 93 | return 94 | 95 | if session.new: 96 | session.create() 97 | hxtool_global.hxtool_db.sessionCreate(session.id) 98 | logger.debug("Created a new session with id: {0}".format(session.id)) 99 | session.new = False 100 | 101 | logger.debug("Saving session with id: {0}".format(session.id)) 102 | hxtool_global.hxtool_db.sessionUpdate(session.id, session) 103 | session.modified = False 104 | 105 | self.session_cache[session.id] = session 106 | 107 | cookie_path = self.get_cookie_path(app) 108 | http_only = self.get_cookie_httponly(app) 109 | secure = self.get_cookie_secure(app) 110 | response.set_cookie(app.config['SESSION_COOKIE_NAME'], session.id, expires=self.get_expiration_time(app, session), path=cookie_path, httponly=http_only, secure=secure, domain=cookie_domain) 111 | 112 | def delete_session(self, app, session_id): 113 | logger.debug("Deleting session with id: {0}".format(session_id)) 114 | hxtool_global.hxtool_db.sessionDelete(session_id) 115 | if session_id in self.session_cache: 116 | del self.session_cache[session_id] 117 | 118 | def session_reaper(self, app): 119 | logger.debug("session_reaper() called.") 120 | for s in hxtool_global.hxtool_db.sessionList(): 121 | if not s['update_timestamp'] or (datetime.datetime.utcnow() - HXAPI.dt_from_str(s['update_timestamp'])) >= (app.permanent_session_lifetime or datetime.timedelta(minutes=self.expiration_delta)): 122 | logger.debug("Deleting session id: {} with update_timestamp: {}".format(s['session_id'], s['update_timestamp'])) 123 | self.delete_session(app, s['session_id']) 124 | return True -------------------------------------------------------------------------------- /static/hxtool-js/hxtool-doc-ready.js: -------------------------------------------------------------------------------- 1 | function collapse_all_dropdowns() { 2 | $(".fe-dropdown__list-container").each(function() { 3 | $(this).css("opacity", 0); 4 | $(this).hide(); 5 | }); 6 | } 7 | 8 | function hxtool_doc_ready() { 9 | 10 | /* Global stuff */ 11 | 12 | // Set the background to proper gradient size depending on browser width 13 | // var myGradient = "radial-gradient(" + Math.round($( window ).width() * 0.52) + "px at 50% 0%, #355881 0%, #222 100%)"; 14 | // $("body").css({ "background": myGradient }); 15 | 16 | $(document).click(function(e) { 17 | // Collapse all top navbar dropdowns 18 | $(".hxtool_topnav_dropdown").hide(100); 19 | 20 | // Collapse all drop-down menus 21 | collapse_all_dropdowns(); 22 | 23 | e.stopPropagation(); 24 | }); 25 | 26 | $("#hxtoolMessageCancel").click(function(e) { 27 | $("#hxtoolMessage").hide(); 28 | e.stopPropagation(); 29 | }); 30 | 31 | /* TOP NAV BAR */ 32 | $(".hxtool_topnav_mainbutton").click(function(e) { 33 | if($(this).attr("data-link") !== undefined) { 34 | window.location.href = $(this).attr('data-link'); 35 | } 36 | else { 37 | $(".hxtool_topnav_dropdown").hide(100); 38 | $(this).next("div").show(100); 39 | } 40 | e.stopPropagation(); 41 | }); 42 | 43 | $("#hxtool_topnavSearch").click(function(e) { 44 | myWidth = $("#hxtool_topnavSearch").closest("div").width(); 45 | 46 | if ($("#hxtool_topnavSearch").data("clicked") == false) { 47 | $("#hxtool_topnavSearch").closest("div").animate({ 48 | width: myWidth + 235 49 | }, 200, function() { 50 | $("#hxtool_topnav_left_container-search").show(); 51 | $("#hxtool_topnavSearch").data("clicked", true); 52 | $("#hxtool_global_search").focus(); 53 | }); 54 | } 55 | else { 56 | $("#hxtool_topnav_left_container-search").hide(); 57 | $("#hxtool_topnavSearch").closest("div").animate({ 58 | width: myWidth - 235 59 | }, 200, function() { 60 | $("#hxtool_topnavSearch").data("clicked", false); 61 | }); 62 | } 63 | e.stopPropagation(); 64 | }); 65 | 66 | $("#hxtool_global_search").keypress(function (e) { 67 | var key = e.which; 68 | if(key == 13) { 69 | location.href = "/hostsearch?q=" + $("#hxtool_global_search").val(); 70 | } 71 | }); 72 | 73 | $(".hxtool_topnav_dropdown_child").click(function(e) { 74 | window.location.href = $(this).attr('data-link'); 75 | e.stopPropagation(); 76 | }); 77 | 78 | $("#hxtoolLogout").click(function(e) { 79 | window.location.href = "/logout" 80 | e.stopPropagation(); 81 | }); 82 | 83 | /* Panel */ 84 | 85 | // show/hide panel 86 | $(".hxtool-panel-toggle").click(function(e) { 87 | if ($(this).closest("div").next("div").css("display") == "none") { 88 | $(this).closest("div").next("div").show(200); 89 | } 90 | else { 91 | $(this).closest("div").next("div").hide(200); 92 | } 93 | }); 94 | 95 | /* DROP DOWN MENUS */ 96 | $(document).on("click", ".fe-dropdown", function(e) { 97 | collapse_all_dropdowns(); 98 | $(this).find("div").show(); 99 | $(this).find("div").fadeTo( "fast" , 1); 100 | e.stopPropagation(); 101 | }); 102 | 103 | $(document).on("click", ".fe-dropdown__item-link", function(e) { 104 | $(this).closest("div").parent().find("button").html($(this).find(".fe-dropdown__item-link-text").html() + ""); 105 | $(this).closest("div").parent().find("button").data("id", $(this).find(".fe-dropdown__item-link-text").data("id") ); 106 | $(this).closest("div").fadeTo( "fast", 0, function() { 107 | $(".fe-dropdown__list-container").hide(); 108 | }); 109 | 110 | e.stopPropagation(); 111 | }); 112 | 113 | /* MODAL */ 114 | $(".fe-modal-close").click(function(){ 115 | $(this).closest("div").parent().parent().parent().parent().hide(); 116 | }); 117 | 118 | /* Detects when OS scaling is active and resizes HXTool to avoid it, doesn't work in FF */ 119 | if (window.devicePixelRatio !== 1 && screen.width <= 1920) { 120 | console.log("HXTool: OS Scaling active. Enforcing HXTool scaling"); 121 | let scaleValue = (1/window.devicePixelRatio); 122 | $(document.body).css('zoom',scaleValue); 123 | var myNewHeight = (window.innerHeight * window.devicePixelRatio); 124 | $(".hxtool5_container").css('min-height',myNewHeight); 125 | $(".hxtool5_container").css('max-height',myNewHeight); 126 | $(".hxtool5_container").css('height',myNewHeight); 127 | $(".hxtool5_content").css('min-height',myNewHeight - 60); 128 | $(".hxtool5_content").css('max-height',myNewHeight - 60); 129 | $(".hxtool5_content").css('height',myNewHeight - 60); 130 | $(".panelAlertsClass").css('height',myNewHeight - 290); 131 | $(".panelContentClass").css('height',myNewHeight - 290); 132 | $(".panelAcqClass").css('height',myNewHeight - 290); 133 | $(".hxtool_panel_stackinganalyze").css('min-height',myNewHeight - 190); 134 | $(".hxtool_panel_scriptbuilder").css('height',myNewHeight - 120); 135 | $(".hxtool_scriptbuilder_scriptarea").css('height',myNewHeight - 450); 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /templates/ht_categories.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}HXTool - Categories{% endblock %} 3 | {% block navlocation %}Manage Categories{% endblock %} 4 | {% block content %} 5 | 6 | 71 | 72 | {{ htPanelNoHeader.widgetHeader(panelDisplay="inline-block") }} 73 | 74 | {{ htPanelNoHeader.widgetFooter() }} 75 | 76 | {{ htPanel.widgetHeader("Rule categories", panelId="categoryTableContainer", panelIcon="fa-table") }} 77 |
78 | {{ htPanel.widgetFooter() }} 79 | 80 | 81 | {{ htModal.widgetHeader("Create new category", modalId="categoryNewPopup", modalSize="medium", modalOverflow="true") }} 82 |

Category name

83 | 84 | Enter a name for your new category 85 | 86 |

Retention policy

87 | {{ htDropdown.widgetHeader("Select a policy", "retention_policy", "false") }} 88 | {{ htDropdown.widgetItem("manual", "manual", elementIcon="fa-check") }} 89 | {{ htDropdown.widgetItem("auto", "auto", elementIcon="fa-check") }} 90 | {{ htDropdown.widgetItem("intel", "intel", elementIcon="fa-check") }} 91 | {{ htDropdown.widgetFooter() }} 92 | 93 |
94 |

Edit policy

95 | {{ htDropdown.widgetHeader("Select a policy", "edit_policy", "false") }} 96 | {{ htDropdown.widgetItem("full", "full", elementIcon="fa-check") }} 97 | {{ htDropdown.widgetItem("edit_delete", "edit_delete", elementIcon="fa-check") }} 98 | {{ htDropdown.widgetItem("delete", "delete", elementIcon="fa-check") }} 99 | {{ htDropdown.widgetItem("read-only", "read-only", elementIcon="fa-check") }} 100 | {{ htDropdown.widgetFooter() }} 101 | 102 | {{ htModal.widgetMiddle() }} 103 | 104 | 105 | {{ htModal.widgetFooter() }} 106 | 107 | {% endblock %} 108 | -------------------------------------------------------------------------------- /README.CONFIG: -------------------------------------------------------------------------------- 1 | The HXTool configuration lives in conf.json, and is/should be well formatted JSON. 2 | What follows is a description of the available configuration elements. 3 | 4 | 1. "log_handlers" # You can have as many handlers in this section as you'd like. 5 | - "handler type" : { .. configuration options .. } 6 | - Valid handler types are: "rotating_file_handler" and "syslog_handler" 7 | - Valid options for both handlers: 8 | - "level" : "string; optional; The name of the logging level to use. Valid values are debug, info, warning, error and critical. Defaults to warning" 9 | - "format" : "string; optiona; The logging entry format to use when writing to this log. See https://docs.python.org/2/howto/logging.html#formatters for valid options. 10 | - Valid options for "rotating_file_handler": # See https://docs.python.org/2/library/logging.handlers.html#logging.handlers.RotatingFileHandler 11 | - "file" : "string; required; The path and file name that the log will be written to, relative paths are allowed." 12 | - "max_bytes" : long integer; optional; The file size threshold of which the file will be rolled over and a new log file created. 13 | - "backup_count" : integer; optional; The number of previous (rolled over) log files to retain. 14 | - Valid options for "syslog_handler": # See https://docs.python.org/2/library/logging.handlers.html#sysloghandler 15 | - "address" : "string; optional; The fully qualified domain name(FQDN) or IP address of the logging target. Defaults to 127.0.0.1" 16 | - "port" : integer; optional; The port with which to connect to the logging target on. Defaults to 514 17 | - "facility" : "string; optional; The name of the logging facility to use. Defaults to LOG_USER, see the above link for valid names." 18 | - "protocol" : "string; optional; The protocol with which to communicate with the logging target. Valid values are tcp or udp. Defaults to udp" 19 | 20 | 2. "network" 21 | - "ssl" : "string; required; Enable or disable SSL/TLS for the HXTool web interface. Valid values are enabled or disabled. Defaults to enabled." 22 | - "listen_address" : "string; required; The IP address with which the HXTool web interface listens on. Defaults to 0.0.0.0 (any)." 23 | - "port" : integer; required; The port with which the HXTool web interface listens on. Defaults to 8080 24 | - "session_timeout" : integer; optional; Unused (at the moment) 25 | - "proxies" : { .. "http" or "https" .. } # Note: only HTTPS will be used, and only the first entry 26 | - "https" : "string; optional; The fully qualified URN of the proxy to use when communicating with the HX controller. Valid values are https://user:password@host:port or socks5://user:password@host:port" 27 | 28 | 3. "ssl" 29 | - "cert" : "string; required if ssl is enabled in network; The path to the SSL certificate file." 30 | - "key" : "string; required if ssl is enabled in network; The path to the SSL certificate key file." 31 | 32 | 4. "headers" : { "name" : "value" .. } 33 | - "name" : "value" - string; optional; The name and value of any headers to add to any API request made to the HX controller. You can add as many as you'd like. 34 | 35 | 5. "cookies" : { "name" : "value" .. } 36 | - "name" : "value" - string; optional; The name and value of any cookies to add to any API request made to the HX controller. You can add as many as you'd like. 37 | 38 | 6 "scheduler" - Used by the scheduler. 39 | - "thread_count" : value - integer; required; The number of threads to be used by the scheduler. Defaults to null, which means the scheduler will use the number of CPUs in the system plus 1. 40 | - "defer_interval" : value - integer; required; The number of seconds the scheduler will use as a base to defer a task, i.e. bulk acquisition that hasn't completed yet. 41 | 42 | 7. "apicache" (requires background credentials set) 43 | - "enabled" : "boolean; required; Enables and disables the API cache in TinyDB" 44 | - "fetcher_interval" : "integer; number of seconds between each attempt to get new data from HX" 45 | - "updater_interval" : "integer; number of seconds between each attempt to update dirty cache records" 46 | - "objects_per_poll" : "integer; number of new objects that will be transferred for each attempt" 47 | - "max_refresh_per_run" : "integer; number of dirty objects that will be updated each attempt to update" 48 | - "refresh_interval" : "integer; age (seconds) when an object is considered to be dirty" 49 | 50 | 8. "db" (right now only for MongoDB usage) 51 | - "type" : "string; required; only acceptable value is mongodb" 52 | - "host" : "string; required; IP or FQDN of the database server" 53 | - "port" : "integer; optional; the port with which to contact the database server on, defaults vary by database type" 54 | - "user" : "string; required; username with which to authenticate with" 55 | - "password" : "string; required; password with which to authenticate with" 56 | - "auth_source" : "string; required; MongoDB only, authentication source database" 57 | - "auth_mechanism" : "string; optional; MongoDB only, the authentication mechanism to use, defaults to SCRAM-SHA-256" 58 | - "db_name" : "string; optional; The name of the database to use, defaults to hxtool" --------------------------------------------------------------------------------