Skip to content

Commit 0a0398e

Browse files
LSD00LSD00
LSD00
authored and
LSD00
committed
Initial commit
0 parents  commit 0a0398e

File tree

7 files changed

+314
-0
lines changed

7 files changed

+314
-0
lines changed

.goreleaser.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# This is an example .goreleaser.yml file with some sensible defaults.
2+
# Make sure to check the documentation at https://goreleaser.com
3+
4+
# The lines below are called `modelines`. See `:help modeline`
5+
# Feel free to remove those if you don't want/need to use them.
6+
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
7+
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
8+
9+
version: 1
10+
11+
before:
12+
hooks:
13+
# You may remove this if you don't use go modules.
14+
- go mod tidy
15+
# you may remove this if you don't need go generate
16+
- go generate ./...
17+
18+
builds:
19+
- env:
20+
- CGO_ENABLED=0
21+
goos:
22+
- linux
23+
- windows
24+
- darwin
25+
26+
archives:
27+
- format: tar.gz
28+
# this name template makes the OS and Arch compatible with the results of `uname`.
29+
name_template: >-
30+
{{ .ProjectName }}_
31+
{{- title .Os }}_
32+
{{- if eq .Arch "amd64" }}x86_64
33+
{{- else if eq .Arch "386" }}i386
34+
{{- else }}{{ .Arch }}{{ end }}
35+
{{- if .Arm }}v{{ .Arm }}{{ end }}
36+
# use zip for windows archives
37+
format_overrides:
38+
- goos: windows
39+
format: zip
40+
41+
changelog:
42+
sort: asc
43+
filters:
44+
exclude:
45+
- "^docs:"
46+
- "^test:"

go.mod

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module webfuzz
2+
3+
go 1.21.10
4+
5+
require (
6+
github.com/alecthomas/kingpin/v2 v2.4.0
7+
github.com/valyala/fasthttp v1.54.0
8+
)
9+
10+
require (
11+
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
12+
github.com/andybalholm/brotli v1.1.0 // indirect
13+
github.com/klauspost/compress v1.17.7 // indirect
14+
github.com/valyala/bytebufferpool v1.0.0 // indirect
15+
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
16+
)

go.sum

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
2+
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
3+
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
4+
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
5+
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
6+
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
7+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
9+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10+
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
11+
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
12+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
13+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
14+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
15+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
16+
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
17+
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
18+
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
19+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
20+
github.com/valyala/fasthttp v1.54.0 h1:cCL+ZZR3z3HPLMVfEYVUMtJqVaui0+gu7Lx63unHwS0=
21+
github.com/valyala/fasthttp v1.54.0/go.mod h1:6dt4/8olwq9QARP/TDuPmWyWcl4byhpvTJ4AAtcz+QM=
22+
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
23+
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
24+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
25+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
26+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
27+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"webfuzz/pkg/workers"
7+
8+
"github.com/alecthomas/kingpin/v2"
9+
)
10+
11+
var (
12+
domain, reqfile, wordlist, invalid string
13+
th int
14+
opt workers.Options
15+
)
16+
17+
func main() {
18+
kingpin.Flag("domain", "target domain").Required().Short('d').StringVar(&domain)
19+
kingpin.Flag("request", "file with http request").Required().Short('r').StringVar(&reqfile)
20+
kingpin.Flag("wordlist", "file with wordlist").Required().Short('w').StringVar(&wordlist)
21+
kingpin.Flag("regex", "regex for search").Default(".+").StringVar(&opt.Regex)
22+
kingpin.Flag("threads", "setting threads").Default("25").IntVar(&th)
23+
kingpin.Flag("tls", "is target use tls").Default("false").BoolVar(&opt.TlsEnabled)
24+
kingpin.Flag("bad-codes", "invalid codes for fuzzing ex. 404, 503, 400").Default("404").StringVar(&invalid)
25+
kingpin.Parse()
26+
opt.InvalidCode = strings.Split(strings.ReplaceAll(invalid, " ", ""), ",")
27+
worker, err := workers.NewPool(wordlist, reqfile, th)
28+
if err != nil {
29+
fmt.Println(err)
30+
}
31+
worker.Options = opt
32+
fmt.Println(`
33+
_ _ _ ______
34+
| | | | | | | ___|
35+
| | | | ___| |__ | |_ _ _ ________
36+
| |/\| |/ _ \ '_ \| _| | | |_ /_ /
37+
\ /\ / __/ |_) | | | |_| |/ / / /
38+
\/ \/ \___|_.__/\_| \__,_/___/___|
39+
40+
41+
`)
42+
worker.Fuzz(domain)
43+
}

pkg/formatter/formatter.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package formatter
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/hex"
6+
"net/url"
7+
"strings"
8+
)
9+
10+
type EncoderFunc func(data string) string
11+
12+
type Payload struct {
13+
encoders map[string]EncoderFunc
14+
payload string
15+
}
16+
17+
func NewPayload(payload string) *Payload {
18+
encoders := map[string]EncoderFunc{
19+
"none": func(data string) string {
20+
return data
21+
},
22+
"urlencode": func(data string) string {
23+
return url.QueryEscape(data)
24+
},
25+
"base64": func(data string) string {
26+
return base64.StdEncoding.EncodeToString([]byte(data))
27+
},
28+
"hex": func(data string) string {
29+
return hex.EncodeToString([]byte(data))
30+
},
31+
}
32+
return &Payload{payload: payload, encoders: encoders}
33+
}
34+
35+
func (p *Payload) CreatePayload(format string) string {
36+
splited_mask := strings.Split(strings.ReplaceAll(format, " ", ""), ",")
37+
for _, value := range splited_mask {
38+
p.payload = p.encoders[value](p.payload)
39+
}
40+
return p.payload
41+
}

