Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/file/file.go
2070 views
1
package file
2
3
import (
4
"path/filepath"
5
"strings"
6
7
"github.com/docker/go-units"
8
"github.com/h2non/filetype"
9
"github.com/pkg/errors"
10
11
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
13
)
14
15
var (
16
defaultMaxReadSize, _ = units.FromHumanSize("1Gb")
17
chunkSize, _ = units.FromHumanSize("100Mb")
18
)
19
20
// Request contains a File matching mechanism for local disk operations.
21
type Request struct {
22
// Operators for the current request go here.
23
operators.Operators `yaml:",inline"`
24
// description: |
25
// Extensions is the list of extensions or mime types to perform matching on.
26
// examples:
27
// - value: '[]string{".txt", ".go", ".json"}'
28
Extensions []string `yaml:"extensions,omitempty" json:"extensions,omitempty" jsonschema:"title=extensions to match,description=List of extensions to perform matching on"`
29
// description: |
30
// DenyList is the list of file, directories, mime types or extensions to deny during matching.
31
//
32
// By default, it contains some non-interesting extensions that are hardcoded
33
// in nuclei.
34
// examples:
35
// - value: '[]string{".avi", ".mov", ".mp3"}'
36
DenyList []string `yaml:"denylist,omitempty" json:"denylist,omitempty" jsonschema:"title=denylist, directories and extensions to deny match,description=List of files, directories and extensions to deny during matching"`
37
38
// ID is the optional id of the request
39
ID string `yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID for the request"`
40
41
// description: |
42
// MaxSize is the maximum size of the file to run request on.
43
//
44
// By default, nuclei will process 1 GB of content and not go more than that.
45
// It can be set to much lower or higher depending on use.
46
// If set to "no" then all content will be processed
47
// examples:
48
// - value: "\"5Mb\""
49
MaxSize string `yaml:"max-size,omitempty" json:"max-size,omitempty" jsonschema:"title=max size data to run request on,description=Maximum size of the file to run request on"`
50
maxSize int64
51
52
// description: |
53
// elaborates archives
54
Archive bool `yaml:"archive,omitempty" json:"archive,omitempty" jsonschema:"title=enable archives,description=Process compressed archives without unpacking"`
55
56
// description: |
57
// enables mime types check
58
MimeType bool `yaml:"mime-type,omitempty" json:"mime-type,omitempty" jsonschema:"title=enable filtering by mime-type,description=Filter files by mime-type"`
59
60
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
61
62
// cache any variables that may be needed for operation.
63
options *protocols.ExecutorOptions
64
mimeTypesChecks []string
65
extensions map[string]struct{}
66
denyList map[string]struct{}
67
denyMimeTypesChecks []string
68
69
// description: |
70
// NoRecursive specifies whether to not do recursive checks if folders are provided.
71
NoRecursive bool `yaml:"no-recursive,omitempty" json:"no-recursive,omitempty" jsonschema:"title=do not perform recursion,description=Specifies whether to not do recursive checks if folders are provided"`
72
73
allExtensions bool
74
}
75
76
// RequestPartDefinitions contains a mapping of request part definitions and their
77
// description. Multiple definitions are separated by commas.
78
// Definitions not having a name (generated on runtime) are prefixed & suffixed by <>.
79
var RequestPartDefinitions = map[string]string{
80
"template-id": "ID of the template executed",
81
"template-info": "Info Block of the template executed",
82
"template-path": "Path of the template executed",
83
"matched": "Matched is the input which was matched upon",
84
"path": "Path is the path of file on local filesystem",
85
"type": "Type is the type of request made",
86
"raw,body,all,data": "Raw contains the raw file contents",
87
}
88
89
// defaultDenylist contains common extensions to exclude
90
var defaultDenylist = []string{".3g2", ".3gp", ".arj", ".avi", ".axd", ".bmp", ".css", ".csv", ".deb", ".dll", ".doc", ".drv", ".eot", ".exe", ".flv", ".gif", ".gifv", ".h264", ".ico", ".iso", ".jar", ".jpeg", ".jpg", ".lock", ".m4a", ".m4v", ".map", ".mkv", ".mov", ".mp3", ".mp4", ".mpeg", ".mpg", ".msi", ".ogg", ".ogm", ".ogv", ".otf", ".pdf", ".pkg", ".png", ".ppt", ".psd", ".rm", ".rpm", ".svg", ".swf", ".sys", ".tif", ".tiff", ".ttf", ".vob", ".wav", ".webm", ".wmv", ".woff", ".woff2", ".xcf", ".xls", ".xlsx"}
91
92
// defaultArchiveDenyList contains common archive extensions to exclude
93
var defaultArchiveDenyList = []string{".7z", ".apk", ".gz", ".rar", ".tar.gz", ".tar", ".zip"}
94
95
// GetID returns the unique ID of the request if any.
96
func (request *Request) GetID() string {
97
return request.ID
98
}
99
100
// Compile compiles the protocol request for further execution.
101
func (request *Request) Compile(options *protocols.ExecutorOptions) error {
102
// if there are no matchers/extractors, we trigger an error as no operation would be performed on the template
103
if request.IsEmpty() {
104
return errors.New("empty operators")
105
}
106
compiled := &request.Operators
107
compiled.ExcludeMatchers = options.ExcludeMatchers
108
compiled.TemplateID = options.TemplateID
109
if err := compiled.Compile(); err != nil {
110
return errors.Wrap(err, "could not compile operators")
111
}
112
request.CompiledOperators = compiled
113
114
// By default, use default max size if not defined
115
switch {
116
case request.MaxSize != "":
117
maxSize, err := units.FromHumanSize(request.MaxSize)
118
if err != nil {
119
return errors.Wrap(err, "could not compile operators")
120
}
121
request.maxSize = maxSize
122
case request.MaxSize == "no":
123
request.maxSize = -1
124
default:
125
request.maxSize = defaultMaxReadSize
126
}
127
128
request.options = options
129
130
request.extensions = make(map[string]struct{})
131
request.denyList = make(map[string]struct{})
132
133
for _, extension := range request.Extensions {
134
switch {
135
case extension == "all":
136
request.allExtensions = true
137
case request.MimeType && filetype.IsMIMESupported(extension):
138
continue
139
default:
140
if !strings.HasPrefix(extension, ".") {
141
extension = "." + extension
142
}
143
request.extensions[extension] = struct{}{}
144
}
145
}
146
request.mimeTypesChecks = extractMimeTypes(request.Extensions)
147
148
// process default denylist (extensions)
149
var denyList []string
150
if !request.Archive {
151
denyList = append(defaultDenylist, defaultArchiveDenyList...)
152
} else {
153
denyList = defaultDenylist
154
}
155
for _, excludeItem := range denyList {
156
if !strings.HasPrefix(excludeItem, ".") {
157
excludeItem = "." + excludeItem
158
}
159
request.denyList[excludeItem] = struct{}{}
160
}
161
for _, excludeItem := range request.DenyList {
162
request.denyList[excludeItem] = struct{}{}
163
// also add a cleaned version as the exclusion path can be dirty (eg. /a/b/c, /a/b/c/, a///b///c/../d)
164
request.denyList[filepath.Clean(excludeItem)] = struct{}{}
165
}
166
request.denyMimeTypesChecks = extractMimeTypes(request.DenyList)
167
return nil
168
}
169
170
func matchAnyMimeTypes(data []byte, mimeTypes []string) bool {
171
for _, mimeType := range mimeTypes {
172
if filetype.Is(data, mimeType) {
173
return true
174
}
175
}
176
return false
177
}
178
179
func extractMimeTypes(m []string) []string {
180
var mimeTypes []string
181
for _, mm := range m {
182
if !filetype.IsMIMESupported(mm) {
183
continue
184
}
185
mimeTypes = append(mimeTypes, mm)
186
}
187
return mimeTypes
188
}
189
190
// Requests returns the total number of requests the YAML rule will perform
191
func (request *Request) Requests() int {
192
return 0
193
}
194
195
// UpdateOptions replaces this request's options with a new copy
196
func (r *Request) UpdateOptions(opts *protocols.ExecutorOptions) {
197
r.options.ApplyNewEngineOptions(opts)
198
}
199
200