Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 54 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +2,101 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![CI](https://github.com/WhiteMuush/Bull/actions/workflows/ci.yml/badge.svg)](https://github.com/WhiteMuush/Bull/actions/workflows/ci.yml)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.md)
[![Wiki](https://img.shields.io/badge/docs-wiki-blue.svg)](https://github.com/WhiteMuush/Bull/wiki)

Launch a fully-equipped pentest VM in seconds with pre-installed security tools, VPN protection, and encrypted storage.
Spin up a fully equipped, hardened pentest VM in one command. Bull wraps Vagrant and a hypervisor (libvirt/KVM or VirtualBox) to provision Kali or Parrot machines with a VPN kill switch, encrypted home, GPG-protected credentials, snapshots, and a reusable toolkit manager.

<img width="1230" height="715" alt="ScreenBull" src="https://github.com/user-attachments/assets/ee4b5fee-67b0-4897-91b7-08605b3a9a32" />

## Features

- **Auto-provisioning** — Kali/Parrot ready to use
- **VPN kill switch** — Blocks traffic if VPN drops
- **Encrypted /home** — User data protected with ecryptfs
- **GPG credentials** — Passwords encrypted with AES256 (65M iterations)
- **Snapshot support** — Rollback before risky operations
- **Install and manage security tools** — Pre-installed toolkit with many pentest utilities, easily add more via the manager
- **Auto-provisioning** — Kali or Parrot, ready to use out of the box
- **VPN kill switch** — iptables rules drop all traffic if the VPN drops (OpenVPN & WireGuard)
- **Encrypted /home** — user data protected with ecryptfs
- **GPG credentials** — passwords encrypted with AES256 + SHA512 (65M iterations), never stored in plaintext
- **Snapshots** — roll back before any risky operation
- **Toolkit manager** — save Git-based security tools once, install them on every new VM
- **Cross-provider** — libvirt/KVM or VirtualBox, auto-detected; WSL2 supported

## Requirements

- Linux with libvirt or VirtualBox
- Vagrant 2.3+, jq, sudo
- Linux with libvirt/KVM or VirtualBox (WSL2 supported via libvirt)
- Vagrant 2.3+, `jq`, `gpg`, `ssh`, `sudo`

WSL2 supported via libvirt.
The installer can pull in everything else for you.

## Quick Start

```bash
# Run as root
sudo ./bull.sh init
# One-shot host setup (Vagrant + hypervisor, unattended)
sudo ./install.sh

# Interactive menu
sudo ./bull.sh
# Initialize Bull and verify dependencies
sudo ./bull.sh init

# Or CLI
# Create your first VM
sudo ./bull.sh create my-vm --os kali
```

## ⚠️ Important: First Run

> **⚠️ First installation can take 10-15 minutes** depending on your internet speed. This includes:
> - Downloading and installing Vagrant (if not present)
> - Downloading the Vagrant box (~2-4 GB for Kali/Parrot)
> - Installing libvirt/VirtualBox dependencies
> - Installing the vagrant-libvirt plugin

Following dependencies may be installed:

- **Vagrant** — VM provisioning from HashiCorp
- **VirtualBox** — Oracle VM hypervisor (optional)
- **libvirt** — KVM/QEMU virtualization
- **qemu-kvm** — KVM kernel modules
- **OVMF** — UEFI firmware for secure boot
- **vagrant-libvirt** — Vagrant plugin for KVM
- **jq** — JSON processing
- **spice-vdagent** — Clipboard/resolution for SPICE
- **xdotool** — X11 automation

## Storage

- **Hypervisor**: VirtualBox (`~/VirtualBox VMs/`) or libvirt (`/var/lib/libvirt/images/`)
- **BULL data**: `~/.bull/` (inventory, credentials, GPG keys, toolkit registry)

### ⚠️ WSL2 — Disk space reclamation
# Or just launch the interactive menu
sudo ./bull.sh
```

WSL2 stores its entire Linux filesystem in a `.vhdx` file that **grows automatically but never shrinks on its own**. After destroying VMs, the disk space is freed inside WSL2 but Windows still sees the `.vhdx` at its peak size.
> **First run takes 10–15 minutes.** It downloads the Vagrant box (~2–4 GB) and installs hypervisor dependencies. See the [Installation guide](https://github.com/WhiteMuush/Bull/wiki/Installation) for details.

To reclaim the space on the Windows side:
After `bull init` you can call `bull` directly instead of `./bull.sh`.

```powershell
# 1. Shut down WSL2
wsl --shutdown
## Common Commands

# 2. Compact the virtual disk (run as Administrator in PowerShell)
$vhdx = (Get-ChildItem "$env:LOCALAPPDATA\Packages\*\LocalState\ext4.vhdx" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1).FullName
Optimize-VHD -Path $vhdx -Mode Full
```bash
sudo bull create my-vm --os kali --ram 4096 --cpu 2
sudo bull start my-vm
sudo bull connect my-vm
sudo bull snapshot my-vm pre-exploit
sudo bull vpn my-vm ~/vpn/config.ovpn
sudo bull restore my-vm pre-exploit
sudo bull destroy my-vm
```

> If `Optimize-VHD` is not available (requires Hyper-V), use `diskpart` instead:
> ```
> diskpart
> select vdisk file="C:\Users\<you>\AppData\Local\Packages\<distro>\LocalState\ext4.vhdx"
> compact vdisk
> exit
> ```

## Security

- Scripts require root with 700 permissions
- Passwords never stored in plaintext
- Credentials: GPG + AES256 + SHA512 (65M iterations)
- /home encrypted with ecryptfs
- Default OS accounts locked after creation
- VPN kill switch blocks non-VPN traffic
- Synced folders disabled
Full command reference: [CLI Reference](https://github.com/WhiteMuush/Bull/wiki/CLI-Reference).

> **Note**: Technical measures only. Does not protect against user error or social engineering.
## Documentation

## Commands
The [**Wiki**](https://github.com/WhiteMuush/Bull/wiki) is the full manual:

```bash
sudo ./bull.sh # Interactive TUI menu
sudo ./bull.sh help # CLI help
sudo ./bull.sh create my-vm --os kali --ram 4096 --cpu 2
sudo ./bull.sh start my-vm
sudo ./bull.sh connect my-vm
sudo ./bull.sh snapshot my-vm pre-exploit
sudo ./bull.sh vpn my-vm ~/vpn/config.ovpn
sudo ./bull.sh destroy my-vm
```
- [Installation](https://github.com/WhiteMuush/Bull/wiki/Installation) — host setup, providers, WSL2, disk reclamation
- [Usage Guide](https://github.com/WhiteMuush/Bull/wiki/Usage-Guide) — creating, managing, and connecting to VMs
- [CLI Reference](https://github.com/WhiteMuush/Bull/wiki/CLI-Reference) — every command and flag
- [VPN & Kill Switch](https://github.com/WhiteMuush/Bull/wiki/VPN-and-Kill-Switch) — how traffic is locked to the tunnel
- [Toolkit Manager](https://github.com/WhiteMuush/Bull/wiki/Toolkit-Manager) — save and deploy your own tools
- [Architecture](https://github.com/WhiteMuush/Bull/wiki/Architecture) — how Bull works internally
- [Security Model](https://github.com/WhiteMuush/Bull/wiki/Security-Model) — what Bull protects and what it does not
- [Troubleshooting](https://github.com/WhiteMuush/Bull/wiki/Troubleshooting) — common errors and fixes

After running `bull init`, you can use the `bull` alias directly.
In-repo references: [Architecture](docs/ARCHITECTURE.md), [Adding a Tool](docs/ADDING_A_TOOL.md), [Contributing](docs/CONTRIBUTING.md), [Security Policy](docs/SECURITY.md).

## Project Layout

```
bull.sh Entry point (TUI + CLI)
bull.sh Entry point (TUI + CLI dispatch)
install.sh Unattended host setup (Vagrant + hypervisor)
lib/
core.sh Colors, logging, dependency checks, GPG encryption
inventory.sh VM inventory CRUD (JSON via jq)
vagrant.sh Vagrant/libvirt VM lifecycle
vpn.sh VPN configuration + kill switch
toolkits.sh Security toolkit installation + registry
configs/
Vagrantfile.template
kali-provision.sh
parrot-provision.sh
docs/
ARCHITECTURE.md Internal design documentation
ADDING_A_TOOL.md How to add tools to the toolkit manager
toolkits.sh Toolkit installation + persistent registry
configs/ Vagrantfile template + per-OS provisioning scripts
docs/ Architecture, contributing, security, tooling guides
```

## Security

Bull hardens every VM it creates: GPG-encrypted credentials, ecryptfs `/home`, locked default OS accounts, disabled synced folders, and an iptables VPN kill switch. These are technical measures only — they do not protect against user error or social engineering. See the [Security Model](https://github.com/WhiteMuush/Bull/wiki/Security-Model) and [SECURITY.md](docs/SECURITY.md) for reporting vulnerabilities.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, conventions, and PR checklist.
Issues and PRs welcome. See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for setup, conventions, and the PR checklist.

## License

Expand Down
10 changes: 5 additions & 5 deletions bull.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1629,11 +1629,11 @@ _tui_render() {
# and re-enter/toggle the alternate screen buffer, wiping the output.
# =============================================================================
_show_goodbye() {
trap - EXIT INT TERM HUP # désactive tous les traps avant de quitter
printf '\033[?1049l' # quitte le buffer alternatif
printf '\033[?25h' # affiche le curseur
printf '\033[0m' # reset couleurs
stty sane 2>/dev/null || true # restaure le terminal
trap - EXIT INT TERM HUP # clear all traps before leaving
printf '\033[?1049l' # exit the alternate screen buffer
printf '\033[?25h' # show the cursor
printf '\033[0m' # reset colors
stty sane 2>/dev/null || true # restore the terminal
clear
echo -e "\n${CYAN}Thanks for using BULL!${RESET}"
echo -e "${RED}See you soon! <3${RESET}\n"
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md → docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ brew install shellcheck # macOS
5. Test with at least one provider (libvirt or VirtualBox)
6. Open a PR against `main`

For adding a new security tool to the toolkit manager, see [docs/ADDING_A_TOOL.md](docs/ADDING_A_TOOL.md).
For adding a new security tool to the toolkit manager, see [ADDING_A_TOOL.md](ADDING_A_TOOL.md).

## PR Checklist

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
# Arch / Manjaro (pacman)
# openSUSE Leap / Tumbleweed (zypper)
#
# Architectures : x86_64, arm64
# Usage : sudo ./install.sh [--provider virtualbox|libvirt] [--skip-provider]
# Architectures: x86_64, arm64
# Usage: sudo ./install.sh [--provider virtualbox|libvirt] [--skip-provider]
# =============================================================================
set -euo pipefail
IFS=$'\n\t'
Expand Down
4 changes: 2 additions & 2 deletions lib/core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,8 @@ try_install_package() {
brew install "${pkg_name}" || install_ok=1
;;
apt)
# Vagrant n'est plus dans les dépôts Ubuntu 24.04+ (Noble)
# Installer depuis le dépôt officiel HashiCorp
# Vagrant is no longer in the Ubuntu 24.04+ (Noble) repos
# Install from the official HashiCorp repository
if [[ "${cmd_name}" == "vagrant" ]]; then
log_info "Vagrant not in apt repos (Ubuntu 24.04+). Installing from HashiCorp..."
log_info "This requires adding the HashiCorp repository."
Expand Down
4 changes: 2 additions & 2 deletions lib/toolkits.sh
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ PROVISION_EOF

# Pass validated values via environment variables — no string interpolation
# in the script body, eliminating shell injection risk.
if (cd "${vm_dir}" && vagrant ssh -c "${install_script}" 2>&1); then
if (cd "${vm_dir}" && "${VAGRANT_CMD}" ssh -c "${install_script}" 2>&1); then
log_success "Toolkit '${repo_name}' installed on '${vm_name}'"
return 0
else
Expand Down Expand Up @@ -348,7 +348,7 @@ list_toolkits() {
return 0
fi

(cd "${vm_dir}" && vagrant ssh -c \
(cd "${vm_dir}" && "${VAGRANT_CMD}" ssh -c \
"ls -1 '${TOOLKITS_INSTALL_DIR}/' 2>/dev/null || echo '(none)'" 2>&1) || {
log_error "Failed to list toolkits"
return 1
Expand Down
16 changes: 8 additions & 8 deletions lib/vpn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ configure_vpn() {
fi

# Upload config to VM
(cd "${vm_dir}" && vagrant upload "vpn/${config_basename}" "/tmp/${config_basename}") || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" upload "vpn/${config_basename}" "/tmp/${config_basename}") || {
log_error "Failed to upload VPN config to VM"
return 1
}
Expand Down Expand Up @@ -172,13 +172,13 @@ PROVISION_EOF
tmp_script=$(mktemp /tmp/bull_ovpn_XXXXXX.sh)
chmod 600 "${tmp_script}"
echo "${setup_script}" > "${tmp_script}"
(cd "${vm_dir}" && vagrant upload "${tmp_script}" "/tmp/bull_ovpn_setup.sh") || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" upload "${tmp_script}" "/tmp/bull_ovpn_setup.sh") || {
rm -f "${tmp_script}"
log_error "Failed to upload OpenVPN setup script to VM"
return 1
}
rm -f "${tmp_script}"
(cd "${vm_dir}" && vagrant ssh -c "sudo bash /tmp/bull_ovpn_setup.sh && rm -f /tmp/bull_ovpn_setup.sh" 2>&1) || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" ssh -c "sudo bash /tmp/bull_ovpn_setup.sh && rm -f /tmp/bull_ovpn_setup.sh" 2>&1) || {
log_error "Failed to configure OpenVPN inside VM"
return 1
}
Expand Down Expand Up @@ -227,13 +227,13 @@ PROVISION_EOF
tmp_script=$(mktemp /tmp/bull_wg_XXXXXX.sh)
chmod 600 "${tmp_script}"
echo "${setup_script}" > "${tmp_script}"
(cd "${vm_dir}" && vagrant upload "${tmp_script}" "/tmp/bull_wg_setup.sh") || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" upload "${tmp_script}" "/tmp/bull_wg_setup.sh") || {
rm -f "${tmp_script}"
log_error "Failed to upload WireGuard setup script to VM"
return 1
}
rm -f "${tmp_script}"
(cd "${vm_dir}" && vagrant ssh -c "sudo bash /tmp/bull_wg_setup.sh && rm -f /tmp/bull_wg_setup.sh" 2>&1) || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" ssh -c "sudo bash /tmp/bull_wg_setup.sh && rm -f /tmp/bull_wg_setup.sh" 2>&1) || {
log_error "Failed to configure WireGuard inside VM"
return 1
}
Expand Down Expand Up @@ -313,13 +313,13 @@ PROVISION_EOF
tmp_script=$(mktemp /tmp/bull_ks_XXXXXX.sh)
chmod 600 "${tmp_script}"
echo "${killswitch_script}" > "${tmp_script}"
(cd "${vm_dir}" && vagrant upload "${tmp_script}" "/tmp/bull_ks_setup.sh") || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" upload "${tmp_script}" "/tmp/bull_ks_setup.sh") || {
rm -f "${tmp_script}"
log_error "Failed to upload kill switch script to VM"
return 1
}
rm -f "${tmp_script}"
(cd "${vm_dir}" && vagrant ssh -c "sudo bash /tmp/bull_ks_setup.sh && rm -f /tmp/bull_ks_setup.sh" 2>&1) || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" ssh -c "sudo bash /tmp/bull_ks_setup.sh && rm -f /tmp/bull_ks_setup.sh" 2>&1) || {
log_error "Failed to configure kill switch"
return 1
}
Expand Down Expand Up @@ -381,7 +381,7 @@ PROVISION_EOF
return 0
fi

(cd "${vm_dir}" && vagrant ssh -c "${check_script}" 2>&1) || {
(cd "${vm_dir}" && "${VAGRANT_CMD}" ssh -c "${check_script}" 2>&1) || {
log_error "VPN verification failed"
return 1
}
Expand Down
Loading