refactor(vardump): use godump lib (#5676)

* refactor(vardump): use `godump` lib

also increate limit char to `255`.

Signed-off-by: Dwi Siswanto <git@dw1.io>

* feat(vardump): add global var `Limit`

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore(protocols): rm newline

Signed-off-by: Dwi Siswanto <git@dw1.io>

* feat(types): add `VarDumpLimit` option

Signed-off-by: Dwi Siswanto <git@dw1.io>

* test(vardump): add test cases

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore: tidy up mod

Signed-off-by: Dwi Siswanto <git@dw1.io>

---------

Signed-off-by: Dwi Siswanto <git@dw1.io>
This commit is contained in:
Dwi Siswanto 2024-10-14 21:01:36 +07:00 committed by GitHub
parent 53f56e179d
commit 2c832f5590
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 130 additions and 46 deletions

View File

@ -425,6 +425,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVar(&memProfile, "profile-mem", "", "generate memory (heap) profile & trace files"), flagSet.StringVar(&memProfile, "profile-mem", "", "generate memory (heap) profile & trace files"),
flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"), flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"),
flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "svd", false, "show variables dump for debugging"), flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "svd", false, "show variables dump for debugging"),
flagSet.IntVarP(&options.VarDumpLimit, "var-dump-limit", "vdl", 255, "limit the number of characters displayed in var dump"),
flagSet.BoolVarP(&options.EnablePprof, "enable-pprof", "ep", false, "enable pprof debugging server"), flagSet.BoolVarP(&options.EnablePprof, "enable-pprof", "ep", false, "enable pprof debugging server"),
flagSet.CallbackVarP(printTemplateVersion, "templates-version", "tv", "shows the version of the installed nuclei-templates"), flagSet.CallbackVarP(printTemplateVersion, "templates-version", "tv", "shows the version of the installed nuclei-templates"),
flagSet.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"), flagSet.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"),

3
go.mod
View File

