pentest_setup deploys a pen-testing-ready Bash environment on top of
common_core and
bash_setup. It ships:
- A set of pentest-specific dotfiles (
pentest.path.sh,pentest.env.sh,pentest.aliases.sh,pentest.keys,renew_tgt.sh, thescreenshothelper) deployed to${HOME}/.config/bash/. - A
pentest.shhook thatbash_setup'sbashrcalready sources, which pulls the above into every interactive shell. - Five interactive menus under
menus/that walk through preflight checks, environment setup, apt/python/go/ruby dependency installs, 60+ tool installs frommodules/tools/, and post-install cleanup. - A
config/layer that definesDATA_DIR,ENGAGEMENT_DIR,BACKUP_DIR,LOOT_DIR, and related engagement paths used by both pentest helpers andbash_setup'stgt.aliases.sh.
It is the fourth repo in a five-repo stack:
common_core → bash_setup → scripts → pentest_setup → pentest_menu
pentest_setup's install.sh will refuse to run unless the earlier repos
in the chain are in place. See Requirements.
- Bash 4+ (macOS users:
brew install bash) - Python 3.12+ for the tool-install modules that ship Python helpers
common_coreinstalled at${HOME}/.config/bash/lib/common_core/(install instructions)bash_setupinstalled (specifically: itsbashrcdeployed to${HOME}/.bashrc, which sources the${BASH_DIR}/pentest.shhook this repo deploys)- Recommended for development:
shellcheck(lint)shfmt(format) — must support-i 4 -ci -srbats(test)
# 1. Install common_core and bash_setup first (see those repos).
# 2. Then clone and install pentest_setup:
git clone https://github.com/tatanus/pentest_setup.git
cd pentest_setup
make install # equivalent to: bash install.shinstall.sh is interactive — it presents the five-menu flow
(00_preflight, 01_environment, 02_requirements, 03_tools,
04_post). Pass --dry-run for a no-op preview.
After install, start a new shell or re-source bashrc to pick up the deployed dotfiles:
exec bash -l.
├── install.sh # menu-driven installer (entry point)
├── Makefile # quality gates + release automation
├── VERSION # date-based version: YYYY.MM.DD.N
├── CHANGELOG.md # Keep a Changelog
├── config/
│ ├── config.sh # DATA_DIR, ENGAGEMENT_DIR, BACKUP_DIR, etc.
│ └── lists.sh # PENTEST_FILES, APT/PIP/GO/RUBY package lists
├── dotfiles/ # files deployed to ${HOME}/.config/bash/
│ ├── pentest.sh # source hook for ${BASH_DIR}/pentest.sh
│ ├── pentest.path.sh # exports DATA_DIR, ENGAGEMENT_DIR, PATH adds
│ ├── pentest.env.sh # NETWORK_IFACE, DC_IP, credentials defaults
│ ├── pentest.alias.sh # pentest-flavored aliases
│ ├── pentest.keys # SSH/PGP key references
│ ├── renew_tgt.sh # cron-payload script (renews Kerberos TGTs)
│ └── screenshot.sh # interactive screenshot helper
├── menus/ # auto-sourced by install.sh in order
│ ├── 00_preflight.sh # tool/OS/root/common_core checks
│ ├── 01_environment.sh # dotfile deploy, dirs, cron jobs
│ ├── 02_requirements.sh # apt / pip / go / ruby package installs
│ ├── 03_tools.sh # interactive 60+ tool installer
│ └── 04_post.sh # cleanup + summary
├── modules/
│ ├── tools/ # one *.sh per tool, sourced by 03_tools.sh
│ └── scripts/ # payloads copied to ${TOOLS_DIR}/SCRIPTS/ at install
│ ├── misc/ # misc support scripts
│ └── msf/ # Metasploit runner + resource scripts (see below)
│ ├── msf_common_runner.rb # run_module(opts) entry point
│ ├── run_all_modules.sh # run every modules/*.rc via msfconsole
│ ├── modules/ # per-module *.rc (incl. all *_version scanners)
│ └── FILES/ # wordlists referenced by the .rc creds blocks
├── tests/ # BATS coverage (structural)
└── tools/
└── check_bash_style.sh # comprehensive style scan
modules/scripts/msf/ is deployed to ${TOOLS_DIR}/SCRIPTS/MSF/ by
menus/01_environment.sh::environment::setup_msf_scripts. It holds a shared
runner, msf_common_runner.rb, plus one resource script per module under
modules/*.rc.
Each .rc file is a thin wrapper: it defines an opts hash (module path,
plus a target_filter of proto + ports + service names) and hands it to
run_module(opts). The runner walks the MSF database, selects every open
host whose service matches the filter by name or port, sets RHOSTS
(and RPORT when the module supports it), and runs the module — spooling
output to ${DATA_DIR}/OUTPUT/TEE/. To add another module, copy an existing
.rc (e.g. smb_version.rc), change the module_path, and set the
proto/ports/services to match where that service is expected to run.
The *_version.rc set covers every auxiliary/.../*_version scanner in the
framework; proto and default port for each were taken from the module's
registered Opt::RPORT (or protocol mixin), then widened to the ports a scan
realistically labels. Alongside them is a set of unauthenticated
enumeration/discovery modules useful for an automated internal pass —
endpoint_mapper, mssql_ping, nbname, pipe_auditor, snmp_enum,
smtp_enum, ssh_enumusers, winrm_auth_methods, redis_server,
couchdb_enum, afp_server_info, ntp_monlist, sip_options,
ssdp_msearch, kerberos_enumusers, and more. Login/brute modules are
intentionally not included by default (account-lockout risk); add them
per-engagement by copying a .rc and filling in the user_file/pass_file
block.
To run the whole set, use run_all_modules.sh (deployed beside modules/):
./run_all_modules.sh # every modules/*.rc in one msfconsole session
./run_all_modules.sh -w engagement # select that msf workspace first
./run_all_modules.sh -p 'snmp_*.rc' # only matching modules
./run_all_modules.sh --isolated -t 5m # one console per module, 5-min cap each
./run_all_modules.sh --results # parse existing tee logs for hits, run nothing
./run_all_modules.sh --list # show what would run, then exitBy default it concatenates every module into one resource file and runs a
single msfconsole (paying startup once; each module still spools its own
OUTPUT/TEE/MSF_<module>.tee). --isolated runs one console per module so a
hang or crash cannot affect the rest, and --timeout bounds each run.
After a run it parses those MSF_*.tee logs (in ${DATA_DIR}/OUTPUT/TEE,
overridable with --tee-dir/MSF_TEE_DIR) for Metasploit success lines —
[+] / print_good — and prints them grouped by module: ANSI colors
stripped, hits de-duplicated, [*]/[-] noise dropped. Findings print to
stdout (so --results > hits.txt captures just them) and the summary to
stderr. Use --no-results to skip the parse, or -R/--results to parse
existing logs without running anything.
dotfiles/renew_tgt.sh looks like a duplicate of bash_setup's
tgt.aliases.sh::renewTGT but isn't — it's a self-contained cron payload
scheduled by menus/01_environment.sh::environment::setup_cron_jobs. It
must stay independent of any sourced shell environment because cron does
not load bashrc.
| Target | What it does |
|---|---|
make help |
Show all targets. |
make ci |
Format check + lint + tests. Non-mutating. Run before PRs. |
make fmt |
Auto-format with shfmt -i 4 -ci -sr. |
make fmt-check |
Verify formatting without writing; same flags as make fmt. |
make lint |
shellcheck -x across git ls-files '*.sh'. |
make test |
bats -r tests. |
make style |
Comprehensive style scan via tools/check_bash_style.sh. |
make install |
bash install.sh — deploy dotfiles, run setup menus. |
make show-version |
Print current VERSION. |
make release V=… |
Cut a release (see Releases). |
make release-today |
Cut a release using today's UTC date (YYYY.MM.DD.0). |
The mandated formatter flags are -i 4 -ci -sr. Do not add -bn or
-kp anywhere.
- Depends on:
common_core(installed at${HOME}/.config/bash/lib/common_core/util.sh) andbash_setup(specifically: itsbashrcmust be deployed so that${BASH_DIR}/pentest.shgets sourced). - Provides for
bash_setup:- The
pentest.shhook deployed to${BASH_DIR}/pentest.sh. DATA_DIRandENGAGEMENT_DIRexports (viapentest.path.sh), whichbash_setup'stgt.aliases.shreads. (tgt.aliases.shalso has a${HOME}/DATAsafe-default fallback so it does not crash ifpentest_setupis not installed.)
- The
Enforced by .shellcheckrc and tools/check_bash_style.sh:
- Bash 4+,
set -uo pipefail,IFS=$'\n\t'. - No
set -e— handle errors explicitly. - No
evaloutside heavily-audited metaprogramming. function name() { … }form; never barename() { … }.- All expansions quoted and braced (
"${var}","$@"). [[ … ]]not[ … ];command -vnotwhich;$(…)not backticks.- Source-guard idiom on every helper:
if [[ -z "${X_LOADED:-}" ]]; then declare -g X_LOADED=true # … fi
See CLAUDE.md (auto-generated) for the canonical policy hash chain.
The repo uses date-based four-part versioning (YYYY.MM.DD.N), tracked in
VERSION and CHANGELOG.md. To cut a release:
# 1. Land your changes as normal commits with `## [Unreleased]` notes.
git add …; git commit -m "feat(…): …"; git push
# 2. Cut the release. `make release` will:
# - run `make ci` (refuse if anything fails)
# - refuse on a dirty working tree
# - stamp `## [Unreleased]` -> `## [Vx] - YYYY-MM-DD` (UTC) in CHANGELOG
# - write VERSION
# - single commit `chore(release): cut Vx`
# - annotated tag `vVx`
# - `git push --follow-tags`
make release-today # uses today's UTC date.0
make release-today N=1 # second cut of the same UTC day -> .1
make release V=2026.06.27.0 # explicit versionThis project is licensed under the MIT License.