From dc8829eccac86d65635ee26377768a3ca1a45c42 Mon Sep 17 00:00:00 2001 From: M09Ic Date: Tue, 6 Aug 2024 02:43:38 +0800 Subject: [PATCH 1/6] fix word not work https://github.com/chainreactors/spray/issues/53 --- internal/option.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/option.go b/internal/option.go index 5a33e3d..48abb75 100644 --- a/internal/option.go +++ b/internal/option.go @@ -521,7 +521,8 @@ func (opt *Option) BuildWords(r *Runner) error { logs.Log.Logf(pkg.LogVerbose, "Loaded %d word from %s", len(dicts[i]), f) } - if len(dicts) == 0 { + + if len(dicts) == 0 && opt.Word == "" { r.IsCheck = true } From ebc74c19872717df979d2d0526354d6df3aa9c4e Mon Sep 17 00:00:00 2001 From: M09Ic Date: Tue, 6 Aug 2024 03:46:30 +0800 Subject: [PATCH 2/6] fix multi http parse bug --- internal/ihttp/response.go | 12 ++---------- pkg/baseline.go | 7 ++++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/internal/ihttp/response.go b/internal/ihttp/response.go index 1de39af..3d2089e 100644 --- a/internal/ihttp/response.go +++ b/internal/ihttp/response.go @@ -1,8 +1,8 @@ package ihttp import ( - "bytes" "github.com/chainreactors/logs" + "github.com/chainreactors/utils/httputils" "github.com/valyala/fasthttp" "io" "net/http" @@ -93,15 +93,7 @@ func (r *Response) Header() []byte { if r.FastResponse != nil { return r.FastResponse.Header.Header() } else if r.StandardResponse != nil { - var header bytes.Buffer - header.WriteString(r.StandardResponse.Proto + " " + r.StandardResponse.Status) - for k, v := range r.StandardResponse.Header { - for _, i := range v { - header.WriteString(k + ": " + i + "\r\n") - } - } - header.WriteString("\r\n") - return header.Bytes() + return append(httputils.ReadRawHeader(r.StandardResponse), []byte("\r\n")...) } else { return nil } diff --git a/pkg/baseline.go b/pkg/baseline.go index 350e066..0099040 100644 --- a/pkg/baseline.go +++ b/pkg/baseline.go @@ -36,9 +36,10 @@ func NewBaseline(u, host string, resp *ihttp.Response) *Baseline { bl.HeaderLength = len(bl.Header) if i := resp.ContentLength(); ihttp.CheckBodySize(i) { - body := resp.Body() - bl.Body = make([]byte, len(body)) - copy(bl.Body, body) + if body := resp.Body(); body != nil { + bl.Body = make([]byte, len(body)) + copy(bl.Body, body) + } if i == -1 { bl.Chunked = true From 021e84ae81c860b6f496b9a193e08bf571ab4cff Mon Sep 17 00:00:00 2001 From: M09Ic Date: Tue, 6 Aug 2024 03:58:30 +0800 Subject: [PATCH 3/6] enhance runner structure --- cmd/cmd.go | 16 +++++----------- go.mod | 2 +- go.sum | 2 ++ internal/pool/checkpool.go | 22 ++++------------------ internal/runner.go | 6 ++++-- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 3edd2bc..94f25e0 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -127,13 +127,6 @@ func Spray() { } ctx, canceler := context.WithTimeout(context.Background(), time.Duration(runner.Deadline)*time.Second) - - err = runner.Prepare(ctx) - if err != nil { - logs.Log.Errorf(err.Error()) - return - } - go func() { exitChan := make(chan os.Signal, 2) signal.Notify(exitChan, os.Interrupt, syscall.SIGTERM) @@ -154,10 +147,11 @@ func Spray() { }() }() - if runner.IsCheck { - runner.RunWithCheck(ctx) - } else { - runner.Run(ctx) + err = runner.Prepare(ctx) + if err != nil { + logs.Log.Errorf(err.Error()) + return } + time.Sleep(1 * time.Second) } diff --git a/go.mod b/go.mod index 120386e..98faacc 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/chainreactors/fingers v0.0.0-20240716172449-2fc3147b9c2a github.com/chainreactors/logs v0.0.0-20240207121836-c946f072f81f github.com/chainreactors/parsers v0.0.0-20240708072709-07deeece7ce2 - github.com/chainreactors/utils v0.0.0-20240716182459-e85f2b01ee16 + github.com/chainreactors/utils v0.0.0-20240805193040-ff3b97aa3c3f github.com/chainreactors/words v0.4.1-0.20240510105042-5ba5c2edc508 github.com/expr-lang/expr v1.16.9 github.com/gookit/config/v2 v2.2.5 diff --git a/go.sum b/go.sum index 7df73e9..aa9c067 100644 --- a/go.sum +++ b/go.sum @@ -98,6 +98,8 @@ github.com/chainreactors/utils v0.0.0-20240704062557-662d623b74f4/go.mod h1:JA4e github.com/chainreactors/utils v0.0.0-20240715080349-d2d0484c95ed/go.mod h1:LajXuvESQwP+qCMAvlcoSXppQCjuLlBrnQpu9XQ1HtU= github.com/chainreactors/utils v0.0.0-20240716182459-e85f2b01ee16 h1:TCOshCp7PrWqhP/HSAM5kT3VxoOe7EoJbRseyoSX3RM= github.com/chainreactors/utils v0.0.0-20240716182459-e85f2b01ee16/go.mod h1:LajXuvESQwP+qCMAvlcoSXppQCjuLlBrnQpu9XQ1HtU= +github.com/chainreactors/utils v0.0.0-20240805193040-ff3b97aa3c3f h1:2NKmadFYP9vCwC0YrazgttFACleOhxScTPzg0i76YAY= +github.com/chainreactors/utils v0.0.0-20240805193040-ff3b97aa3c3f/go.mod h1:LajXuvESQwP+qCMAvlcoSXppQCjuLlBrnQpu9XQ1HtU= github.com/chainreactors/words v0.4.1-0.20240510105042-5ba5c2edc508 h1:iT4HWkoZzUAfQYcQMRH8XyrMau9tCVE0zSuFQnkhrqw= github.com/chainreactors/words v0.4.1-0.20240510105042-5ba5c2edc508/go.mod h1:DUDx7PdsMEm5PvVhzkFyppzpiUhQb8dOJaWjVc1SMVk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/internal/pool/checkpool.go b/internal/pool/checkpool.go index a351aa6..45bc087 100644 --- a/internal/pool/checkpool.go +++ b/internal/pool/checkpool.go @@ -50,35 +50,21 @@ type CheckPool struct { func (pool *CheckPool) Run(ctx context.Context, offset, limit int) { pool.Worder.Run() - var done bool - // 挂起一个监控goroutine, 每100ms判断一次done, 如果已经done, 则关闭closeCh, 然后通过Loop中的select case closeCh去break, 实现退出 - go func() { - for { - if done { - pool.wg.Wait() - close(pool.closeCh) - return - } - time.Sleep(100 * time.Millisecond) - } - }() - Loop: for { select { case u, ok := <-pool.Worder.C: if !ok { - done = true - continue + break Loop } if pool.reqCount < offset { pool.reqCount++ - continue + break Loop } if pool.reqCount > limit { - continue + break Loop } pool.wg.Add(1) @@ -96,7 +82,7 @@ Loop: break Loop } } - + pool.wg.Wait() pool.Close() } diff --git a/internal/runner.go b/internal/runner.go index c412057..aeeae11 100644 --- a/internal/runner.go +++ b/internal/runner.go @@ -111,6 +111,7 @@ func (r *Runner) AppendFunction(fn func(string) []string) { } func (r *Runner) Prepare(ctx context.Context) error { + r.OutputHandler() var err error if r.IsCheck { // 仅check, 类似httpx @@ -138,6 +139,7 @@ func (r *Runner) Prepare(ctx context.Context) error { checkPool.Run(ctx, r.Offset, r.Count) r.poolwg.Done() }) + r.RunWithCheck(ctx) } else { // 完整探测模式 go func() { @@ -214,12 +216,12 @@ func (r *Runner) Prepare(ctx context.Context) error { r.PrintStat(brutePool) r.Done() }) + r.Run(ctx) } - if err != nil { return err } - r.OutputHandler() + return nil } From 38bc2d33f21ac742ab7b6ac70c9d1cca279d8b26 Mon Sep 17 00:00:00 2001 From: M09Ic Date: Tue, 6 Aug 2024 04:01:35 +0800 Subject: [PATCH 4/6] add --active flag and fix plugin not work bug https://github.com/chainreactors/spray/issues/51 --- internal/option.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/internal/option.go b/internal/option.go index 48abb75..d1bf3f8 100644 --- a/internal/option.go +++ b/internal/option.go @@ -111,6 +111,7 @@ type PluginOptions struct { Advance bool `short:"a" long:"advance" description:"Bool, enable all plugin" config:"all" ` Extracts []string `long:"extract" description:"Strings, extract response, e.g.: --extract js --extract ip --extract version:(.*?)" config:"extract"` ExtractConfig string `long:"extract-config" description:"String, extract config filename" config:"extract-config"` + Active bool `long:"active" description:"Bool, enable active finger path"` Recon bool `long:"recon" description:"Bool, enable recon" config:"recon"` Bak bool `long:"bak" description:"Bool, enable bak found" config:"bak"` FileBak bool `long:"file-bak" description:"Bool, enable valid result bak found, equal --append-rule rule/filebak.txt" config:"file-bak"` @@ -312,25 +313,39 @@ func (opt *Option) NewRunner() (*Runner, error) { pkg.Extractors["recon"] = pkg.ExtractRegexps["pentest"] } + if opt.Finger { + pkg.EnableAllFingerEngine = true + } + + // brute only if opt.Advance { r.Crawl = true r.Finger = true r.Bak = true r.Common = true + r.Active = true pkg.EnableAllFingerEngine = true pkg.Extractors["recon"] = pkg.ExtractRegexps["pentest"] + r.IsCheck = false opt.AppendRule = append(opt.AppendRule, "filebak") } if opt.FileBak { + r.IsCheck = false opt.AppendRule = append(opt.AppendRule, "filebak") } if opt.Common { + r.IsCheck = false r.AppendWords = append(r.AppendWords, mask.SpecialWords["common_file"]...) } - if opt.Finger { + + if opt.Active { + r.IsCheck = false r.AppendWords = append(r.AppendWords, pkg.ActivePath...) - pkg.EnableAllFingerEngine = true + } + + if opt.Crawl { + r.IsCheck = false } opt.PrintPlugin() From b1aa68f20ca57d2f9883c8b5a188380e2635ba81 Mon Sep 17 00:00:00 2001 From: M09Ic Date: Tue, 6 Aug 2024 16:29:33 +0800 Subject: [PATCH 5/6] misc update --- internal/option.go | 4 ++++ templates | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/option.go b/internal/option.go index d1bf3f8..e1d0b32 100644 --- a/internal/option.go +++ b/internal/option.go @@ -349,6 +349,9 @@ func (opt *Option) NewRunner() (*Runner, error) { } opt.PrintPlugin() + if r.IsCheck == false { + logs.Log.Important("enabling brute mod, because of enabled brute plugin") + } if opt.NoScope { r.Scope = []string{"*"} @@ -512,6 +515,7 @@ func (opt *Option) PrintPlugin() { if opt.RetryCount > 0 { s.WriteString("Retry Count: " + strconv.Itoa(opt.RetryCount)) } + if s.Len() > 0 { logs.Log.Important(s.String()) } diff --git a/templates b/templates index 3e85234..f2980b8 160000 --- a/templates +++ b/templates @@ -1 +1 @@ -Subproject commit 3e85234341b95f7e6e45b31468311f01093ac970 +Subproject commit f2980b8d312c8088f3947d914499e96cfc40d975 From 28aacea18c4777ee2617182ec35b9bb243378476 Mon Sep 17 00:00:00 2001 From: M09Ic Date: Tue, 6 Aug 2024 16:31:22 +0800 Subject: [PATCH 6/6] update quickstart note --- cmd/cmd.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 94f25e0..7d44fd2 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -15,7 +15,7 @@ import ( "time" ) -var ver = "v1.0.0" +var ver = "v1.0.1" var DefaultConfig = "config.yaml" func init() { @@ -44,13 +44,19 @@ func Spray() { WIKI: https://chainreactors.github.io/wiki/spray QUICKSTART: - simple example: + basic: + spray -u http://example.com + + basic cidr and port: + spray -i example -p top2,top3 + + simple brute: spray -u http://example.com -d wordlist1.txt -d wordlist2.txt - mask-base wordlist: + mask-base brute with wordlist: spray -u http://example.com -w "/aaa/bbb{?l#4}/ccc" - rule-base wordlist: + rule-base brute with wordlist: spray -u http://example.com -r rule.txt -d 1.txt list input spray: