mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 19:35:27 +00:00
add support for multiple ports in network template (#4401)
* add support for multiple ports in network template * backwords compatibility for templates without 'port' field * fix nil panic in compile
This commit is contained in:
parent
8d7bbdd978
commit
a09b8afd0f
@ -1,6 +1,7 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
|
||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
|
||||||
|
errorutil "github.com/projectdiscovery/utils/errors"
|
||||||
fileutil "github.com/projectdiscovery/utils/file"
|
fileutil "github.com/projectdiscovery/utils/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,6 +76,10 @@ type Request struct {
|
|||||||
// SelfContained specifies if the request is self-contained.
|
// SelfContained specifies if the request is self-contained.
|
||||||
SelfContained bool `yaml:"-" json:"-"`
|
SelfContained bool `yaml:"-" json:"-"`
|
||||||
|
|
||||||
|
// description: |
|
||||||
|
// ports is post processed list of ports to scan (obtained from Port)
|
||||||
|
ports []string `yaml:"-" json:"-"`
|
||||||
|
|
||||||
// Operators for the current request go here.
|
// Operators for the current request go here.
|
||||||
operators.Operators `yaml:",inline,omitempty"`
|
operators.Operators `yaml:",inline,omitempty"`
|
||||||
CompiledOperators *operators.Operators `yaml:"-"`
|
CompiledOperators *operators.Operators `yaml:"-"`
|
||||||
@ -169,6 +175,23 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse ports and validate
|
||||||
|
if request.Port != "" {
|
||||||
|
for _, port := range strings.Split(request.Port, ",") {
|
||||||
|
if port == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
portInt, err := strconv.Atoi(port)
|
||||||
|
if err != nil {
|
||||||
|
return errorutil.NewWithErr(err).Msgf("could not parse port %v from '%s'", port, request.Port)
|
||||||
|
}
|
||||||
|
if portInt < 1 || portInt > 65535 {
|
||||||
|
return errorutil.NewWithTag(request.TemplateID, "port %v is not in valid range", portInt)
|
||||||
|
}
|
||||||
|
request.ports = append(request.ports, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve payload paths from vars if they exists
|
// Resolve payload paths from vars if they exists
|
||||||
for name, payload := range request.options.Options.Vars.AsMap() {
|
for name, payload := range request.options.Options.Vars.AsMap() {
|
||||||
payloadStr, ok := payload.(string)
|
payloadStr, ok := payload.(string)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/multierr"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
"github.com/projectdiscovery/gologger"
|
"github.com/projectdiscovery/gologger"
|
||||||
@ -22,6 +23,7 @@ import (
|
|||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
|
||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
|
||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
|
"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/replacer"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
|
||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
|
||||||
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
|
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
|
||||||
@ -44,19 +46,83 @@ func (request *Request) Type() templateTypes.ProtocolType {
|
|||||||
return templateTypes.NetworkProtocol
|
return templateTypes.NetworkProtocol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getOpenPorts returns all open ports from list of ports provided in template
|
||||||
|
// if only 1 port is provided, no need to check if port is open or not
|
||||||
|
func (request *Request) getOpenPorts(target *contextargs.Context) ([]string, error) {
|
||||||
|
if len(request.ports) == 1 {
|
||||||
|
// no need to check if port is open or not
|
||||||
|
return request.ports, nil
|
||||||
|
}
|
||||||
|
errs := []error{}
|
||||||
|
// if more than 1 port is provided, check if port is open or not
|
||||||
|
openPorts := make([]string, 0)
|
||||||
|
for _, port := range request.ports {
|
||||||
|
cloned := target.Clone()
|
||||||
|
if err := cloned.UseNetworkPort(port, request.ExcludePorts); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr, err := getAddress(cloned.MetaInput.Input)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn, err := protocolstate.Dialer.Dial(context.TODO(), "tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_ = conn.Close()
|
||||||
|
openPorts = append(openPorts, port)
|
||||||
|
}
|
||||||
|
if len(openPorts) == 0 {
|
||||||
|
return nil, multierr.Combine(errs...)
|
||||||
|
}
|
||||||
|
return openPorts, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
||||||
func (request *Request) ExecuteWithResults(target *contextargs.Context, metadata, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
func (request *Request) ExecuteWithResults(target *contextargs.Context, metadata, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
||||||
|
visitedAddresses := make(mapsutil.Map[string, struct{}])
|
||||||
|
|
||||||
|
if request.Port == "" {
|
||||||
|
// backwords compatibility or for other use cases
|
||||||
|
// where port is not provided in template
|
||||||
|
if err := request.executeOnTarget(target, visitedAddresses, metadata, previous, callback); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get open ports from list of ports provided in template
|
||||||
|
ports, err := request.getOpenPorts(target)
|
||||||
|
if len(ports) == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// TODO: replace this after scan context is implemented
|
||||||
|
gologger.Verbose().Msgf("[%v] got errors while checking open ports: %s\n", request.options.TemplateID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, port := range ports {
|
||||||
|
input := target.Clone()
|
||||||
|
// use network port updates input with new port requested in template file
|
||||||
|
// and it is ignored if input port is not standard http(s) ports like 80,8080,8081 etc
|
||||||
|
// idea is to reduce redundant dials to http ports
|
||||||
|
if err := input.UseNetworkPort(port, request.ExcludePorts); err != nil {
|
||||||
|
gologger.Debug().Msgf("Could not network port from constants: %s\n", err)
|
||||||
|
}
|
||||||
|
if err := request.executeOnTarget(input, visitedAddresses, metadata, previous, callback); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (request *Request) executeOnTarget(input *contextargs.Context, visited mapsutil.Map[string, struct{}], metadata, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
||||||
var address string
|
var address string
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
input := target.Clone()
|
|
||||||
// use network port updates input with new port requested in template file
|
|
||||||
// and it is ignored if input port is not standard http(s) ports like 80,8080,8081 etc
|
|
||||||
// idea is to reduce redundant dials to http ports
|
|
||||||
if err := input.UseNetworkPort(request.Port, request.ExcludePorts); err != nil {
|
|
||||||
gologger.Debug().Msgf("Could not network port from constants: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if request.SelfContained {
|
if request.SelfContained {
|
||||||
address = ""
|
address = ""
|
||||||
} else {
|
} else {
|
||||||
@ -73,15 +139,13 @@ func (request *Request) ExecuteWithResults(target *contextargs.Context, metadata
|
|||||||
variablesMap := request.options.Variables.Evaluate(variables)
|
variablesMap := request.options.Variables.Evaluate(variables)
|
||||||
variables = generators.MergeMaps(variablesMap, variables, request.options.Constants)
|
variables = generators.MergeMaps(variablesMap, variables, request.options.Constants)
|
||||||
|
|
||||||
visitedAddresses := make(mapsutil.Map[string, struct{}])
|
|
||||||
|
|
||||||
for _, kv := range request.addresses {
|
for _, kv := range request.addresses {
|
||||||
actualAddress := replacer.Replace(kv.address, variables)
|
actualAddress := replacer.Replace(kv.address, variables)
|
||||||
|
|
||||||
if visitedAddresses.Has(actualAddress) && !request.options.Options.DisableClustering {
|
if visited.Has(actualAddress) && !request.options.Options.DisableClustering {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
visitedAddresses.Set(actualAddress, struct{}{})
|
visited.Set(actualAddress, struct{}{})
|
||||||
|
|
||||||
if err := request.executeAddress(variables, actualAddress, address, input, kv.tls, previous, callback); err != nil {
|
if err := request.executeAddress(variables, actualAddress, address, input, kv.tls, previous, callback); err != nil {
|
||||||
outputEvent := request.responseToDSLMap("", "", "", address, "")
|
outputEvent := request.responseToDSLMap("", "", "", address, "")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user