@ -1,6 +1,6 @@
module github.com/projectdiscovery/nuclei/v3 module github.com/projectdiscovery/nuclei/v3
go 1.21 go 1.21.0
require ( require (
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
@ -104,6 +104,7 @@ require (
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9 github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
github.com/yassinebenaid/godump v0.10.0
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706 github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706
go.mongodb.org/mongo-driver v1.17.0 go.mongodb.org/mongo-driver v1.17.0
golang.org/x/term v0.24.0 golang.org/x/term v0.24.0

2
go.sum
View File

@ -1104,6 +1104,8 @@ github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yassinebenaid/godump v0.10.0 h1:FolBA+Ix5uwUiXYBBYOsf1VkT5+0f4gtFNTkYTiIR08=
github.com/yassinebenaid/godump v0.10.0/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=

View File

@ -68,6 +68,7 @@ func ParseOptions(options *types.Options) {
if options.ShowVarDump { if options.ShowVarDump {
vardump.EnableVarDump = true vardump.EnableVarDump = true
vardump.Limit = options.VarDumpLimit
} }
if options.ShowActions { if options.ShowActions {
gologger.Info().Msgf("Showing available headless actions: ") gologger.Info().Msgf("Showing available headless actions: ")

View File

@ -235,7 +235,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
gologger.Verbose().Msgf("[%s] Executed code on local machine %v", request.options.TemplateID, input.MetaInput.Input) gologger.Verbose().Msgf("[%s] Executed code on local machine %v", request.options.TemplateID, input.MetaInput.Input)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Code Protocol request variables: \n%s\n", vardump.DumpVariables(allvars)) gologger.Debug().Msgf("Code Protocol request variables: %s\n", vardump.DumpVariables(allvars))
} }
if request.options.Options.Debug || request.options.Options.DebugRequests { if request.options.Options.Debug || request.options.Options.DebugRequests {

View File

@ -24,7 +24,7 @@ func CreateEventWithAdditionalOptions(request protocols.Request, outputEvent out
// Dump response variables if ran in debug mode // Dump response variables if ran in debug mode
if vardump.EnableVarDump { if vardump.EnableVarDump {
protoName := cases.Title(language.English).String(request.Type().String()) protoName := cases.Title(language.English).String(request.Type().String())
gologger.Debug().Msgf("%v Protocol response variables: \n%s\n", protoName, vardump.DumpVariables(outputEvent)) gologger.Debug().Msgf("%v Protocol response variables: %s\n", protoName, vardump.DumpVariables(outputEvent))
} }
for _, compiledOperator := range request.GetCompiledOperators() { for _, compiledOperator := range request.GetCompiledOperators() {
if compiledOperator != nil { if compiledOperator != nil {

View File

@ -1,53 +1,67 @@
package vardump package vardump
import ( import (
"strconv"
"strings" "strings"
"github.com/projectdiscovery/nuclei/v3/pkg/types" "github.com/projectdiscovery/nuclei/v3/pkg/types"
mapsutil "github.com/projectdiscovery/utils/maps" mapsutil "github.com/projectdiscovery/utils/maps"
"github.com/yassinebenaid/godump"
) )
// EnableVarDump enables var dump for debugging optionally // variables is a map of variables
var EnableVarDump bool type variables = map[string]any
// DumpVariables writes the truncated dump of variables to a string // DumpVariables dumps the variables in a pretty format
// in a formatted key-value manner. func DumpVariables(data variables) string {
// if !EnableVarDump {
// The values are truncated to return 50 characters from start and end. return ""
func DumpVariables(data map[string]interface{}) string { }
var counter int
buffer := &strings.Builder{} d := godump.Dumper{
buffer.Grow(len(data) * 78) // grow buffer to an approximate size Indentation: " ",
HidePrivateFields: false,
ShowPrimitiveNamedTypes: true,
}
builder := &strings.Builder{} d.Theme = godump.Theme{
// sort keys for deterministic output String: godump.RGB{R: 138, G: 201, B: 38},
Quotes: godump.RGB{R: 112, G: 214, B: 255},
Bool: godump.RGB{R: 249, G: 87, B: 56},
Number: godump.RGB{R: 10, G: 178, B: 242},
Types: godump.RGB{R: 0, G: 150, B: 199},
Address: godump.RGB{R: 205, G: 93, B: 0},
PointerTag: godump.RGB{R: 110, G: 110, B: 110},
Nil: godump.RGB{R: 219, G: 57, B: 26},
Func: godump.RGB{R: 160, G: 90, B: 220},
Fields: godump.RGB{R: 189, G: 176, B: 194},
Chan: godump.RGB{R: 195, G: 154, B: 76},
UnsafePointer: godump.RGB{R: 89, G: 193, B: 180},
Braces: godump.RGB{R: 185, G: 86, B: 86},
}
return d.Sprint(process(data, Limit))
}
// process is a helper function that processes the variables
// and returns a new map of variables
func process(data variables, limit int) variables {
keys := mapsutil.GetSortedKeys(data) keys := mapsutil.GetSortedKeys(data)
vars := make(variables)
if limit == 0 {
limit = 255
}
for _, k := range keys { for _, k := range keys {
v := data[k] v := types.ToString(data[k])
valueString := types.ToString(v) v = strings.ReplaceAll(strings.ReplaceAll(v, "\r", " "), "\n", " ")
if len(v) > limit {
counter++ v = v[:limit]
if len(valueString) > 50 { v += " [...]"
builder.Grow(56)
builder.WriteString(valueString[0:25])
builder.WriteString(" .... ")
builder.WriteString(valueString[len(valueString)-25:])
valueString = builder.String()
builder.Reset()
} }
valueString = strings.ReplaceAll(strings.ReplaceAll(valueString, "\r", " "), "\n", " ")
buffer.WriteString("\t") vars[k] = v
buffer.WriteString(strconv.Itoa(counter))
buffer.WriteString(". ")
buffer.WriteString(k)
buffer.WriteString(" => ")
buffer.WriteString(valueString)
buffer.WriteString("\n")
} }
final := buffer.String()
return final return vars
} }

View File

@ -0,0 +1,55 @@
package vardump
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDumpVariables(t *testing.T) {
// Enable var dump for testing
EnableVarDump = true
// Test case
testVars := variables{
"string": "test",
"int": 42,
"bool": true,
"slice": []string{"a", "b", "c"},
}
result := DumpVariables(testVars)
// Assertions
assert.NotEmpty(t, result)
assert.Contains(t, result, "string")
assert.Contains(t, result, "test")
assert.Contains(t, result, "int")
assert.Contains(t, result, "42")
assert.Contains(t, result, "bool")
assert.Contains(t, result, "true")
assert.Contains(t, result, "slice")
assert.Contains(t, result, "a")
assert.Contains(t, result, "b")
assert.Contains(t, result, "c")
// Test with EnableVarDump set to false
EnableVarDump = false
result = DumpVariables(testVars)
assert.Empty(t, result)
}
func TestProcess(t *testing.T) {
testVars := variables{
"short": "short string",
"long": strings.Repeat("a", 300),
"number": 42,
}
processed := process(testVars, 255)
assert.Equal(t, "short string", processed["short"])
assert.Equal(t, strings.Repeat("a", 255)+" [...]", processed["long"])
assert.Equal(t, "42", processed["number"])
}

View File

@ -0,0 +1,8 @@
package vardump
var (
// EnableVarDump enables var dump for debugging optionally
EnableVarDump bool
// Limit is the maximum characters to be dumped
Limit int = 255
)

View File

@ -108,7 +108,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, metadata,
func (request *Request) execute(input *contextargs.Context, domain string, metadata, previous output.InternalEvent, vars map[string]interface{}, callback protocols.OutputEventCallback) error { func (request *Request) execute(input *contextargs.Context, domain string, metadata, previous output.InternalEvent, vars map[string]interface{}, callback protocols.OutputEventCallback) error {
var err error var err error
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("DNS Protocol request variables: \n%s\n", vardump.DumpVariables(vars)) gologger.Debug().Msgf("DNS Protocol request variables: %s\n", vardump.DumpVariables(vars))
} }
// Compile each request for the template based on the URL // Compile each request for the template based on the URL

View File

@ -334,7 +334,7 @@ func (p *Page) NavigateURL(action *Action, out ActionData, allvars map[string]in
allvars = generators.MergeMaps(allvars, defaultReqVars) allvars = generators.MergeMaps(allvars, defaultReqVars)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Headless Protocol request variables: \n%s\n", vardump.DumpVariables(allvars)) gologger.Debug().Msgf("Headless Protocol request variables: %s\n", vardump.DumpVariables(allvars))
} }
// Evaluate the target url with all variables // Evaluate the target url with all variables

View File

@ -122,7 +122,7 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p
defer instance.Close() defer instance.Close()
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Headless Protocol request variables: \n%s\n", vardump.DumpVariables(payloads)) gologger.Debug().Msgf("Headless Protocol request variables: %s\n", vardump.DumpVariables(payloads))
} }
instance.SetInteractsh(request.options.Interactsh) instance.SetInteractsh(request.options.Interactsh)

View File

@ -204,7 +204,7 @@ func (r *requestGenerator) Make(ctx context.Context, input *contextargs.Context,
finalVars := generators.MergeMaps(allVars, payloads) finalVars := generators.MergeMaps(allVars, payloads)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("HTTP Protocol request variables: \n%s\n", vardump.DumpVariables(finalVars)) gologger.Debug().Msgf("HTTP Protocol request variables: %s\n", vardump.DumpVariables(finalVars))
} }
// Note: If possible any changes to current logic (i.e evaluate -> then parse URL) // Note: If possible any changes to current logic (i.e evaluate -> then parse URL)

View File

@ -319,7 +319,7 @@ func (request *Request) ExecuteWithResults(target *contextargs.Context, dynamicV
templateCtx.Merge(payloadValues) templateCtx.Merge(payloadValues)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Javascript Protocol request variables: \n%s\n", vardump.DumpVariables(payloadValues)) gologger.Debug().Msgf("JavaScript Protocol request variables: %s\n", vardump.DumpVariables(payloadValues))
} }
if request.PreCondition != "" { if request.PreCondition != "" {

View File

@ -283,7 +283,7 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
interimValues := generators.MergeMaps(variables, payloads) interimValues := generators.MergeMaps(variables, payloads)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Network Protocol request variables: \n%s\n", vardump.DumpVariables(interimValues)) gologger.Debug().Msgf("Network Protocol request variables: %s\n", vardump.DumpVariables(interimValues))
} }
inputEvents := make(map[string]interface{}) inputEvents := make(map[string]interface{})

View File

@ -222,7 +222,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
payloadValues = generators.MergeMaps(variablesMap, payloadValues, request.options.Constants) payloadValues = generators.MergeMaps(variablesMap, payloadValues, request.options.Constants)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("SSL Protocol request variables: \n%s\n", vardump.DumpVariables(payloadValues)) gologger.Debug().Msgf("SSL Protocol request variables: %s\n", vardump.DumpVariables(payloadValues))
} }
finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues) finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues)

