/
options.go
170 lines (147 loc) · 4.2 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package libgobuster
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
"time"
multierror "github.com/hashicorp/go-multierror"
)
const (
// ModeDir represents -m dir
ModeDir = "dir"
// ModeDNS represents -m dns
ModeDNS = "dns"
)
// Options helds all options that can be passed to libgobuster
type Options struct {
Extensions string
ExtensionsParsed stringSet
Mode string
Password string
StatusCodes string
StatusCodesParsed intSet
Threads int
URL string
UserAgent string
Username string
Wordlist string
Proxy string
Cookies string
Timeout time.Duration
FollowRedirect bool
IncludeLength bool
NoStatus bool
NoProgress bool
Expanded bool
Quiet bool
ShowIPs bool
ShowCNAME bool
InsecureSSL bool
WildcardForced bool
Verbose bool
UseSlash bool
}
// NewOptions returns a new initialized Options object
func NewOptions() *Options {
return &Options{
StatusCodesParsed: newIntSet(),
ExtensionsParsed: newStringSet(),
}
}
// Validate validates the given options
func (opt *Options) validate() *multierror.Error {
var errorList *multierror.Error
if strings.ToLower(opt.Mode) != ModeDir && strings.ToLower(opt.Mode) != ModeDNS {
errorList = multierror.Append(errorList, fmt.Errorf("Mode (-m): Invalid value: %s", opt.Mode))
}
if opt.Threads < 0 {
errorList = multierror.Append(errorList, fmt.Errorf("Threads (-t): Invalid value: %d", opt.Threads))
}
if opt.Wordlist == "" {
errorList = multierror.Append(errorList, fmt.Errorf("WordList (-w): Must be specified (use `-w -` for stdin)"))
} else if opt.Wordlist == "-" {
// STDIN
} else if _, err := os.Stat(opt.Wordlist); os.IsNotExist(err) {
errorList = multierror.Append(errorList, fmt.Errorf("Wordlist (-w): File does not exist: %s", opt.Wordlist))
}
if opt.URL == "" {
errorList = multierror.Append(errorList, fmt.Errorf("Url/Domain (-u): Must be specified"))
}
if opt.StatusCodes != "" {
if err := opt.parseStatusCodes(); err != nil {
errorList = multierror.Append(errorList, err)
}
}
if opt.Extensions != "" {
if err := opt.parseExtensions(); err != nil {
errorList = multierror.Append(errorList, err)
}
}
if opt.Mode == ModeDir {
if !strings.HasSuffix(opt.URL, "/") {
opt.URL = fmt.Sprintf("%s/", opt.URL)
}
if err := opt.validateDirMode(); err != nil {
errorList = multierror.Append(errorList, err)
}
}
return errorList
}
// ParseExtensions parses the extensions provided as a comma seperated list
func (opt *Options) parseExtensions() error {
if opt.Extensions == "" {
return fmt.Errorf("invalid extension string provided")
}
exts := strings.Split(opt.Extensions, ",")
for _, e := range exts {
e = strings.TrimSpace(e)
// remove leading . from extensions
opt.ExtensionsParsed.Add(strings.TrimPrefix(e, "."))
}
return nil
}
// ParseStatusCodes parses the status codes provided as a comma seperated list
func (opt *Options) parseStatusCodes() error {
if opt.StatusCodes == "" {
return fmt.Errorf("invalid status code string provided")
}
for _, c := range strings.Split(opt.StatusCodes, ",") {
c = strings.TrimSpace(c)
i, err := strconv.Atoi(c)
if err != nil {
return fmt.Errorf("invalid status code given: %s", c)
}
opt.StatusCodesParsed.Add(i)
}
return nil
}
func (opt *Options) validateDirMode() error {
// bail out if we are not in dir mode
if opt.Mode != ModeDir {
return nil
}
if !strings.HasPrefix(opt.URL, "http") {
// check to see if a port was specified
re := regexp.MustCompile(`^[^/]+:(\d+)`)
match := re.FindStringSubmatch(opt.URL)
if len(match) < 2 {
// no port, default to http on 80
opt.URL = fmt.Sprintf("http://%s", opt.URL)
} else {
port, err := strconv.Atoi(match[1])
if err != nil || (port != 80 && port != 443) {
return fmt.Errorf("url scheme not specified")
} else if port == 80 {
opt.URL = fmt.Sprintf("http://%s", opt.URL)
} else {
opt.URL = fmt.Sprintf("https://%s", opt.URL)
}
}
}
if opt.Username != "" && opt.Password == "" {
return fmt.Errorf("username was provided but password is missing")
}
return nil
}