From 073cf2a095db4aef05ba341cea01821a245451a9 Mon Sep 17 00:00:00 2001 From: M09Ic Date: Thu, 15 Dec 2022 00:19:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=99=E5=85=A8=E5=B1=80=E7=9A=84=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E6=B7=BB=E5=8A=A0=E9=85=8D=E8=89=B2,=20=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E4=BD=BF=E7=94=A8--no-color=E6=88=96-q=E5=85=B3?= =?UTF-8?q?=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- go.mod | 4 ++-- go.sum | 10 ++++++++++ internal/option.go | 9 +++++++++ internal/pool.go | 8 ++++---- internal/runner.go | 49 ++++++++++++++++++++++++++++++++++++---------- pkg/baseline.go | 42 +++++++++++++++++++++++++++++++++++++++ pkg/statistor.go | 29 +++++++++++++++++++++++++++ 8 files changed, 136 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 3145b46..008a835 100644 --- a/README.md +++ b/README.md @@ -284,7 +284,7 @@ spray支持断点续传, 可以通过`--resume-from`参数指定断点文件. 断点续传支持比命令行更自由的字典配置. 每个任务都可以拥有独立的-w/-r/-d配置. 因此某些特殊情况下要进行批量操作, 可以通过脚本去构造对应的stat文件, 实现更加自由的任务配置. ### 递归 -spray并不鼓励使用递归, 因为spray的定位是批量从反代/cdn中发现隐形资产. 不管是因为批量, 还是因为反代/cdn, 99.9的情况都用不到递归. +spray并不鼓励使用递归, 因为spray的定位是批量从反代/cdn中发现隐形资产. 不管是因为批量, 还是因为反代/cdn, 绝大多数的情况都用不到递归. 但为了兼容某些极为罕见的情况, spray依旧保留了递归的功能. diff --git a/go.mod b/go.mod index 88eeebc..8c1114e 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( github.com/chainreactors/go-metrics v0.0.0-20220926021830-24787b7a10f8 github.com/chainreactors/gogo/v2 v2.10.1 github.com/chainreactors/ipcs v0.0.13 - github.com/chainreactors/logs v0.6.2 + github.com/chainreactors/logs v0.7.1-0.20221214153111-85f123ff6580 github.com/chainreactors/parsers v0.2.9-0.20221210155102-cc0814762410 - github.com/chainreactors/words v0.3.2-0.20221214062855-48dff09b01ad + github.com/chainreactors/words v0.3.2-0.20221214154622-381fc37abdf9 ) require ( diff --git a/go.sum b/go.sum index 647479a..85da0a7 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,14 @@ github.com/chainreactors/ipcs v0.0.13/go.mod h1:E9M3Ohyq0TYQLlV4i2dbM9ThBZB1Nnd7 github.com/chainreactors/logs v0.6.1/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA= github.com/chainreactors/logs v0.6.2 h1:Yz5oayjwxO6KkjfjnmtT5WKbWjTaBdttFcneaFTpBe0= github.com/chainreactors/logs v0.6.2/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA= +github.com/chainreactors/logs v0.7.1-0.20221214130332-9bc5319887fe h1:FRMBKyuuh6EoHefqprP+pSblHrUxTaSp9GPJahYa+Fc= +github.com/chainreactors/logs v0.7.1-0.20221214130332-9bc5319887fe/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA= +github.com/chainreactors/logs v0.7.1-0.20221214130646-2e08f98a1f71 h1:SpyPYjRihGyBiqoMUggXzCc4t9A0tmAvYdjghDG8s+M= +github.com/chainreactors/logs v0.7.1-0.20221214130646-2e08f98a1f71/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA= +github.com/chainreactors/logs v0.7.1-0.20221214152543-60422cf64610 h1:ErODIlY9NmlrwEi6np3bm7HmuRZSaH3+ID2fJ2ViUpM= +github.com/chainreactors/logs v0.7.1-0.20221214152543-60422cf64610/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA= +github.com/chainreactors/logs v0.7.1-0.20221214153111-85f123ff6580 h1:28gbL1t+Mm4AoP1MeKM9oeSHoPcUwIrzrLtmdusHMIo= +github.com/chainreactors/logs v0.7.1-0.20221214153111-85f123ff6580/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA= github.com/chainreactors/parsers v0.2.9-0.20221210155102-cc0814762410 h1:K7EV0wtUuN6Rvh/MgqaBXyElD3guPsgNR5kF8nrV7iw= github.com/chainreactors/parsers v0.2.9-0.20221210155102-cc0814762410/go.mod h1:Z9weht+lnFCk7UcwqFu6lXpS7u5vttiy0AJYOAyCCLA= github.com/chainreactors/words v0.3.2-0.20221212161820-bae5f18558db h1:Rv6mcLAKXRXoZuifCwGTlXnuDbDpbDKC0JsTI1op/OA= @@ -27,6 +35,8 @@ github.com/chainreactors/words v0.3.2-0.20221214061028-a7cf9f9f8ddb h1:9AV8SH+Sv github.com/chainreactors/words v0.3.2-0.20221214061028-a7cf9f9f8ddb/go.mod h1:QIWX1vMT5j/Mp9zx3/wgZh3FqskhjCbo/3Ffy/Hxj9w= github.com/chainreactors/words v0.3.2-0.20221214062855-48dff09b01ad h1:uL3TIQgvFY7dLoX0tAzIIXilCPIcNeLz/124gs+SA/Q= github.com/chainreactors/words v0.3.2-0.20221214062855-48dff09b01ad/go.mod h1:QIWX1vMT5j/Mp9zx3/wgZh3FqskhjCbo/3Ffy/Hxj9w= +github.com/chainreactors/words v0.3.2-0.20221214154622-381fc37abdf9 h1:IUNopSuorfINmn4pOuSwZtxJbg8zsRIZ67a33SiYoQ0= +github.com/chainreactors/words v0.3.2-0.20221214154622-381fc37abdf9/go.mod h1:QIWX1vMT5j/Mp9zx3/wgZh3FqskhjCbo/3Ffy/Hxj9w= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/internal/option.go b/internal/option.go index 90a4a9a..140ea38 100644 --- a/internal/option.go +++ b/internal/option.go @@ -92,6 +92,7 @@ type MiscOptions struct { PoolSize int `short:"p" long:"pool" default:"5" description:"Int, Pool size"` Threads int `short:"t" long:"thread" default:"20" description:"Int, number of threads per pool (seconds)"` Debug bool `long:"debug" description:"Bool, output debug info"` + NoColor bool `long:"no-color" description:"Bool, no color"` Quiet bool `short:"q" long:"quiet" description:"Bool, Quiet"` NoBar bool `long:"no-bar" description:"Bool, No progress bar"` Mod string `short:"m" long:"mod" default:"path" choice:"path" choice:"host" description:"String, path/host spray"` @@ -139,11 +140,19 @@ func (opt *Option) PrepareRunner() (*Runner, error) { } } // 一些全局变量初始化 + if !opt.NoColor { + logs.Log.Color = true + logs.DefaultColorMap[logs.Info] = logs.PurpleBold + logs.DefaultColorMap[logs.Important] = logs.Green + r.Color = true + } if opt.Debug { logs.Log.Level = logs.Debug } if opt.Quiet { logs.Log.Quiet = true + logs.Log.Color = false + r.Color = false } if !(opt.Quiet || opt.NoBar) { r.Progress.Start() diff --git a/internal/pool.go b/internal/pool.go index 1642309..9752031 100644 --- a/internal/pool.go +++ b/internal/pool.go @@ -230,7 +230,7 @@ func (pool *Pool) Init() error { return fmt.Errorf(pool.index.String()) } pool.index.Collect() - logs.Log.Important("[baseline.index] " + pool.index.String()) + logs.Log.Info("[baseline.index] " + pool.index.String()) pool.initwg.Add(1) pool.reqPool.Invoke(newUnit(pkg.RandPath(), InitRandomSource)) @@ -240,14 +240,14 @@ func (pool *Pool) Init() error { return fmt.Errorf(pool.random.String()) } pool.random.Collect() - logs.Log.Important("[baseline.random] " + pool.random.String()) + logs.Log.Info("[baseline.random] " + pool.random.String()) if pool.random.RedirectURL != "" { // 自定协议升级 // 某些网站http会重定向到https, 如果发现随机目录出现这种情况, 则自定将baseurl升级为https rurl, err := url.Parse(pool.random.RedirectURL) if err == nil && rurl.Hostname() == pool.random.Url.Hostname() && pool.random.Url.Scheme == "http" && rurl.Scheme == "https" { - logs.Log.Importantf("baseurl %s upgrade http to https", pool.BaseURL) + logs.Log.Infof("baseurl %s upgrade http to https", pool.BaseURL) pool.BaseURL = strings.Replace(pool.BaseURL, "http", "https", 1) } } @@ -435,7 +435,7 @@ func (pool *Pool) addFuzzyBaseline(bl *pkg.Baseline) { pool.locker.Lock() pool.baselines[bl.Status] = bl pool.locker.Unlock() - logs.Log.Importantf("[baseline.%dinit] %s", bl.Status, bl.String()) + logs.Log.Infof("[baseline.%dinit] %s", bl.Status, bl.String()) } } diff --git a/internal/runner.go b/internal/runner.go index 25e4ea4..559c33a 100644 --- a/internal/runner.go +++ b/internal/runner.go @@ -68,6 +68,7 @@ type Runner struct { CheckPeriod int ErrPeriod int BreakThreshold int + Color bool CheckOnly bool Force bool IgnoreWaf bool @@ -198,8 +199,14 @@ func (r *Runner) Prepare(ctx context.Context) error { } pool.Run(ctx, pool.Statistor.Offset, limit) - logs.Log.Important(pool.Statistor.String()) - logs.Log.Important(pool.Statistor.Detail()) + if r.Color { + logs.Log.Important(pool.Statistor.ColorString()) + logs.Log.Important(pool.Statistor.ColorDetail()) + } else { + logs.Log.Important(pool.Statistor.String()) + logs.Log.Important(pool.Statistor.Detail()) + } + if r.StatFile != nil { r.StatFile.SafeWrite(pool.Statistor.Json()) r.StatFile.SafeSync() @@ -314,13 +321,26 @@ func (r *Runner) Outputting() { } else { if len(r.Probes) > 0 { - saveFunc = func(bl *pkg.Baseline) { - logs.Log.Console("[+] " + bl.Format(r.Probes) + "\n") + if r.Color { + saveFunc = func(bl *pkg.Baseline) { + logs.Log.Console(logs.GreenBold("[+] " + bl.Format(r.Probes) + "\n")) + } + } else { + saveFunc = func(bl *pkg.Baseline) { + logs.Log.Console("[+] " + bl.Format(r.Probes) + "\n") + } } } else { - saveFunc = func(bl *pkg.Baseline) { - logs.Log.Console("[+] " + bl.String() + "\n") + if r.Color { + saveFunc = func(bl *pkg.Baseline) { + logs.Log.Console(logs.GreenBold("[+] " + bl.ColorString() + "\n")) + } + } else { + saveFunc = func(bl *pkg.Baseline) { + logs.Log.Console("[+] " + bl.String() + "\n") + } } + } } @@ -340,7 +360,12 @@ func (r *Runner) Outputting() { r.AddPool(&Task{baseUrl: bl.UrlString, depth: bl.RecuDepth + 1}) } } else { - logs.Log.Debug(bl.String()) + if r.Color { + logs.Log.Debug(bl.ColorString()) + } else { + logs.Log.Debug(bl.String()) + } + } } } @@ -353,9 +378,13 @@ func (r *Runner) Outputting() { r.FuzzyFile.SafeWrite(bl.Jsonify() + "\n") } } else { - fuzzySaveFunc = func(bl *pkg.Baseline) { - if r.Fuzzy { - logs.Log.Console("[baseline.fuzzy] " + bl.String() + "\n") + if r.Color { + fuzzySaveFunc = func(bl *pkg.Baseline) { + logs.Log.Console(logs.GreenBold("[fuzzy] " + bl.ColorString() + "\n")) + } + } else { + fuzzySaveFunc = func(bl *pkg.Baseline) { + logs.Log.Console("[fuzzy] " + bl.String() + "\n") } } } diff --git a/pkg/baseline.go b/pkg/baseline.go index da86397..54e99e4 100644 --- a/pkg/baseline.go +++ b/pkg/baseline.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "github.com/chainreactors/gogo/v2/pkg/utils" + "github.com/chainreactors/logs" "github.com/chainreactors/parsers" "github.com/chainreactors/spray/pkg/ihttp" "net/url" @@ -227,6 +228,47 @@ func (bl *Baseline) Format(probes []string) string { return line.String() } +func (bl *Baseline) ColorString() string { + var line strings.Builder + if bl.FrontURL != "" { + line.WriteString("\t") + line.WriteString(logs.CyanLine(bl.FrontURL)) + line.WriteString(" --> ") + } + line.WriteString(logs.GreenLine(bl.UrlString)) + if bl.Host != "" { + line.WriteString(" (" + bl.Host + ")") + } + + if bl.Reason != "" { + line.WriteString(" [reason: ") + line.WriteString(logs.YellowBold(bl.Reason)) + line.WriteString("]") + } + if bl.ErrString != "" { + line.WriteString(" [err: ") + line.WriteString(logs.RedBold(bl.ErrString)) + line.WriteString("]") + return line.String() + } + + line.WriteString(" - ") + line.WriteString(logs.GreenBold(strconv.Itoa(bl.Status))) + line.WriteString(" - ") + line.WriteString(logs.Blue(strconv.Itoa(bl.BodyLength))) + line.WriteString(" - ") + line.WriteString(logs.Blue(strconv.Itoa(int(bl.Spended)) + "ms")) + line.WriteString(logs.GreenLine(bl.Additional("title"))) + line.WriteString(logs.Blue(bl.Frameworks.String())) + line.WriteString(logs.Blue(bl.Extracteds.String())) + if bl.RedirectURL != "" { + line.WriteString(" --> ") + line.WriteString(logs.CyanLine(bl.RedirectURL)) + line.WriteString(" ") + } + return line.String() +} + func (bl *Baseline) String() string { var line strings.Builder if bl.FrontURL != "" { diff --git a/pkg/statistor.go b/pkg/statistor.go index 6be7de0..974dd83 100644 --- a/pkg/statistor.go +++ b/pkg/statistor.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/chainreactors/logs" "io/ioutil" "strconv" "strings" @@ -56,6 +57,21 @@ type Statistor struct { RuleFilter string `json:"rule_filter"` } +func (stat *Statistor) ColorString() string { + var s strings.Builder + s.WriteString(fmt.Sprintf("[stat] %s took %d s, request total: %s, finish: %s/%s, found: %s, check: %s, failed: %s", logs.GreenLine(stat.BaseUrl), stat.EndTime-stat.StartTime, logs.YellowBold(strconv.Itoa(int(stat.ReqTotal))), logs.YellowBold(strconv.Itoa(stat.End)), logs.YellowBold(strconv.Itoa(stat.Total)), logs.YellowBold(strconv.Itoa(stat.FoundNumber)), logs.YellowBold(strconv.Itoa(stat.CheckNumber)), logs.YellowBold(strconv.Itoa(int(stat.FailedNumber))))) + + if stat.FuzzyNumber != 0 { + s.WriteString(", fuzzy: " + logs.Yellow(strconv.Itoa(stat.FuzzyNumber))) + } + if stat.FilteredNumber != 0 { + s.WriteString(", filtered: " + logs.Yellow(strconv.Itoa(stat.FilteredNumber))) + } + if stat.WafedNumber != 0 { + s.WriteString(", wafed: " + logs.Yellow(strconv.Itoa(stat.WafedNumber))) + } + return s.String() +} func (stat *Statistor) String() string { var s strings.Builder s.WriteString(fmt.Sprintf("[stat] %s took %d s, request total: %d, finish: %d/%d, found: %d, check: %d, failed: %d", stat.BaseUrl, stat.EndTime-stat.StartTime, stat.ReqTotal, stat.End, stat.Total, stat.FoundNumber, stat.CheckNumber, stat.FailedNumber)) @@ -85,6 +101,19 @@ func (stat *Statistor) Detail() string { return s.String() } +func (stat *Statistor) ColorDetail() string { + var s strings.Builder + s.WriteString("[stat] ") + s.WriteString(stat.BaseUrl) + for k, v := range stat.Counts { + if k == 0 { + continue + } + s.WriteString(fmt.Sprintf(" %s: %s,", logs.YellowBold(strconv.Itoa(k)), logs.YellowBold(strconv.Itoa(v)))) + } + return s.String() +} + func (stat *Statistor) Json() string { content, err := json.Marshal(stat) if err != nil {