View File

@ -207,7 +207,7 @@ func (request *Request) executeRequestWithPayloads(target *contextargs.Context,
} }
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Websocket Protocol request variables: \n%s\n", vardump.DumpVariables(payloadValues)) gologger.Debug().Msgf("WebSocket Protocol request variables: %s\n", vardump.DumpVariables(payloadValues))
} }
finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues) finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues)

View File

@ -99,7 +99,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
variables := generators.MergeMaps(vars, defaultVars, optionVars, dynamicValues, request.options.Constants) variables := generators.MergeMaps(vars, defaultVars, optionVars, dynamicValues, request.options.Constants)
if vardump.EnableVarDump { if vardump.EnableVarDump {
gologger.Debug().Msgf("Whois Protocol request variables: \n%s\n", vardump.DumpVariables(variables)) gologger.Debug().Msgf("Whois Protocol request variables: %s\n", vardump.DumpVariables(variables))
} }
// and replace placeholders // and replace placeholders

View File

@ -206,6 +206,8 @@ type Options struct {
VerboseVerbose bool VerboseVerbose bool
// ShowVarDump displays variable dump // ShowVarDump displays variable dump
ShowVarDump bool ShowVarDump bool
// VarDumpLimit limits the number of characters displayed in var dump
VarDumpLimit int
// No-Color disables the colored output. // No-Color disables the colored output.
NoColor bool NoColor bool
// UpdateTemplates updates the templates installed at startup (also used by cloud to update datasources) // UpdateTemplates updates the templates installed at startup (also used by cloud to update datasources)