mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-23 17:15:25 +00:00
Improvements to interactsh integration + no fatal for interact
This commit is contained in:
parent
c19438ce84
commit
f85a421550
@ -212,9 +212,10 @@ func New(options *types.Options) (*Runner, error) {
|
|||||||
Progress: runner.progress,
|
Progress: runner.progress,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
gologger.Error().Msgf("Could not create interactsh client: %s", err)
|
||||||
|
} else {
|
||||||
|
runner.interactsh = interactshClient
|
||||||
}
|
}
|
||||||
runner.interactsh = interactshClient
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable Polling
|
// Enable Polling
|
||||||
|
|||||||
@ -23,7 +23,10 @@ type Client struct {
|
|||||||
interactsh *client.Client
|
interactsh *client.Client
|
||||||
// requests is a stored cache for interactsh-url->request-event data.
|
// requests is a stored cache for interactsh-url->request-event data.
|
||||||
requests *ccache.Cache
|
requests *ccache.Cache
|
||||||
|
// interactions is a stored cache for interactsh-interaction->interactsh-url data
|
||||||
|
interactions *ccache.Cache
|
||||||
|
|
||||||
|
options *Options
|
||||||
matched bool
|
matched bool
|
||||||
dotHostname string
|
dotHostname string
|
||||||
eviction time.Duration
|
eviction time.Duration
|
||||||
@ -31,7 +34,10 @@ type Client struct {
|
|||||||
cooldownDuration time.Duration
|
cooldownDuration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
var interactshURLMarker = "{{interactsh-url}}"
|
var (
|
||||||
|
defaultInteractionDuration = 60 * time.Second
|
||||||
|
interactshURLMarker = "{{interactsh-url}}"
|
||||||
|
)
|
||||||
|
|
||||||
// Options contains configuration options for interactsh nuclei integration.
|
// Options contains configuration options for interactsh nuclei integration.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@ -56,6 +62,8 @@ type Options struct {
|
|||||||
Progress progress.Progress
|
Progress progress.Progress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultMaxInteractionsCount = 5000
|
||||||
|
|
||||||
// New returns a new interactsh server client
|
// New returns a new interactsh server client
|
||||||
func New(options *Options) (*Client, error) {
|
func New(options *Options) (*Client, error) {
|
||||||
parsed, err := url.Parse(options.ServerURL)
|
parsed, err := url.Parse(options.ServerURL)
|
||||||
@ -74,10 +82,16 @@ func New(options *Options) (*Client, error) {
|
|||||||
configure = configure.MaxSize(options.CacheSize)
|
configure = configure.MaxSize(options.CacheSize)
|
||||||
cache := ccache.New(configure)
|
cache := ccache.New(configure)
|
||||||
|
|
||||||
|
interactionsConfig := ccache.Configure()
|
||||||
|
interactionsConfig = configure.MaxSize(defaultMaxInteractionsCount)
|
||||||
|
interactionsCache := ccache.New(interactionsConfig)
|
||||||
|
|
||||||
interactClient := &Client{
|
interactClient := &Client{
|
||||||
interactsh: interactsh,
|
interactsh: interactsh,
|
||||||
eviction: options.Eviction,
|
eviction: options.Eviction,
|
||||||
|
interactions: interactionsCache,
|
||||||
dotHostname: "." + parsed.Host,
|
dotHostname: "." + parsed.Host,
|
||||||
|
options: options,
|
||||||
requests: cache,
|
requests: cache,
|
||||||
pollDuration: options.PollDuration,
|
pollDuration: options.PollDuration,
|
||||||
cooldownDuration: options.ColldownPeriod,
|
cooldownDuration: options.ColldownPeriod,
|
||||||
@ -86,46 +100,63 @@ func New(options *Options) (*Client, error) {
|
|||||||
interactClient.interactsh.StartPolling(interactClient.pollDuration, func(interaction *server.Interaction) {
|
interactClient.interactsh.StartPolling(interactClient.pollDuration, func(interaction *server.Interaction) {
|
||||||
item := interactClient.requests.Get(interaction.UniqueID)
|
item := interactClient.requests.Get(interaction.UniqueID)
|
||||||
if item == nil {
|
if item == nil {
|
||||||
|
// If we don't have any request for this ID, add it to temporary
|
||||||
|
// lru cache so we can correlate when we get an add request.
|
||||||
|
gotItem := interactClient.interactions.Get(interaction.UniqueID)
|
||||||
|
if gotItem == nil {
|
||||||
|
interactClient.interactions.Set(interaction.UniqueID, []*server.Interaction{interaction}, defaultInteractionDuration)
|
||||||
|
} else {
|
||||||
|
if items, ok := gotItem.Value().([]*server.Interaction); ok {
|
||||||
|
items = append(items, interaction)
|
||||||
|
interactClient.interactions.Set(interaction.UniqueID, items, defaultInteractionDuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, ok := item.Value().(*RequestData)
|
request, ok := item.Value().(*RequestData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
_ = interactClient.processInteractionForRequest(interaction, request)
|
||||||
data.Event.InternalEvent["interactsh_protocol"] = interaction.Protocol
|
|
||||||
data.Event.InternalEvent["interactsh_request"] = interaction.RawRequest
|
|
||||||
data.Event.InternalEvent["interactsh_response"] = interaction.RawResponse
|
|
||||||
result, matched := data.Operators.Execute(data.Event.InternalEvent, data.MatchFunc, data.ExtractFunc)
|
|
||||||
if !matched || result == nil {
|
|
||||||
return // if we don't match, return
|
|
||||||
}
|
|
||||||
interactClient.requests.Delete(interaction.UniqueID)
|
|
||||||
|
|
||||||
if data.Event.OperatorsResult != nil {
|
|
||||||
data.Event.OperatorsResult.Merge(result)
|
|
||||||
} else {
|
|
||||||
data.Event.OperatorsResult = result
|
|
||||||
}
|
|
||||||
data.Event.Results = data.MakeResultFunc(data.Event)
|
|
||||||
for _, result := range data.Event.Results {
|
|
||||||
result.Interaction = interaction
|
|
||||||
_ = options.Output.Write(result)
|
|
||||||
if !interactClient.matched {
|
|
||||||
interactClient.matched = true
|
|
||||||
}
|
|
||||||
options.Progress.IncrementMatched()
|
|
||||||
|
|
||||||
if options.IssuesClient != nil {
|
|
||||||
if err := options.IssuesClient.CreateIssue(result); err != nil {
|
|
||||||
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
return interactClient, nil
|
return interactClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processInteractionForRequest processes an interaction for a request
|
||||||
|
func (c *Client) processInteractionForRequest(interaction *server.Interaction, data *RequestData) bool {
|
||||||
|
data.Event.InternalEvent["interactsh_protocol"] = interaction.Protocol
|
||||||
|
data.Event.InternalEvent["interactsh_request"] = interaction.RawRequest
|
||||||
|
data.Event.InternalEvent["interactsh_response"] = interaction.RawResponse
|
||||||
|
result, matched := data.Operators.Execute(data.Event.InternalEvent, data.MatchFunc, data.ExtractFunc)
|
||||||
|
if !matched || result == nil {
|
||||||
|
return false // if we don't match, return
|
||||||
|
}
|
||||||
|
c.requests.Delete(interaction.UniqueID)
|
||||||
|
|
||||||
|
if data.Event.OperatorsResult != nil {
|
||||||
|
data.Event.OperatorsResult.Merge(result)
|
||||||
|
} else {
|
||||||
|
data.Event.OperatorsResult = result
|
||||||
|
}
|
||||||
|
data.Event.Results = data.MakeResultFunc(data.Event)
|
||||||
|
|
||||||
|
for _, result := range data.Event.Results {
|
||||||
|
result.Interaction = interaction
|
||||||
|
_ = c.options.Output.Write(result)
|
||||||
|
if !c.matched {
|
||||||
|
c.matched = true
|
||||||
|
}
|
||||||
|
c.options.Progress.IncrementMatched()
|
||||||
|
|
||||||
|
if c.options.IssuesClient != nil {
|
||||||
|
if err := c.options.IssuesClient.CreateIssue(result); err != nil {
|
||||||
|
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// URL returns a new URL that can be interacted with
|
// URL returns a new URL that can be interacted with
|
||||||
func (c *Client) URL() string {
|
func (c *Client) URL() string {
|
||||||
return c.interactsh.URL()
|
return c.interactsh.URL()
|
||||||
@ -171,7 +202,28 @@ type RequestData struct {
|
|||||||
// RequestEvent is the event for a network request sent by nuclei.
|
// RequestEvent is the event for a network request sent by nuclei.
|
||||||
func (c *Client) RequestEvent(interactshURL string, data *RequestData) {
|
func (c *Client) RequestEvent(interactshURL string, data *RequestData) {
|
||||||
id := strings.TrimSuffix(interactshURL, c.dotHostname)
|
id := strings.TrimSuffix(interactshURL, c.dotHostname)
|
||||||
c.requests.Set(id, data, c.eviction)
|
|
||||||
|
interaction := c.interactions.Get(id)
|
||||||
|
if interaction != nil {
|
||||||
|
// If we have previous interactions, get them and process them.
|
||||||
|
interactions, ok := interaction.Value().([]*server.Interaction)
|
||||||
|
if !ok {
|
||||||
|
c.requests.Set(id, data, c.eviction)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
matched := false
|
||||||
|
for _, interaction := range interactions {
|
||||||
|
if c.processInteractionForRequest(interaction, data) {
|
||||||
|
matched = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
|
c.interactions.Delete(id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.requests.Set(id, data, c.eviction)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasMatchers returns true if an operator has interactsh part
|
// HasMatchers returns true if an operator has interactsh part
|
||||||
|
|||||||
@ -229,8 +229,9 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp
|
|||||||
MatchFunc: r.Match,
|
MatchFunc: r.Match,
|
||||||
ExtractFunc: r.Extract,
|
ExtractFunc: r.Extract,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
callback(event)
|
||||||
}
|
}
|
||||||
callback(event)
|
|
||||||
}, requestCount)
|
}, requestCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
requestErr = multierr.Append(requestErr, err)
|
requestErr = multierr.Append(requestErr, err)
|
||||||
|
|||||||
@ -168,6 +168,7 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse
|
|||||||
event.Results = r.MakeResultEvent(event)
|
event.Results = r.MakeResultEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
callback(event)
|
||||||
} else {
|
} else {
|
||||||
if r.options.Interactsh != nil {
|
if r.options.Interactsh != nil {
|
||||||
r.options.Interactsh.RequestEvent(interactURL, &interactsh.RequestData{
|
r.options.Interactsh.RequestEvent(interactURL, &interactsh.RequestData{
|
||||||
@ -179,7 +180,6 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback(event)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user