| 1 | + | #!/bin/bash |
| 2 | + | # -*- coding: utf-8 -*- |
| 3 | + | |
| 4 | + | # 测试 |
| 5 | + | # set -xeuo pipefail |
| 6 | + | |
| 7 | + | # ANSI颜色代码 |
| 8 | + | RED='\033[91m' |
| 9 | + | GREEN='\033[92m' |
| 10 | + | RESET='\033[0m' |
| 11 | + | |
| 12 | + | # 显示帮助菜单的函数 |
| 13 | + | display_help() { |
| 14 | + | echo -e "NucleiFuzzinator是一个自动化工具,用于收集指定域名或域名文件中的URL,并通过Nuclei进行全面的Web应用漏洞扫描。\n" |
| 15 | + | echo -e "使用方法: $0 [选项]\n\n" |
| 16 | + | echo "选项:" |
| 17 | + | echo " -h, --help 显示帮助信息" |
| 18 | + | echo " -d, --domain <domain> 用于扫描 XSS、SQLi、SSRF、Open-Redirect 等漏洞的单个域名" |
| 19 | + | echo " -f, --file <filename> 包含多个域名的文件" |
| 20 | + | echo " -p, --proxy <proxy> 请求代理,例如 http://127.0.0.1:8080" |
| 21 | + | echo " -P, --project <projectName> 项目名称,输出目录名,默认为output" |
| 22 | + | exit 0 |
| 23 | + | } |
| 24 | + | |
| 25 | + | display_logo(){ |
| 26 | + | # ASCII art |
| 27 | + | echo -e "${RED}" |
| 28 | + | cat << "EOF" |
| 29 | + | _ __ __ _ ____ _ __ |
| 30 | + | / |/ /_ ______/ /__ (_) __/_ ________ (_)__ ___ _/ /____ ____ |
| 31 | + | / / // / __/ / -_) / _// // /_ /_ // / _ \/ _ `/ __/ _ \/ __/ |
| 32 | + | /_/|_/\_,_/\__/_/\__/_/_/ \_,_//__/__/_/_//_/\_,_/\__/\___/_/ |
| 33 | + | |
| 34 | + | Made by leeissonba (simonlee-hello) |
| 35 | + | EOF |
| 36 | + | echo -e "${RESET}" |
| 37 | + | } |
| 38 | + | |
| 39 | + | check_go_env(){ |
| 40 | + | if ! command -v go &> /dev/null; then |
| 41 | + | echo "未找到 Go,请先安装 Go 并设置相应的环境变量。" |
| 42 | + | echo "安装完成后请手动设置以下环境变量:" |
| 43 | + | echo " - GOROOT: 指向 Go 的安装目录 export GOROOT=$HOME/go export PATH=$GOROOT/bin:$PATH" |
| 44 | + | echo " - GOPATH: 指向您的 Go 工作目录 export GOPATH=$HOME/gopath/go export PATH=$GOPATH/bin:$PATH" |
| 45 | + | echo " - GOMODCACHE: 指向您的 Go 工作目录 export GOMODCACHE=$HOME/go/pkg/mod" |
| 46 | + | exit 1 |
| 47 | + | fi |
| 48 | + | } |
| 49 | + | |
| 50 | + | # 检查命令是否存在的函数 |
| 51 | + | check_command() { |
| 52 | + | if ! command -v "$1" &> /dev/null; then |
| 53 | + | echo "正在安装 $1..." |
| 54 | + | $2 || exit 1 |
| 55 | + | fi |
| 56 | + | } |
| 57 | + | |
| 58 | + | # 运行httpx的函数 |
| 59 | + | run_httpx() { |
| 60 | + | local url_file="$1" |
| 61 | + | local line_count |
| 62 | + | local httpx_command="httpx $proxy_arg $httpx_args" |
| 63 | + | echo "正在对收集到的 URL 进行 httpx 探活..." |
| 64 | + | cat "$url_file" | $httpx_command -o "$url_file" || exit 1 |
| 65 | + | line_count=$(wc -l < "$url_file" | awk '{print $1}') |
| 66 | + | echo -e "${GREEN}httpx 执行完成。找到 $line_count 个活跃的 URL。${RESET}" |
| 67 | + | } |
| 68 | + | |
| 69 | + | # 运行subfinder的函数 |
| 70 | + | run_subfinder() { |
| 71 | + | local line_count |
| 72 | + | echo "正在使用 Subfinder 查找子域..." |
| 73 | + | $subfinder_command || exit 1 |
| 74 | + | line_count=$(wc -l < "$subfinder_domains_file" | awk '{print $1}') |
| 75 | + | echo -e "${GREEN}subfinder 执行完成。找到 $line_count 个子域。${RESET}" |
| 76 | + | } |
| 77 | + | |
| 78 | + | # 运行katana的函数 |
| 79 | + | run_katana() { |
| 80 | + | local subfinder_alive_urls_file="$1" |
| 81 | + | local url_file="$2" |
| 82 | + | local line_count |
| 83 | + | # 检查 $subfinder_alive_urls_file 是否包含 URL |
| 84 | + | if [ ! -s "$subfinder_alive_urls_file" ]; then |
| 85 | + | echo -e "${RED}警告:$subfinder_alive_urls_file 文件为空。跳过执行 katana 命令。${RESET}" |
| 86 | + | return 1 |
| 87 | + | fi |
| 88 | + | katana -silent -list "$subfinder_alive_urls_file" -headless -no-incognito -xhr -d 5 -jc -aff -ef $excluded_extentions | anew "$url_file" |
| 89 | + | line_count=$(wc -l < "$url_file" | awk '{print $1}') |
| 90 | + | echo -e "${GREEN}katana 执行完成。总共找到 $line_count 个活跃的 URL。${RESET}" |
| 91 | + | } |
| 92 | + | |
| 93 | + | # 运行nuclei的函数 |
| 94 | + | run_nuclei() { |
| 95 | + | local url_file="$1" |
| 96 | + | echo "正在对收集到的 URL 运行Nuclei" |
| 97 | + | echo -e "${GREEN}Nuclei_command : $nuclei_command ${RESET}" |
| 98 | + | cat "$url_file" | $nuclei_command || exit 1 |
| 99 | + | } |
| 100 | + | |
| 101 | + | # 命令行参数默认值 |
| 102 | + | proxy="" |
| 103 | + | domain="" |
| 104 | + | filename="" |
| 105 | + | project="" |
| 106 | + | |
| 107 | + | # 默认变量值 |
| 108 | + | output_domain_file="" |
| 109 | + | output_all_file="" |
| 110 | + | excluded_extentions="png,jpg,gif,jpeg,swf,woff,svg,pdf,json,css,js,webp,woff,woff2,eot,ttf,otf,mp4" |
| 111 | + | httpx_args="-silent -mc 200,301,302 -threads 200" |
| 112 | + | nuclei_fuzzing_args="-silent -dast -nh -rl 10" |
| 113 | + | proxy_arg="" |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | # 检查 gau、nuclei、httpx 和 uro 是否已安装 |
| 118 | + | check_go_env |
| 119 | + | check_command gau "go install github.com/lc/gau/v2/cmd/gau@latest" |
| 120 | + | check_command subfinder "go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest" |
| 121 | + | check_command nuclei "go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest" |
| 122 | + | check_command httpx "go install github.com/projectdiscovery/httpx/cmd/httpx@latest" |
| 123 | + | check_command anew "go install github.com/tomnomnom/anew@latest" |
| 124 | + | check_command katana "go install github.com/projectdiscovery/katana/cmd/katana@latest" |
| 125 | + | check_command uro "pip3 install uro" |
| 126 | + | |
| 127 | + | |
| 128 | + | display_logo |
| 129 | + | |
| 130 | + | |
| 131 | + | # 解析命令行参数 |
| 132 | + | while getopts ":hd:f:p:P:" opt; do |
| 133 | + | case $opt in |
| 134 | + | h) display_help ;; |
| 135 | + | d) domain="$OPTARG" ;; |
| 136 | + | f) filename="$OPTARG" ;; |
| 137 | + | p) proxy="$OPTARG" ;; |
| 138 | + | P) project="$OPTARG" ;; |
| 139 | + | \?) echo -e "${RED}无效选项: -$OPTARG${RESET}" >&2; display_help ;; |
| 140 | + | esac |
| 141 | + | done |
| 142 | + | |
| 143 | + | if [ -n "$proxy" ]; then |
| 144 | + | proxy_arg="-proxy $proxy" |
| 145 | + | fi |
| 146 | + | |
| 147 | + | # 检查是否提供了域名或文件名 |
| 148 | + | if [ -z "$domain" ] && [ -z "$filename" ]; then |
| 149 | + | echo -e "${RED}请使用 -d 提供域名,或使用 -f 提供包含多个域/URL 的文件。${RESET}" |
| 150 | + | display_help |
| 151 | + | fi |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | # 根据域名或文件名设置输出文件 |
| 156 | + | if [ -n "$domain" ]; then |
| 157 | + | # 检查是否提供了项目名称 |
| 158 | + | if [ -z "$project" ]; then |
| 159 | + | project=$domain |
| 160 | + | fi |
| 161 | + | output_domain_file="$project/$domain.txt" |
| 162 | + | else |
| 163 | + | output_all_file="$project/allurls.txt" |
| 164 | + | # 检查是否提供了项目名称 |
| 165 | + | if [ -z "$project" ]; then |
| 166 | + | project="output" |
| 167 | + | fi |
| 168 | + | fi |
| 169 | + | |
| 170 | + | nuclei_fuzzing_output_file="$project/nuclei_fuzzing_results_$(date +%Y%m%d%H%M%S).txt" |
| 171 | + | subfinder_domains_file="$project/subfinder_urls.txt" |
| 172 | + | subfinder_alive_urls_file="$project/subfinder_alive_urls.txt" |
| 173 | + | |
| 174 | + | |
| 175 | + | # 检查输出目录是否存在,不存在则创建 |
| 176 | + | if [ ! -d "$project" ]; then |
| 177 | + | mkdir "$project" |
| 178 | + | fi |
| 179 | + | |
| 180 | + | # 检查是否已运行gau 并创建了输出文件 |
| 181 | + | if [ -n "$domain" ]; then |
| 182 | + | if [ ! -f "$output_domain_file" ]; then |
| 183 | + | echo "正在对 $domain 运行gau" |
| 184 | + | gau_args="--blacklist $excluded_extentions --subs" |
| 185 | + | [ -n "$proxy" ] && gau_args+=" --proxy $proxy" |
| 186 | + | gau $gau_args $domain | uro > "$output_domain_file" || exit 1 |
| 187 | + | fi |
| 188 | + | else |
| 189 | + | if [ ! -f "$output_all_file" ]; then |
| 190 | + | echo "正在对 $filename 中的 URL 运行gau" |
| 191 | + | gau_args="--blacklist $excluded_extentions --subs" |
| 192 | + | [ -n "$proxy" ] && gau_args+=" --proxy $proxy" |
| 193 | + | cat "$filename" | gau $gau_args | uro > "$output_all_file" || exit 1 |
| 194 | + | fi |
| 195 | + | fi |
| 196 | + | |
| 197 | + | # 运行httpx 函数 |
| 198 | + | if [ -n "$domain" ]; then |
| 199 | + | url_file="$output_domain_file" |
| 200 | + | else |
| 201 | + | url_file="$output_all_file" |
| 202 | + | fi |
| 203 | + | |
| 204 | + | run_httpx "$url_file" |
| 205 | + | |
| 206 | + | # 运行subfinder 函数 |
| 207 | + | # 定义 subfinder_command 变量,根据提供的域名或文件进行选择 |
| 208 | + | if [ -n "$domain" ]; then |
| 209 | + | subfinder_command="subfinder -d $domain -all -silent -o $subfinder_domains_file" |
| 210 | + | elif [ -n "$filename" ]; then |
| 211 | + | subfinder_command="subfinder -dL $filename -all -silent -o $subfinder_domains_file" |
| 212 | + | fi |
| 213 | + | |
| 214 | + | run_subfinder |
| 215 | + | |
| 216 | + | # 运行httpx 在收集到的子域上 |
| 217 | + | if [ ! -f "$subfinder_domains_file" ]; then |
| 218 | + | echo -e "${RED} 警告:$subfinder_domains_file 文件不存在。跳过运行httpx 命令。${RESET}" |
| 219 | + | else |
| 220 | + | echo "正在对收集到的子域运行httpx" |
| 221 | + | httpx -l "$subfinder_domains_file" -ports=80,443,8080,8443,8000,8888 $httpx_args -o "$subfinder_alive_urls_file" || exit 1 |
| 222 | + | line_count=$(wc -l < "$subfinder_alive_urls_file" | awk '{print $1}') |
| 223 | + | echo -e "${GREEN}Httpx 探活子域执行完成。找到 $line_count 个活跃的 URL。${RESET}" |
| 224 | + | fi |
| 225 | + | |
| 226 | + | # 运行katana 函数 |
| 227 | + | run_katana "$subfinder_alive_urls_file" "$url_file" |
| 228 | + | |
| 229 | + | # 提取所有URL,方便做其他扫描 |
| 230 | + | sed -E 's#^(https?://[^/]+).*#\1#' "$url_file" | sort -u | tee "$project/websites.txt" |
| 231 | + | line_count=$(wc -l < "$project/websites.txt" | awk '{print $1}') |
| 232 | + | echo -e "${GREEN}所有存活websites已提取成功。共 $line_count 个website。\nnuclei完整扫描命令:${RED}nuclei -l $project/websites.txt -nh -es info -et ssl,dns -p $proxy -o $project/nuclei_full_results_$(date +%Y%m%d%H%M%S).txt ${RESET} ${RESET}" |
| 233 | + | # 运行nuclei 函数 |
| 234 | + | # 定义 nuclei_command 变量 |
| 235 | + | nuclei_command="nuclei $proxy_arg $nuclei_fuzzing_args -o $nuclei_fuzzing_output_file" |
| 236 | + | run_nuclei "$url_file" |
| 237 | + | |
| 238 | + | # 结束时显示一般消息 |
| 239 | + | echo "扫描完成 - Happy Fuzzing" |