Merge pull request #1008 from projectdiscovery/clusterer-fixes

Clusterer fix + interactsh improvements
dev
Ice3man 2021-09-10 14:27:22 +05:30 committed by GitHub
commit c5f478962b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 122 additions and 69 deletions

View File

@ -2,7 +2,9 @@ name: ⏰ Publish Docs
on: on:
push: push:
pull_request: branches:
- master
- dev
workflow_dispatch: workflow_dispatch:
jobs: jobs:

View File

@ -282,7 +282,7 @@ name: Nagios Default Credentials Check
<div class="dd"> <div class="dd">
<code>author</code> <i>StringSlice</i> <code>author</code> <i><a href="#stringslicestringslice">stringslice.StringSlice</a></i>
</div> </div>
<div class="dt"> <div class="dt">
@ -307,7 +307,7 @@ author: <username>
<div class="dd"> <div class="dd">
<code>tags</code> <i>StringSlice</i> <code>tags</code> <i><a href="#stringslicestringslice">stringslice.StringSlice</a></i>
</div> </div>
<div class="dt"> <div class="dt">
@ -362,7 +362,7 @@ description: Subversion ALM for the enterprise before 8.8.2 allows reflected XSS
<div class="dd"> <div class="dd">
<code>reference</code> <i>StringSlice</i> <code>reference</code> <i><a href="#stringslicestringslice">stringslice.StringSlice</a></i>
</div> </div>
<div class="dt"> <div class="dt">
@ -389,7 +389,7 @@ reference:
<div class="dd"> <div class="dd">
<code>severity</code> <i><a href="#severityseverityholder">severity.SeverityHolder</a></i> <code>severity</code> <i><a href="#severityholder">severity.Holder</a></i>
</div> </div>
<div class="dt"> <div class="dt">
@ -441,18 +441,38 @@ additional-fields:
## model.StringSlice ## stringslice.StringSlice
StringSlice represents a single (in-lined) or multiple string value(s).
The unmarshaller does not automatically convert in-lined strings to []string, hence the interface{} type is required.
Appears in: Appears in:
- <code><a href="#modelinfo">model.Info</a>.author</code>
- <code><a href="#modelinfo">model.Info</a>.tags</code>
- <code><a href="#modelinfo">model.Info</a>.reference</code>
- <code><a href="#workflowsworkflowtemplate">workflows.WorkflowTemplate</a>.tags</code> - <code><a href="#workflowsworkflowtemplate">workflows.WorkflowTemplate</a>.tags</code>
```yaml
<username>
```
```yaml
# Example tags
cve,cve2019,grafana,auth-bypass,dos
```
```yaml
- https://github.com/strapi/strapi
- https://github.com/getgrav/grav
```
## severity.SeverityHolder ## severity.Holder
Holder holds a Severity type. Required for un/marshalling purposes
Appears in: Appears in:
@ -2617,7 +2637,7 @@ template: misconfigurations/aem
<div class="dd"> <div class="dd">
<code>tags</code> <i><a href="#modelstringslice">model.StringSlice</a></i> <code>tags</code> <i><a href="#stringslicestringslice">stringslice.StringSlice</a></i>
</div> </div>
<div class="dt"> <div class="dt">

View File

