diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 6e23320..b24b262 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -26,8 +26,8 @@ archives: {{- if .Arm }}v{{ .Arm }}{{ end }} # use zip for windows archives format_overrides: - - goos: windows - format: zip + - goos: windows + format: zip checksum: algorithm: sha256 snapshot: @@ -40,8 +40,8 @@ changelog: - '^test:' dockers: - image_templates: - - "wjlin0/path_scan:latest" - "wjlin0/path_scan:{{ .Tag }}" + - "wjlin0/path_scan:latest" dockerfile: Dockerfile skip_push: false build_flag_templates: diff --git a/README.md b/README.md index 61abf4e..2f1d0b7 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,13 @@

- - GitHub contributors - - - + +GitHub contributors + +Docker Pulls +

- # 特征 - 快速发现路径 @@ -18,7 +17,7 @@ - 可恢复上次扫描进度 - 从网络空间测绘中发现目标 - 支持使用HTTP/SOCKS代理 -- 随机UserAgent、证书跳过验证 +- 自定义请求头 # 用法 @@ -48,7 +47,7 @@ Flags: 输出: -o, -output string 输出文件路径(可忽略) - -c, -csv csv格式输出 + -csv csv格式输出 -nc, -no-color 无颜色输出 -vb, -verbose 详细输出模式 -sl, -silent 管道模式 @@ -72,11 +71,19 @@ Flags: -ucd, -uncover-delay int 打开查询请求之间的延迟(秒) (default 1) -uo, -uncover-output string 搜索引擎查询结果保存 +请求头参数: + -ua, -user-agent string[] User-Agent + -c, -cookie string cookie + -auth, -authorization string Auth请求头 + -header string[] 自定义请求头,以逗号隔开 + -hf, -header-file string[] 从文件中加载自定义请求头 + 速率: -rh, -rate-http int 允许每秒钟最大http请求数 (default 100) 更新: - -update 更新版本 + -update 更新版本 + -ud, -update-dict 更新字典版本 ``` # 安装pathScan @@ -134,6 +141,8 @@ pathScan -uc -ue "fofa" -uq "domain=baidu.com" pathScan -resume Hc7wUXRoH2G1RjrNgjB2OMzXlXo1Hg.cfg # 输出 pathScan -t https://www.baidu.com -csv -output 1.csv +# 自定义请求头 +pathScan -t http://www.baidu.com -header User-Agent:pathScan/1.8,Cookie:a=1 -header a:1 ``` diff --git a/pkg/runner/banner.go b/pkg/runner/banner.go index 417f2f8..9696e9b 100644 --- a/pkg/runner/banner.go +++ b/pkg/runner/banner.go @@ -6,11 +6,11 @@ const banner = ` __ __ ____ ___ ___ _ / /_ / / / __/____ ___ _ ___ / _ \/ _ // __// _ \ _\ \ / __// _ // _ \ - / .__/\_,_/ \__//_//_//___/ \__/ \_,_//_//_/ v1.0.7 + / .__/\_,_/ \__//_//_//___/ \__/ \_,_//_//_/ v1.0.8 /_/ ` -const Version = `1.0.7` +const Version = `1.0.8` // showBanner is used to show the banner to the user func showBanner() { diff --git a/pkg/runner/handler.go b/pkg/runner/handler.go new file mode 100644 index 0000000..9a958a4 --- /dev/null +++ b/pkg/runner/handler.go @@ -0,0 +1,242 @@ +package runner + +import ( + "bufio" + "github.com/projectdiscovery/gologger" + fileutil "github.com/projectdiscovery/utils/file" + "github.com/wjlin0/pathScan/pkg/common/uncover" + "github.com/wjlin0/pathScan/pkg/util" + "io" + "net/http" + "net/url" + "os" + "strings" +) + +func (r *Runner) handlerHeader() map[string]interface{} { + headerMap := make(map[string]interface{}) + if r.Cfg.Options.UserAgent != nil { + headerMap["User-Agent"] = r.Cfg.Options.UserAgent + } + if r.Cfg.Options.Cookie != "" { + headerMap["Cookie"] = r.Cfg.Options.Cookie + } + if r.Cfg.Options.Authorization != "" { + headerMap["Authorization"] = r.Cfg.Options.Authorization + } + if r.Cfg.Options.Header != nil { + for _, v := range r.Cfg.Options.Header { + + split := strings.Split(v, ":") + if len(split) == 2 { + headerMap[split[0]] = split[1] + } + } + } + if r.Cfg.Options.HeaderFile != nil { + + for _, v := range r.Cfg.Options.HeaderFile { + split := strings.Split(v, ":") + if len(split) == 2 { + headerMap[split[0]] = split[1] + } + } + } + _, ok := headerMap["User-Agent"] + if !ok { + headerMap["User-Agent"] = []string{"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5", "Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,like Gecko)Version/5.1 Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0;+http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (iPhone;CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko)Version/9.0 Mobile/13B143 Safari/601.1 (compatible; Baiduspider-render/2.0;Smartapp; +http://www.baidu.com/search/spider.html)"} + } + + return headerMap +} +func (r *Runner) handlerGetTargetPath() map[string]struct{} { + at := make(map[string]struct{}) + var resp *http.Response + var err error + + if r.Cfg.Options.Path != nil { + for _, p := range r.Cfg.Options.Path { + if _, ok := at[p]; !ok { + p = strings.TrimSpace(p) + at[p] = struct{}{} + } + } + } + if r.Cfg.Options.PathFile != nil { + for _, p := range r.Cfg.Options.PathFile { + if _, ok := at[p]; !ok { + p = strings.TrimSpace(p) + at[p] = struct{}{} + } + } + } + if r.Cfg.Options.PathRemote != "" { + request, _ := http.NewRequest("GET", r.Cfg.Options.PathRemote, nil) + resp, err = r.client.Do(request) + if err == nil { + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + + } + }(resp.Body) + body, _ := io.ReadAll(resp.Body) + for _, p := range strings.Split(string(body), "\n") { + p = strings.Trim(p, "\r") + p = strings.Trim(p, "\n") + if p == "" { + continue + } + if _, ok := at[p]; !ok { + at[p] = struct{}{} + } + + } + } + gologger.Debug().Msg("从远程加载字典 完成...") + } + + if len(r.targets) == 1 && r.Cfg.Options.Path == nil && r.Cfg.Options.PathFile == nil && r.Cfg.Options.PathRemote == "" { + u := r.handlerGetFilePath("main.txt") + if u != nil { + for _, s := range u { + at[s] = struct{}{} + } + } + } + if len(at) == 0 { + at["/"] = struct{}{} + } + return at +} +func (r *Runner) handlerGetFilePath(filename string) []string { + + path := util.DataRoot("dict", "v"+Version, filename) + out, err := fileutil.ReadFile(path) + if err != nil { + return nil + } + var str []string + for o := range out { + str = append(str, o) + } + return str +} +func (r *Runner) handlerGetTargets() map[string]struct{} { + at := make(map[string]struct{}) + var resp *http.Response + var err error + if r.Cfg.Options.Url != nil { + for _, u := range r.Cfg.Options.Url { + u = strings.Trim(u, "\r") + u = strings.Trim(u, "\n") + if !strings.HasSuffix(u, "/") { + u, _ = url.JoinPath(u, "/") + } + if !strings.HasPrefix(u, "http") { + u1 := "http://" + u + u2 := "https://" + u + at[u1] = struct{}{} + at[u2] = struct{}{} + } else { + at[u] = struct{}{} + } + } + } + if r.Cfg.Options.UrlFile != nil { + for _, u := range r.Cfg.Options.UrlFile { + u = strings.Trim(u, "\r") + u = strings.Trim(u, "\n") + if !strings.HasSuffix(u, "/") { + u, _ = url.JoinPath(u, "/") + } + if !strings.HasPrefix(u, "http") { + u1 := "http://" + u + u2 := "https://" + u + at[u1] = struct{}{} + at[u2] = struct{}{} + } else { + at[u] = struct{}{} + } + } + } + if r.Cfg.Options.UrlRemote != "" { + resp, err = http.Get(r.Cfg.Options.UrlRemote) + if err == nil { + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + for _, u := range strings.Split(string(body), "\n") { + u = strings.Trim(u, "\r") + u = strings.Trim(u, "\n") + if !strings.HasSuffix(u, "/") { + u, _ = url.JoinPath(u, "/") + } + if !strings.HasPrefix(u, "http") { + u1 := "http://" + u + u2 := "https://" + u + at[u1] = struct{}{} + at[u2] = struct{}{} + } else { + at[u] = struct{}{} + } + } + } + } + if r.Cfg.Options.Silent && fileutil.HasStdin() { + s := bufio.NewScanner(os.Stdin) + for s.Scan() { + u := strings.TrimSpace(s.Text()) + if u == "" { + continue + } + if !strings.HasSuffix(u, "/") { + u, _ = url.JoinPath(u, "/") + } + if !strings.HasPrefix(u, "http") { + u1 := "http://" + u + u2 := "https://" + u + at[u1] = struct{}{} + at[u2] = struct{}{} + } else { + at[u] = struct{}{} + } + } + os.Stdin.Close() + } + if r.Cfg.Options.Uncover && r.Cfg.Options.UncoverQuery != nil { + if r.Cfg.Options.UncoverEngine == nil { + r.Cfg.Options.UncoverEngine = []string{"quake", "fofa"} + } + gologger.Info().Msgf("正在运行: %s", strings.Join(r.Cfg.Options.UncoverEngine, ",")) + ch, err := uncover.GetTargetsFromUncover(r.Cfg.Options.UncoverDelay, r.Cfg.Options.UncoverLimit, r.Cfg.Options.UncoverField, r.Cfg.Options.UncoverOutput, r.Cfg.Options.Csv, r.Cfg.Options.UncoverEngine, r.Cfg.Options.UncoverQuery) + if err != nil { + gologger.Error().Label("WRN").Msg(err.Error()) + } else { + for c := range ch { + c = strings.Trim(c, "\r") + c = strings.Trim(c, "\n") + if c == "" { + continue + } + if !strings.HasPrefix(c, "http") { + c1 := "http://" + c + c = "https://" + c + if !strings.HasSuffix(c1, "/") { + c1, _ = url.JoinPath(c1, "/") + } + at[c1] = struct{}{} + } + if !strings.HasSuffix(c, "/") { + c, _ = url.JoinPath(c, "/") + } + at[c] = struct{}{} + } + } + + } + for _, skip := range r.Cfg.Options.SkipUrl { + delete(at, skip) + } + + return at +} diff --git a/pkg/runner/handlerPath.go b/pkg/runner/handlerPath.go deleted file mode 100644 index 88d7578..0000000 --- a/pkg/runner/handlerPath.go +++ /dev/null @@ -1,85 +0,0 @@ -package runner - -import ( - "github.com/projectdiscovery/fileutil" - "github.com/projectdiscovery/gologger" - "github.com/wjlin0/pathScan/pkg/util" - "io" - "net/http" - "strings" -) - -func (r *Runner) getAllPaths() map[string]struct{} { - at := make(map[string]struct{}) - var resp *http.Response - var err error - - if r.Cfg.Options.Path != nil { - for _, p := range r.Cfg.Options.Path { - if _, ok := at[p]; !ok { - p = strings.TrimSpace(p) - at[p] = struct{}{} - } - } - } - if r.Cfg.Options.PathFile != nil { - for _, p := range r.Cfg.Options.PathFile { - if _, ok := at[p]; !ok { - p = strings.TrimSpace(p) - at[p] = struct{}{} - } - } - } - if r.Cfg.Options.PathRemote != "" { - request, _ := http.NewRequest("GET", r.Cfg.Options.PathRemote, nil) - resp, err = r.client.Do(request) - if err == nil { - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - - } - }(resp.Body) - body, _ := io.ReadAll(resp.Body) - for _, p := range strings.Split(string(body), "\n") { - p = strings.Trim(p, "\r") - p = strings.Trim(p, "\n") - if p == "" { - continue - } - if _, ok := at[p]; !ok { - at[p] = struct{}{} - } - - } - } - gologger.Debug().Msg("从远程加载字典 完成...") - } - - if len(r.targets) == 1 && r.Cfg.Options.Path == nil && r.Cfg.Options.PathFile == nil && r.Cfg.Options.PathRemote == "" { - u := r.getFilePath("main.txt") - if u != nil { - for _, s := range u { - at[s] = struct{}{} - } - } - } - if len(at) == 0 { - at["/"] = struct{}{} - } - return at -} - -func (r *Runner) getFilePath(filename string) []string { - - path := util.DataRoot("dict", "v"+Version, filename) - out, err := fileutil.ReadFile(path) - if err != nil { - return nil - } - var str []string - for o := range out { - str = append(str, o) - } - return str -} diff --git a/pkg/runner/handlerUrl.go b/pkg/runner/handlerUrl.go deleted file mode 100644 index 59c5989..0000000 --- a/pkg/runner/handlerUrl.go +++ /dev/null @@ -1,132 +0,0 @@ -package runner - -import ( - "bufio" - "github.com/projectdiscovery/fileutil" - "github.com/projectdiscovery/gologger" - "github.com/wjlin0/pathScan/pkg/common/uncover" - "io" - "net/http" - "net/url" - "os" - "strings" -) - -func (r *Runner) getAllTargets() map[string]struct{} { - at := make(map[string]struct{}) - var resp *http.Response - var err error - if r.Cfg.Options.Url != nil { - for _, u := range r.Cfg.Options.Url { - u = strings.Trim(u, "\r") - u = strings.Trim(u, "\n") - if !strings.HasSuffix(u, "/") { - u, _ = url.JoinPath(u, "/") - } - if !strings.HasPrefix(u, "http") { - u1 := "http://" + u - u2 := "https://" + u - at[u1] = struct{}{} - at[u2] = struct{}{} - } else { - at[u] = struct{}{} - } - } - } - if r.Cfg.Options.UrlFile != nil { - for _, u := range r.Cfg.Options.UrlFile { - u = strings.Trim(u, "\r") - u = strings.Trim(u, "\n") - if !strings.HasSuffix(u, "/") { - u, _ = url.JoinPath(u, "/") - } - if !strings.HasPrefix(u, "http") { - u1 := "http://" + u - u2 := "https://" + u - at[u1] = struct{}{} - at[u2] = struct{}{} - } else { - at[u] = struct{}{} - } - } - } - if r.Cfg.Options.UrlRemote != "" { - resp, err = http.Get(r.Cfg.Options.UrlRemote) - if err == nil { - defer resp.Body.Close() - body, _ := io.ReadAll(resp.Body) - for _, u := range strings.Split(string(body), "\n") { - u = strings.Trim(u, "\r") - u = strings.Trim(u, "\n") - if !strings.HasSuffix(u, "/") { - u, _ = url.JoinPath(u, "/") - } - if !strings.HasPrefix(u, "http") { - u1 := "http://" + u - u2 := "https://" + u - at[u1] = struct{}{} - at[u2] = struct{}{} - } else { - at[u] = struct{}{} - } - } - } - } - if r.Cfg.Options.Silent && fileutil.HasStdin() { - s := bufio.NewScanner(os.Stdin) - for s.Scan() { - u := strings.TrimSpace(s.Text()) - if u == "" { - continue - } - if !strings.HasSuffix(u, "/") { - u, _ = url.JoinPath(u, "/") - } - if !strings.HasPrefix(u, "http") { - u1 := "http://" + u - u2 := "https://" + u - at[u1] = struct{}{} - at[u2] = struct{}{} - } else { - at[u] = struct{}{} - } - } - os.Stdin.Close() - } - if r.Cfg.Options.Uncover && r.Cfg.Options.UncoverQuery != nil { - if r.Cfg.Options.UncoverEngine == nil { - r.Cfg.Options.UncoverEngine = []string{"quake", "fofa"} - } - gologger.Info().Msgf("正在运行: %s", strings.Join(r.Cfg.Options.UncoverEngine, ",")) - ch, err := uncover.GetTargetsFromUncover(r.Cfg.Options.UncoverDelay, r.Cfg.Options.UncoverLimit, r.Cfg.Options.UncoverField, r.Cfg.Options.UncoverOutput, r.Cfg.Options.Csv, r.Cfg.Options.UncoverEngine, r.Cfg.Options.UncoverQuery) - if err != nil { - gologger.Error().Label("WRN").Msg(err.Error()) - } else { - for c := range ch { - c = strings.Trim(c, "\r") - c = strings.Trim(c, "\n") - if c == "" { - continue - } - if !strings.HasPrefix(c, "http") { - c1 := "http://" + c - c = "https://" + c - if !strings.HasSuffix(c1, "/") { - c1, _ = url.JoinPath(c1, "/") - } - at[c1] = struct{}{} - } - if !strings.HasSuffix(c, "/") { - c, _ = url.JoinPath(c, "/") - } - at[c] = struct{}{} - } - } - - } - for _, skip := range r.Cfg.Options.SkipUrl { - delete(at, skip) - } - - return at -} diff --git a/pkg/runner/options.go b/pkg/runner/options.go index 154c5de..bb33d4a 100644 --- a/pkg/runner/options.go +++ b/pkg/runner/options.go @@ -49,6 +49,12 @@ type Options struct { UncoverField string `json:"uncover_field"` UncoverOutput string `json:"uncover_output"` UpdatePathScanVersion bool `json:"update"` + UpdatePathDictVersion bool `json:"update_path_dict_version"` + UserAgent goflags.StringSlice `json:"user_agent"` + Cookie string `json:"cookie"` + Authorization string `json:"authorization"` + Header goflags.StringSlice `json:"header"` + HeaderFile goflags.StringSlice `json:"header_file"` } var defaultProviderConfigLocation = filepath.Join(folderutil.HomeDirOrDefault("."), ".config/pathScan/provider-config.yaml") @@ -69,13 +75,13 @@ func ParserOptions() *Options { set.BoolVarP(&options.SkipHost, "skip-host", "sh", false, "跳过目标验证"), ) set.CreateGroup("Dict", "扫描字典", - set.StringSliceVarP(&options.Path, "path", "ps", nil, "路径(以逗号分割)", goflags.StringSliceOptions), + set.StringSliceVarP(&options.Path, "path", "ps", nil, "路径(以逗号分割)", goflags.CommaSeparatedStringSliceOptions), set.StringSliceVarP(&options.PathFile, "path-file", "pf", nil, "从文件中,读取路径", goflags.FileStringSliceOptions), set.StringVarP(&options.PathRemote, "path-remote", "pr", "", "从远程加载字典"), ) set.CreateGroup("output", "输出", set.StringVarP(&options.Output, "output", "o", "", "输出文件路径(可忽略)"), - set.BoolVarP(&options.Csv, "csv", "c", false, "csv格式输出"), + set.BoolVar(&options.Csv, "csv", false, "csv格式输出"), set.BoolVarP(&options.NoColor, "no-color", "nc", false, "无颜色输出"), set.BoolVarP(&options.Verbose, "verbose", "vb", false, "详细输出模式"), set.BoolVarP(&options.Silent, "silent", "sl", false, "管道模式"), @@ -92,19 +98,26 @@ func ParserOptions() *Options { ) set.CreateGroup("uncover", "引擎", set.BoolVarP(&options.Uncover, "uncover", "uc", false, "启用打开搜索引擎"), - set.StringSliceVarP(&options.UncoverQuery, "uncover-query", "uq", nil, "搜索查询", goflags.StringSliceOptions), + set.StringSliceVarP(&options.UncoverQuery, "uncover-query", "uq", nil, "搜索查询", goflags.CommaSeparatedStringSliceOptions), set.StringSliceVarP(&options.UncoverEngine, "uncover-engine", "ue", nil, fmt.Sprintf("支持的引擎 (%s) (default quake,fofa)", uncover.GetUncoverSupportedAgents()), goflags.NormalizedStringSliceOptions), set.StringVarP(&options.UncoverField, "uncover-field", "uf", "host", "引擎返回字段 (ip,port,host)"), set.IntVarP(&options.UncoverLimit, "uncover-limit", "ul", 200, "发现要返回的结果"), set.IntVarP(&options.UncoverDelay, "uncover-delay", "ucd", 1, "打开查询请求之间的延迟(秒)"), set.StringVarP(&options.UncoverOutput, "uncover-output", "uo", "", "搜索引擎查询结果保存"), ) - + set.CreateGroup("header", "请求头参数", + set.StringSliceVarP(&options.UserAgent, "user-agent", "ua", nil, "User-Agent", goflags.CommaSeparatedStringSliceOptions), + set.StringVarP(&options.Cookie, "cookie", "c", "", "cookie"), + set.StringVarP(&options.Authorization, "authorization", "auth", "", "Auth请求头"), + set.StringSliceVar(&options.Header, "header", nil, "自定义请求头,以逗号隔开", goflags.CommaSeparatedStringSliceOptions), + set.StringSliceVarP(&options.HeaderFile, "header-file", "hf", nil, "从文件中加载自定义请求头", goflags.FileStringSliceOptions), + ) set.CreateGroup("rate", "速率", set.IntVarP(&options.RateHttp, "rate-http", "rh", 100, "允许每秒钟最大http请求数"), ) set.CreateGroup("update", "更新", set.BoolVar(&options.UpdatePathScanVersion, "update", false, "更新版本"), + set.BoolVarP(&options.UpdatePathDictVersion, "update-dict", "ud", false, "更新字典版本"), ) _ = set.Parse() if !options.Silent { @@ -117,7 +130,7 @@ func ParserOptions() *Options { // create default provider file if it doesn't exist if !fileutil.FileExists(defaultProviderConfigLocation) { if err := fileutil.Marshal(fileutil.YAML, []byte(defaultProviderConfigLocation), ucRunner.Provider{}); err != nil { - gologger.Warning().Msgf("couldn't write provider default file: %s\n", err) + gologger.Warning().Msgf("无法写入提供程序默认文件: %s\n", err) } } diff --git a/pkg/runner/run.go b/pkg/runner/run.go index 5a121fc..a53bd14 100644 --- a/pkg/runner/run.go +++ b/pkg/runner/run.go @@ -11,7 +11,6 @@ import ( "github.com/wjlin0/pathScan/pkg/result" "github.com/wjlin0/pathScan/pkg/util" "golang.org/x/net/context" - "math/rand" "net/http" "os" "path/filepath" @@ -21,14 +20,14 @@ import ( ) type Runner struct { - wg sizedwaitgroup.SizedWaitGroup - Cfg *ResumeCfg - client *http.Client - limiter *ratelimit.Limiter - targets map[string]struct{} - paths map[string]struct{} - userAgent []string - stats *clistats.Statistics + wg sizedwaitgroup.SizedWaitGroup + Cfg *ResumeCfg + client *http.Client + limiter *ratelimit.Limiter + targets map[string]struct{} + paths map[string]struct{} + headers map[string]interface{} + stats *clistats.Statistics } func NewRun(options *Options) (*Runner, error) { @@ -59,40 +58,44 @@ func NewRun(options *Options) (*Runner, error) { } run.Cfg.Options.configureOutput() + err = run.Cfg.Options.Validate() + if err != nil { + return nil, err + } if !run.Cfg.Options.UpdatePathScanVersion && !run.Cfg.Options.Silent { err := CheckVersion() if err != nil { gologger.Error().Msgf(err.Error()) } } - - err = run.Cfg.Options.DownloadDict() - if err != nil { - gologger.Error().Msgf(err.Error()) - } - if run.Cfg.Options.UpdatePathScanVersion { - ok, err := run.Cfg.Options.UpdateVersion() - if err != nil && ok == false { - gologger.Error().Msg(err.Error()) + if run.Cfg.Options.UpdatePathDictVersion || run.Cfg.Options.UpdatePathScanVersion { + if run.Cfg.Options.UpdatePathDictVersion { + err = run.Cfg.Options.DownloadDict() + if err != nil { + gologger.Error().Msgf(err.Error()) + } + } + if run.Cfg.Options.UpdatePathScanVersion { + ok, err := run.Cfg.Options.UpdateVersion() + if err != nil && ok == false { + gologger.Error().Msg(err.Error()) + } } return nil, nil } + if run.Cfg.Options.ClearResume { _ = os.RemoveAll(DefaultResumeFolderPath()) gologger.Print().Msgf("clear success: %s", DefaultResumeFolderPath()) os.Exit(0) } - err = run.Cfg.Options.Validate() - if err != nil { - return nil, err - } run.client = newClient(run.Cfg.Options, run.Cfg.Options.ErrUseLastResponse) run.limiter = ratelimit.New(context.Background(), uint(run.Cfg.Options.RateHttp), time.Duration(1)*time.Second) run.wg = sizedwaitgroup.New(run.Cfg.Options.RateHttp) - run.targets = run.getAllTargets() - run.paths = run.getAllPaths() - run.userAgent = []string{"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5", "Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,like Gecko)Version/5.1 Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0;+http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (iPhone;CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko)Version/9.0 Mobile/13B143 Safari/601.1 (compatible; Baiduspider-render/2.0;Smartapp; +http://www.baidu.com/search/spider.html)"} + run.targets = run.handlerGetTargets() + run.paths = run.handlerGetTargetPath() + run.headers = run.handlerHeader() if run.Cfg.Options.EnableProgressBar { stats, err := clistats.New() if err != nil { @@ -104,11 +107,6 @@ func NewRun(options *Options) (*Runner, error) { return run, nil } -func (r *Runner) GetUserAgent() string { - rand.Seed(time.Now().Unix()) - return r.userAgent[rand.Intn(len(r.userAgent))] -} - func (r *Runner) Run() error { targets := r.targets diff --git a/pkg/runner/scan.go b/pkg/runner/scan.go index a79edd4..b058edc 100644 --- a/pkg/runner/scan.go +++ b/pkg/runner/scan.go @@ -5,6 +5,7 @@ import ( "github.com/projectdiscovery/gologger" "github.com/wjlin0/pathScan/pkg/result" "io" + "math/rand" "net/http" "net/url" "regexp" @@ -12,6 +13,19 @@ import ( "time" ) +func (r *Runner) CustomHeader(req *http.Request) { + for k, v := range r.headers { + switch v.(type) { + case string: + req.Header.Set(k, v.(string)) + case []string: + rand.Seed(time.Now().Unix()) + i := v.([]string) + req.Header.Set(k, i[rand.Intn(len(i))]) + } + } +} + func (r *Runner) GoTargetPath(target, path string) (*result.TargetResult, error) { reg := regexp.MustCompile(`(.*?)`) _url, err := url.JoinPath(target, path) @@ -22,7 +36,7 @@ func (r *Runner) GoTargetPath(target, path string) (*result.TargetResult, error) if err != nil { return nil, err } - req.Header.Set("User-Agent", r.GetUserAgent()) + r.CustomHeader(req) resp, err := r.client.Do(req) if err != nil { return nil, err diff --git a/pkg/runner/util.go b/pkg/runner/util.go index 9fe2d5e..5ca5520 100644 --- a/pkg/runner/util.go +++ b/pkg/runner/util.go @@ -26,6 +26,7 @@ func (o *Options) DownloadDict() error { } path := filepath.Join(home, ".config", "pathScan", "dict", "v"+Version) if fileutil.FileExists(filepath.Join(path, ".check")) { + gologger.Info().Msgf("远程字典下载成功->%s", path) return nil } gologger.Info().Msg("本地不存在字典,正在下载...") @@ -77,10 +78,10 @@ func (o *Options) UpdateVersion() (bool, error) { } releases, err := m.LatestReleases() if err != nil { - return false, errors.Wrap(err, "could not fetch latest release") + return false, errors.Wrap(err, "无法获取最新版本") } if len(releases) == 0 { - gologger.Info().Msgf("No new updates found for nuclei engine!") + gologger.Info().Msgf("已经为最新版本%v", Version) return true, nil } latest := releases[0]