diff --git a/README.md b/README.md index 61568424..d8b016f8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,94 @@ -** Make sure to pip install ansible, apt has an older copy ** - -# Instructions -* Start with Parrot HTB Edition -* Install Ansible (python3 -m pip install ansible) -* Clone and enter the repo (git clone) -* ansible-galaxy install -r requirements.yml -* Make sure we have a sudo token (sudo whoami) -* ansible-playbook main.yml - -# Off-Video Changes -* Mate-Terminal Colors, I show how to configure it here (https://www.youtube.com/watch?v=2y68gluYTcc). I just did the steps in that video on my old VM to backup the color scheme, then copied it to this repo. -* Evil-Winrm/Certipy/SharpCollection/CME/Impacket, will make a video for these soon -* Updated BurpSuite Activation. Later versions of ansible would hang if a shell script started a process that didn't die. Put a timeout on the java process +# Parrot OS 7.2 HTB Edition - Build Automation Playbook + +This repository contains an updated and modernized Ansible playbook (originally designed by Ippsec) to automate the configuration and customization of a **Parrot OS 7.2 HTB Edition** virtual machine or local install. + +It configures a complete, high-productivity ethical hacking and development environment with custom terminal styling, browser extensions, global proxy configurations, logging rules, VSCode plugins, and modern security tools. + +--- + +## What's Configured? + +### 1. Terminal Customization +- **Shell (`.bashrc`):** + - Forces terminal session encoding to `UTF-8` globally (resolving Python/Ansible encoding errors). + - Custom multi-line prompt that parses active network interfaces, IP addresses, and Hack The Box VPN connection status dynamically. + - Adds helpful shortcuts (like `_` as an alias for `sudo` and `_i` for `sudo -i`). + - Pre-configures search `PATH` to include `~/go/bin` and `~/.local/bin`. +- **MATE Terminal Profile:** Restores Ippsec's custom "Video" profile (large high-contrast fonts, custom palette) for visibility and streaming. +- **Tmux:** Custom status bar styles, vi-mode window navigation, clipboard integration (`xclip`), and join/send pane shortcuts. + +### 2. VSCode Configuration +- Native installation of Visual Studio Code (`code`) using Microsoft's official signing keys and repositories. +- Automatic, idempotent installation of security and programming extensions: + - **Snyk Security** (vulnerability scanner) + - **Python** (IntelliSense and debugging) + - **Go** (Golang syntax and utilities) + - **C/C++** (native compilation tools support) + - **PHP Tools** (PHP language support) + - **GitHub Copilot** (AI assistance) + - **Code Spell Checker** + - **YAML** (Ansible playbook syntax highlighting) + +### 3. Browser & Proxy Setup (Burp Suite & Firefox) +- **Burp Suite:** + - Automated headless JRE/Java launch to generate the Burp CA certificate dynamically. + - Registers the CA certificate in the system trust store (`update-ca-certificates`) so system CLI tools trust Burp traffic. + - Copies and applies the default custom dark-themed community config, setting SOCKS configurations, layout styles, and optimal hotkeys. +- **Firefox:** + - Configures system-wide Firefox Enterprise policies. + - Automatically installs and locks trusted Burp Suite CA certificates. + - Auto-installs critical pentesting and utility extensions: + - **FoxyProxy Standard** (quick proxy switcher) + - **Hack-Tools** (payload cheat sheet and generator) + - **Cookie-Editor** (cookie inspector/editor) + - **Wappalyzer** (web technology detector) + - **Dark Reader** (forced dark modes) + +### 4. Hacking & Development Tools +- **Pipx Packages (Python CLI):** + - `impacket` (latest Git version) + - `netexec` (successor to CME, installed via pipx to avoid package conflicts) + - `certipy-ad` (Active Directory Certificate Services tool) + - `bloodhound-ce` (Python collector for BloodHound Community Edition) +- **Go Installed Binaries:** + - `kerbrute` (Active Directory Kerberos brute-forcing tool) +- **Ruby Gems:** + - `evil-winrm` (interactive WinRM shell) along with essential WinRM and parsing library dependencies. +- **Standalone Binaries:** + - `chisel` (TCP/UDP tunnels over HTTP, Linux & Windows amd64 binaries in `/opt/chisel`) + - `PEASS-ng` (`linpeas.sh` and `winPEASx64.exe` binaries in `/opt/peas`) + - `chainsaw` (rapid event log analysis tool in `/opt/chainsaw`) + - `BloodHound Legacy GUI` (standalone client extractor in `/opt/BloodHound-Legacy`) +- **BloodHound Community Edition (CE):** + - Configures localized docker-compose servers in `/opt/bloodhound/server`. + - Runs BloodHound CE via Docker, binds the interface port to `8088`, and logs the initial generated admin password to `/opt/bloodhound/server/initial-password.txt`. + +### 5. System & Logging Configuration +- Configures passwordless `sudo` rights (`NOPASSWD`) for the invoking user. +- Installs and enables `rsyslog` and `ufw` firewall rules (logging TCP SYN packets in the input chain). +- Installs `auditd` and sets up optimized audit rules. +- Installs **Laurel v0.7.3** (JSON logging plugin for auditd) ensuring modern glibc compatibility with Parrot OS 7.2. + +--- + +## Instructions + +To build and customize your environment in one command, simply run the bootstrap script: + +1. Clone and enter the repository: + ```bash + git clone https://github.com/yokesh-kumar-M/parrot-build.git + cd parrot-build + ``` + +2. Make the bootstrap script executable: + ```bash + chmod +x setup.sh + ``` + +3. Run the bootstrap runner: + ```bash + ./setup.sh + ``` + +The script will automatically refresh your sudo credentials, configure your terminal to use UTF-8, install base compilers and package dependencies (including `Ansible`), and run the custom playbook. diff --git a/main.yml b/main.yml index f7883e4b..c8a8e0e0 100644 --- a/main.yml +++ b/main.yml @@ -2,6 +2,36 @@ - name: "Customizing Parrot" hosts: localhost connection: local + gather_facts: true + + pre_tasks: + - name: "Get login user or sudo user" + set_fact: + real_user: "{{ ansible_env.SUDO_USER | default(ansible_env.USER) | default(ansible_user_id) }}" + + - name: "Fallback if real_user is root" + shell: "logname || echo $LOGNAME || whoami" + register: logname_output + when: real_user == 'root' + changed_when: false + failed_when: false + + - name: "Set real_user from logname if needed" + set_fact: + real_user: "{{ logname_output.stdout | default('root') }}" + when: real_user == 'root' and logname_output.stdout is defined and logname_output.stdout != "" + + - name: "Get passwd database information for real_user" + getent: + database: passwd + key: "{{ real_user }}" + register: passwd_info + failed_when: false + + - name: "Set home directory fact" + set_fact: + real_user_home: "{{ getent_passwd[real_user][4] if (getent_passwd is defined and real_user in getent_passwd) else ansible_env.HOME }}" + roles: - role: "roles/install-tools" - role: "roles/configure-tmux" @@ -9,13 +39,6 @@ - role: "roles/customize-browser" - role: "roles/configure-logging" - role: "roles/configure-system" - - role: gantsign.visual-studio-code - users: - - username: "{{ ansible_user_id }}" - visual_studio_code_extensions: - - streetsidesoftware.code-spell-checker - - ms-python.python - - DEVSENSE.phptools-vscode - - GitHub.copilot - - snyk-security.snyk-vulnerability-scanner + - role: "roles/customize-vscode" + diff --git a/requirements.yml b/requirements.yml deleted file mode 100644 index 82f93068..00000000 --- a/requirements.yml +++ /dev/null @@ -1 +0,0 @@ -- src: gantsign.visual-studio-code diff --git a/roles/configure-logging/tasks/auditd.yml b/roles/configure-logging/tasks/auditd.yml index 2ab2c08d..1e1cb7e4 100644 --- a/roles/configure-logging/tasks/auditd.yml +++ b/roles/configure-logging/tasks/auditd.yml @@ -61,15 +61,15 @@ become: true become_method: sudo -- name: "Downloading https://github.com/threathunters-io/laurel/releases/download/v0.5.2/laurel-v0.5.2-x86_64-glibc.tar.gz" +- name: "Downloading https://github.com/threathunters-io/laurel/releases/download/v0.7.3/laurel-0.7.3-x86_64-glibc.tar.gz" get_url: - url: https://github.com/threathunters-io/laurel/releases/download/v0.5.2/laurel-v0.5.2-x86_64-glibc.tar.gz - dest: /tmp/laurel-v0.5.2-x86_64-glibc.tar.gz + url: https://github.com/threathunters-io/laurel/releases/download/v0.7.3/laurel-0.7.3-x86_64-glibc.tar.gz + dest: /tmp/laurel-0.7.3-x86_64-glibc.tar.gz mode: 0640 -- name: "Extract /tmp/laurel-v0.5.2-x86_64-glibc.tar.gz" +- name: "Extract /tmp/laurel-0.7.3-x86_64-glibc.tar.gz" unarchive: - src: /tmp/laurel-v0.5.2-x86_64-glibc.tar.gz + src: /tmp/laurel-0.7.3-x86_64-glibc.tar.gz dest: /tmp/laurel/ owner: root group: root @@ -78,7 +78,8 @@ become_method: sudo - name: "Running install -m755 laurel /usr/local/sbin/laurel" - command: "install -m755 laurel /usr/local/sbin/laurel" + shell: | + find . -type f -name laurel -exec install -m755 {} /usr/local/sbin/laurel \; args: chdir: /tmp/laurel/ become: true diff --git a/roles/configure-system/tasks/configure-sudoers.yml b/roles/configure-system/tasks/configure-sudoers.yml index 2d0cb6dc..a40e7a57 100644 --- a/roles/configure-system/tasks/configure-sudoers.yml +++ b/roles/configure-system/tasks/configure-sudoers.yml @@ -4,9 +4,9 @@ lineinfile: dest: /etc/sudoers insertbefore: EOF - regexp: "{{ ansible_user_id }} ALL=" + regexp: "{{ real_user }} ALL=" line: "{{ item }}" validate: visudo -cf %s - when: ansible_user_id != 'root' + when: real_user != 'root' with_items: - - "{{ ansible_user_id }}\tALL=(ALL) NOPASSWD:ALL" \ No newline at end of file + - "{{ real_user }}\tALL=(ALL) NOPASSWD:ALL" \ No newline at end of file diff --git a/roles/configure-tmux/tasks/main.yml b/roles/configure-tmux/tasks/main.yml index 2c547cb6..e263e3b6 100644 --- a/roles/configure-tmux/tasks/main.yml +++ b/roles/configure-tmux/tasks/main.yml @@ -8,6 +8,10 @@ - name: "Copying Tmux Config" copy: src: "{{ role_path }}/files/.tmux.conf" - dest: "{{ ansible_env.HOME }}" + dest: "{{ real_user_home }}/.tmux.conf" + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0644' + become: true diff --git a/roles/customize-browser/files/getburpcert.sh b/roles/customize-browser/files/getburpcert.sh index cc152b7f..bd6a636a 100644 --- a/roles/customize-browser/files/getburpcert.sh +++ b/roles/customize-browser/files/getburpcert.sh @@ -1,7 +1,42 @@ #!/bin/bash -burp=$(find / -name burp*.jar 2>/dev/null | tail -1) -/bin/bash -c "timeout 45 /usr/share/burpsuite/jre/bin/java -Djava.awt.headless=true -jar $burp < <(echo y) &" -sleep 30 -curl http://localhost:8080/cert -o /tmp/cacert.der -exit +# ============================================================================== +# Retriever script to headlessly launch Burp Suite and download its CA Certificate +# ============================================================================== +# Search for the Burp Suite jar in a localized, standard path (much faster than root find) +burp=$(find /usr/share/burpsuite -name "burpsuite*.jar" -o -name "burp*.jar" 2>/dev/null | head -n 1) + +if [ -z "$burp" ]; then + # Fallback search if not in standard directory + burp=$(find /usr/share/ -name "burpsuite*.jar" -o -name "burp*.jar" 2>/dev/null | head -n 1) +fi + +# Locate the appropriate Java binary (bundled JRE vs system-wide fallback) +java_bin="/usr/share/burpsuite/jre/bin/java" +if [ ! -f "$java_bin" ]; then + java_bin=$(which java) +fi + +if [ -n "$burp" ] && [ -n "$java_bin" ]; then + echo "[*] Found Burp Suite Jar: $burp" + echo "[*] Using Java binary: $java_bin" + + # Start Burp headlessly in background. It automatically listens on port 8080 + timeout 45 "$java_bin" -Djava.awt.headless=true -jar "$burp" --headless < <(echo y) & + + # Loop and check if the port is open and we can download the certificate + echo "[*] Waiting for Burp Suite web server to start up..." + for i in {1..15}; do + if curl -s http://localhost:8080/cert -o /tmp/cacert.der; then + echo "[+] Successfully downloaded Burp Suite CA Certificate!" + exit 0 + fi + sleep 2 + done + + echo "[-] Error: Failed to retrieve Burp Suite CA Certificate (Timeout)." + exit 1 +else + echo "[-] Error: Could not locate Burp Suite or Java." + exit 1 +fi diff --git a/roles/customize-browser/tasks/burp.yml b/roles/customize-browser/tasks/burp.yml index 7793da4e..ff4f4d03 100644 --- a/roles/customize-browser/tasks/burp.yml +++ b/roles/customize-browser/tasks/burp.yml @@ -1,24 +1,62 @@ -- name: "Check if BurpSuiteCA.der exists" +- name: "Check if BurpSuiteCA.crt exists" stat: - path: /usr/local/share/ca-certificates/BurpSuiteCA.der + path: /usr/local/share/ca-certificates/BurpSuiteCA.crt register: burp_cert +- name: "Create Java userPrefs directory for Burp" + ansible.builtin.file: + path: "{{ real_user_home }}/.java/.userPrefs/burp" + state: directory + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0755' + recurse: yes + become: true + when: burp_cert.stat.exists == False + +- name: "Create Burp Java preferences file to accept EULA" + ansible.builtin.copy: + dest: "{{ real_user_home }}/.java/.userPrefs/burp/prefs.xml" + content: | + + + + + + + + + + + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0644' + become: true + when: burp_cert.stat.exists == False + - name: "Copying Burp Script" copy: src: files/getburpcert.sh dest: /tmp/getburpcert.sh - mode: 0744 + mode: 0755 when: burp_cert.stat.exists == False - name: "Executing bash script to Download CA Certificate" shell: /tmp/getburpcert.sh + become: true + become_user: "{{ real_user }}" + when: burp_cert.stat.exists == False + +- name: "Convert DER Certificate to PEM format" + ansible.builtin.command: + cmd: openssl x509 -inform der -in /tmp/cacert.der -out /tmp/BurpSuiteCA.crt when: burp_cert.stat.exists == False - name: "Copying CA Certificate to /usr/local/share/ca-certificates" copy: - src: /tmp/cacert.der - dest: /usr/local/share/ca-certificates/BurpSuiteCA.der + src: /tmp/BurpSuiteCA.crt + dest: /usr/local/share/ca-certificates/BurpSuiteCA.crt owner: root group: root mode: 0644 @@ -26,6 +64,12 @@ become_method: sudo when: burp_cert.stat.exists == False +- name: "Update CA Certificates" + ansible.builtin.command: update-ca-certificates + become: true + become_method: sudo + when: burp_cert.stat.exists == False + - name: Create directory for Burp Suite extras ansible.builtin.file: path: "{{ burpsuite_extras_dir }}" @@ -44,8 +88,21 @@ become_method: sudo loop: "{{ lookup('dict', burpsuite_extras_jars) }}" +- name: Create .BurpSuite directory + ansible.builtin.file: + path: "{{ real_user_home }}/.BurpSuite" + state: directory + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0755' + become: true + - name: Copy BurpSuite Community Config template: src: "templates/UserConfigCommunity.json.j2" - dest: "/home/{{ ansible_user_id }}/.BurpSuite/UserConfigCommunity.json" + dest: "{{ real_user_home }}/.BurpSuite/UserConfigCommunity.json" + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0644' + become: true diff --git a/roles/customize-browser/tasks/firefox.yml b/roles/customize-browser/tasks/firefox.yml index a948383f..912a52f2 100644 --- a/roles/customize-browser/tasks/firefox.yml +++ b/roles/customize-browser/tasks/firefox.yml @@ -1,7 +1,45 @@ -- name: "Updating Firefox Policies" +- name: "Ensure Firefox policies directory exists" + ansible.builtin.file: + path: /etc/firefox/policies + state: directory + mode: '0755' + become: true + become_method: sudo + +- name: "Ensure Firefox standard distribution directory exists" + ansible.builtin.file: + path: /usr/share/firefox/distribution + state: directory + mode: '0755' + become: true + become_method: sudo + +- name: "Ensure Firefox ESR distribution directory exists" + ansible.builtin.file: + path: /usr/share/firefox-esr/distribution + state: directory + mode: '0755' + become: true + become_method: sudo + +- name: "Updating Firefox Policies (System-wide)" + template: + src: "templates/policies.json.j2" + dest: /etc/firefox/policies/policies.json + become: true + become_method: sudo + +- name: "Updating Firefox Policies (Standard App)" + template: + src: "templates/policies.json.j2" + dest: /usr/share/firefox/distribution/policies.json + become: true + become_method: sudo + +- name: "Updating Firefox Policies (ESR App)" template: src: "templates/policies.json.j2" - dest: "/usr/share/firefox-esr/distribution/policies.json" + dest: /usr/share/firefox-esr/distribution/policies.json become: true become_method: sudo diff --git a/roles/customize-browser/templates/policies.json.j2 b/roles/customize-browser/templates/policies.json.j2 index 6daf7740..511b7231 100644 --- a/roles/customize-browser/templates/policies.json.j2 +++ b/roles/customize-browser/templates/policies.json.j2 @@ -1,7 +1,7 @@ { "policies": { "Certificates": { - "Install": ["/usr/local/share/ca-certificates/BurpSuiteCA.der"] + "Install": ["/usr/local/share/ca-certificates/BurpSuiteCA.crt"] }, "DisableAppUpdate": true, "DisplayBookmarksToolbar": true, @@ -51,6 +51,32 @@ {% endfor %} ] }, + "Preferences": { + "network.proxy.type": { + "Value": 1, + "Status": "default" + }, + "network.proxy.http": { + "Value": "127.0.0.1", + "Status": "default" + }, + "network.proxy.http_port": { + "Value": 8080, + "Status": "default" + }, + "network.proxy.ssl": { + "Value": "127.0.0.1", + "Status": "default" + }, + "network.proxy.ssl_port": { + "Value": 8080, + "Status": "default" + }, + "network.proxy.share_proxy_settings": { + "Value": true, + "Status": "default" + } + }, "FirefoxHome": { "Search": true, "TopSites": true, diff --git a/roles/customize-browser/vars/main.yml b/roles/customize-browser/vars/main.yml index e81692a7..845f12f1 100644 --- a/roles/customize-browser/vars/main.yml +++ b/roles/customize-browser/vars/main.yml @@ -14,3 +14,5 @@ FirefoxPlugins: - "darkreader" - "foxyproxy-standard" - "wappalyzer" + - "hack-tools" + - "cookie-editor" diff --git a/roles/customize-terminal/files/.bashrc b/roles/customize-terminal/files/.bashrc index 37df6a81..b5237a43 100644 --- a/roles/customize-terminal/files/.bashrc +++ b/roles/customize-terminal/files/.bashrc @@ -1,3 +1,7 @@ +# Force terminal session to UTF-8 to resolve coding and tool errors +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 + # ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples @@ -8,7 +12,7 @@ case $- in *) return;; esac -export PATH=~/.local/bin:/snap/bin:/usr/sandbox/:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/share/games:/usr/local/sbin:/usr/sbin:/sbin:$PATH +export PATH=~/go/bin:~/.local/bin:/snap/bin:/usr/sandbox/:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/share/games:/usr/local/sbin:/usr/sbin:/sbin:$PATH # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options diff --git a/roles/customize-terminal/tasks/main.yml b/roles/customize-terminal/tasks/main.yml index ce8914ba..d55747db 100644 --- a/roles/customize-terminal/tasks/main.yml +++ b/roles/customize-terminal/tasks/main.yml @@ -1,30 +1,40 @@ ---- - name: "Copy BashRC" copy: src: "{{ role_path }}/files/.bashrc" - dest: "{{ ansible_env.HOME }}" + dest: "{{ real_user_home }}/.bashrc" + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0644' + become: true - name: "Ensure .bash_profile sources .bashrc inside tmux" lineinfile: - path: "{{ ansible_env.HOME }}/.bash_profile" + path: "{{ real_user_home }}/.bash_profile" line: | if [[ -n "$TMUX" ]]; then source ~/.bashrc fi insertafter: EOF create: yes + owner: "{{ real_user }}" + group: "{{ real_user }}" + mode: '0644' + become: true - name: "Read current mate terminal profiles" dconf: key: "/org/mate/terminal/global/profile-list" state: "read" register: "profile_list" + failed_when: false + become: true + become_user: "{{ real_user }}" - name: "profile_list was not set, setting" set_fact: profile_list: value: '["default"]' - when: profile_list.value is none + when: profile_list is failed or profile_list.value is none or profile_list.value is not defined - name: "Adding our profile" set_fact: @@ -34,10 +44,16 @@ dconf: key: "/org/mate/terminal/global/profile-list" value: "{{ new_profile_list }}" - when: "'video' not in profile_list.value" + when: "'video' not in (profile_list.value | default(''))" + failed_when: false + become: true + become_user: "{{ real_user }}" - name: "Restoring Video Profile from Dump" shell: cmd: "dconf load /org/mate/terminal/profiles/video/ < {{ role_path }}/files/dconf-dump-video" - when: "'video' not in profile_list.value" + when: "'video' not in (profile_list.value | default(''))" + failed_when: false + become: true + become_user: "{{ real_user }}" diff --git a/roles/customize-vscode/defaults/main.yml b/roles/customize-vscode/defaults/main.yml new file mode 100644 index 00000000..5a8f1b82 --- /dev/null +++ b/roles/customize-vscode/defaults/main.yml @@ -0,0 +1,16 @@ +--- +# defaults file for customize-vscode + +# VS Code extensions installed for the invoking user. These are installed +# with `code --install-extension` rather than through the gantsign role so a +# single failing extension (a pre-bundled Copilot build, a publisher rename, +# or a Node.js deprecation notice written to stderr) cannot abort the play. +vscode_extensions: + - streetsidesoftware.code-spell-checker + - ms-python.python + - DEVSENSE.phptools-vscode + - GitHub.copilot + - snyk-security.snyk-vulnerability-scanner + - golang.go + - ms-vscode.cpptools + - redhat.vscode-yaml diff --git a/roles/customize-vscode/tasks/main.yml b/roles/customize-vscode/tasks/main.yml new file mode 100644 index 00000000..c184b175 --- /dev/null +++ b/roles/customize-vscode/tasks/main.yml @@ -0,0 +1,27 @@ +--- +# Install VS Code extensions for the current user. +# +# gantsign.visual-studio-code installs the `code` binary itself; here we own +# the extension list so we can keep it idempotent and tolerant of the noisy +# exit behaviour of `code --install-extension` (stderr deprecation notices and +# "already installed" collisions that would otherwise fail the playbook). + +- name: "Gather already installed VS Code extensions" + ansible.builtin.command: + cmd: "code --list-extensions" + register: vscode_installed_extensions + changed_when: false + failed_when: false + become: true + become_user: "{{ real_user }}" + +- name: "Install missing VS Code extensions (tolerating stderr and collisions)" + ansible.builtin.command: + cmd: "code --install-extension {{ item }}" + loop: "{{ vscode_extensions }}" + when: (item | lower) not in (vscode_installed_extensions.stdout_lines | default([]) | map('lower') | list) + register: vscode_extension_install + changed_when: "'successfully installed' in (vscode_extension_install.stdout | default(''))" + failed_when: false + become: true + become_user: "{{ real_user }}" diff --git a/roles/install-tools/defaults/main.yml b/roles/install-tools/defaults/main.yml index b833b7f5..b1bd125e 100644 --- a/roles/install-tools/defaults/main.yml +++ b/roles/install-tools/defaults/main.yml @@ -1,3 +1,10 @@ --- -# defaults file for configure-logging +# defaults file for install-tools + +# Debian release codename used for the Docker APT repository. +# download.docker.com/linux/debian only publishes packages for Debian +# codenames, and Parrot reports its own codename (which Docker does not +# build for), so we pin a known-good Debian release here by default. +# Set this to "" to fall back to the auto-detected +# ansible_facts['distribution_release'] on a pure Debian host. distribution: "bookworm" \ No newline at end of file diff --git a/roles/install-tools/tasks/apt-stuff.yml b/roles/install-tools/tasks/apt-stuff.yml index 7f0d39c9..98b2dd7e 100644 --- a/roles/install-tools/tasks/apt-stuff.yml +++ b/roles/install-tools/tasks/apt-stuff.yml @@ -51,22 +51,51 @@ - ca-certificates - curl - gh + - python3-debian + - golang-go + - ruby + - ruby-dev + - build-essential + - dconf-cli state: latest become: true become_method: sudo -- name: "Add Docker keyring to apt" - apt_key: +- name: "Ensure APT keyrings directory exists" + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: "0755" + become: true + become_method: sudo + +- name: "Add Docker's official GPG key to /etc/apt/keyrings" + ansible.builtin.get_url: url: "https://download.docker.com/linux/debian/gpg" - state: present + dest: /etc/apt/keyrings/docker.asc + mode: "0644" become: true become_method: sudo -- name: "Install Docker Repository" - apt_repository: - repo: "deb [arch=amd64] https://download.docker.com/linux/debian {{ distribution }} stable" +- name: "Configure the Docker APT repository (DEB822)" + ansible.builtin.deb822_repository: + name: docker + types: [deb] + uris: "https://download.docker.com/linux/debian" + suites: "{{ distribution | default(ansible_facts['distribution_release'], true) }}" + components: [stable] + architectures: [amd64] + signed_by: /etc/apt/keyrings/docker.asc state: present - update_cache: yes + enabled: true + register: docker_repo + become: true + become_method: sudo + +- name: "Update apt cache after configuring the Docker repository" + ansible.builtin.apt: + update_cache: true + when: docker_repo.changed become: true become_method: sudo @@ -86,3 +115,56 @@ state: latest become: true become_method: sudo + +- name: "Ensure APT keyrings directory exists for VSCode" + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: "0755" + become: true + become_method: sudo + +- name: "Add Microsoft GPG key for VSCode" + ansible.builtin.get_url: + url: "https://packages.microsoft.com/keys/microsoft.asc" + dest: "/etc/apt/keyrings/microsoft.asc" + mode: "0644" + become: true + become_method: sudo + +- name: "Configure the VSCode APT repository" + ansible.builtin.deb822_repository: + name: vscode + types: [deb] + uris: "https://packages.microsoft.com/repos/code" + suites: [stable] + components: [main] + architectures: [amd64] + signed_by: /etc/apt/keyrings/microsoft.asc + state: present + enabled: true + register: vscode_repo + become: true + become_method: sudo + +- name: "Remove conflicting or duplicate packages.microsoft.gpg if it exists" + ansible.builtin.file: + path: /etc/apt/keyrings/packages.microsoft.gpg + state: absent + become: true + become_method: sudo + +- name: "Update apt cache after configuring the VSCode repository" + ansible.builtin.apt: + update_cache: true + when: vscode_repo.changed + become: true + become_method: sudo + +- name: "Install VSCode" + package: + name: + - code + state: latest + become: true + become_method: sudo diff --git a/roles/install-tools/tasks/bloodhound.yml b/roles/install-tools/tasks/bloodhound.yml index 8ded801f..79b1e08f 100644 --- a/roles/install-tools/tasks/bloodhound.yml +++ b/roles/install-tools/tasks/bloodhound.yml @@ -22,10 +22,10 @@ replace: 'BLOODHOUND_PORT:-8088' become: true -- name: "Download BloodHound" - community.docker.docker_compose_v2: - project_src: "/opt/bloodhound/server" - state: present +- name: "Start BloodHound CE via Docker Compose" + ansible.builtin.command: + cmd: "docker compose up -d" + chdir: "/opt/bloodhound/server" become: true - name: "Wait for bloodhound to be up" diff --git a/roles/install-tools/tasks/github-repos.yml b/roles/install-tools/tasks/github-repos.yml index 3aa31632..9be729b7 100644 --- a/roles/install-tools/tasks/github-repos.yml +++ b/roles/install-tools/tasks/github-repos.yml @@ -3,6 +3,7 @@ git: repo: "{{ item.repo }}" dest: "{{ item.location }}" + depth: 1 loop: - { repo: "https://github.com/Flangvik/SharpCollection", location: "/opt/SharpCollection" } - { repo: "https://github.com/danielmiessler/SecLists", location: "/opt/SecLists" } @@ -32,8 +33,8 @@ #- { repo: "jpillora/chisel", regex: "_darwin_amd64", location: "/opt/chisel", filename: "chisel_osx" } - { repo: "carlospolop/PEASS-ng", regex: "linpeas.sh", location: "/opt/peas" } - { repo: "carlospolop/PEASS-ng", regex: "winPEASx64.exe", location: "/opt/peas" } - - { repo: "WithSecureLabs/chainsaw", regex: "chainsaw_all_", location: "/opt/" } - - { repo: "BloodHoundAD/BloodHound", regex: "BloodHound-linux-x64.zip", location: "/opt/" } + - { repo: "WithSecureLabs/chainsaw", regex: "chainsaw_x86_64-unknown-linux-gnu.tar.gz", location: "/opt/" } + - { repo: "SpecterOps/BloodHound-Legacy", regex: "BloodHound-linux-x64.zip", location: "/opt/" } async: 45 poll: 0 become: true diff --git a/setup.sh b/setup.sh new file mode 100644 index 00000000..a0841256 --- /dev/null +++ b/setup.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# ============================================================================== +# Parrot OS 7.2 HTB Edition - Build Automation Bootstrap Script +# Author: Antigravity AI +# ============================================================================== + +# Exit immediately if a command exits with a non-zero status +set -e + +# Force terminal session to UTF-8 to resolve Ansible/Python locale errors +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 + +echo -e "\e[1;34m" +echo "==========================================================" +echo " Parrot OS 7.2 HTB Edition - Automation Bootstrap " +echo "==========================================================" +echo -e "\e[0m" + +# Ensure sudo token is active +echo -e "\e[1;33m[*] Refreshing sudo credentials...\e[0m" +sudo -v + +# Clean up conflicting legacy VS Code keys and sources from previous runs +for file in /etc/apt/sources.list /etc/apt/sources.list.d/*; do + if [ -f "$file" ] && sudo grep -q "packages.microsoft.gpg" "$file"; then + echo -e "\e[1;33m[*] Removing conflicting VS Code repository config in $file...\e[0m" + sudo rm -f "$file" + fi +done +if [ -f /etc/apt/keyrings/packages.microsoft.gpg ]; then + sudo rm -f /etc/apt/keyrings/packages.microsoft.gpg +fi + +# Check for updates and install base dependencies +echo -e "\e[1;33m[*] Updating package list & installing base dependencies...\e[0m" +sudo apt-get update +sudo apt-get install -y python3-pip python3-venv git curl dconf-cli build-essential ruby ruby-dev golang-go + +# Install Ansible safely (handling PEP 668 / Debian 12 Managed Environment) +if ! command -v ansible-playbook &> /dev/null; then + echo -e "\e[1;33m[*] Ansible is not installed. Installing...\e[0m" + sudo apt-get install -y ansible || \ + python3 -m pip install --break-system-packages --user ansible || \ + python3 -m pip install --user ansible +else + echo -e "\e[1;32m[+] Ansible is already installed.\e[0m" +fi + +# Run the playbook +echo -e "\e[1;32m[+] Starting Parrot Customization Playbook...\e[0m" +ansible-playbook main.yml + +echo -e "\e[1;32m[+] Bootstrap completed successfully!\e[0m"