pkg/reqgen/reqgen.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package reqgen
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
7+
"github.com/valyala/fasthttp"
8+
)
9+
10+
type Worker struct {
11+
domain string
12+
tlsEnabled bool
13+
req *bufio.Reader
14+
}
15+
16+
type Resp struct {
17+
BodyData string
18+
Len, Status int
19+
}
20+
21+
func NewWorker(tlsEnabled bool, req *bufio.Reader, domain string) *Worker {
22+
return &Worker{
23+
tlsEnabled: tlsEnabled,
24+
req: req,
25+
domain: domain,
26+
}
27+
}
28+
29+
func (w *Worker) MakeRequest() (Resp, error) {
30+
request := fasthttp.AcquireRequest()
31+
err := request.Read(w.req)
32+
if err != nil {
33+
return Resp{}, err
34+
}
35+
if w.tlsEnabled {
36+
request.SetRequestURI(fmt.Sprintf("https://%s%s", w.domain, string(request.RequestURI())))
37+
} else {
38+
request.SetRequestURI(fmt.Sprintf("http://%s%s", w.domain, string(request.RequestURI())))
39+
}
40+
41+
resp := fasthttp.AcquireResponse()
42+
client := &fasthttp.Client{}
43+
client.Do(request, resp)
44+
45+
bodyBytes, err := resp.BodyUncompressed()
46+
if err != nil {
47+
return Resp{}, err
48+
}
49+
return Resp{
50+
BodyData: string(bodyBytes),
51+
Len: len(string(bodyBytes)),
52+
Status: resp.StatusCode(),
53+
}, nil
54+
}

pkg/workers/workers.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package workers
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"fmt"
7+
"io"
8+
"os"
9+
"regexp"
10+
"slices"
11+
"sync"
12+
"text/template"
13+
"webfuzz/pkg/formatter"
14+
"webfuzz/pkg/reqgen"
15+
)
16+
17+
type Options struct {
18+
TlsEnabled bool
19+
Regex string
20+
InvalidCode []string
21+
}
22+
23+
type Pool struct {
24+
concurrents int
25+
wordlists []string
26+
req *template.Template
27+
Options Options
28+
}
29+
30+
func NewPool(wordlist, reqfile string, concurrents int) (*Pool, error) {
31+
var pool Pool
32+
pool.concurrents = concurrents
33+
file, err := os.Open(wordlist)
34+
if err != nil {
35+
return nil, err
36+
}
37+
defer file.Close()
38+
reader := bufio.NewScanner(file)
39+
for reader.Scan() {
40+
pool.wordlists = append(pool.wordlists, reader.Text())
41+
}
42+
pool.req, err = template.ParseFiles(reqfile)
43+
if err != nil {
44+
return nil, err
45+
}
46+
return &pool, nil
47+
}
48+
49+
func (p *Pool) Fuzz(domain string) {
50+
var wg sync.WaitGroup
51+
chunks := len(p.wordlists) / p.concurrents
52+
for i := 0; i < p.concurrents; i++ {
53+
var chunked_wordlist []string
54+
if i != p.concurrents-1 {
55+
chunked_wordlist = p.wordlists[i*chunks : (i+1)*chunks]
56+
} else {
57+
chunked_wordlist = p.wordlists[i*chunks:]
58+
}
59+
wg.Add(1)
60+
go func(wg *sync.WaitGroup, wordlist []string) {
61+
defer wg.Done()
62+
re := regexp.MustCompile(p.Options.Regex)
63+
for _, value := range wordlist {
64+
var buf bytes.Buffer
65+
payload := formatter.NewPayload(value)
66+
p.req.Execute(&buf, payload)
67+
worker := reqgen.NewWorker(p.Options.TlsEnabled, bufio.NewReader(&buf), domain)
68+
resp, err := worker.MakeRequest()
69+
io.WriteString(os.Stdout, buf.String())
70+
if err != nil {
71+
return
72+
} else if !slices.Contains(p.Options.InvalidCode, fmt.Sprint(resp.Status)) && re.MatchString(resp.BodyData) {
73+
var formatted_code string
74+
if resp.Status >= 200 && resp.Status < 300 {
75+
formatted_code = fmt.Sprintf("\033[92m%d\033[0m", resp.Status)
76+
} else if resp.Status >= 300 && resp.Status < 400 {
77+
formatted_code = fmt.Sprintf("\033[96m%d\033[0m", resp.Status)
78+
} else if resp.Status >= 400 {
79+
formatted_code = fmt.Sprintf("\033[91m%d\033[0m", resp.Status)
80+
}
81+
io.WriteString(os.Stdout, fmt.Sprintf("%s -> %s (%d)\r\n", value, formatted_code, resp.Len))
82+
}
83+
}
84+
}(&wg, chunked_wordlist)
85+
}
86+
wg.Wait()
87+
}

0 commit comments

Comments
 (0)