Merge branch 'dev' into feat-3072-init-adaptive-speed

dev
mzack 2024-04-09 15:19:51 +02:00
commit 7e363984b2
35 changed files with 1797 additions and 631 deletions

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"log"
"os"
"reflect"
"regexp"
"strings"
@ -33,6 +34,12 @@ func main() {
// Generate jsonschema
r := &jsonschema.Reflector{}
r.Namer = func(r reflect.Type) string {
if r.Kind() == reflect.Slice {
return ""
}
return r.String()
}
jsonschemaData := r.Reflect(&templates.Template{})
var buf bytes.Buffer

View File

@ -231,7 +231,7 @@ func logErrMsg(path string, err error, debug bool, errFile *os.File) string {
return msg
}
// enhanceTemplateData enhances template data using templateman
// enhanceTemplate enhances template data using templateman
// ref: https://github.com/projectdiscovery/templateman/blob/main/templateman-rest-api/README.md#enhance-api
func enhanceTemplate(data string) (string, bool, error) {
resp, err := retryablehttp.DefaultClient().Post(fmt.Sprintf("%s/enhance", tmBaseUrl), "application/x-yaml", strings.NewReader(data))

8
go.mod
View File

@ -20,12 +20,12 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1
github.com/projectdiscovery/clistats v0.0.20
github.com/projectdiscovery/fastdialer v0.0.65
github.com/projectdiscovery/fastdialer v0.0.66
github.com/projectdiscovery/hmap v0.0.41
github.com/projectdiscovery/interactsh v1.1.9
github.com/projectdiscovery/rawhttp v0.1.41
github.com/projectdiscovery/rawhttp v0.1.44
github.com/projectdiscovery/retryabledns v1.0.58
github.com/projectdiscovery/retryablehttp-go v1.0.54
github.com/projectdiscovery/retryablehttp-go v1.0.55
github.com/projectdiscovery/yamldoc-go v1.0.4
github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.5.0
@ -78,7 +78,7 @@ require (
github.com/mholt/archiver v3.1.1+incompatible
github.com/ory/dockertest/v3 v3.10.0
github.com/praetorian-inc/fingerprintx v1.1.9
github.com/projectdiscovery/dsl v0.0.50
github.com/projectdiscovery/dsl v0.0.51
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
github.com/projectdiscovery/goflags v0.1.46

16
go.sum
View File

@ -832,10 +832,10 @@ github.com/projectdiscovery/cdncheck v1.0.9 h1:BS15gzj9gb5AVSKqTDzPamfSgStu7nJQO
github.com/projectdiscovery/cdncheck v1.0.9/go.mod h1:18SSl1w7rMj53CGeRIZTbDoa286a6xZIxGbaiEo4Fxs=
github.com/projectdiscovery/clistats v0.0.20 h1:5jO5SLiRJ7f0nDV0ndBNmBeesbROouPooH+DGMgoWq4=
github.com/projectdiscovery/clistats v0.0.20/go.mod h1:GJ2av0KnOvK0AISQnP8hyDclYIji1LVkx2l0pwnzAu4=
github.com/projectdiscovery/dsl v0.0.50 h1:4SuAwTS9l6o1tqlIC/79+EcUwTM6CjaU7MpY/nDlFaM=
github.com/projectdiscovery/dsl v0.0.50/go.mod h1:6g740l4tH4d2j9UYtIchtxudb0Dphkq4o+VatpR4M6g=
github.com/projectdiscovery/fastdialer v0.0.65 h1:msvKVJyILtP04CXSgSEWv4rUVsk0CCd3xhauo+H82IU=
github.com/projectdiscovery/fastdialer v0.0.65/go.mod h1:wIE10NL7oa/zBCJfr1xAduv3q73aeuGbhfZ1Z8o4NUo=
github.com/projectdiscovery/dsl v0.0.51 h1:7OQPumOrrUCFnCA7Y0nchhPvRo3IJGMIJ2Oy4DVTQsc=
github.com/projectdiscovery/dsl v0.0.51/go.mod h1:GYhusn+T9EL7t+iJ8zN/GXlp8ohLGU+Yv/nevAPlJZg=
github.com/projectdiscovery/fastdialer v0.0.66 h1:DRpmok9TArLyQKaSjRWSzikt2N2Qyzx/z0BmTmDyJvI=
github.com/projectdiscovery/fastdialer v0.0.66/go.mod h1:7uPrwFsIBhtUBkXd72K4VSo9lvcwqOzOGXIZ9UZXFYw=
github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw=
github.com/projectdiscovery/freeport v0.0.5 h1:jnd3Oqsl4S8n0KuFkE5Hm8WGDP24ITBvmyw5pFTHS8Q=
@ -868,14 +868,14 @@ github.com/projectdiscovery/networkpolicy v0.0.8 h1:XvfBaBwSDNTesSfNQP9VLk3HX9I7
github.com/projectdiscovery/networkpolicy v0.0.8/go.mod h1:xnjNqhemxUPxU+UD5Jgsc3+K8IVmcqT1SJeo6UzMtkI=
github.com/projectdiscovery/ratelimit v0.0.35 h1:epEzFATOcXZ4tssV4Hax5Op9lrbUnQMEGMV5PoUpTKc=
github.com/projectdiscovery/ratelimit v0.0.35/go.mod h1:mPqa8UpV5I7eAN5/ZcsjLiXMhjtVvZRrHtpBRsTPuyA=
github.com/projectdiscovery/rawhttp v0.1.41 h1:0n6CohOf0Aq7dsXv+ozznhlYr4ANDKLwvPmdzTet3qU=
github.com/projectdiscovery/rawhttp v0.1.41/go.mod h1:TyVfCwNbAsQSwrMOKu8o1g80AO3t1OnlJx+flgSV/CQ=
github.com/projectdiscovery/rawhttp v0.1.44 h1:mkXTTUR65TTNisQGpLo5y5PRYRgNwZLW15KZNhNpsO8=
github.com/projectdiscovery/rawhttp v0.1.44/go.mod h1:jaldbYYP0QihgQKk6Ar9ym9NPLAz5QkXp5TPET0sjYM=
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gBVSorSzvmm0bFa7gDV4QNSOWPL/fgZ4kTXBxk=
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
github.com/projectdiscovery/retryabledns v1.0.58 h1:ut1FSB9+GZ6zQIlKJFLqIz2RZs81EmkbsHTuIrWfYLE=
github.com/projectdiscovery/retryabledns v1.0.58/go.mod h1:RobmKoNBgngAVE4H9REQtaLP1pa4TCyypHy1MWHT1mY=
github.com/projectdiscovery/retryablehttp-go v1.0.54 h1:lUmQA3obq3Ya3xU1vouKf+hVjbLFKzJCK6FcNKPZ8vQ=
github.com/projectdiscovery/retryablehttp-go v1.0.54/go.mod h1:J+pg00bYLEgWOZJISi16icHUDbsnkjnA1PmSa2kSMYs=
github.com/projectdiscovery/retryablehttp-go v1.0.55 h1:ADgugnl9jKkNXn5m/Zd8TGPq1P7GplYlqUNKm/qTmls=
github.com/projectdiscovery/retryablehttp-go v1.0.55/go.mod h1:Kpvh4ruFPOEPYaYxgbFmlvBJr4lJKqpcbGvx1j0r/Ng=
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=

View File

@ -21,7 +21,7 @@ type AuthLazyFetchOptions struct {
OnError func(error)
}
// GetAuthTemlStore create new loader for loading auth templates
// GetAuthTmplStore create new loader for loading auth templates
func GetAuthTmplStore(opts types.Options, catalog catalog.Catalog, execOpts protocols.ExecutorOptions) (*loader.Store, error) {
tmpls := []string{}
for _, file := range opts.SecretsFile {

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ const (
CLIConfigFileName = "config.yaml"
ReportingConfigFilename = "reporting-config.yaml"
// Version is the current version of nuclei
Version = `v3.2.3`
Version = `v3.2.4`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"

View File

@ -94,20 +94,35 @@ func (f *Form) Encode(data KV) (string, error) {
}
}
}
if maxIndex >= 0 { // Ensure the slice is only created if maxIndex is valid
data := make([]string, maxIndex+1) // Ensure the slice is large enough
for key, value := range v {
matches := reNormalized.FindStringSubmatch(key)
if len(matches) == 2 {
dataIdx, _ := strconv.Atoi(matches[1]) // Error already checked above
dataIdx, err := strconv.Atoi(matches[1]) // Error already checked above
if err != nil {
gologger.Verbose().Msgf("error converting data index to integer: %v", err)
continue
}
// Validate dataIdx to avoid index out of range errors
if dataIdx > 0 && dataIdx <= len(data) {
data[dataIdx-1] = value // Use dataIdx-1 since slice is 0-indexed
} else {
gologger.Verbose().Msgf("data index out of range: %d", dataIdx)
}
}
}
if len(params.Get(k)) > 0 {
data[maxIndex] = fmt.Sprint(params.Get(k)) // Use maxIndex which is the last index
}
// remove existing
params.Del(k)
if len(data) > 0 {
params.Add(k, data...)
}
}
}
}
encoded := params.Encode()
return encoded, nil

View File

@ -11,6 +11,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/component"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/retryablehttp-go"
errorutil "github.com/projectdiscovery/utils/errors"
@ -100,8 +101,11 @@ func (rule *Rule) Execute(input *ExecuteRuleInput) (err error) {
baseValues := input.Values
if rule.generator == nil {
for _, component := range finalComponentList {
// get vars from variables while replacing interactsh urls
evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(baseValues, rule.options.Interactsh)
input.Values = generators.MergeMaps(evaluatedValues, baseValues, rule.options.Constants)
input.Values = generators.MergeMaps(evaluatedValues, baseValues, rule.options.Options.Vars.AsMap(), rule.options.Constants)
// evaluate all vars with interactsh
input.Values, interactURLs = rule.evaluateVarsWithInteractsh(input.Values, interactURLs)
input.InteractURLs = interactURLs
err := rule.executeRuleValues(input, component)
if err != nil {
@ -118,9 +122,12 @@ mainLoop:
if !next {
continue mainLoop
}
// get vars from variables while replacing interactsh urls
evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(values, baseValues), rule.options.Interactsh)
input.Values = generators.MergeMaps(values, evaluatedValues, baseValues, rule.options.Options.Vars.AsMap(), rule.options.Constants)
// evaluate all vars with interactsh
input.Values, interactURLs = rule.evaluateVarsWithInteractsh(input.Values, interactURLs)
input.InteractURLs = interactURLs
input.Values = generators.MergeMaps(values, evaluatedValues, baseValues, rule.options.Constants)
if err := rule.executeRuleValues(input, component); err != nil {
if err == io.EOF {
@ -134,6 +141,33 @@ mainLoop:
return nil
}
// evaluateVarsWithInteractsh evaluates the variables with Interactsh URLs and updates them accordingly.
func (rule *Rule) evaluateVarsWithInteractsh(data map[string]interface{}, interactshUrls []string) (map[string]interface{}, []string) {
// Check if Interactsh options are configured
if rule.options.Interactsh != nil {
// Iterate through the data to replace and evaluate variables with Interactsh URLs
for k, v := range data {
// Replace variables with Interactsh URLs and collect new URLs
got, oastUrls := rule.options.Interactsh.Replace(fmt.Sprint(v), interactshUrls)
// Append new OAST URLs if any
if len(oastUrls) > 0 {
interactshUrls = append(interactshUrls, oastUrls...)
}
// Evaluate the replaced data
evaluatedData, err := expressions.Evaluate(got, data)
if err == nil {
// Update the data if there is a change after evaluation
if evaluatedData != got {
data[k] = evaluatedData
}
}
}
}
// Return the updated data and Interactsh URLs without any error
return data, interactshUrls
}
// isInputURLValid returns true if url is valid after parsing it
func (rule *Rule) isInputURLValid(input *contextargs.Context) bool {
if input == nil || input.MetaInput == nil || input.MetaInput.Input == "" {

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/invopop/jsonschema"
mapsutil "github.com/projectdiscovery/utils/maps"
"gopkg.in/yaml.v2"
)
@ -29,6 +30,44 @@ type SliceOrMapSlice struct {
KV *mapsutil.OrderedMap[string, string]
}
func (v SliceOrMapSlice) JSONSchemaExtend(schema *jsonschema.Schema) *jsonschema.Schema {
schema = &jsonschema.Schema{
Title: schema.Title,
Description: schema.Description,
Type: "array",
Items: &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
{
Type: "string",
},
{
Type: "object",
},
},
},
}
return schema
}
func (v SliceOrMapSlice) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Title: "Payloads of Fuzz Rule",
Description: "Payloads to perform fuzzing substitutions with.",
Type: "array",
Items: &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
{
Type: "string",
},
{
Type: "object",
},
},
},
}
return gotType
}
// UnmarshalJSON implements json.Unmarshaler interface.
func (v *SliceOrMapSlice) UnmarshalJSON(data []byte) error {
// try to unmashal as a string and fallback to map

View File

@ -200,9 +200,9 @@ export interface AuthorizationDataEntry {
*/
export interface BitString {
Bytes?: Uint8Array,
BitLength?: number,
Bytes?: Uint8Array,
}
@ -212,9 +212,9 @@ export interface BitString {
*/
export interface BitString {
Bytes?: Uint8Array,
BitLength?: number,
Bytes?: Uint8Array,
}
@ -236,17 +236,15 @@ export interface Config {
*/
export interface EncTicketPart {
RenewTill?: Date,
CRealm?: string,
AuthTime?: Date,
StartTime?: Date,
EndTime?: Date,
Transited?: TransitedEncoding,
RenewTill?: Date,
CRealm?: string,
CAddr?: HostAddress,
@ -257,6 +255,8 @@ export interface EncTicketPart {
Key?: EncryptionKey,
CName?: PrincipalName,
Transited?: TransitedEncoding,
}
@ -266,11 +266,11 @@ export interface EncTicketPart {
*/
export interface EncryptedData {
KVNO?: number,
Cipher?: Uint8Array,
EType?: number,
KVNO?: number,
}
@ -318,15 +318,41 @@ export interface HostAddress {
*/
export interface LibDefaults {
NoAddresses?: boolean,
RealmTryDomains?: number,
DNSLookupKDC?: boolean,
DefaultRealm?: string,
SafeChecksumType?: number,
VerifyAPReqNofail?: boolean,
AllowWeakCrypto?: boolean,
DefaultTGSEnctypes?: string[],
DefaultTktEnctypeIDs?: number[],
IgnoreAcceptorHostname?: boolean,
K5LoginAuthoritative?: boolean,
PermittedEnctypes?: string[],
/**
* time in nanoseconds
*/
Clockskew?: number,
KDCTimeSync?: number,
DNSCanonicalizeHostname?: boolean,
SafeChecksumType?: number,
Proxiable?: boolean,
RDNS?: boolean,
/**
* time in nanoseconds
@ -334,51 +360,31 @@ export interface LibDefaults {
TicketLifetime?: number,
Forwardable?: boolean,
K5LoginAuthoritative?: boolean,
AllowWeakCrypto?: boolean,
DefaultClientKeytabName?: string,
DefaultTktEnctypes?: string[],
ExtraAddresses?: Uint8Array,
K5LoginDirectory?: string,
PreferredPreauthTypes?: number[],
RDNS?: boolean,
DefaultKeytabName?: string,
DefaultRealm?: string,
DefaultTGSEnctypeIDs?: number[],
DNSCanonicalizeHostname?: boolean,
PermittedEnctypes?: string[],
VerifyAPReqNofail?: boolean,
DNSLookupRealm?: boolean,
PermittedEnctypeIDs?: number[],
UDPPreferenceLimit?: number,
Canonicalize?: boolean,
DefaultTGSEnctypeIDs?: number[],
DefaultTktEnctypes?: string[],
CCacheType?: number,
DefaultTGSEnctypes?: string[],
DNSLookupRealm?: boolean,
Proxiable?: boolean,
ExtraAddresses?: Uint8Array,
DNSLookupKDC?: boolean,
PreferredPreauthTypes?: number[],
RealmTryDomains?: number,
Canonicalize?: boolean,
Forwardable?: boolean,
K5LoginDirectory?: string,
KDCTimeSync?: number,
/**
* time in nanoseconds
@ -386,13 +392,7 @@ export interface LibDefaults {
RenewLifetime?: number,
DefaultTktEnctypeIDs?: number[],
IgnoreAcceptorHostname?: boolean,
NoAddresses?: boolean,
PermittedEnctypeIDs?: number[],
DefaultKeytabName?: string,
KDCDefaultOptions?: BitString,
}
@ -404,9 +404,9 @@ export interface LibDefaults {
*/
export interface PrincipalName {
NameType?: number,
NameString?: string[],
NameType?: number,
}
@ -416,8 +416,6 @@ export interface PrincipalName {
*/
export interface Realm {
Realm?: string,
AdminServer?: string[],
DefaultDomain?: string,
@ -427,6 +425,8 @@ export interface Realm {
KPasswdServer?: string[],
MasterKDC?: string[],
Realm?: string,
}
@ -450,10 +450,10 @@ export interface TGS {
*/
export interface Ticket {
Realm?: string,
TktVNO?: number,
Realm?: string,
SName?: PrincipalName,
EncPart?: EncryptedData,

View File

@ -358,6 +358,22 @@ export class Client {
}
/**
* GetADUserAsRepRoastable returns all AD users that are AsRepRoastable
* using FilterIsPerson, and FilterDontRequirePreauth filter query
* @example
* ```javascript
* const ldap = require('nuclei/ldap');
* const client = new ldap.Client('ldap://ldap.example.com', 'acme.com');
* const AsRepRoastable = client.GetADUserAsRepRoastable();
* log(to_json(AsRepRoastable));
* ```
*/
public GetADUserAsRepRoastable(): ADObject[] {
return [];
}
/**
* GetADDomainSID returns the SID of the AD domain
* @example

View File

@ -209,9 +209,9 @@ export interface MySQLOptions {
*/
export interface SQLResult {
Columns?: string[],
Count?: number,
Columns?: string[],
}

View File

@ -137,10 +137,6 @@ export interface NegotiationLog {
*/
export interface SMBCapabilities {
DFSSupport?: boolean,
Leasing?: boolean,
LargeMTU?: boolean,
MultiChan?: boolean,
@ -150,6 +146,10 @@ export interface SMBCapabilities {
DirLeasing?: boolean,
Encryption?: boolean,
DFSSupport?: boolean,
Leasing?: boolean,
}
@ -159,6 +159,8 @@ export interface SMBCapabilities {
*/
export interface SMBLog {
SupportV1?: boolean,
NativeOs?: string,
NTLM?: string,
@ -167,15 +169,13 @@ export interface SMBLog {
HasNTLM?: boolean,
SupportV1?: boolean,
Version?: SMBVersions,
Capabilities?: SMBCapabilities,
NegotiationLog?: NegotiationLog,
SessionSetupLog?: SessionSetupLog,
Version?: SMBVersions,
}
@ -185,13 +185,13 @@ export interface SMBLog {
*/
export interface SMBVersions {
VerString?: string,
Major?: number,
Minor?: number,
Revision?: number,
VerString?: string,
}
@ -201,10 +201,6 @@ export interface SMBVersions {
*/
export interface ServiceSMB {
SigningEnabled?: boolean,
SigningRequired?: boolean,
OSVersion?: string,
NetBIOSComputerName?: string,
@ -216,6 +212,10 @@ export interface ServiceSMB {
DNSDomainName?: string,
ForestName?: string,
SigningEnabled?: boolean,
SigningRequired?: boolean,
}
@ -225,12 +225,12 @@ export interface ServiceSMB {
*/
export interface SessionSetupLog {
NegotiateFlags?: number,
SetupFlags?: number,
TargetName?: string,
NegotiateFlags?: number,
HeaderLog?: HeaderLog,
}

View File

@ -133,9 +133,9 @@ export interface Algorithms {
HostKey?: string,
W?: DirectionAlgorithms,
R?: DirectionAlgorithms,
W?: DirectionAlgorithms,
}
@ -197,34 +197,34 @@ export interface HandshakeLog {
*/
export interface KexInitMsg {
CiphersServerClient?: string[],
MACsClientServer?: string[],
MACsServerClient?: string[],
LanguagesClientServer?: string[],
KexAlgos?: string[],
CiphersClientServer?: string[],
Reserved?: number,
CompressionClientServer?: string[],
CompressionServerClient?: string[],
LanguagesServerClient?: string[],
FirstKexFollows?: boolean,
/**
* fixed size array of length: [16]
*/
Cookie?: Uint8Array,
CiphersClientServer?: string[],
MACsClientServer?: string[],
MACsServerClient?: string[],
CompressionServerClient?: string[],
LanguagesClientServer?: string[],
FirstKexFollows?: boolean,
KexAlgos?: string[],
CiphersServerClient?: string[],
CompressionClientServer?: string[],
LanguagesServerClient?: string[],
ServerHostKeyAlgos?: string[],
}

View File

@ -253,6 +253,19 @@ func (c *Client) GetADUserKerberoastable() []ADObject {
return c.FindADObjects(JoinFilters(FilterIsPerson, FilterAccountEnabled, FilterHasServicePrincipalName))
}
// GetADUserAsRepRoastable returns all AD users that are AsRepRoastable
// using FilterIsPerson, and FilterDontRequirePreauth filter query
// @example
// ```javascript
// const ldap = require('nuclei/ldap');
// const client = new ldap.Client('ldap://ldap.example.com', 'acme.com');
// const AsRepRoastable = client.GetADUserAsRepRoastable();
// log(to_json(AsRepRoastable));
// ```
func (c *Client) GetADUserAsRepRoastable() []ADObject {
return c.FindADObjects(JoinFilters(FilterIsPerson, FilterDontRequirePreauth))
}
// GetADDomainSID returns the SID of the AD domain
// @example
// ```javascript

View File

@ -61,7 +61,7 @@ type UserAgentHolder struct {
Value UserAgent `mapping:"true"`
}
func (userAgentHolder UserAgentHolder) JSONSchemaType() *jsonschema.Schema {
func (userAgentHolder UserAgentHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "userAgent for the headless",

View File

@ -72,7 +72,7 @@ type ExtractorTypeHolder struct {
ExtractorType ExtractorType `mapping:"true"`
}
func (holder ExtractorTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder ExtractorTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type of the extractor",

View File

@ -82,7 +82,7 @@ func (t MatcherTypeHolder) String() string {
return t.MatcherType.String()
}
func (holder MatcherTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder MatcherTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type of the matcher",

View File

@ -48,25 +48,25 @@ var (
type Request struct {
// Operators for the current request go here.
operators.Operators `yaml:",inline,omitempty"`
CompiledOperators *operators.Operators `yaml:"-"`
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
// ID is the optional id of the request
ID string `yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID of the Request"`
// description: |
// Engine type
Engine []string `yaml:"engine,omitempty" jsonschema:"title=engine,description=Engine"`
Engine []string `yaml:"engine,omitempty" json:"engine,omitempty" jsonschema:"title=engine,description=Engine"`
// description: |
// PreCondition is a condition which is evaluated before sending the request.
PreCondition string `yaml:"pre-condition,omitempty" json:"pre-condition,omitempty" jsonschema:"title=pre-condition for the request,description=PreCondition is a condition which is evaluated before sending the request"`
// description: |
// Engine Arguments
Args []string `yaml:"args,omitempty" jsonschema:"title=args,description=Args"`
Args []string `yaml:"args,omitempty" json:"args,omitempty" jsonschema:"title=args,description=Args"`
// description: |
// Pattern preferred for file name
Pattern string `yaml:"pattern,omitempty" jsonschema:"title=pattern,description=Pattern"`
Pattern string `yaml:"pattern,omitempty" json:"pattern,omitempty" jsonschema:"title=pattern,description=Pattern"`
// description: |
// Source File/Snippet
Source string `yaml:"source,omitempty" jsonschema:"title=source file/snippet,description=Source snippet"`
Source string `yaml:"source,omitempty" json:"source,omitempty" jsonschema:"title=source file/snippet,description=Source snippet"`
options *protocols.ExecutorOptions `yaml:"-" json:"-"`
preConditionCompiled *goja.Program `yaml:"-" json:"-"`

View File

@ -61,7 +61,7 @@ type AttackTypeHolder struct {
Value AttackType `mapping:"true"`
}
func (holder AttackTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder AttackTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type of the attack",

View File

@ -132,6 +132,9 @@ func Init(options *types.Options) error {
opts.WithDialerHistory = true
opts.SNIName = options.SNI
// this instance is used in javascript protocol libraries and
// dial history is required to get dialed ip of a host
opts.WithDialerHistory = true
// fastdialer now by default fallbacks to ztls when there are tls related errors
dialer, err := fastdialer.NewDialer(opts)

View File

@ -21,7 +21,7 @@ type Variable struct {
utils.InsertionOrderedStringMap `yaml:"-" json:"-"`
}
func (variables Variable) JSONSchemaType() *jsonschema.Schema {
func (variables Variable) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "object",
Title: "variables for the request",

View File

@ -60,7 +60,7 @@ type Request struct {
// examples:
// - name: Use a retry of 100 to 150 generally
// value: 100
TraceMaxRecursion int `yaml:"trace-max-recursion,omitempty" jsonschema:"title=trace-max-recursion level for dns request,description=TraceMaxRecursion is the number of max recursion allowed for trace operations"`
TraceMaxRecursion int `yaml:"trace-max-recursion,omitempty" json:"trace-max-recursion,omitempty" jsonschema:"title=trace-max-recursion level for dns request,description=TraceMaxRecursion is the number of max recursion allowed for trace operations"`
// description: |
// Attack is the type of payload combinations to perform.
@ -83,7 +83,7 @@ type Request struct {
Threads int `yaml:"threads,omitempty" json:"threads,omitempty" jsonschema:"title=threads for sending requests,description=Threads specifies number of threads to use sending requests. This enables Connection Pooling"`
generator *generators.PayloadGenerator
CompiledOperators *operators.Operators `yaml:"-"`
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
dnsClient *retryabledns.Client
options *protocols.ExecutorOptions

View File

@ -92,7 +92,7 @@ func (holder DNSRequestTypeHolder) String() string {
return holder.DNSRequestType.String()
}
func (holder DNSRequestTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder DNSRequestTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type of DNS request to make",

View File

@ -1,6 +1,10 @@
package engine
import "strings"
import (
"strings"
"github.com/invopop/jsonschema"
)
// Action is an action taken by the browser to reach a navigation
//
@ -29,6 +33,29 @@ type Action struct {
ActionType ActionTypeHolder `yaml:"action" json:"action" jsonschema:"title=action to perform,description=Type of actions to perform,enum=navigate,enum=script,enum=click,enum=rightclick,enum=text,enum=screenshot,enum=time,enum=select,enum=files,enum=waitload,enum=getresource,enum=extract,enum=setmethod,enum=addheader,enum=setheader,enum=deleteheader,enum=setbody,enum=waitevent,enum=keyboard,enum=debug,enum=sleep"`
}
func (a Action) JSONSchemaExtend(schema *jsonschema.Schema) {
argsSchema, ok := schema.Properties.Get("args")
if !ok {
return
}
argsSchema.PatternProperties = map[string]*jsonschema.Schema{
".*": {
OneOf: []*jsonschema.Schema{
{
Type: "string",
},
{
Type: "integer",
},
{
Type: "boolean",
},
},
},
}
argsSchema.Ref = ""
}
// String returns the string representation of an action
func (a *Action) String() string {
builder := &strings.Builder{}

View File

@ -171,7 +171,7 @@ type ActionTypeHolder struct {
func (holder ActionTypeHolder) String() string {
return holder.ActionType.String()
}
func (holder ActionTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder ActionTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "action to perform",

View File

@ -5,9 +5,11 @@ import (
"fmt"
"strings"
"github.com/invopop/jsonschema"
json "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"
@ -219,6 +221,29 @@ type Request struct {
fuzzPreConditionOperator matchers.ConditionType `yaml:"-" json:"-"`
}
func (e Request) JSONSchemaExtend(schema *jsonschema.Schema) {
headersSchema, ok := schema.Properties.Get("headers")
if !ok {
return
}
headersSchema.PatternProperties = map[string]*jsonschema.Schema{
".*": {
OneOf: []*jsonschema.Schema{
{
Type: "string",
},
{
Type: "integer",
},
{
Type: "boolean",
},
},
},
}
headersSchema.Ref = ""
}
// Options returns executer options for http request
func (r *Request) Options() *protocols.ExecutorOptions {
return r.options
@ -411,13 +436,35 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}
}
if len(request.Payloads) > 0 {
// Due to a known issue (https://github.com/projectdiscovery/nuclei/issues/5015),
// dynamic extractors cannot be used with payloads. To address this,
// execution is handled by the standard engine without concurrency,
// achieved by setting the thread count to 0.
// this limitation will be removed once we have a better way to handle dynamic extractors with payloads
hasMultipleRequests := false
if len(request.Raw)+len(request.Path) > 1 {
hasMultipleRequests = true
}
// look for dynamic extractor ( internal: true with named extractor)
hasNamedInternalExtractor := false
for _, extractor := range request.Extractors {
if extractor.Internal && extractor.Name != "" {
hasNamedInternalExtractor = true
break
}
}
if hasNamedInternalExtractor && hasMultipleRequests {
gologger.Warning().Label(options.TemplateID).Msgf("Setting thread count to 0 because dynamic extractors are not supported with payloads yet")
request.Threads = 0
} else {
// specifically for http requests high concurrency and and threads will lead to memory exausthion, hence reduce the maximum parallelism
if protocolstate.IsLowOnMemory() {
request.Threads = protocolstate.GuardThreadsOrDefault(request.Threads)
}
// if we have payloads, adjust threads if none specified
request.Threads = options.GetThreadsForNPayloadRequests(request.Requests(), request.Threads)
}
}
return nil
}

View File

@ -89,7 +89,7 @@ func (holder HTTPMethodTypeHolder) String() string {
return holder.MethodType.String()
}
func (holder HTTPMethodTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder HTTPMethodTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "method is the HTTP request method",

View File

@ -51,7 +51,7 @@ type SignatureTypeHolder struct {
Value SignatureType
}
func (holder SignatureTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder SignatureTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type of the signature",

View File

@ -27,11 +27,13 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
errorutil "github.com/projectdiscovery/utils/errors"
iputil "github.com/projectdiscovery/utils/ip"
syncutil "github.com/projectdiscovery/utils/sync"
urlutil "github.com/projectdiscovery/utils/url"
)
@ -530,6 +532,46 @@ func (request *Request) executeRequestWithPayloads(hostPort string, input *conte
data["stop-at-first-match"] = true
}
// add ip address to data
if input.MetaInput.CustomIP != "" {
data["ip"] = input.MetaInput.CustomIP
} else {
// context: https://github.com/projectdiscovery/nuclei/issues/5021
hostname := input.MetaInput.Input
if strings.Contains(hostname, ":") {
host, _, err := net.SplitHostPort(hostname)
if err == nil {
hostname = host
} else {
// naive way
if !strings.Contains(hostname, "]") {
hostname = hostname[:strings.LastIndex(hostname, ":")]
}
}
}
data["ip"] = protocolstate.Dialer.GetDialedIP(hostname)
// if input itself was an ip, use it
if iputil.IsIP(hostname) {
data["ip"] = hostname
}
// if ip is not found,this is because ssh and other protocols do not use fastdialer
// although its not perfect due to its use case dial and get ip
dnsData, err := protocolstate.Dialer.GetDNSData(hostname)
if err == nil {
for _, v := range dnsData.A {
data["ip"] = v
break
}
if data["ip"] == "" {
for _, v := range dnsData.AAAA {
data["ip"] = v
break
}
}
}
}
// add and get values from templatectx
request.options.AddTemplateVars(input.MetaInput, request.Type(), request.GetID(), data)
data = generators.MergeMaps(data, request.options.GetTemplateCtx(input.MetaInput).GetAll())

View File

@ -61,7 +61,7 @@ type Request struct {
// description: |
// Port is the port to send network requests to. this acts as default port but is overriden if target/input contains
// non-http(s) ports like 80,8080,8081 etc
Port string `yaml:"port,omitempty" json:"port,omitempty" jsonschema:"title=port to send requests to,description=Port to send network requests to"`
Port string `yaml:"port,omitempty" json:"port,omitempty" jsonschema:"title=port to send requests to,description=Port to send network requests to,oneof_type=string;integer"`
// description: |
// ExcludePorts is the list of ports to exclude from being scanned . It is intended to be used with `Port` field and contains a list of ports which are ignored/skipped
@ -91,7 +91,7 @@ type Request struct {
// Operators for the current request go here.
operators.Operators `yaml:",inline,omitempty"`
CompiledOperators *operators.Operators `yaml:"-"`
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
generator *generators.PayloadGenerator
// cache any variables that may be needed for operation.
@ -128,7 +128,7 @@ type Input struct {
// examples:
// - value: "\"TEST\""
// - value: "\"hex_decode('50494e47')\""
Data string `yaml:"data,omitempty" json:"data,omitempty" jsonschema:"title=data to send as input,description=Data is the data to send as the input"`
Data string `yaml:"data,omitempty" json:"data,omitempty" jsonschema:"title=data to send as input,description=Data is the data to send as the input,oneof_type=string;integer"`
// description: |
// Type is the type of input specified in `data` field.
//

View File

@ -66,7 +66,7 @@ func (holder NetworkInputTypeHolder) String() string {
return holder.NetworkInputType.String()
}
func (holder NetworkInputTypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder NetworkInputTypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type is the type of input data",

View File

@ -282,6 +282,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
} else {
data["ip"] = request.dialer.GetDialedIP(hostname)
}
data["Port"] = port
data["template-path"] = requestOptions.TemplatePath
data["template-id"] = requestOptions.TemplateID
data["template-info"] = requestOptions.TemplateInfo
@ -405,6 +406,9 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
if fields.Port == "80" {
fields.Port = "443"
}
if types.ToString(wrapped.InternalEvent["Port"]) != "" {
fields.Port = types.ToString(wrapped.InternalEvent["Port"])
}
data := &output.ResultEvent{
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),

View File

@ -92,7 +92,7 @@ type TypeHolder struct {
ProtocolType ProtocolType `mapping:"true"`
}
func (holder TypeHolder) JSONSchemaType() *jsonschema.Schema {
func (holder TypeHolder) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Type: "string",
Title: "type of the protocol",