@ -2,18 +2,6 @@
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/templates.Template", "$ref": "#/definitions/templates.Template",
"definitions": { "definitions": {
"severity.SeverityHolder": {
"enum": [
"info",
"low",
"medium",
"high",
"critical"
],
"type": "string",
"title": "severity of the template",
"description": "Seriousness of the implications of the template"
},
"model.Info": { "model.Info": {
"properties": { "properties": {
"name": { "name": {
@ -26,12 +14,12 @@
}, },
"author": { "author": {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/model.StringSlice", "$ref": "#/definitions/stringslice.StringSlice",
"title": "author of the template", "title": "author of the template",
"description": "Author is the author of the template" "description": "Author is the author of the template"
}, },
"tags": { "tags": {
"$ref": "#/definitions/model.StringSlice", "$ref": "#/definitions/stringslice.StringSlice",
"title": "tags of the template", "title": "tags of the template",
"description": "Any tags for the template" "description": "Any tags for the template"
}, },
@ -44,13 +32,13 @@
] ]
}, },
"reference": { "reference": {
"$ref": "#/definitions/model.StringSlice", "$ref": "#/definitions/stringslice.StringSlice",
"title": "references for the template", "title": "references for the template",
"description": "Links relevant to the template" "description": "Links relevant to the template"
}, },
"severity": { "severity": {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/severity.SeverityHolder" "$ref": "#/definitions/severity.Holder"
}, },
"additional-fields": { "additional-fields": {
"patternProperties": { "patternProperties": {
@ -66,7 +54,19 @@
"additionalProperties": false, "additionalProperties": false,
"type": "object" "type": "object"
}, },
"model.StringSlice": { "severity.Holder": {
"enum": [
"info",
"low",
"medium",
"high",
"critical"
],
"type": "string",
"title": "severity of the template",
"description": "Seriousness of the implications of the template"
},
"stringslice.StringSlice": {
"oneOf": [ "oneOf": [
{ {
"type": "string" "type": "string"
@ -885,7 +885,7 @@
"description": "Template or directory to execute as part of workflow" "description": "Template or directory to execute as part of workflow"
}, },
"tags": { "tags": {
"$ref": "#/definitions/model.StringSlice", "$ref": "#/definitions/stringslice.StringSlice",
"title": "tags to execute", "title": "tags to execute",
"description": "Tags to run template based on" "description": "Tags to run template based on"
}, },

View File

@ -20,6 +20,6 @@ func showBanner() {
gologger.Print().Msgf("%s\n", banner) gologger.Print().Msgf("%s\n", banner)
gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
gologger.Error().Label("WRN").Msgf("Use with caution. You are responsible for your actions\n") gologger.Error().Label("WRN").Msgf("Use with caution. You are responsible for your actions.\n")
gologger.Error().Label("WRN").Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n") gologger.Error().Label("WRN").Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n")
} }

View File

@ -439,7 +439,7 @@ func (r *Runner) RunEnumeration() error {
} }
templatesMap := make(map[string]*templates.Template) templatesMap := make(map[string]*templates.Template)
for _, v := range store.Templates() { for _, v := range store.Templates() {
templatesMap[v.ID] = v templatesMap[v.Path] = v
} }
originalTemplatesCount := len(store.Templates()) originalTemplatesCount := len(store.Templates())
clusterCount := 0 clusterCount := 0
@ -471,6 +471,7 @@ func (r *Runner) RunEnumeration() error {
finalTemplates = append(finalTemplates, cluster...) finalTemplates = append(finalTemplates, cluster...)
} }
} }
finalTemplates = append(finalTemplates, store.Workflows()...) finalTemplates = append(finalTemplates, store.Workflows()...)
var totalRequests int64 var totalRequests int64

View File

@ -6,6 +6,7 @@ import (
"net/url" "net/url"
"os" "os"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -35,8 +36,9 @@ type Client struct {
pollDuration time.Duration pollDuration time.Duration
cooldownDuration time.Duration cooldownDuration time.Duration
generated uint32 // decide to wait if we have a generated url firstTimeGroup sync.Once
matched bool generated uint32 // decide to wait if we have a generated url
matched bool
} }
var ( var (
@ -80,14 +82,6 @@ func New(options *Options) (*Client, error) {
return nil, errors.Wrap(err, "could not parse server url") return nil, errors.Wrap(err, "could not parse server url")
} }
interactsh, err := client.New(&client.Options{
ServerURL: options.ServerURL,
Token: options.Authorization,
PersistentSession: false,
})
if err != nil {
return nil, errors.Wrap(err, "could not create client")
}
configure := ccache.Configure() configure := ccache.Configure()
configure = configure.MaxSize(options.CacheSize) configure = configure.MaxSize(options.CacheSize)
cache := ccache.New(configure) cache := ccache.New(configure)
@ -97,7 +91,6 @@ func New(options *Options) (*Client, error) {
interactionsCache := ccache.New(interactionsCfg) interactionsCache := ccache.New(interactionsCfg)
interactClient := &Client{ interactClient := &Client{
interactsh: interactsh,
eviction: options.Eviction, eviction: options.Eviction,
interactions: interactionsCache, interactions: interactionsCache,
dotHostname: "." + parsed.Host, dotHostname: "." + parsed.Host,
@ -106,21 +99,34 @@ func New(options *Options) (*Client, error) {
pollDuration: options.PollDuration, pollDuration: options.PollDuration,
cooldownDuration: options.ColldownPeriod, cooldownDuration: options.ColldownPeriod,
} }
return interactClient, nil
}
interactClient.interactsh.StartPolling(interactClient.pollDuration, func(interaction *server.Interaction) { func (c *Client) firstTimeInitializeClient() error {
if options.Debug { interactsh, err := client.New(&client.Options{
ServerURL: c.options.ServerURL,
Token: c.options.Authorization,
PersistentSession: false,
})
if err != nil {
return errors.Wrap(err, "could not create client")
}
c.interactsh = interactsh
interactsh.StartPolling(c.pollDuration, func(interaction *server.Interaction) {
if c.options.Debug {
debugPrintInteraction(interaction) debugPrintInteraction(interaction)
} }
item := interactClient.requests.Get(interaction.UniqueID) item := c.requests.Get(interaction.UniqueID)
if item == nil { if item == nil {
// If we don't have any request for this ID, add it to temporary // 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. // lru cache so we can correlate when we get an add request.
gotItem := interactClient.interactions.Get(interaction.UniqueID) gotItem := c.interactions.Get(interaction.UniqueID)
if gotItem == nil { if gotItem == nil {
interactClient.interactions.Set(interaction.UniqueID, []*server.Interaction{interaction}, defaultInteractionDuration) c.interactions.Set(interaction.UniqueID, []*server.Interaction{interaction}, defaultInteractionDuration)
} else if items, ok := gotItem.Value().([]*server.Interaction); ok { } else if items, ok := gotItem.Value().([]*server.Interaction); ok {
items = append(items, interaction) items = append(items, interaction)
interactClient.interactions.Set(interaction.UniqueID, items, defaultInteractionDuration) c.interactions.Set(interaction.UniqueID, items, defaultInteractionDuration)
} }
return return
} }
@ -128,9 +134,9 @@ func New(options *Options) (*Client, error) {
if !ok { if !ok {
return return
} }
_ = interactClient.processInteractionForRequest(interaction, request) _ = c.processInteractionForRequest(interaction, request)
}) })
return interactClient, nil return nil
} }
// processInteractionForRequest processes an interaction for a request // processInteractionForRequest processes an interaction for a request
@ -170,6 +176,11 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
// 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 {
c.firstTimeGroup.Do(func() {
if err := c.firstTimeInitializeClient(); err != nil {
gologger.Error().Msgf("Could not initialize interactsh client: %s", err)
}
})
atomic.CompareAndSwapUint32(&c.generated, 0, 1) atomic.CompareAndSwapUint32(&c.generated, 0, 1)
return c.interactsh.URL() return c.interactsh.URL()
} }
@ -179,8 +190,10 @@ func (c *Client) Close() bool {
if c.cooldownDuration > 0 && atomic.LoadUint32(&c.generated) == 1 { if c.cooldownDuration > 0 && atomic.LoadUint32(&c.generated) == 1 {
time.Sleep(c.cooldownDuration) time.Sleep(c.cooldownDuration)
} }
c.interactsh.StopPolling() if c.interactsh != nil {
c.interactsh.Close() c.interactsh.StopPolling()
c.interactsh.Close()
}
return c.matched return c.matched
} }

View File

@ -1,4 +1,3 @@
// Package templates
// This Source Code Form is subject to the terms of the Mozilla Public // This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
@ -12,8 +11,8 @@ import (
var ( var (
TemplateDoc encoder.Doc TemplateDoc encoder.Doc
MODELInfoDoc encoder.Doc MODELInfoDoc encoder.Doc
MODELStringSliceDoc encoder.Doc STRINGSLICEStringSliceDoc encoder.Doc
SEVERITYSeverityHolderDoc encoder.Doc SEVERITYHolderDoc encoder.Doc
HTTPRequestDoc encoder.Doc HTTPRequestDoc encoder.Doc
MATCHERSMatcherDoc encoder.Doc MATCHERSMatcherDoc encoder.Doc
EXTRACTORSExtractorDoc encoder.Doc EXTRACTORSExtractorDoc encoder.Doc
@ -107,14 +106,14 @@ func init() {
MODELInfoDoc.Fields[0].AddExample("", "Nagios Default Credentials Check") MODELInfoDoc.Fields[0].AddExample("", "Nagios Default Credentials Check")
MODELInfoDoc.Fields[1].Name = "author" MODELInfoDoc.Fields[1].Name = "author"
MODELInfoDoc.Fields[1].Type = "StringSlice" MODELInfoDoc.Fields[1].Type = "stringslice.StringSlice"
MODELInfoDoc.Fields[1].Note = "" MODELInfoDoc.Fields[1].Note = ""
MODELInfoDoc.Fields[1].Description = "Author of the template.\n\nMultiple values can also be specified separated by commas." MODELInfoDoc.Fields[1].Description = "Author of the template.\n\nMultiple values can also be specified separated by commas."
MODELInfoDoc.Fields[1].Comments[encoder.LineComment] = "Author of the template." MODELInfoDoc.Fields[1].Comments[encoder.LineComment] = "Author of the template."
MODELInfoDoc.Fields[1].AddExample("", "<username>") MODELInfoDoc.Fields[1].AddExample("", "<username>")
MODELInfoDoc.Fields[2].Name = "tags" MODELInfoDoc.Fields[2].Name = "tags"
MODELInfoDoc.Fields[2].Type = "StringSlice" MODELInfoDoc.Fields[2].Type = "stringslice.StringSlice"
MODELInfoDoc.Fields[2].Note = "" MODELInfoDoc.Fields[2].Note = ""
MODELInfoDoc.Fields[2].Description = "Any tags for the template.\n\nMultiple values can also be specified separated by commas." MODELInfoDoc.Fields[2].Description = "Any tags for the template.\n\nMultiple values can also be specified separated by commas."
MODELInfoDoc.Fields[2].Comments[encoder.LineComment] = "Any tags for the template." MODELInfoDoc.Fields[2].Comments[encoder.LineComment] = "Any tags for the template."
@ -130,14 +129,14 @@ func init() {
MODELInfoDoc.Fields[3].AddExample("", "Subversion ALM for the enterprise before 8.8.2 allows reflected XSS at multiple locations") MODELInfoDoc.Fields[3].AddExample("", "Subversion ALM for the enterprise before 8.8.2 allows reflected XSS at multiple locations")
MODELInfoDoc.Fields[4].Name = "reference" MODELInfoDoc.Fields[4].Name = "reference"
MODELInfoDoc.Fields[4].Type = "StringSlice" MODELInfoDoc.Fields[4].Type = "stringslice.StringSlice"
MODELInfoDoc.Fields[4].Note = "" MODELInfoDoc.Fields[4].Note = ""
MODELInfoDoc.Fields[4].Description = "References for the template.\n\nThis should contain links relevant to the template." MODELInfoDoc.Fields[4].Description = "References for the template.\n\nThis should contain links relevant to the template."
MODELInfoDoc.Fields[4].Comments[encoder.LineComment] = "References for the template." MODELInfoDoc.Fields[4].Comments[encoder.LineComment] = "References for the template."
MODELInfoDoc.Fields[4].AddExample("", []string{"https://github.com/strapi/strapi", "https://github.com/getgrav/grav"}) MODELInfoDoc.Fields[4].AddExample("", []string{"https://github.com/strapi/strapi", "https://github.com/getgrav/grav"})
MODELInfoDoc.Fields[5].Name = "severity" MODELInfoDoc.Fields[5].Name = "severity"
MODELInfoDoc.Fields[5].Type = "severity.SeverityHolder" MODELInfoDoc.Fields[5].Type = "severity.Holder"
MODELInfoDoc.Fields[5].Note = "" MODELInfoDoc.Fields[5].Note = ""
MODELInfoDoc.Fields[5].Description = "Severity of the template." MODELInfoDoc.Fields[5].Description = "Severity of the template."
MODELInfoDoc.Fields[5].Comments[encoder.LineComment] = "Severity of the template." MODELInfoDoc.Fields[5].Comments[encoder.LineComment] = "Severity of the template."
@ -156,27 +155,45 @@ func init() {
MODELInfoDoc.Fields[6].AddExample("", map[string]string{"customField1": "customValue1"}) MODELInfoDoc.Fields[6].AddExample("", map[string]string{"customField1": "customValue1"})
MODELStringSliceDoc.Type = "model.StringSlice" STRINGSLICEStringSliceDoc.Type = "stringslice.StringSlice"
MODELStringSliceDoc.Comments[encoder.LineComment] = "" STRINGSLICEStringSliceDoc.Comments[encoder.LineComment] = " StringSlice represents a single (in-lined) or multiple string value(s)."
MODELStringSliceDoc.Description = "" STRINGSLICEStringSliceDoc.Description = "StringSlice represents a single (in-lined) or multiple string value(s).\n The unmarshaller does not automatically convert in-lined strings to []string, hence the interface{} type is required."
MODELStringSliceDoc.AppearsIn = []encoder.Appearance{
STRINGSLICEStringSliceDoc.AddExample("", "<username>")
STRINGSLICEStringSliceDoc.AddExample("Example tags", "cve,cve2019,grafana,auth-bypass,dos")
STRINGSLICEStringSliceDoc.AddExample("", []string{"https://github.com/strapi/strapi", "https://github.com/getgrav/grav"})
STRINGSLICEStringSliceDoc.AppearsIn = []encoder.Appearance{
{
TypeName: "model.Info",
FieldName: "author",
},
{
TypeName: "model.Info",
FieldName: "tags",
},
{
TypeName: "model.Info",
FieldName: "reference",
},
{ {
TypeName: "workflows.WorkflowTemplate", TypeName: "workflows.WorkflowTemplate",
FieldName: "tags", FieldName: "tags",
}, },
} }
MODELStringSliceDoc.Fields = make([]encoder.Doc, 0) STRINGSLICEStringSliceDoc.Fields = make([]encoder.Doc, 0)
SEVERITYSeverityHolderDoc.Type = "severity.SeverityHolder" SEVERITYHolderDoc.Type = "severity.Holder"
SEVERITYSeverityHolderDoc.Comments[encoder.LineComment] = "" SEVERITYHolderDoc.Comments[encoder.LineComment] = " Holder holds a Severity type. Required for un/marshalling purposes"
SEVERITYSeverityHolderDoc.Description = "" SEVERITYHolderDoc.Description = "Holder holds a Severity type. Required for un/marshalling purposes"
SEVERITYSeverityHolderDoc.AppearsIn = []encoder.Appearance{ SEVERITYHolderDoc.AppearsIn = []encoder.Appearance{
{ {
TypeName: "model.Info", TypeName: "model.Info",
FieldName: "severity", FieldName: "severity",
}, },
} }
SEVERITYSeverityHolderDoc.Fields = make([]encoder.Doc, 0) SEVERITYHolderDoc.Fields = make([]encoder.Doc, 0)
HTTPRequestDoc.Type = "http.Request" HTTPRequestDoc.Type = "http.Request"
HTTPRequestDoc.Comments[encoder.LineComment] = " Request contains a http request to be made from a template" HTTPRequestDoc.Comments[encoder.LineComment] = " Request contains a http request to be made from a template"
@ -971,7 +988,7 @@ func init() {
WORKFLOWSWorkflowTemplateDoc.Fields[0].AddExample("A template directory", "misconfigurations/aem") WORKFLOWSWorkflowTemplateDoc.Fields[0].AddExample("A template directory", "misconfigurations/aem")
WORKFLOWSWorkflowTemplateDoc.Fields[1].Name = "tags" WORKFLOWSWorkflowTemplateDoc.Fields[1].Name = "tags"
WORKFLOWSWorkflowTemplateDoc.Fields[1].Type = "model.StringSlice" WORKFLOWSWorkflowTemplateDoc.Fields[1].Type = "stringslice.StringSlice"
WORKFLOWSWorkflowTemplateDoc.Fields[1].Note = "" WORKFLOWSWorkflowTemplateDoc.Fields[1].Note = ""
WORKFLOWSWorkflowTemplateDoc.Fields[1].Description = "Tags to run templates based on." WORKFLOWSWorkflowTemplateDoc.Fields[1].Description = "Tags to run templates based on."
WORKFLOWSWorkflowTemplateDoc.Fields[1].Comments[encoder.LineComment] = "Tags to run templates based on." WORKFLOWSWorkflowTemplateDoc.Fields[1].Comments[encoder.LineComment] = "Tags to run templates based on."
@ -1016,8 +1033,8 @@ func GetTemplateDoc() *encoder.FileDoc {
Structs: []*encoder.Doc{ Structs: []*encoder.Doc{
&TemplateDoc, &TemplateDoc,
&MODELInfoDoc, &MODELInfoDoc,
&MODELStringSliceDoc, &STRINGSLICEStringSliceDoc,
&SEVERITYSeverityHolderDoc, &SEVERITYHolderDoc,
&HTTPRequestDoc, &HTTPRequestDoc,
&MATCHERSMatcherDoc, &MATCHERSMatcherDoc,
&EXTRACTORSExtractorDoc, &EXTRACTORSExtractorDoc,