├── .env.example ├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── BugBountyScanner.sh ├── Dockerfile ├── LICENSE ├── README.md ├── dist └── github-markdown.css ├── setup.sh └── utils ├── ScopeToBurp.sh ├── runTests.sh └── screenshotReport.sh /.env.example: -------------------------------------------------------------------------------- 1 | toolsDir='/opt' 2 | telegram_api_key='XXXXXXXXX:XXX_XXXXXXXXXXXXX_XXXXXXXXXXXX' 3 | telegram_chat_id='XXXXXXXXX' -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [chvancooten] 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test Docker Container 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '0 4 * * SAT' 10 | 11 | env: 12 | TEST_TAG: chvancooten/bugbountyscanner:test 13 | LATEST_TAG: chvancooten/bugbountyscanner:latest 14 | 15 | jobs: 16 | docker: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v3 21 | 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@v2 24 | 25 | - name: Set up Docker Buildx 26 | uses: docker/setup-buildx-action@v2 27 | 28 | - name: Login to Docker Hub 29 | uses: docker/login-action@v2 30 | with: 31 | username: chvancooten 32 | password: ${{ secrets.DOCKERHUB_TOKEN }} 33 | 34 | - name: Build and export to Docker 35 | uses: docker/build-push-action@v4 36 | with: 37 | context: . 38 | load: true 39 | tags: ${{ env.TEST_TAG }} 40 | 41 | - name: Test image 42 | run: | 43 | docker run --rm -i ${{ env.TEST_TAG }} bash < ./utils/runTests.sh 44 | 45 | - name: Build and push 46 | uses: docker/build-push-action@v4 47 | with: 48 | context: . 49 | platforms: linux/amd64 50 | push: true 51 | tags: ${{ env.LATEST_TAG }} -------------------------------------------------------------------------------- /BugBountyScanner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Automated Bug Bounty recon script 3 | ## By Cas van Cooten 4 | 5 | scriptDir=$(dirname "$(readlink -f "$0")") 6 | baseDir=$PWD 7 | lastNotified=0 8 | thorough=true 9 | notify=true 10 | overwrite=false 11 | 12 | source "./utils/screenshotReport.sh" 13 | 14 | function notify { 15 | if [ "$notify" = true ] 16 | then 17 | if [ $(($(date +%s) - lastNotified)) -le 3 ] 18 | then 19 | echo "[!] Notifying too quickly, sleeping to avoid skipped notifications..." 20 | sleep 3 21 | fi 22 | 23 | # Format string to escape special characters and send message through Telegram API. 24 | if [ -z "$DOMAIN" ] 25 | then 26 | message=`echo -ne "*BugBountyScanner:* $1" | sed 's/[^a-zA-Z 0-9*_]/\\\\&/g'` 27 | else 28 | message=`echo -ne "*BugBountyScanner [$DOMAIN]:* $1" | sed 's/[^a-zA-Z 0-9*_]/\\\\&/g'` 29 | fi 30 | 31 | curl -s -X POST "https://api.telegram.org/bot$telegram_api_key/sendMessage" -d chat_id="$telegram_chat_id" -d text="$message" -d parse_mode="MarkdownV2" &> /dev/null 32 | lastNotified=$(date +%s) 33 | fi 34 | } 35 | 36 | for arg in "$@" 37 | do 38 | case $arg in 39 | -h|--help) 40 | echo "BugBountyHunter - Automated Bug Bounty reconnaissance script" 41 | echo " " 42 | echo "$0 [options]" 43 | echo " " 44 | echo "options:" 45 | echo "-h, --help show brief help" 46 | echo "-t, --toolsdir tools directory (no trailing /), defaults to '/opt'" 47 | echo "-q, --quick perform quick recon only (default: false)" 48 | echo "-d, --domain top domain to scan, can take multiple" 49 | echo "-o, --outputdirectory parent output directory, defaults to current directory (subfolders will be created per domain)" 50 | echo "-w, --overwrite overwrite existing files. Skip steps with existing files if not provided (default: false)" 51 | echo " " 52 | echo "Note: 'ToolsDir', as well as your 'telegram_api_key' and 'telegram_chat_id' can be defined in .env or through (Docker) environment variables." 53 | echo " " 54 | echo "example:" 55 | echo "$0 --quick -d google.com -d uber.com -t /opt" 56 | exit 0 57 | ;; 58 | -q|--quick) 59 | thorough=false 60 | shift 61 | ;; 62 | -d|--domain) 63 | domainargs+=("$2") 64 | shift 65 | shift 66 | ;; 67 | -t|--toolsdir) 68 | toolsDir="$2" 69 | shift 70 | shift 71 | ;; 72 | -o|--outputdirectory) 73 | baseDir="$2" 74 | shift 75 | shift 76 | ;; 77 | -w|--overwrite) 78 | overwrite=true 79 | shift 80 | esac 81 | done 82 | 83 | if [ -f "$scriptDir/.env" ] 84 | then 85 | set -a 86 | . .env 87 | set +a 88 | fi 89 | 90 | if [ -z "$telegram_api_key" ] || [ -z "$telegram_chat_id" ] 91 | then 92 | echo "[i] \$telegram_api_key and \$telegram_chat_id variables not found, disabling notifications..." 93 | notify=false 94 | fi 95 | 96 | if [ ! -d "$baseDir" ] 97 | then 98 | read -r -N 1 -p "[?] Provided output directory \"$baseDir\" does not exist, create it? [Y/N] " 99 | echo 100 | if [[ ! $REPLY =~ ^[Yy]$ ]] 101 | then 102 | exit 1 103 | fi 104 | mkdir -p "$baseDir" 105 | fi 106 | 107 | if [ "${#domainargs[@]}" -ne 0 ] 108 | then 109 | IFS=', ' read -r -a DOMAINS <<< "${domainargs[@]}" 110 | else 111 | read -r -p "[?] What's the target domain(s)? E.g. \"domain.com,domain2.com\". DOMAIN: " domainsresponse 112 | IFS=', ' read -r -a DOMAINS <<< "$domainsresponse" 113 | fi 114 | 115 | if [ -z "$toolsDir" ] 116 | then 117 | echo "[i] \$toolsDir variable not defined in .env, defaulting to /opt..." 118 | toolsDir="/opt" 119 | fi 120 | 121 | echo "$PATH" | grep -q "$HOME/go/bin" || export PATH=$PATH:$HOME/go/bin 122 | 123 | if command -v nuclei &> /dev/null # Very crude dependency check :D 124 | then 125 | echo "[*] Dependencies found." 126 | else 127 | echo "[*] Dependencies not found, running install script..." 128 | bash "$scriptDir/setup.sh" -t "$toolsDir" 129 | fi 130 | 131 | cd "$baseDir" || { echo "Something went wrong"; exit 1; } 132 | 133 | # Enable logging for stdout and stderr (timestamp format [dd/mm/yy hh:mm:ss]) 134 | LOG_FILE="./BugBountyScanner-$(date +'%Y%m%d-%T').log" 135 | exec > >(while read -r line; do printf '%s %s\n' "[$(date +'%D %T')]" "$line" | tee -a "${LOG_FILE}"; done) 2>&1 136 | 137 | echo "[*] STARTING RECON." 138 | notify "Starting recon on *${#DOMAINS[@]}* domains." 139 | 140 | for DOMAIN in "${DOMAINS[@]}" 141 | do 142 | mkdir -p "$DOMAIN" 143 | cd "$DOMAIN" || { echo "Something went wrong"; exit 1; } 144 | 145 | cp -r "$scriptDir/dist" . 146 | 147 | echo "[*] RUNNING RECON ON $DOMAIN." 148 | notify "Starting recon on $DOMAIN. Enumerating subdomains with Amass..." 149 | 150 | if [ ! -f "domains-$DOMAIN.txt" ] || [ "$overwrite" = true ] 151 | then 152 | echo "[*] RUNNING AMASS..." 153 | amass enum --passive -d "$DOMAIN" -o "domains-$DOMAIN.txt" 154 | notify "Amass completed! Identified *$(wc -l < "domains-$DOMAIN.txt")* subdomains. Resolving IP addresses..." 155 | else 156 | echo "[-] SKIPPING AMASS" 157 | fi 158 | 159 | if [ ! -f "ip-addresses-$DOMAIN.txt" ] || [ "$overwrite" = true ] 160 | then 161 | echo "[*] RESOLVING IP ADDRESSES FROM HOSTS..." 162 | while read -r hostname; do 163 | dig "$hostname" +short >> "dig.txt" 164 | done < "domains-$DOMAIN.txt" 165 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' "dig.txt" | sort -u > "ip-addresses-$DOMAIN.txt" && rm "dig.txt" 166 | notify "Resolving done! Enriching *$(wc -l < "ip-addresses-$DOMAIN.txt")* IP addresses with Shodan data..." 167 | else 168 | echo "[-] SKIPPING RESOLVING HOST IP ADDRESSES" 169 | fi 170 | 171 | if [ ! -f "nrich-$DOMAIN.txt" ] || [ "$overwrite" = true ] 172 | then 173 | echo "[*] ENRICHING IP ADDRESS DATA WITH SHODAN..." 174 | nrich "ip-addresses-$DOMAIN.txt" > "nrich-$DOMAIN.txt" 175 | notify "IP addresses enriched! Make sure to give that a manual look. Getting live domains with HTTPX..." 176 | else 177 | echo "[-] SKIPPING IP ENRICHMENT" 178 | fi 179 | 180 | if [ ! -f "livedomains-$DOMAIN.txt" ] || [ "$overwrite" = true ] 181 | then 182 | echo "[*] RUNNING HTTPX..." 183 | httpx -silent -no-color -l "domains-$DOMAIN.txt" -title -content-length -web-server -status-code -ports 80,8080,443,8443 -threads 25 -o "httpx-$DOMAIN.txt" 184 | cut -d' ' -f1 < "httpx-$DOMAIN.txt" | sort -u > "livedomains-$DOMAIN.txt" 185 | notify "HTTPX completed. *$(wc -l < "livedomains-$DOMAIN.txt")* endpoints seem to be alive. Checking for hijackable subdomains with SubJack..." 186 | else 187 | echo "[-] SKIPPING HTTPX" 188 | fi 189 | 190 | if [ ! -f "subjack-$DOMAIN.txt" ] || [ "$overwrite" = true ] 191 | then 192 | echo "[*] RUNNING SUBJACK..." 193 | subjack -w "domains-$DOMAIN.txt" -t 100 -c "$toolsDir/subjack/fingerprints.json" -o "subjack-$DOMAIN.txt" -a 194 | if [ -f "subjack-$DOMAIN.txt" ]; then 195 | echo "[+] HIJACKABLE SUBDOMAINS FOUND!" 196 | notify "SubJack completed. One or more hijackable subdomains found!" 197 | notify "Hijackable domains: $(cat "subjack-$DOMAIN.txt")" 198 | notify "Gathering live page screenshots with aquatone..." 199 | else 200 | echo "[-] NO HIJACKABLE SUBDOMAINS FOUND." 201 | notify "No hijackable subdomains found. Gathering live page screenshots with aquatone..." 202 | fi 203 | else 204 | echo "[-] SKIPPING SUBJACK" 205 | fi 206 | 207 | if [ ! -f "aquatone_report.html" ] || [ "$overwrite" = true ] 208 | then 209 | echo "[*] RUNNING AQUATONE..." 210 | cat livedomains-$DOMAIN.txt | aquatone -ports medium 211 | generate_screenshot_report "$DOMAIN" 212 | notify "Aquatone completed! Took *$(find screenshots/* -maxdepth 0 | wc -l)* screenshots. Getting Wayback Machine path list with GAU..." 213 | else 214 | echo "[-] SKIPPING AQUATONE" 215 | fi 216 | 217 | if [ ! -f "WayBack-$DOMAIN.txt" ] || [ "$overwrite" = true ] 218 | then 219 | echo "[*] RUNNING GAU..." 220 | # Get ONLY Wayback URLs with parameters to prevent clutter 221 | gau -subs -providers wayback -o "gau-$DOMAIN.txt" "$DOMAIN" 222 | grep '?' < "gau-$DOMAIN.txt" | qsreplace -a > "WayBack-$DOMAIN.txt" 223 | rm "gau-$DOMAIN.txt" 224 | notify "GAU completed. Got *$(wc -l < "WayBack-$DOMAIN.txt")* paths." 225 | else 226 | echo "[-] SKIPPING GAU" 227 | fi 228 | 229 | if [ "$thorough" = true ] ; then 230 | if [ ! -f "nuclei-$DOMAIN.txt" ] || [ "$overwrite" = true ] 231 | then 232 | echo "[*] RUNNING NUCLEI..." 233 | notify "Detecting known vulnerabilities with Nuclei..." 234 | nuclei -c 150 -l "livedomains-$DOMAIN.txt" -severity low,medium,high,critical -etags "intrusive" -o "nuclei-$DOMAIN.txt" 235 | 236 | if [ -f "nuclei-$DOMAIN.txt" ] 237 | then 238 | highIssues="$(grep -c 'high' < "nuclei-$DOMAIN.txt")" 239 | critIssues="$(grep -c 'critical' < "nuclei-$DOMAIN.txt")" 240 | if [ "$critIssues" -gt 0 ] 241 | then 242 | notify "Nuclei completed. Found *$(wc -l < "nuclei-$DOMAIN.txt")* (potential) issues, of which *$critIssues* are critical, and *$highIssues* are high severity. Finding temporary files with ffuf.." 243 | elif [ "$highIssues" -gt 0 ] 244 | then 245 | notify "Nuclei completed. Found *$(wc -l < "nuclei-$DOMAIN.txt")* (potential) issues, of which *$highIssues* are high severity. Finding temporary files with ffuf..." 246 | else 247 | notify "Nuclei completed. Found *$(wc -l < "nuclei-$DOMAIN.txt")* (potential) issues, of which none are critical or high severity. Finding temporary files with ffuf..." 248 | fi 249 | else 250 | notify "Nuclei completed. No issues found. Finding temporary files with ffuf..." 251 | fi 252 | else 253 | echo "[-] SKIPPING NUCLEI" 254 | fi 255 | 256 | if [ ! -d "ffuf" ] || [ "$overwrite" = true ] 257 | then 258 | echo "[*] RUNNING FFUF..." 259 | mkdir ffuf 260 | cd ffuf || { echo "Something went wrong"; exit 1; } 261 | 262 | while read -r dname; 263 | do 264 | filename=$(echo "${dname##*/}" | sed 's/:/./g') 265 | ffuf -w "$toolsDir/wordlists/tempfiles.txt" -u "$dname/FUZZ" -mc 200-299 -maxtime 180 -o "ffuf-$filename.csv" -of csv 266 | done < "../livedomains-$DOMAIN.txt" 267 | 268 | # Remove all files with only a header row 269 | find . -type f -size -1c -delete 270 | 271 | # Count the number of files (lines in the ffuf files, excluding the header row for each file) and sum into variable 272 | ffufFiles=$(find . -type f -exec wc -l {} + | sed '$d' | awk '{sum+=$1-1} END{print sum}') 273 | 274 | if [ "$ffufFiles" -gt 0 ] 275 | then 276 | notify "FFUF completed. Got *$ffufFiles* files. Spidering paths with GoSpider..." 277 | cd .. || { echo "Something went wrong"; exit 1; } 278 | else 279 | notify "FFUF completed. No temporary files identified. Spidering paths with GoSpider..." 280 | cd .. || { echo "Something went wrong"; exit 1; } 281 | rm -rf ffuf 282 | fi 283 | 284 | fi 285 | else 286 | echo "[-] SKIPPING ffuf" 287 | fi 288 | 289 | if [ ! -f "paths-$DOMAIN.txt" ] || [ "$overwrite" = true ] 290 | then 291 | echo "[*] RUNNING GOSPIDER..." 292 | # Spider for unique URLs, filter duplicate parameters 293 | gospider -S "livedomains-$DOMAIN.txt" -o GoSpider -t 2 -c 4 -d 3 -m 3 --no-redirect --blacklist jpg,jpeg,gif,css,tif,tiff,png,ttf,woff,woff2,ico,svg 294 | cat GoSpider/* | grep -o -E "(([a-zA-Z][a-zA-Z0-9+-.]*\:\/\/)|mailto|data\:)([a-zA-Z0-9\.\&\/\?\:@\+-\_=#%;,])*" | sort -u | qsreplace -a | grep "$DOMAIN" > "tmp-GoSpider-$DOMAIN.txt" 295 | rm -rf GoSpider 296 | notify "GoSpider completed. Crawled *$(wc -l < "tmp-GoSpider-$DOMAIN.txt")* endpoints. Getting interesting endpoints and parameters..." 297 | 298 | ## Enrich GoSpider list with parameters from GAU/WayBack. Disregard new GAU endpoints to prevent clogging with unreachable endpoints (See Issue #24). 299 | # Get only endpoints from GoSpider list (assumed to be live), disregard parameters, and append ? for grepping 300 | sed "s/\?.*//" "tmp-GoSpider-$DOMAIN.txt" | sort -u | sed -e 's/$/\?/' > "tmp-LivePathsQuery-$DOMAIN.txt" 301 | # Find common endpoints containing (hopefully new and interesting) parameters from GAU/Wayback list 302 | grep -f "tmp-LivePathsQuery-$DOMAIN.txt" "WayBack-$DOMAIN.txt" > "tmp-LiveWayBack-$DOMAIN.txt" 303 | # Merge new parameters with GoSpider list and get only unique endpoints 304 | cat "tmp-LiveWayBack-$DOMAIN.txt" "tmp-GoSpider-$DOMAIN.txt" | sort -u | qsreplace -a > "paths-$DOMAIN.txt" 305 | rm "tmp-LivePathsQuery-$DOMAIN.txt" "tmp-LiveWayBack-$DOMAIN.txt" "tmp-GoSpider-$DOMAIN.txt" 306 | else 307 | echo "[-] SKIPPING GOSPIDER" 308 | fi 309 | 310 | if [ ! -d "check-manually" ] || [ "$overwrite" = true ] 311 | then 312 | echo "[*] GETTING INTERESTING PARAMETERS WITH GF..." 313 | mkdir "check-manually" 314 | # Use GF to identify "suspicious" endpoints that may be vulnerable (automatic checks below) 315 | gf ssrf < "paths-$DOMAIN.txt" > "check-manually/server-side-request-forgery.txt" 316 | gf xss < "paths-$DOMAIN.txt" > "check-manually/cross-site-scripting.txt" 317 | gf redirect < "paths-$DOMAIN.txt" > "check-manually/open-redirect.txt" 318 | gf rce < "paths-$DOMAIN.txt" > "check-manually/rce.txt" 319 | gf idor < "paths-$DOMAIN.txt" > "check-manually/insecure-direct-object-reference.txt" 320 | gf sqli < "paths-$DOMAIN.txt" > "check-manually/sql-injection.txt" 321 | gf lfi < "paths-$DOMAIN.txt" > "check-manually/local-file-inclusion.txt" 322 | gf ssti < "paths-$DOMAIN.txt" > "check-manually/server-side-template-injection.txt" 323 | notify "Done! Gathered a total of *$(wc -l < "paths-$DOMAIN.txt")* paths, of which *$(cat check-manually/* | wc -l)* possibly exploitable. Testing for Server-Side Template Injection..." 324 | else 325 | echo "[-] SKIPPING GF" 326 | fi 327 | 328 | if [ ! -f "potential-ssti.txt" ] || [ "$overwrite" = true ] 329 | then 330 | echo "[*] TESTING FOR SSTI..." 331 | qsreplace "BugBountyScanner{{9*9}}" < "check-manually/server-side-template-injection.txt" | \ 332 | xargs -I % -P 100 sh -c 'curl -s "%" 2>&1 | grep -q "BugBountyScanner81" && echo "[+] Found endpoint likely to be vulnerable to SSTI: %" && echo "%" >> potential-ssti.txt' 333 | if [ -f "potential-ssti.txt" ]; then 334 | notify "Identified *$(wc -l < potential-ssti.txt)* endpoints potentially vulnerable to SSTI! Testing for Local File Inclusion..." 335 | else 336 | notify "No SSTI found. Testing for Local File Inclusion..." 337 | fi 338 | else 339 | echo "[-] SKIPPING TEST FOR SSTI" 340 | fi 341 | 342 | if [ ! -f "potential-lfi.txt" ] || [ "$overwrite" = true ] 343 | then 344 | echo "[*] TESTING FOR (*NIX) LFI..." 345 | qsreplace "/etc/passwd" < "check-manually/local-file-inclusion.txt" | \ 346 | xargs -I % -P 100 sh -c 'curl -s "%" 2>&1 | grep -q "root:x:" && echo "[+] Found endpoint likely to be vulnerable to LFI: %" && echo "%" >> potential-lfi.txt' 347 | if [ -f "potential-lfi.txt" ]; then 348 | notify "Identified *$(wc -l < potential-lfi.txt)* endpoints potentially vulnerable to LFI! Testing for Open Redirections..." 349 | else 350 | notify "No LFI found. Testing for Open Redirections..." 351 | fi 352 | else 353 | echo "[-] SKIPPING TEST FOR (*NIX) LFI" 354 | fi 355 | 356 | if [ ! -f "potential-or.txt" ] || [ "$overwrite" = true ] 357 | then 358 | echo "[*] TESTING FOR OPEN REDIRECTS..." 359 | qsreplace "https://www.testing123.com" < "check-manually/open-redirect.txt" | \ 360 | xargs -I % -P 100 sh -c 'curl -s "%" 2>&1 | grep -q "Location: https://www.testing123.com" && echo "[+] Found endpoint likely to be vulnerable to OR: %" && echo "%" >> potential-or.txt' 361 | if [ -f "potential-or.txt" ]; then 362 | notify "Identified *$(wc -l < potential-or.txt)* endpoints potentially vulnerable to open redirects! Resolving IP Addresses..." 363 | else 364 | notify "No open redirects found. Starting Nmap for *$(wc -l < "ip-addresses-$DOMAIN.txt")* IP addresses..." 365 | fi 366 | else 367 | echo "[-] SKIPPING TEST FOR OPEN REDIRECTS" 368 | fi 369 | 370 | if [ ! -d "nmap" ] || [ "$overwrite" = true ] 371 | then 372 | echo "[*] RUNNING NMAP (TOP 1000 TCP)..." 373 | mkdir nmap 374 | nmap -T4 -sV --open --source-port 53 --max-retries 3 --host-timeout 15m -iL "ip-addresses-$DOMAIN.txt" -oA nmap/nmap-tcp 375 | grep Port < nmap/nmap-tcp.gnmap | cut -d' ' -f2 | sort -u > nmap/tcpips.txt 376 | notify "Nmap TCP done! Identified *$(grep -c "Port" < "nmap/nmap-tcp.gnmap")* IPs with ports open. Starting Nmap UDP/SNMP scan for *$(wc -l < "nmap/tcpips.txt")* IP addresses..." 377 | 378 | echo "[*] RUNNING NMAP (SNMP UDP)..." 379 | nmap -T4 -sU -sV -p 161 --open --source-port 53 -iL nmap/tcpips.txt -oA nmap/nmap-161udp 380 | rm nmap/tcpips.txt 381 | notify "Nmap UDP done! Identified *$(grep "Port" < "nmap/nmap-161udp.gnmap" | grep -cv "filtered")* IPS with SNMP port open." 382 | else 383 | echo "[-] SKIPPING NMAP" 384 | fi 385 | 386 | 387 | cd .. 388 | echo "[+] DONE SCANNING $DOMAIN." 389 | notify "Recon on $DOMAIN finished." 390 | 391 | done 392 | 393 | echo "[+] DONE! :D" 394 | notify "Recon finished! Go hack em!" 395 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | LABEL maintainer="Cas van Cooten" 4 | 5 | ARG DEBIAN_FRONTEND=noninteractive 6 | WORKDIR /root 7 | 8 | ENV TZ=Europe/Amsterdam 9 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 10 | 11 | COPY setup.sh /root 12 | COPY BugBountyScanner.sh /root 13 | COPY utils /root/utils 14 | COPY dist /root/dist 15 | COPY .env.example /root 16 | 17 | ENV GOROOT=/usr/local/go 18 | ENV GOPATH=/root/go 19 | ENV PATH=$PATH:/root/go/bin:/usr/local/go/bin 20 | ENV GO111MODULE=on 21 | 22 | RUN chmod +x /root/BugBountyScanner.sh /root/setup.sh 23 | RUN /root/setup.sh 24 | RUN rm /root/setup.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Cas van Cooten 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BugBountyScanner 2 | 3 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/chvancooten/BugBountyScanner/main.yml)](https://github.com/chvancooten/BugBountyScanner/actions) 4 | [![Docker Pulls Badge](https://img.shields.io/docker/pulls/chvancooten/bugbountyscanner)](https://hub.docker.com/r/chvancooten/bugbountyscanner/) 5 | [![Docker Image Size Badge](https://img.shields.io/docker/image-size/chvancooten/bugbountyscanner)](https://hub.docker.com/r/chvancooten/bugbountyscanner/) 6 | [![PRs Welcome](https://img.shields.io/badge/Contributions-Welcome-brightgreen.svg)](http://makeapullrequest.com) 7 | 8 | A Bash script and Docker image for Bug Bounty reconnaissance, intended for headless use. Low on resources, high on information output. 9 | 10 | Helpful? BugBountyScanner helped you net a bounty? 11 | 12 | [![Sponsor on GitHub](https://img.shields.io/badge/%F0%9F%A5%B0-Sponsor%20me%20on%20github-red)](https://github.com/sponsors/chvancooten) 13 | 14 | ## Description 15 | 16 | > ⚠ Note: Using the script over a VPN is highly recommended. 17 | 18 | It's recommended to run BugBountyScanner from a server (VPS or home server), and _not_ from your terminal. It is programmed to be low on resources, with potentially multiple days of scanning in mind for bigger scopes. The script functions on a stand-alone basis. 19 | 20 | You can run the script either as a docker image or from your preferred Debian/Ubuntu system (see below). All that is required is kicking off the script and forgetting all about it! Running the script takes anywhere in between several minutes (for very small scopes < 10 subdomains) and several days (for very large scopes > 20000 subdomains). A 'quick mode' flag is present, which drops some time-consuming tasks such as vulnerability identification, port scanning, and web endpoint crawling. 21 | 22 | ## Installation 23 | 24 | ### Docker 25 | 26 | Docker Hub Link: https://hub.docker.com/r/chvancooten/bugbountyscanner. Images are pushed to the `:latest` tag by CI/CD whenever an update to BugBountyScanner is pushed and all tests pass. 27 | 28 | You can pull and run the Docker image from Docker Hub as below. 29 | 30 | ``` 31 | docker pull chvancooten/bugbountyscanner 32 | docker run -v $(pwd):/root/bugbounty -it chvancooten/bugbountyscanner /bin/bash 33 | ``` 34 | 35 | Docker-Compose can also be used. 36 | 37 | ``` 38 | version: "3" 39 | services: 40 | bugbountybox: 41 | container_name: BugBountyBox 42 | stdin_open: true 43 | tty: true 44 | image: chvancooten/bugbountyscanner:latest 45 | environment: 46 | - telegram_api_key=X 47 | - telegram_chat_id=X 48 | volumes: 49 | - ${USERDIR}/docker/bugbountybox:/root/bugbounty 50 | # VPN recommended :) 51 | network_mode: service:your_vpn_container 52 | depends_on: 53 | - your_vpn_container 54 | ``` 55 | 56 | Alternatively, you can build the image from source. 57 | 58 | ``` 59 | git clone https://github.com/chvancooten/BugBountyScanner.git 60 | cd BugBountyScanner 61 | docker build . 62 | ``` 63 | 64 | ### Manual 65 | 66 | If you prefer running the script manually, you can do so. 67 | 68 | > ℹ Note: The script has been built on -and tested for- Ubuntu 20.04. Your mileage may vary with other distro's, but it should work on most Debian-based installs (such as Kali Linux). 69 | 70 | ``` 71 | git clone https://github.com/chvancooten/BugBountyScanner.git 72 | cd BugBountyScanner 73 | cp .env.example .env # Edit accordingly 74 | chmod +x BugBountyScanner.sh setup.sh 75 | ./setup.sh -t /custom/tools/dir # Setup is automatically triggered, but can be manually run 76 | ./BugBountyScanner.sh --help 77 | ./BugBountyScanner.sh -d target1.com -d target2.net -t /custom/tools/dir --quick 78 | ``` 79 | 80 | ## Usage 81 | 82 | Use `--help` or `-h` for a brief help menu. 83 | 84 | ``` 85 | root@dockerhost:~# ./BugBountyScanner.sh -h 86 | BugBountyHunter - Automated Bug Bounty reconnaissance script 87 | 88 | ./BugBountyScanner.sh [options] 89 | 90 | options: 91 | -h, --help show brief help 92 | -t, --toolsdir tools directory (no trailing /), defaults to '/opt' 93 | -q, --quick perform quick recon only (default: false) 94 | -d, --domain top domain to scan, can take multiple 95 | -o, --outputdirectory parent output directory, defaults to current directory (subfolders will be created per domain) 96 | -w, --overwrite overwrite existing files. Skip steps with existing files if not provided (default: false) 97 | 98 | Note: 'ToolsDir', 'telegram_api_key' and 'telegram_chat_id' can be defined in .env or through Docker environment variables. 99 | 100 | example: 101 | ./BugBountyScanner.sh --quick -d google.com -d uber.com -t /opt 102 | ``` 103 | 104 | ## Features 105 | 106 | - Resource-efficient, suitable for running in the background for a prolonged period of time on a low-resource VPS, home server, or Raspberry Pi 107 | - Telegram status notifications with per-command results 108 | - Extensive CVE and misconfiguration detection with Nuclei (no intrusive or informational checks) 109 | - Subdomain enumeration and live webserver detection 110 | - Web screenshotting and crawling, HTML screenshot report generation 111 | - Retrieving (hopefully sensitive) endpoints from the Wayback Machine 112 | - Identification of interesting parameterized URLs with Gf 113 | - Enumeration of common "temporary" and forgotten files with Ffuf 114 | - Automatic detection of LFI, SSTI, and Open Redirects in URL parameters 115 | - Subdomain takeover detection 116 | - Port scanning (Top 1000 TCP + SNMP) 117 | - 'Quick Mode' for opsec-safe (ish) infrastructure reconnaissance 118 | 119 | ## Tools 120 | 121 | - `amass` 122 | - `aquatone` 123 | - `dnsutils` 124 | - `ffuf` 125 | - `gau` 126 | - `Gf` (with `Gf-Patterns`) 127 | - `Go` 128 | - `gospider` 129 | - `httpx` 130 | - `nmap` 131 | - `Nuclei` (with `Nuclei-Templates`) 132 | - `qsreplace` 133 | - `subjack` 134 | 135 | ## Contributers 136 | A big thanks to all the contributors who have helped improve. Your contributions are highly appreciated. 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /dist/github-markdown.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 'github-markdown.css' by sindresorhus 4 | https://github.com/sindresorhus/github-markdown-css 5 | 6 | Distributed under MIT license 7 | 8 | */ 9 | 10 | .markdown-body .octicon { 11 | display: inline-block; 12 | fill: currentColor; 13 | vertical-align: text-bottom; 14 | } 15 | 16 | .markdown-body .anchor { 17 | float: left; 18 | line-height: 1; 19 | margin-left: -20px; 20 | padding-right: 4px; 21 | } 22 | 23 | .markdown-body .anchor:focus { 24 | outline: none; 25 | } 26 | 27 | .markdown-body h1 .octicon-link, 28 | .markdown-body h2 .octicon-link, 29 | .markdown-body h3 .octicon-link, 30 | .markdown-body h4 .octicon-link, 31 | .markdown-body h5 .octicon-link, 32 | .markdown-body h6 .octicon-link { 33 | color: #1b1f23; 34 | vertical-align: middle; 35 | visibility: hidden; 36 | } 37 | 38 | .markdown-body h1:hover .anchor, 39 | .markdown-body h2:hover .anchor, 40 | .markdown-body h3:hover .anchor, 41 | .markdown-body h4:hover .anchor, 42 | .markdown-body h5:hover .anchor, 43 | .markdown-body h6:hover .anchor { 44 | text-decoration: none; 45 | } 46 | 47 | .markdown-body h1:hover .anchor .octicon-link, 48 | .markdown-body h2:hover .anchor .octicon-link, 49 | .markdown-body h3:hover .anchor .octicon-link, 50 | .markdown-body h4:hover .anchor .octicon-link, 51 | .markdown-body h5:hover .anchor .octicon-link, 52 | .markdown-body h6:hover .anchor .octicon-link { 53 | visibility: visible; 54 | } 55 | 56 | .markdown-body h1:hover .anchor .octicon-link:before, 57 | .markdown-body h2:hover .anchor .octicon-link:before, 58 | .markdown-body h3:hover .anchor .octicon-link:before, 59 | .markdown-body h4:hover .anchor .octicon-link:before, 60 | .markdown-body h5:hover .anchor .octicon-link:before, 61 | .markdown-body h6:hover .anchor .octicon-link:before { 62 | width: 16px; 63 | height: 16px; 64 | content: ' '; 65 | display: inline-block; 66 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z'%3E%3C/path%3E%3C/svg%3E"); 67 | }.markdown-body { 68 | -ms-text-size-adjust: 100%; 69 | -webkit-text-size-adjust: 100%; 70 | line-height: 1.5; 71 | color: #24292e; 72 | font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji; 73 | font-size: 16px; 74 | line-height: 1.5; 75 | word-wrap: break-word; 76 | } 77 | 78 | .markdown-body details { 79 | display: block; 80 | } 81 | 82 | .markdown-body summary { 83 | display: list-item; 84 | } 85 | 86 | .markdown-body a { 87 | background-color: initial; 88 | } 89 | 90 | .markdown-body a:active, 91 | .markdown-body a:hover { 92 | outline-width: 0; 93 | } 94 | 95 | .markdown-body strong { 96 | font-weight: inherit; 97 | font-weight: bolder; 98 | } 99 | 100 | .markdown-body h1 { 101 | font-size: 2em; 102 | margin: .67em 0; 103 | } 104 | 105 | .markdown-body img { 106 | border-style: none; 107 | } 108 | 109 | .markdown-body code, 110 | .markdown-body kbd, 111 | .markdown-body pre { 112 | font-family: monospace,monospace; 113 | font-size: 1em; 114 | } 115 | 116 | .markdown-body hr { 117 | box-sizing: initial; 118 | height: 0; 119 | overflow: visible; 120 | } 121 | 122 | .markdown-body input { 123 | font: inherit; 124 | margin: 0; 125 | } 126 | 127 | .markdown-body input { 128 | overflow: visible; 129 | } 130 | 131 | .markdown-body [type=checkbox] { 132 | box-sizing: border-box; 133 | padding: 0; 134 | } 135 | 136 | .markdown-body * { 137 | box-sizing: border-box; 138 | } 139 | 140 | .markdown-body input { 141 | font-family: inherit; 142 | font-size: inherit; 143 | line-height: inherit; 144 | } 145 | 146 | .markdown-body a { 147 | color: #0366d6; 148 | text-decoration: none; 149 | } 150 | 151 | .markdown-body a:hover { 152 | text-decoration: underline; 153 | } 154 | 155 | .markdown-body strong { 156 | font-weight: 600; 157 | } 158 | 159 | .markdown-body hr { 160 | height: 0; 161 | margin: 15px 0; 162 | overflow: hidden; 163 | background: transparent; 164 | border: 0; 165 | border-bottom: 1px solid #dfe2e5; 166 | } 167 | 168 | .markdown-body hr:after, 169 | .markdown-body hr:before { 170 | display: table; 171 | content: ""; 172 | } 173 | 174 | .markdown-body hr:after { 175 | clear: both; 176 | } 177 | 178 | .markdown-body table { 179 | border-spacing: 0; 180 | border-collapse: collapse; 181 | } 182 | 183 | .markdown-body td, 184 | .markdown-body th { 185 | padding: 0; 186 | } 187 | 188 | .markdown-body details summary { 189 | cursor: pointer; 190 | } 191 | 192 | .markdown-body kbd { 193 | display: inline-block; 194 | padding: 3px 5px; 195 | font: 11px SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 196 | line-height: 10px; 197 | color: #444d56; 198 | vertical-align: middle; 199 | background-color: #fafbfc; 200 | border: 1px solid #d1d5da; 201 | border-radius: 3px; 202 | box-shadow: inset 0 -1px 0 #d1d5da; 203 | } 204 | 205 | .markdown-body h1, 206 | .markdown-body h2, 207 | .markdown-body h3, 208 | .markdown-body h4, 209 | .markdown-body h5, 210 | .markdown-body h6 { 211 | margin-top: 0; 212 | margin-bottom: 0; 213 | } 214 | 215 | .markdown-body h1 { 216 | font-size: 32px; 217 | } 218 | 219 | .markdown-body h1, 220 | .markdown-body h2 { 221 | font-weight: 600; 222 | } 223 | 224 | .markdown-body h2 { 225 | font-size: 24px; 226 | } 227 | 228 | .markdown-body h3 { 229 | font-size: 20px; 230 | } 231 | 232 | .markdown-body h3, 233 | .markdown-body h4 { 234 | font-weight: 600; 235 | } 236 | 237 | .markdown-body h4 { 238 | font-size: 16px; 239 | } 240 | 241 | .markdown-body h5 { 242 | font-size: 14px; 243 | } 244 | 245 | .markdown-body h5, 246 | .markdown-body h6 { 247 | font-weight: 600; 248 | } 249 | 250 | .markdown-body h6 { 251 | font-size: 12px; 252 | } 253 | 254 | .markdown-body p { 255 | margin-top: 0; 256 | margin-bottom: 10px; 257 | } 258 | 259 | .markdown-body blockquote { 260 | margin: 0; 261 | } 262 | 263 | .markdown-body ol, 264 | .markdown-body ul { 265 | padding-left: 0; 266 | margin-top: 0; 267 | margin-bottom: 0; 268 | } 269 | 270 | .markdown-body ol ol, 271 | .markdown-body ul ol { 272 | list-style-type: lower-roman; 273 | } 274 | 275 | .markdown-body ol ol ol, 276 | .markdown-body ol ul ol, 277 | .markdown-body ul ol ol, 278 | .markdown-body ul ul ol { 279 | list-style-type: lower-alpha; 280 | } 281 | 282 | .markdown-body dd { 283 | margin-left: 0; 284 | } 285 | 286 | .markdown-body code, 287 | .markdown-body pre { 288 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 289 | font-size: 12px; 290 | } 291 | 292 | .markdown-body pre { 293 | margin-top: 0; 294 | margin-bottom: 0; 295 | } 296 | 297 | .markdown-body input::-webkit-inner-spin-button, 298 | .markdown-body input::-webkit-outer-spin-button { 299 | margin: 0; 300 | -webkit-appearance: none; 301 | appearance: none; 302 | } 303 | 304 | .markdown-body :checked+.radio-label { 305 | position: relative; 306 | z-index: 1; 307 | border-color: #0366d6; 308 | } 309 | 310 | .markdown-body .border { 311 | border: 1px solid #e1e4e8!important; 312 | } 313 | 314 | .markdown-body .border-0 { 315 | border: 0!important; 316 | } 317 | 318 | .markdown-body .border-bottom { 319 | border-bottom: 1px solid #e1e4e8!important; 320 | } 321 | 322 | .markdown-body .rounded-1 { 323 | border-radius: 3px!important; 324 | } 325 | 326 | .markdown-body .bg-white { 327 | background-color: #fff!important; 328 | } 329 | 330 | .markdown-body .bg-gray-light { 331 | background-color: #fafbfc!important; 332 | } 333 | 334 | .markdown-body .text-gray-light { 335 | color: #6a737d!important; 336 | } 337 | 338 | .markdown-body .mb-0 { 339 | margin-bottom: 0!important; 340 | } 341 | 342 | .markdown-body .my-2 { 343 | margin-top: 8px!important; 344 | margin-bottom: 8px!important; 345 | } 346 | 347 | .markdown-body .pl-0 { 348 | padding-left: 0!important; 349 | } 350 | 351 | .markdown-body .py-0 { 352 | padding-top: 0!important; 353 | padding-bottom: 0!important; 354 | } 355 | 356 | .markdown-body .pl-1 { 357 | padding-left: 4px!important; 358 | } 359 | 360 | .markdown-body .pl-2 { 361 | padding-left: 8px!important; 362 | } 363 | 364 | .markdown-body .py-2 { 365 | padding-top: 8px!important; 366 | padding-bottom: 8px!important; 367 | } 368 | 369 | .markdown-body .pl-3, 370 | .markdown-body .px-3 { 371 | padding-left: 16px!important; 372 | } 373 | 374 | .markdown-body .px-3 { 375 | padding-right: 16px!important; 376 | } 377 | 378 | .markdown-body .pl-4 { 379 | padding-left: 24px!important; 380 | } 381 | 382 | .markdown-body .pl-5 { 383 | padding-left: 32px!important; 384 | } 385 | 386 | .markdown-body .pl-6 { 387 | padding-left: 40px!important; 388 | } 389 | 390 | .markdown-body .f6 { 391 | font-size: 12px!important; 392 | } 393 | 394 | .markdown-body .lh-condensed { 395 | line-height: 1.25!important; 396 | } 397 | 398 | .markdown-body .text-bold { 399 | font-weight: 600!important; 400 | } 401 | 402 | .markdown-body .pl-c { 403 | color: #6a737d; 404 | } 405 | 406 | .markdown-body .pl-c1, 407 | .markdown-body .pl-s .pl-v { 408 | color: #005cc5; 409 | } 410 | 411 | .markdown-body .pl-e, 412 | .markdown-body .pl-en { 413 | color: #6f42c1; 414 | } 415 | 416 | .markdown-body .pl-s .pl-s1, 417 | .markdown-body .pl-smi { 418 | color: #24292e; 419 | } 420 | 421 | .markdown-body .pl-ent { 422 | color: #22863a; 423 | } 424 | 425 | .markdown-body .pl-k { 426 | color: #d73a49; 427 | } 428 | 429 | .markdown-body .pl-pds, 430 | .markdown-body .pl-s, 431 | .markdown-body .pl-s .pl-pse .pl-s1, 432 | .markdown-body .pl-sr, 433 | .markdown-body .pl-sr .pl-cce, 434 | .markdown-body .pl-sr .pl-sra, 435 | .markdown-body .pl-sr .pl-sre { 436 | color: #032f62; 437 | } 438 | 439 | .markdown-body .pl-smw, 440 | .markdown-body .pl-v { 441 | color: #e36209; 442 | } 443 | 444 | .markdown-body .pl-bu { 445 | color: #b31d28; 446 | } 447 | 448 | .markdown-body .pl-ii { 449 | color: #fafbfc; 450 | background-color: #b31d28; 451 | } 452 | 453 | .markdown-body .pl-c2 { 454 | color: #fafbfc; 455 | background-color: #d73a49; 456 | } 457 | 458 | .markdown-body .pl-c2:before { 459 | content: "^M"; 460 | } 461 | 462 | .markdown-body .pl-sr .pl-cce { 463 | font-weight: 700; 464 | color: #22863a; 465 | } 466 | 467 | .markdown-body .pl-ml { 468 | color: #735c0f; 469 | } 470 | 471 | .markdown-body .pl-mh, 472 | .markdown-body .pl-mh .pl-en, 473 | .markdown-body .pl-ms { 474 | font-weight: 700; 475 | color: #005cc5; 476 | } 477 | 478 | .markdown-body .pl-mi { 479 | font-style: italic; 480 | color: #24292e; 481 | } 482 | 483 | .markdown-body .pl-mb { 484 | font-weight: 700; 485 | color: #24292e; 486 | } 487 | 488 | .markdown-body .pl-md { 489 | color: #b31d28; 490 | background-color: #ffeef0; 491 | } 492 | 493 | .markdown-body .pl-mi1 { 494 | color: #22863a; 495 | background-color: #f0fff4; 496 | } 497 | 498 | .markdown-body .pl-mc { 499 | color: #e36209; 500 | background-color: #ffebda; 501 | } 502 | 503 | .markdown-body .pl-mi2 { 504 | color: #f6f8fa; 505 | background-color: #005cc5; 506 | } 507 | 508 | .markdown-body .pl-mdr { 509 | font-weight: 700; 510 | color: #6f42c1; 511 | } 512 | 513 | .markdown-body .pl-ba { 514 | color: #586069; 515 | } 516 | 517 | .markdown-body .pl-sg { 518 | color: #959da5; 519 | } 520 | 521 | .markdown-body .pl-corl { 522 | text-decoration: underline; 523 | color: #032f62; 524 | } 525 | 526 | .markdown-body .mb-0 { 527 | margin-bottom: 0!important; 528 | } 529 | 530 | .markdown-body .my-2 { 531 | margin-bottom: 8px!important; 532 | } 533 | 534 | .markdown-body .my-2 { 535 | margin-top: 8px!important; 536 | } 537 | 538 | .markdown-body .pl-0 { 539 | padding-left: 0!important; 540 | } 541 | 542 | .markdown-body .py-0 { 543 | padding-top: 0!important; 544 | padding-bottom: 0!important; 545 | } 546 | 547 | .markdown-body .pl-1 { 548 | padding-left: 4px!important; 549 | } 550 | 551 | .markdown-body .pl-2 { 552 | padding-left: 8px!important; 553 | } 554 | 555 | .markdown-body .py-2 { 556 | padding-top: 8px!important; 557 | padding-bottom: 8px!important; 558 | } 559 | 560 | .markdown-body .pl-3 { 561 | padding-left: 16px!important; 562 | } 563 | 564 | .markdown-body .pl-4 { 565 | padding-left: 24px!important; 566 | } 567 | 568 | .markdown-body .pl-5 { 569 | padding-left: 32px!important; 570 | } 571 | 572 | .markdown-body .pl-6 { 573 | padding-left: 40px!important; 574 | } 575 | 576 | .markdown-body .pl-7 { 577 | padding-left: 48px!important; 578 | } 579 | 580 | .markdown-body .pl-8 { 581 | padding-left: 64px!important; 582 | } 583 | 584 | .markdown-body .pl-9 { 585 | padding-left: 80px!important; 586 | } 587 | 588 | .markdown-body .pl-10 { 589 | padding-left: 96px!important; 590 | } 591 | 592 | .markdown-body .pl-11 { 593 | padding-left: 112px!important; 594 | } 595 | 596 | .markdown-body .pl-12 { 597 | padding-left: 128px!important; 598 | } 599 | 600 | .markdown-body hr { 601 | border-bottom-color: #eee; 602 | } 603 | 604 | .markdown-body kbd { 605 | display: inline-block; 606 | padding: 3px 5px; 607 | font: 11px SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 608 | line-height: 10px; 609 | color: #444d56; 610 | vertical-align: middle; 611 | background-color: #fafbfc; 612 | border: 1px solid #d1d5da; 613 | border-radius: 3px; 614 | box-shadow: inset 0 -1px 0 #d1d5da; 615 | } 616 | 617 | .markdown-body:after, 618 | .markdown-body:before { 619 | display: table; 620 | content: ""; 621 | } 622 | 623 | .markdown-body:after { 624 | clear: both; 625 | } 626 | 627 | .markdown-body>:first-child { 628 | margin-top: 0!important; 629 | } 630 | 631 | .markdown-body>:last-child { 632 | margin-bottom: 0!important; 633 | } 634 | 635 | .markdown-body a:not([href]) { 636 | color: inherit; 637 | text-decoration: none; 638 | } 639 | 640 | .markdown-body blockquote, 641 | .markdown-body details, 642 | .markdown-body dl, 643 | .markdown-body ol, 644 | .markdown-body p, 645 | .markdown-body pre, 646 | .markdown-body table, 647 | .markdown-body ul { 648 | margin-top: 0; 649 | margin-bottom: 16px; 650 | } 651 | 652 | .markdown-body hr { 653 | height: .25em; 654 | padding: 0; 655 | margin: 24px 0; 656 | background-color: #e1e4e8; 657 | border: 0; 658 | } 659 | 660 | .markdown-body blockquote { 661 | padding: 0 1em; 662 | color: #6a737d; 663 | border-left: .25em solid #dfe2e5; 664 | } 665 | 666 | .markdown-body blockquote>:first-child { 667 | margin-top: 0; 668 | } 669 | 670 | .markdown-body blockquote>:last-child { 671 | margin-bottom: 0; 672 | } 673 | 674 | .markdown-body h1, 675 | .markdown-body h2, 676 | .markdown-body h3, 677 | .markdown-body h4, 678 | .markdown-body h5, 679 | .markdown-body h6 { 680 | margin-top: 24px; 681 | margin-bottom: 16px; 682 | font-weight: 600; 683 | line-height: 1.25; 684 | } 685 | 686 | .markdown-body h1 { 687 | font-size: 2em; 688 | } 689 | 690 | .markdown-body h1, 691 | .markdown-body h2 { 692 | padding-bottom: .3em; 693 | /*border-bottom: 1px solid #eaecef;*/ 694 | border-bottom: 3px solid #dfe2e5; 695 | } 696 | 697 | .markdown-body h2 { 698 | font-size: 1.5em; 699 | } 700 | 701 | .markdown-body h3 { 702 | font-size: 1.25em; 703 | } 704 | 705 | .markdown-body h4 { 706 | font-size: 1em; 707 | } 708 | 709 | .markdown-body h5 { 710 | font-size: .875em; 711 | } 712 | 713 | .markdown-body h6 { 714 | font-size: .85em; 715 | color: #6a737d; 716 | } 717 | 718 | .markdown-body ol, 719 | .markdown-body ul { 720 | padding-left: 2em; 721 | } 722 | 723 | .markdown-body ol ol, 724 | .markdown-body ol ul, 725 | .markdown-body ul ol, 726 | .markdown-body ul ul { 727 | margin-top: 0; 728 | margin-bottom: 0; 729 | } 730 | 731 | .markdown-body li { 732 | word-wrap: break-all; 733 | } 734 | 735 | .markdown-body li>p { 736 | margin-top: 16px; 737 | } 738 | 739 | .markdown-body li+li { 740 | margin-top: .25em; 741 | } 742 | 743 | .markdown-body dl { 744 | padding: 0; 745 | } 746 | 747 | .markdown-body dl dt { 748 | padding: 0; 749 | margin-top: 16px; 750 | font-size: 1em; 751 | font-style: italic; 752 | font-weight: 600; 753 | } 754 | 755 | .markdown-body dl dd { 756 | padding: 0 16px; 757 | margin-bottom: 16px; 758 | } 759 | 760 | .markdown-body table { 761 | display: block; 762 | width: 100%; 763 | overflow: auto; 764 | } 765 | 766 | .markdown-body table th { 767 | font-weight: 600; 768 | } 769 | 770 | .markdown-body table td, 771 | .markdown-body table th { 772 | padding: 6px 13px; 773 | border: 1px solid #dfe2e5; 774 | } 775 | 776 | .markdown-body table tr { 777 | background-color: #fff; 778 | border-top: 1px solid #c6cbd1; 779 | } 780 | 781 | .markdown-body table tr:nth-child(2n) { 782 | background-color: #f6f8fa; 783 | } 784 | 785 | .markdown-body img { 786 | max-width: 100%; 787 | box-sizing: initial; 788 | background-color: #fff; 789 | } 790 | 791 | .markdown-body img[align=right] { 792 | padding-left: 20px; 793 | } 794 | 795 | .markdown-body img[align=left] { 796 | padding-right: 20px; 797 | } 798 | 799 | .markdown-body code { 800 | padding: .2em .4em; 801 | margin: 0; 802 | font-size: 85%; 803 | background-color: rgba(27,31,35,.05); 804 | border-radius: 3px; 805 | } 806 | 807 | .markdown-body pre { 808 | word-wrap: normal; 809 | } 810 | 811 | .markdown-body pre>code { 812 | padding: 0; 813 | margin: 0; 814 | font-size: 100%; 815 | word-break: normal; 816 | white-space: pre; 817 | background: transparent; 818 | border: 0; 819 | } 820 | 821 | .markdown-body .highlight { 822 | margin-bottom: 16px; 823 | } 824 | 825 | .markdown-body .highlight pre { 826 | margin-bottom: 0; 827 | word-break: normal; 828 | } 829 | 830 | .markdown-body .highlight pre, 831 | .markdown-body pre { 832 | padding: 16px; 833 | overflow: auto; 834 | font-size: 85%; 835 | line-height: 1.45; 836 | background-color: #f6f8fa; 837 | border-radius: 3px; 838 | } 839 | 840 | .markdown-body pre code { 841 | display: inline; 842 | max-width: auto; 843 | padding: 0; 844 | margin: 0; 845 | overflow: visible; 846 | line-height: inherit; 847 | word-wrap: normal; 848 | background-color: initial; 849 | border: 0; 850 | } 851 | 852 | .markdown-body .commit-tease-sha { 853 | display: inline-block; 854 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 855 | font-size: 90%; 856 | color: #444d56; 857 | } 858 | 859 | .markdown-body .full-commit .btn-outline:not(:disabled):hover { 860 | color: #005cc5; 861 | border-color: #005cc5; 862 | } 863 | 864 | .markdown-body .blob-wrapper { 865 | overflow-x: auto; 866 | overflow-y: hidden; 867 | } 868 | 869 | .markdown-body .blob-wrapper-embedded { 870 | max-height: 240px; 871 | overflow-y: auto; 872 | } 873 | 874 | .markdown-body .blob-num { 875 | width: 1%; 876 | min-width: 50px; 877 | padding-right: 10px; 878 | padding-left: 10px; 879 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 880 | font-size: 12px; 881 | line-height: 20px; 882 | color: rgba(27,31,35,.3); 883 | text-align: right; 884 | white-space: nowrap; 885 | vertical-align: top; 886 | cursor: pointer; 887 | -webkit-user-select: none; 888 | -moz-user-select: none; 889 | -ms-user-select: none; 890 | user-select: none; 891 | } 892 | 893 | .markdown-body .blob-num:hover { 894 | color: rgba(27,31,35,.6); 895 | } 896 | 897 | .markdown-body .blob-num:before { 898 | content: attr(data-line-number); 899 | } 900 | 901 | .markdown-body .blob-code { 902 | position: relative; 903 | padding-right: 10px; 904 | padding-left: 10px; 905 | line-height: 20px; 906 | vertical-align: top; 907 | } 908 | 909 | .markdown-body .blob-code-inner { 910 | overflow: visible; 911 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 912 | font-size: 12px; 913 | color: #24292e; 914 | word-wrap: normal; 915 | white-space: pre; 916 | } 917 | 918 | .markdown-body .pl-token.active, 919 | .markdown-body .pl-token:hover { 920 | cursor: pointer; 921 | background: #ffea7f; 922 | } 923 | 924 | .markdown-body .tab-size[data-tab-size="1"] { 925 | -moz-tab-size: 1; 926 | tab-size: 1; 927 | } 928 | 929 | .markdown-body .tab-size[data-tab-size="2"] { 930 | -moz-tab-size: 2; 931 | tab-size: 2; 932 | } 933 | 934 | .markdown-body .tab-size[data-tab-size="3"] { 935 | -moz-tab-size: 3; 936 | tab-size: 3; 937 | } 938 | 939 | .markdown-body .tab-size[data-tab-size="4"] { 940 | -moz-tab-size: 4; 941 | tab-size: 4; 942 | } 943 | 944 | .markdown-body .tab-size[data-tab-size="5"] { 945 | -moz-tab-size: 5; 946 | tab-size: 5; 947 | } 948 | 949 | .markdown-body .tab-size[data-tab-size="6"] { 950 | -moz-tab-size: 6; 951 | tab-size: 6; 952 | } 953 | 954 | .markdown-body .tab-size[data-tab-size="7"] { 955 | -moz-tab-size: 7; 956 | tab-size: 7; 957 | } 958 | 959 | .markdown-body .tab-size[data-tab-size="8"] { 960 | -moz-tab-size: 8; 961 | tab-size: 8; 962 | } 963 | 964 | .markdown-body .tab-size[data-tab-size="9"] { 965 | -moz-tab-size: 9; 966 | tab-size: 9; 967 | } 968 | 969 | .markdown-body .tab-size[data-tab-size="10"] { 970 | -moz-tab-size: 10; 971 | tab-size: 10; 972 | } 973 | 974 | .markdown-body .tab-size[data-tab-size="11"] { 975 | -moz-tab-size: 11; 976 | tab-size: 11; 977 | } 978 | 979 | .markdown-body .tab-size[data-tab-size="12"] { 980 | -moz-tab-size: 12; 981 | tab-size: 12; 982 | } 983 | 984 | .markdown-body .task-list-item { 985 | list-style-type: none; 986 | } 987 | 988 | .markdown-body .task-list-item+.task-list-item { 989 | margin-top: 3px; 990 | } 991 | 992 | .markdown-body .task-list-item input { 993 | margin: 0 .2em .25em -1.6em; 994 | vertical-align: middle; 995 | } -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Automated Bug Bounty recon script dependency installer 3 | ## By Cas van Cooten 4 | 5 | if [ "$EUID" -ne 0 ] 6 | then 7 | echo "[-] Installation requires elevated privileges, please run as root" 8 | echo "[*] Running 'sudo $0' will install for current user" 9 | echo "[*] Running 'sudo su; $0' will install for root user" 10 | exit 1 11 | fi 12 | 13 | if [[ "$OSTYPE" != "linux-gnu" ]] || [[ "$(uname -m)" != "x86_64" ]] 14 | then 15 | echo "[-] Installation requires 64-bit Linux" 16 | exit 1 17 | fi 18 | 19 | for arg in "$@" 20 | do 21 | case $arg in 22 | -h|--help) 23 | echo "BugBountyHunter Dependency Installer" 24 | echo " " 25 | echo "$0 [options]" 26 | echo " " 27 | echo "options:" 28 | echo "-h, --help show brief help" 29 | echo "-t, --toolsdir tools directory, defaults to '/opt'" 30 | echo "" 31 | echo "Note: If you choose a non-default tools directory, please adapt the default in the BugBountyAutomator.sh file or pass the -t flag to ensure it finds the right tools." 32 | echo "" 33 | echo "example:" 34 | echo "$0 -t /opt" 35 | exit 0 36 | ;; 37 | -t|--toolsdir) 38 | toolsDir="$2" 39 | shift 40 | shift 41 | ;; 42 | esac 43 | done 44 | 45 | if [ -z "$toolsDir" ] 46 | then 47 | toolsDir="/opt" 48 | fi 49 | 50 | echo "[*] INSTALLING DEPENDENCIES IN \"$toolsDir\"..." 51 | echo "[!] NOTE: INSTALLATION HAS BEEN TESTED ON UBUNTU ONLY. RESULTS MAY VARY FOR OTHER DISTRIBUTIONS." 52 | 53 | baseDir=$PWD 54 | username="$(logname 2>/dev/null || echo root)" 55 | homeDir=$(eval echo "~$username") 56 | 57 | mkdir -p "$toolsDir" 58 | cd "$toolsDir" || { echo "Something went wrong"; exit 1; } 59 | 60 | # Various apt packages 61 | echo "[*] Running apt update and installing apt-based packages, this may take a while..." 62 | apt-get update >/dev/null 63 | apt-get install -y xvfb dnsutils nmap python3 python2 python3-pip curl wget unzip git libfreetype6 libfontconfig1 >/dev/null 64 | rm -rf /var/lib/apt/lists/* 65 | 66 | # Chrome (for aquatone) 67 | wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 68 | apt update -qq 69 | apt install ./google-chrome-stable_current_amd64.deb -y >/dev/null 70 | rm google-chrome-stable_current_amd64.deb 71 | 72 | # Golang 73 | go version &> /dev/null 74 | if [ $? -ne 0 ]; then 75 | echo "[*] Installing Golang..." 76 | wget -q https://golang.org/dl/go1.24.2.linux-amd64.tar.gz 77 | tar -xvf go1.24.2.linux-amd64.tar.gz -C /usr/local >/dev/null 78 | rm -rf ./go1.24.2.linux-amd64.tar.gz >/dev/null 79 | export GOROOT="/usr/local/go" 80 | export GOPATH="$homeDir/go" 81 | export PATH="$PATH:${GOPATH}/bin:${GOROOT}/bin:${PATH}" 82 | else 83 | echo "[*] Skipping Golang install, already installed." 84 | echo "[!] Note: This may cause errors. If it does, check your Golang version and settings." 85 | fi 86 | 87 | # Go packages 88 | echo "[*] Installing various Go packages..." 89 | export GO111MODULE="on" 90 | go install github.com/lc/gau@latest &>/dev/null 91 | go install github.com/tomnomnom/gf@latest &>/dev/null 92 | go install github.com/jaeles-project/gospider@latest &>/dev/null 93 | go install github.com/tomnomnom/qsreplace@latest &>/dev/null 94 | go install github.com/haccer/subjack@latest &>/dev/null 95 | go install github.com/ffuf/ffuf/v2@latest &>/dev/null 96 | go install github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest &>/dev/null 97 | 98 | # Nuclei-templates 99 | nuclei -update-templates -update-template-dir $toolsDir/nuclei-templates &>/dev/null 100 | 101 | # PhantomJS (removed from Kali packages) 102 | echo "[*] Installing PhantomJS..." 103 | wget -q https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 104 | tar xvf phantomjs-2.1.1-linux-x86_64.tar.bz2 >/dev/null 105 | rm phantomjs-2.1.1-linux-x86_64.tar.bz2 106 | cp $toolsDir/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/phantomjs 107 | 108 | # Aquatone 109 | echo "[*] Installing Aquatone" 110 | wget -q https://github.com/michenriksen/aquatone/releases/download/v1.7.0/aquatone_linux_amd64_1.7.0.zip 111 | unzip -j aquatone_linux_amd64_1.7.0.zip -d /usr/bin/ aquatone >/dev/null 112 | rm aquatone_linux_amd64_1.7.0.zip 113 | 114 | # Subjack fingerprints file 115 | echo "[*] Installing Subjack fingerprints..." 116 | mkdir "$toolsDir/subjack" 117 | wget -q https://raw.githubusercontent.com/haccer/subjack/master/fingerprints.json -O $toolsDir/subjack/fingerprints.json 118 | 119 | # Temporary files wordlist 120 | echo "[*] Installing ffuf wordlist..." 121 | mkdir "$toolsDir/wordlists" 122 | wget -q https://raw.githubusercontent.com/Bo0oM/fuzz.txt/master/fuzz.txt -O $toolsDir/wordlists/tempfiles.txt 123 | 124 | # HTTPX 125 | echo "[*] Installing HTTPX..." 126 | wget -q https://github.com/projectdiscovery/httpx/releases/download/v1.6.10/httpx_1.6.10_linux_amd64.zip 127 | unzip -j httpx_1.6.10_linux_amd64.zip -d /usr/bin/ httpx >/dev/null 128 | rm httpx_1.6.10_linux_amd64.zip 129 | 130 | # Amass 131 | echo "[*] Installing Amass..." 132 | wget -q https://github.com/owasp-amass/amass/releases/download/v4.2.0/amass_Linux_amd64.zip 133 | unzip -q amass_Linux_amd64.zip 134 | mv amass_Linux_amd64 amass 135 | rm amass_Linux_amd64.zip 136 | cp $toolsDir/amass/amass /usr/bin/amass 137 | 138 | # Gf-patterns 139 | echo "[*] Installing Gf-patterns..." 140 | git clone -q https://github.com/1ndianl33t/Gf-Patterns 141 | mkdir "$homeDir"/.gf 142 | cp "$toolsDir"/Gf-Patterns/*.json "$homeDir"/.gf 143 | 144 | # nrich 145 | echo "[*] Installing nrich..." 146 | wget -q https://gitlab.com/api/v4/projects/33695681/packages/generic/nrich/latest/nrich_latest_amd64.deb 147 | dpkg -i nrich_latest_amd64.deb &>/dev/null 148 | rm nrich_latest_amd64.deb 149 | 150 | # Persist configured environment variables via global profile.d script 151 | echo "[*] Setting environment variables..." 152 | if [ -f "$homeDir"/.bashrc ] 153 | then 154 | { echo "export GOROOT=/usr/local/go"; 155 | echo "export GOPATH=$homeDir/go"; 156 | echo 'export PATH=$PATH:$GOPATH/bin:$GOROOT/bin'; 157 | echo "export GO111MODULE=on"; } >> "$homeDir"/.bashrc 158 | fi 159 | 160 | if [ -f "$homeDir"/.zshrc ] 161 | then 162 | { echo "export GOROOT=/usr/local/go"; 163 | echo "export GOPATH=$homeDir/go"; 164 | echo 'export PATH=$PATH:$GOPATH/bin:$GOROOT/bin'; 165 | echo "export GO111MODULE=on"; } >> "$homeDir"/.zshrc 166 | fi 167 | 168 | # Cleanup 169 | apt remove unzip -y &>/dev/null 170 | cd "$baseDir" || { echo "Something went wrong"; exit 1; } 171 | 172 | echo "[*] SETUP FINISHED." 173 | exit 0 174 | -------------------------------------------------------------------------------- /utils/ScopeToBurp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Simple helper script to load BugBountyAutomator.sh results (the live scope) to BurpSuite for passive/active scanning and crawling. 3 | 4 | if [ -z "$1" ] 5 | then 6 | read -r -p "[?] What's the target live hosts file? [e.g. /root/BugBounty/scope.com/livedomains-scope.com.txt]: " file 7 | else 8 | file=$1 9 | fi 10 | 11 | echo "[*] Loading live target hosts into burp, make sure burp proxy is running..." 12 | 13 | httpx -silent -no-color -http-proxy httpx://127.0.0.1:8080 -follow-redirects -l "$file" -------------------------------------------------------------------------------- /utils/runTests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Test script to validate the correctness of Dockerized Github CI builds 3 | 4 | echo "ENVIRONMENT:" 5 | env 6 | 7 | # Validate correct installation of key tools 8 | echo 9 | echo "Checking required tools..." 10 | 11 | # Golang 12 | go version &> /dev/null 13 | if [ $? -ne 0 ]; then 14 | echo "Error - Go not (properly) installed" 15 | exit 1 16 | fi 17 | 18 | # Amass 19 | amass -version &> /dev/null 20 | if [ $? -ne 0 ]; then 21 | echo "Error - Amass not (properly) installed" 22 | exit 1 23 | fi 24 | 25 | # HTTPX 26 | httpx -version &> /dev/null 27 | if [ $? -ne 0 ]; then 28 | echo "Error - HTTPX not (properly) installed" 29 | exit 1 30 | fi 31 | 32 | # Subjack 33 | which subjack &> /dev/null 34 | if [ $? -ne 0 ]; then 35 | echo "Error - Subjack not (properly) installed" 36 | exit 1 37 | fi 38 | 39 | # aquatone 40 | aquatone -h &> /dev/null 41 | if [ $? -ne 2 ]; then 42 | echo "Error - Aquatone not (properly) installed" 43 | exit 1 44 | fi 45 | 46 | # GAU 47 | gau -version &> /dev/null 48 | if [ $? -ne 0 ]; then 49 | echo "Error - GAU not (properly) installed" 50 | exit 1 51 | fi 52 | 53 | # Nuclei 54 | nuclei -version &> /dev/null 55 | if [ $? -ne 0 ]; then 56 | echo "Error - Nuclei not (properly) installed" 57 | exit 1 58 | fi 59 | 60 | # Nuclei-templates (directory must exist and not be empty) 61 | if [ ! -d "/opt/nuclei-templates" ] || [ ! -n "$(ls -A /opt/nuclei-templates)" ]; then 62 | echo "Error - Nuclei-templates not (properly) installed" 63 | exit 1 64 | fi 65 | 66 | # nrich 67 | nrich --version &> /dev/null 68 | if [ $? -ne 0 ]; then 69 | echo "Error - Nrich not (properly) installed" 70 | exit 1 71 | fi 72 | 73 | ## ffuf 74 | ffuf -h &> /dev/null 75 | if [ $? -ne 0 ]; then 76 | echo "Error - ffuf not (properly) installed" 77 | exit 1 78 | fi 79 | 80 | # GoSpider 81 | gospider --version &> /dev/null 82 | if [ $? -ne 0 ]; then 83 | echo "Error - GoSpider not (properly) installed" 84 | exit 1 85 | fi 86 | 87 | # GF 88 | gf -h &> /dev/null 89 | if [ $? -ne 0 ]; then 90 | echo "Error - GF not (properly) installed" 91 | exit 1 92 | fi 93 | 94 | # Dig 95 | dig -v &> /dev/null 96 | if [ $? -ne 0 ]; then 97 | echo "Error - Dig not (properly) installed" 98 | exit 1 99 | fi 100 | 101 | # Nmap 102 | nmap -V &> /dev/null 103 | if [ $? -ne 0 ]; then 104 | echo "Error - Nmap not (properly) installed" 105 | exit 1 106 | fi 107 | 108 | echo "All good!" 109 | exit 0 110 | -------------------------------------------------------------------------------- /utils/screenshotReport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Generate gallery from screenshot files for easy review 3 | 4 | generate_screenshot_report() { 5 | 6 | domain=$1 7 | cd "./screenshots" || { echo "Something went wrong"; exit 1; } 8 | 9 | if [ -e screenshotReport.html ] 10 | then 11 | rm screenshotReport.html 12 | fi 13 | 14 | cat >> ../screenshotReport.html << HEADER 15 | 16 | 17 | 18 | 19 | 20 | 21 | Screenshots for $domain 22 | 37 | 38 | 39 |
40 |

Screenshots for $domain

41 |

Note: This report has been deprecated in favor of Aquatone. Please check out the Aquatone report instead.

42 | HEADER 43 | 44 | for i in *.png 45 | do 46 | caption="$i" 47 | cat >> ../screenshotReport.html << HTML 48 |
49 | 50 |

$caption

51 | $caption 52 |
53 |
54 |
55 |
56 | HTML 57 | 58 | done 59 | 60 | cat >> ../screenshotReport.html << FOOTER 61 |
62 |

Report generated by BugBountyScanner

63 |
64 | 65 | 66 | FOOTER 67 | 68 | cd .. 69 | } 70 | 71 | --------------------------------------------------------------------------------