mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 20:25:27 +00:00
Working interactsh integration
This commit is contained in:
parent
4c594627a9
commit
33bf306f28
@ -372,7 +372,10 @@ func (r *Runner) RunEnumeration() {
|
|||||||
wgtemplates.Wait()
|
wgtemplates.Wait()
|
||||||
|
|
||||||
if r.interactsh != nil {
|
if r.interactsh != nil {
|
||||||
r.interactsh.Close()
|
matched := r.interactsh.Close()
|
||||||
|
if matched {
|
||||||
|
results.CAS(false, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r.progress.Stop()
|
r.progress.Stop()
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,32 @@ type Result struct {
|
|||||||
PayloadValues map[string]interface{}
|
PayloadValues map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge merges a result structure into the other.
|
||||||
|
func (r *Result) Merge(result *Result) {
|
||||||
|
if !r.Matched && result.Matched {
|
||||||
|
r.Matched = result.Matched
|
||||||
|
}
|
||||||
|
if !r.Extracted && result.Extracted {
|
||||||
|
r.Extracted = result.Extracted
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range result.Matches {
|
||||||
|
r.Matches[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range result.Extracts {
|
||||||
|
r.Extracts[k] = v
|
||||||
|
}
|
||||||
|
for _, v := range result.OutputExtracts {
|
||||||
|
r.OutputExtracts = append(r.OutputExtracts, v)
|
||||||
|
}
|
||||||
|
for k, v := range result.DynamicValues {
|
||||||
|
r.DynamicValues[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range result.PayloadValues {
|
||||||
|
r.PayloadValues[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MatchFunc performs matching operation for a matcher on model and returns true or false.
|
// MatchFunc performs matching operation for a matcher on model and returns true or false.
|
||||||
type MatchFunc func(data map[string]interface{}, matcher *matchers.Matcher) bool
|
type MatchFunc func(data map[string]interface{}, matcher *matchers.Matcher) bool
|
||||||
|
|
||||||
@ -81,6 +107,7 @@ func (r *Operators) Execute(data map[string]interface{}, match MatchFunc, extrac
|
|||||||
Extracts: make(map[string][]string),
|
Extracts: make(map[string][]string),
|
||||||
DynamicValues: make(map[string]interface{}),
|
DynamicValues: make(map[string]interface{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start with the extractors first and evaluate them.
|
// Start with the extractors first and evaluate them.
|
||||||
for _, extractor := range r.Extractors {
|
for _, extractor := range r.Extractors {
|
||||||
var extractorResults []string
|
var extractorResults []string
|
||||||
|
|||||||
@ -22,6 +22,7 @@ type Client struct {
|
|||||||
// 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
|
||||||
|
|
||||||
|
matched bool
|
||||||
dotHostname string
|
dotHostname string
|
||||||
eviction time.Duration
|
eviction time.Duration
|
||||||
pollDuration time.Duration
|
pollDuration time.Duration
|
||||||
@ -77,24 +78,38 @@ func New(options *Options) (*Client, error) {
|
|||||||
pollDuration: options.PollDuration,
|
pollDuration: options.PollDuration,
|
||||||
cooldownDuration: options.ColldownPeriod,
|
cooldownDuration: options.ColldownPeriod,
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, ok := item.Value().(*internalRequestEvent)
|
data, ok := item.Value().(*RequestData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
interactClient.requests.Delete(interaction.UniqueID)
|
||||||
|
|
||||||
data.event.OperatorsResult = &operators.Result{
|
if data.Event.OperatorsResult != nil {
|
||||||
Matches: map[string]struct{}{strings.ToLower(interaction.Protocol): {}},
|
data.Event.OperatorsResult.Merge(result)
|
||||||
|
} else {
|
||||||
|
data.Event.OperatorsResult = result
|
||||||
}
|
}
|
||||||
data.event.Results = data.makeResultFunc(data.event)
|
data.Event.Results = data.MakeResultFunc(data.Event)
|
||||||
for _, result := range data.event.Results {
|
for _, result := range data.Event.Results {
|
||||||
result.Interaction = interaction
|
result.Interaction = interaction
|
||||||
_ = options.Output.Write(result)
|
_ = options.Output.Write(result)
|
||||||
|
if !interactClient.matched {
|
||||||
|
interactClient.matched = true
|
||||||
|
}
|
||||||
options.Progress.IncrementMatched()
|
options.Progress.IncrementMatched()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -107,12 +122,13 @@ func (c *Client) URL() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the interactsh clients after waiting for cooldown period.
|
// Close closes the interactsh clients after waiting for cooldown period.
|
||||||
func (c *Client) Close() {
|
func (c *Client) Close() bool {
|
||||||
if c.cooldownDuration > 0 {
|
if c.cooldownDuration > 0 {
|
||||||
time.Sleep(c.cooldownDuration)
|
time.Sleep(c.cooldownDuration)
|
||||||
}
|
}
|
||||||
c.interactsh.StopPolling()
|
c.interactsh.StopPolling()
|
||||||
c.interactsh.Close()
|
c.interactsh.Close()
|
||||||
|
return c.matched
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplaceMarkers replaces the {{interactsh-url}} placeholders to actual
|
// ReplaceMarkers replaces the {{interactsh-url}} placeholders to actual
|
||||||
@ -133,13 +149,36 @@ func (c *Client) ReplaceMarkers(data, interactshURL string) string {
|
|||||||
// MakeResultEventFunc is a result making function for nuclei
|
// MakeResultEventFunc is a result making function for nuclei
|
||||||
type MakeResultEventFunc func(wrapped *output.InternalWrappedEvent) []*output.ResultEvent
|
type MakeResultEventFunc func(wrapped *output.InternalWrappedEvent) []*output.ResultEvent
|
||||||
|
|
||||||
type internalRequestEvent struct {
|
// RequestData contains data for a request event
|
||||||
makeResultFunc MakeResultEventFunc
|
type RequestData struct {
|
||||||
event *output.InternalWrappedEvent
|
MakeResultFunc MakeResultEventFunc
|
||||||
|
Event *output.InternalWrappedEvent
|
||||||
|
Operators *operators.Operators
|
||||||
|
MatchFunc operators.MatchFunc
|
||||||
|
ExtractFunc operators.ExtractFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, event *output.InternalWrappedEvent, makeResult MakeResultEventFunc) {
|
func (c *Client) RequestEvent(interactshURL string, data *RequestData) {
|
||||||
id := strings.TrimSuffix(interactshURL, c.dotHostname)
|
id := strings.TrimSuffix(interactshURL, c.dotHostname)
|
||||||
c.requests.Set(id, &internalRequestEvent{makeResultFunc: makeResult, event: event}, c.eviction)
|
c.requests.Set(id, data, c.eviction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasMatchers returns true if an operator has interactsh part
|
||||||
|
// matchers or extractors.
|
||||||
|
//
|
||||||
|
// Used by requests to show result or not depending on presence of interact.sh
|
||||||
|
// data part matchers.
|
||||||
|
func HasMatchers(operators *operators.Operators) bool {
|
||||||
|
for _, matcher := range operators.Matchers {
|
||||||
|
if strings.HasPrefix(matcher.Part, "interactsh-") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, matcher := range operators.Extractors {
|
||||||
|
if strings.HasPrefix(matcher.Part, "interactsh-") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
||||||
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/tostring"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/tostring"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool"
|
||||||
"github.com/projectdiscovery/rawhttp"
|
"github.com/projectdiscovery/rawhttp"
|
||||||
@ -219,8 +220,16 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp
|
|||||||
gotOutput = true
|
gotOutput = true
|
||||||
dynamicValues = generators.MergeMaps(dynamicValues, event.OperatorsResult.DynamicValues)
|
dynamicValues = generators.MergeMaps(dynamicValues, event.OperatorsResult.DynamicValues)
|
||||||
}
|
}
|
||||||
if r.options.Interactsh != nil {
|
if interactsh.HasMatchers(r.CompiledOperators) {
|
||||||
r.options.Interactsh.RequestEvent(interactURL, event, r.MakeResultEvent)
|
if r.options.Interactsh != nil {
|
||||||
|
r.options.Interactsh.RequestEvent(interactURL, &interactsh.RequestData{
|
||||||
|
MakeResultFunc: r.MakeResultEvent,
|
||||||
|
Event: event,
|
||||||
|
Operators: r.CompiledOperators,
|
||||||
|
MatchFunc: r.Match,
|
||||||
|
ExtractFunc: r.Extract,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
callback(event)
|
callback(event)
|
||||||
}, requestCount)
|
}, requestCount)
|
||||||
@ -398,14 +407,16 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, previ
|
|||||||
}
|
}
|
||||||
|
|
||||||
event := &output.InternalWrappedEvent{InternalEvent: outputEvent}
|
event := &output.InternalWrappedEvent{InternalEvent: outputEvent}
|
||||||
if r.CompiledOperators != nil {
|
if !interactsh.HasMatchers(r.CompiledOperators) {
|
||||||
var ok bool
|
if r.CompiledOperators != nil {
|
||||||
event.OperatorsResult, ok = r.CompiledOperators.Execute(finalEvent, r.Match, r.Extract)
|
var ok bool
|
||||||
if ok && event.OperatorsResult != nil {
|
event.OperatorsResult, ok = r.CompiledOperators.Execute(finalEvent, r.Match, r.Extract)
|
||||||
event.OperatorsResult.PayloadValues = request.meta
|
if ok && event.OperatorsResult != nil {
|
||||||
event.Results = r.MakeResultEvent(event)
|
event.OperatorsResult.PayloadValues = request.meta
|
||||||
|
event.Results = r.MakeResultEvent(event)
|
||||||
|
}
|
||||||
|
event.InternalEvent = outputEvent
|
||||||
}
|
}
|
||||||
event.InternalEvent = outputEvent
|
|
||||||
}
|
}
|
||||||
callback(event)
|
callback(event)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/projectdiscovery/gologger"
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||||
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,6 +78,11 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_ = conn.SetReadDeadline(time.Now().Add(time.Duration(r.options.Options.Timeout) * time.Second))
|
_ = conn.SetReadDeadline(time.Now().Add(time.Duration(r.options.Options.Timeout) * time.Second))
|
||||||
|
|
||||||
|
var interactURL string
|
||||||
|
if r.options.Interactsh != nil {
|
||||||
|
interactURL = r.options.Interactsh.URL()
|
||||||
|
}
|
||||||
|
|
||||||
responseBuilder := &strings.Builder{}
|
responseBuilder := &strings.Builder{}
|
||||||
reqBuilder := &strings.Builder{}
|
reqBuilder := &strings.Builder{}
|
||||||
|
|
||||||
@ -88,6 +94,9 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse
|
|||||||
case "hex":
|
case "hex":
|
||||||
data, err = hex.DecodeString(input.Data)
|
data, err = hex.DecodeString(input.Data)
|
||||||
default:
|
default:
|
||||||
|
if r.options.Interactsh != nil {
|
||||||
|
input.Data = r.options.Interactsh.ReplaceMarkers(input.Data, interactURL)
|
||||||
|
}
|
||||||
data = []byte(input.Data)
|
data = []byte(input.Data)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -150,11 +159,23 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse
|
|||||||
}
|
}
|
||||||
|
|
||||||
event := &output.InternalWrappedEvent{InternalEvent: outputEvent}
|
event := &output.InternalWrappedEvent{InternalEvent: outputEvent}
|
||||||
if r.CompiledOperators != nil {
|
if !interactsh.HasMatchers(r.CompiledOperators) {
|
||||||
result, ok := r.CompiledOperators.Execute(outputEvent, r.Match, r.Extract)
|
if r.CompiledOperators != nil {
|
||||||
if ok && result != nil {
|
result, ok := r.CompiledOperators.Execute(outputEvent, r.Match, r.Extract)
|
||||||
event.OperatorsResult = result
|
if ok && result != nil {
|
||||||
event.Results = r.MakeResultEvent(event)
|
event.OperatorsResult = result
|
||||||
|
event.Results = r.MakeResultEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if r.options.Interactsh != nil {
|
||||||
|
r.options.Interactsh.RequestEvent(interactURL, &interactsh.RequestData{
|
||||||
|
MakeResultFunc: r.MakeResultEvent,
|
||||||
|
Event: event,
|
||||||
|
Operators: r.CompiledOperators,
|
||||||
|
MatchFunc: r.Match,
|
||||||
|
ExtractFunc: r.Extract,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback(event)
|
callback(event)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user