2021-01-01 09:58:28 +00:00
package file
import (
2021-12-16 10:51:06 +00:00
"path/filepath"
2021-03-05 06:44:46 +00:00
"strings"
2022-02-23 12:54:46 +00:00
"github.com/docker/go-units"
2022-03-22 11:35:11 +00:00
"github.com/h2non/filetype"
2021-01-01 09:58:28 +00:00
"github.com/pkg/errors"
2021-09-07 14:31:46 +00:00
2021-01-01 09:58:28 +00:00
"github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
)
2022-02-23 12:54:46 +00:00
var (
defaultMaxReadSize , _ = units . FromHumanSize ( "1Gb" )
chunkSize , _ = units . FromHumanSize ( "100Mb" )
)
2021-01-01 09:58:28 +00:00
// Request contains a File matching mechanism for local disk operations.
type Request struct {
2021-02-26 07:43:11 +00:00
// Operators for the current request go here.
operators . Operators ` yaml:",inline" `
2021-07-27 10:33:56 +00:00
// description: |
2022-03-22 11:35:11 +00:00
// Extensions is the list of extensions or mime types to perform matching on.
2021-07-27 10:33:56 +00:00
// examples:
// - value: '[]string{".txt", ".go", ".json"}'
2023-02-07 08:10:40 +00:00
Extensions [ ] string ` yaml:"extensions,omitempty" json:"extensions,omitempty" jsonschema:"title=extensions to match,description=List of extensions to perform matching on" `
2021-07-27 10:33:56 +00:00
// description: |
2022-03-22 11:35:11 +00:00
// DenyList is the list of file, directories, mime types or extensions to deny during matching.
2021-07-27 10:33:56 +00:00
//
// By default, it contains some non-interesting extensions that are hardcoded
// in nuclei.
// examples:
// - value: '[]string{".avi", ".mov", ".mp3"}'
2023-02-07 08:10:40 +00:00
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" `
2021-01-01 09:58:28 +00:00
2021-09-07 14:31:46 +00:00
// ID is the optional id of the request
2023-02-07 08:10:40 +00:00
ID string ` yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID for the request" `
2021-02-26 07:43:11 +00:00
2021-07-27 10:33:56 +00:00
// description: |
// MaxSize is the maximum size of the file to run request on.
//
2022-02-23 12:54:46 +00:00
// By default, nuclei will process 1 GB of content and not go more than that.
2021-07-27 10:33:56 +00:00
// It can be set to much lower or higher depending on use.
2022-02-23 12:54:46 +00:00
// If set to "no" then all content will be processed
2021-07-27 10:33:56 +00:00
// examples:
2022-03-21 10:20:28 +00:00
// - value: "\"5Mb\""
2023-02-07 08:10:40 +00:00
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" `
2022-02-23 12:54:46 +00:00
maxSize int64
2022-03-01 17:59:33 +00:00
// description: |
// elaborates archives
2023-05-15 13:45:11 +00:00
Archive bool ` yaml:"archive,omitempty" json:"archive,omitempty" jsonschema:"title=enable archives,description=Process compressed archives without unpacking" `
2022-03-01 17:59:33 +00:00
2022-03-22 13:18:01 +00:00
// description: |
// enables mime types check
2023-05-15 13:45:11 +00:00
MimeType bool ` yaml:"mime-type,omitempty" json:"mime-type,omitempty" jsonschema:"title=enable filtering by mime-type,description=Filter files by mime-type" `
2022-03-22 13:18:01 +00:00
2023-02-07 08:10:40 +00:00
CompiledOperators * operators . Operators ` yaml:"-" json:"-" `
2021-01-01 09:58:28 +00:00
// cache any variables that may be needed for operation.
2022-03-22 11:35:11 +00:00
options * protocols . ExecuterOptions
mimeTypesChecks [ ] string
extensions map [ string ] struct { }
denyList map [ string ] struct { }
denyMimeTypesChecks [ ] string
2021-02-26 07:43:11 +00:00
2021-07-27 10:33:56 +00:00
// description: |
// NoRecursive specifies whether to not do recursive checks if folders are provided.
2023-02-07 08:10:40 +00:00
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" `
2021-02-26 07:43:11 +00:00
allExtensions bool
2021-01-01 09:58:28 +00:00
}
2021-11-26 10:53:54 +00:00
// RequestPartDefinitions contains a mapping of request part definitions and their
// description. Multiple definitions are separated by commas.
// Definitions not having a name (generated on runtime) are prefixed & suffixed by <>.
var RequestPartDefinitions = map [ string ] string {
"template-id" : "ID of the template executed" ,
"template-info" : "Info Block of the template executed" ,
"template-path" : "Path of the template executed" ,
"matched" : "Matched is the input which was matched upon" ,
"path" : "Path is the path of file on local filesystem" ,
"type" : "Type is the type of request made" ,
"raw,body,all,data" : "Raw contains the raw file contents" ,
}
2022-03-01 17:59:33 +00:00
// defaultDenylist contains common extensions to exclude
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" }
// defaultArchiveDenyList contains common archive extensions to exclude
var defaultArchiveDenyList = [ ] string { ".7z" , ".apk" , ".gz" , ".rar" , ".tar.gz" , ".tar" , ".zip" }
2021-01-01 09:58:28 +00:00
2021-01-16 08:40:24 +00:00
// GetID returns the unique ID of the request if any.
2021-10-01 11:30:04 +00:00
func ( request * Request ) GetID ( ) string {
return request . ID
2021-01-16 08:40:24 +00:00
}
2021-01-01 09:58:28 +00:00
// Compile compiles the protocol request for further execution.
2021-10-01 11:30:04 +00:00
func ( request * Request ) Compile ( options * protocols . ExecuterOptions ) error {
2022-12-20 20:59:28 +00:00
// if there are no matchers/extractors, we trigger an error as no operation would be performed on the template
if request . Operators . IsEmpty ( ) {
return errors . New ( "empty operators" )
2021-01-01 09:58:28 +00:00
}
2022-12-20 20:59:28 +00:00
compiled := & request . Operators
compiled . ExcludeMatchers = options . ExcludeMatchers
compiled . TemplateID = options . TemplateID
if err := compiled . Compile ( ) ; err != nil {
return errors . Wrap ( err , "could not compile operators" )
}
request . CompiledOperators = compiled
2022-02-23 12:54:46 +00:00
// By default, use default max size if not defined
switch {
case request . MaxSize != "" :
maxSize , err := units . FromHumanSize ( request . MaxSize )
if err != nil {
return errors . Wrap ( err , "could not compile operators" )
}
request . maxSize = maxSize
case request . MaxSize == "no" :
request . maxSize = - 1
default :
request . maxSize = defaultMaxReadSize
2021-01-01 09:58:28 +00:00
}
2022-02-23 12:54:46 +00:00
2021-10-01 11:30:04 +00:00
request . options = options
2021-01-01 09:58:28 +00:00
2021-10-01 11:30:04 +00:00
request . extensions = make ( map [ string ] struct { } )
2021-12-16 10:51:06 +00:00
request . denyList = make ( map [ string ] struct { } )
2021-01-01 09:58:28 +00:00
2021-10-01 11:30:04 +00:00
for _ , extension := range request . Extensions {
2022-03-22 11:35:11 +00:00
switch {
case extension == "all" :
2021-10-01 11:30:04 +00:00
request . allExtensions = true
2022-03-22 13:18:01 +00:00
case request . MimeType && filetype . IsMIMESupported ( extension ) :
2022-03-22 11:35:11 +00:00
continue
default :
2021-03-08 13:50:40 +00:00
if ! strings . HasPrefix ( extension , "." ) {
2021-03-05 06:44:46 +00:00
extension = "." + extension
}
2021-10-01 11:30:04 +00:00
request . extensions [ extension ] = struct { } { }
2021-01-01 10:01:44 +00:00
}
2021-01-01 09:58:28 +00:00
}
2022-03-22 11:35:11 +00:00
request . mimeTypesChecks = extractMimeTypes ( request . Extensions )
2021-12-16 10:51:06 +00:00
// process default denylist (extensions)
2022-03-01 17:59:33 +00:00
var denyList [ ] string
if ! request . Archive {
denyList = append ( defaultDenylist , defaultArchiveDenyList ... )
} else {
denyList = defaultDenylist
}
for _ , excludeItem := range denyList {
2021-12-16 10:51:06 +00:00
if ! strings . HasPrefix ( excludeItem , "." ) {
excludeItem = "." + excludeItem
2021-03-05 06:44:46 +00:00
}
2021-12-16 10:51:06 +00:00
request . denyList [ excludeItem ] = struct { } { }
2021-01-01 09:58:28 +00:00
}
2021-12-16 10:51:06 +00:00
for _ , excludeItem := range request . DenyList {
request . denyList [ excludeItem ] = struct { } { }
// also add a cleaned version as the exclusion path can be dirty (eg. /a/b/c, /a/b/c/, a///b///c/../d)
request . denyList [ filepath . Clean ( excludeItem ) ] = struct { } { }
2021-01-01 09:58:28 +00:00
}
2022-03-22 11:35:11 +00:00
request . denyMimeTypesChecks = extractMimeTypes ( request . DenyList )
2021-01-01 09:58:28 +00:00
return nil
}
2022-03-22 11:35:11 +00:00
func matchAnyMimeTypes ( data [ ] byte , mimeTypes [ ] string ) bool {
for _ , mimeType := range mimeTypes {
if filetype . Is ( data , mimeType ) {
return true
}
}
return false
}
func extractMimeTypes ( m [ ] string ) [ ] string {
var mimeTypes [ ] string
for _ , mm := range m {
if ! filetype . IsMIMESupported ( mm ) {
continue
}
mimeTypes = append ( mimeTypes , mm )
}
return mimeTypes
}
2021-01-01 09:58:28 +00:00
// Requests returns the total number of requests the YAML rule will perform
2021-10-01 11:30:04 +00:00
func ( request * Request ) Requests ( ) int {
2022-02-10 10:29:05 +00:00
return 0
2021-01-01 09:58:28 +00:00
}