Merge branch 'dev' into feat-4842-vnc

This commit is contained in:
Mzack9999 2025-09-12 11:51:17 +02:00
commit 521a21c06a
41 changed files with 2097 additions and 251 deletions

76
.github/DISCUSSION_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,76 @@
# Nuclei Discussion Guidelines
## Before Creating a Discussion
1. **Search existing discussions and issues** to avoid duplicates
2. **Check the documentation** and README first
3. **Browse the FAQ** and common questions
## Bug Reports in Discussions
When reporting a bug in [Q&A Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/q-a), please include:
### Required Information:
- **Clear title** with `[BUG]` prefix (e.g., "[BUG] Nuclei crashes when...")
- **Current behavior** - What's happening now?
- **Expected behavior** - What should happen instead?
- **Steps to reproduce** - Commands or actions that trigger the issue
- **Environment details**:
- OS and version
- Nuclei version (`nuclei -version`)
- Go version (if installed via `go install`)
- **Log output** - Run with `-verbose` or `-debug` for detailed logs
- **Redact sensitive information** - Remove target URLs, credentials, etc.
### After Discussion:
- Maintainers will review and validate the bug report
- Valid bugs will be converted to issues with proper labels and tracking
- Questions and misconfigurations will be resolved in the discussion
## Feature Requests in Discussions
When requesting a feature in [Ideas Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/ideas), please include:
### Required Information:
- **Clear title** with `[FEATURE]` prefix (e.g., "[FEATURE] Add support for...")
- **Feature description** - What do you want to be added?
- **Use case** - Why is this feature needed? What problem does it solve?
- **Implementation ideas** - If you have suggestions on how it could work
- **Alternatives considered** - What other solutions have you thought about?
### After Discussion:
- Community and maintainers will discuss the feasibility
- Popular and viable features will be converted to issues
- Similar features may be grouped together
- Rejected features will be explained in the discussion
## Getting Help
For general questions, troubleshooting, and "how-to" topics:
- Use [Q&A Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/q-a)
- Join the [Discord server](https://discord.gg/projectdiscovery) #nuclei channel
- Check existing discussions for similar questions
## Discussion to Issue Conversion Process
Only maintainers can convert discussions to issues. The process:
1. **Validation** - Maintainers review the discussion for completeness and validity
2. **Classification** - Determine if it's a bug, feature, enhancement, etc.
3. **Issue creation** - Create a properly formatted issue with appropriate labels
4. **Linking** - Link the issue back to the original discussion
5. **Resolution** - Mark the discussion as resolved or close it
This process ensures:
- High-quality issues that are actionable
- Proper triage and labeling
- Reduced noise in the issue tracker
- Community involvement in the validation process
## Why This Process?
- **Better organization** - Issues contain only validated, actionable items
- **Community input** - Discussions allow for community feedback before escalation
- **Quality control** - Maintainers ensure proper formatting and information
- **Reduced maintenance** - Fewer invalid or duplicate issues to manage
- **Clear separation** - Questions vs. actual bugs/features are clearly distinguished

View File

@ -2,14 +2,22 @@ blank_issues_enabled: false
contact_links: contact_links:
- name: Ask an question / advise on using nuclei - name: 🐛 Report a Bug (Start with Discussion)
url: https://github.com/projectdiscovery/nuclei/discussions/categories/q-a url: https://github.com/orgs/projectdiscovery/discussions/new?category=q-a
about: Ask a question or request support for using nuclei about: Start by reporting your issue in discussions for proper triage. Issues will be created after review to avoid duplicate/invalid reports.
- name: Share idea / feature to discuss for nuclei - name: 💡 Request a Feature (Start with Discussion)
url: https://github.com/projectdiscovery/nuclei/discussions/categories/ideas url: https://github.com/orgs/projectdiscovery/discussions/new?category=ideas
about: Share idea / feature to discuss for nuclei about: Share your feature idea in discussions first. This helps validate and refine the request before creating an issue.
- name: Connect with PD Team (Discord) - name: ❓ Ask Questions / Get Help
url: https://github.com/orgs/projectdiscovery/discussions
about: Get help and ask questions about using Nuclei. Many questions don't require issues.
- name: 🔍 Browse Existing Issues
url: https://github.com/projectdiscovery/nuclei/issues
about: Check existing issues to see if your problem has already been reported or is being worked on.
- name: 💬 Connect with PD Team (Discord)
url: https://discord.gg/projectdiscovery url: https://discord.gg/projectdiscovery
about: Connect with PD Team for direct communication about: Join our Discord for real-time discussions and community support on the #nuclei channel.

View File

@ -0,0 +1,45 @@
# Issue Template References
## Overview
This folder contains the preserved issue templates that are **not** directly accessible to users. These templates serve as references for maintainers when converting discussions to issues.
## New Workflow
### For Users:
1. **All reports start in Discussions** - Users cannot create issues directly
2. Bug reports go to [Q&A Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/q-a)
3. Feature requests go to [Ideas Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/ideas)
4. This helps filter out duplicate questions, invalid reports, and ensures proper triage
### For Maintainers:
1. **Review discussions** in both Q&A and Ideas categories
2. **Validate the reports** - ensure they're actual bugs/valid feature requests
3. **Use reference templates** when converting discussions to issues:
- Copy content from `bug-report-reference.yml` or `feature-request-reference.yml`
- Create a new issue manually with the appropriate template structure
- Link back to the original discussion
- Close the discussion or mark it as resolved
## Benefits
- **Better triage**: Avoid cluttering issues with questions and invalid reports
- **Community involvement**: Discussions allow for community input before creating issues
- **Quality control**: Maintainers can ensure issues follow proper format and contain necessary information
- **Reduced noise**: Only validated, actionable items become issues
## Reference Templates
- `bug-report-reference.yml` - Use when converting bug reports from discussions to issues
- `feature-request-reference.yml` - Use when converting feature requests from discussions to issues
## Converting a Discussion to Issue
1. Identify a valid discussion that needs to become an issue
2. Go to the main repository's Issues tab
3. Click "New Issue"
4. Manually create the issue using the reference template structure
5. Include all relevant information from the discussion
6. Add a comment linking back to the original discussion
7. Apply appropriate labels
8. Close or mark the discussion as resolved with a link to the created issue

View File

@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]' if: github.actor == 'dependabot[bot]'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
token: ${{ secrets.DEPENDABOT_PAT }} token: ${{ secrets.DEPENDABOT_PAT }}

View File

@ -13,7 +13,7 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go/compat-checks@v1 - uses: projectdiscovery/actions/setup/go/compat-checks@v1
with: with:
release-test: true release-test: true

View File

@ -11,7 +11,7 @@ jobs:
if: "${{ !endsWith(github.actor, '[bot]') }}" if: "${{ !endsWith(github.actor, '[bot]') }}"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/setup/git@v1 - uses: projectdiscovery/actions/setup/git@v1
- run: make syntax-docs - run: make syntax-docs

View File

@ -28,7 +28,7 @@ jobs:
LIST_FILE: "/tmp/targets-${{ matrix.targets }}.txt" LIST_FILE: "/tmp/targets-${{ matrix.targets }}.txt"
PROFILE_MEM: "/tmp/nuclei-profile-${{ matrix.targets }}-targets" PROFILE_MEM: "/tmp/nuclei-profile-${{ matrix.targets }}-targets"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/git@v1 - uses: projectdiscovery/actions/setup/git@v1
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- name: Generate list - name: Generate list

View File

@ -16,7 +16,7 @@ jobs:
env: env:
OUTPUT: "/tmp/results.sarif" OUTPUT: "/tmp/results.sarif"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- run: go install golang.org/x/vuln/cmd/govulncheck@latest - run: go install golang.org/x/vuln/cmd/govulncheck@latest
- run: govulncheck -scan package -format sarif ./... > $OUTPUT - run: govulncheck -scan package -format sarif ./... > $OUTPUT

View File

@ -11,7 +11,7 @@ jobs:
env: env:
BENCH_OUT: "/tmp/bench.out" BENCH_OUT: "/tmp/bench.out"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- run: make build-test - run: make build-test
- run: ./bin/nuclei.test -test.run - -test.bench=. -test.benchmem ./cmd/nuclei/ | tee $BENCH_OUT - run: ./bin/nuclei.test -test.run - -test.bench=. -test.benchmem ./cmd/nuclei/ | tee $BENCH_OUT

View File

@ -16,7 +16,7 @@ jobs:
LIST_FILE: "/tmp/targets-${{ matrix.count }}.txt" LIST_FILE: "/tmp/targets-${{ matrix.count }}.txt"
PROFILE_MEM: "/tmp/nuclei-perf-test-${{ matrix.count }}" PROFILE_MEM: "/tmp/nuclei-perf-test-${{ matrix.count }}"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- run: make verify - run: make verify
- name: Generate list - name: Generate list

View File

@ -10,7 +10,7 @@ jobs:
release: release:
runs-on: ubuntu-latest-16-cores runs-on: ubuntu-latest-16-cores
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1

View File

@ -13,7 +13,7 @@ jobs:
issues: write issues: write
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v10
with: with:
days-before-stale: 90 days-before-stale: 90
days-before-close: 7 days-before-close: 7

View File

@ -22,7 +22,7 @@ jobs:
if: "${{ !endsWith(github.actor, '[bot]') }}" if: "${{ !endsWith(github.actor, '[bot]') }}"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/golangci-lint/v2@v1 - uses: projectdiscovery/actions/golangci-lint/v2@v1
@ -35,7 +35,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: "${{ matrix.os }}" runs-on: "${{ matrix.os }}"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- run: make vet - run: make vet
- run: make build - run: make build
@ -52,7 +52,7 @@ jobs:
needs: ["tests"] needs: ["tests"]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- name: "Simple" - name: "Simple"
run: go run . run: go run .
@ -74,7 +74,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/setup/python@v1 - uses: projectdiscovery/actions/setup/python@v1
- run: bash run.sh "${{ matrix.os }}" - run: bash run.sh "${{ matrix.os }}"
@ -93,7 +93,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/setup/python@v1 - uses: projectdiscovery/actions/setup/python@v1
- run: bash run.sh - run: bash run.sh
@ -106,7 +106,7 @@ jobs:
needs: ["tests"] needs: ["tests"]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- run: make template-validate - run: make template-validate
@ -119,7 +119,7 @@ jobs:
contents: read contents: read
security-events: write security-events: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: github/codeql-action/init@v3 - uses: github/codeql-action/init@v3
with: with:
languages: 'go' languages: 'go'
@ -131,7 +131,7 @@ jobs:
needs: ["tests"] needs: ["tests"]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/goreleaser@v1 - uses: projectdiscovery/actions/goreleaser@v1
@ -143,7 +143,7 @@ jobs:
TARGET_URL: "http://scanme.sh/a/?b=c" TARGET_URL: "http://scanme.sh/a/?b=c"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- run: make build - run: make build
- name: "Setup environment (push)" - name: "Setup environment (push)"
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}

View File

@ -0,0 +1,104 @@
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/mongo"
"github.com/testcontainers/testcontainers-go"
mongocontainer "github.com/testcontainers/testcontainers-go/modules/mongodb"
osutil "github.com/projectdiscovery/utils/os"
mongoclient "go.mongodb.org/mongo-driver/mongo"
mongooptions "go.mongodb.org/mongo-driver/mongo/options"
)
const (
dbName = "test"
dbImage = "mongo:8"
)
var exportersTestCases = []TestCaseInfo{
{Path: "exporters/mongo", TestCase: &mongoExporter{}, DisableOn: func() bool {
return osutil.IsWindows() || osutil.IsOSX()
}},
}
type mongoExporter struct{}
func (m *mongoExporter) Execute(filepath string) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
// Start a MongoDB container
mongodbContainer, err := mongocontainer.Run(ctx, dbImage)
defer func() {
if err := testcontainers.TerminateContainer(mongodbContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
return fmt.Errorf("failed to start container: %w", err)
}
connString, err := mongodbContainer.ConnectionString(ctx)
if err != nil {
return fmt.Errorf("failed to get connection string for MongoDB container: %s", err)
}
connString = connString + dbName
// Create a MongoDB exporter and write a test result to the database
opts := mongo.Options{
ConnectionString: connString,
CollectionName: "test",
BatchSize: 1, // Ensure we write the result immediately
}
exporter, err := mongo.New(&opts)
if err != nil {
return fmt.Errorf("failed to create MongoDB exporter: %s", err)
}
defer func() {
if err := exporter.Close(); err != nil {
fmt.Printf("failed to close exporter: %s\n", err)
}
}()
res := &output.ResultEvent{
Request: "test request",
Response: "test response",
}
err = exporter.Export(res)
if err != nil {
return fmt.Errorf("failed to export result event to MongoDB: %s", err)
}
// Verify that the result was written to the database
clientOptions := mongooptions.Client().ApplyURI(connString)
client, err := mongoclient.Connect(ctx, clientOptions)
if err != nil {
return fmt.Errorf("error creating MongoDB client: %s", err)
}
defer func() {
if err := client.Disconnect(ctx); err != nil {
fmt.Printf("failed to disconnect from MongoDB: %s\n", err)
}
}()
collection := client.Database(dbName).Collection(opts.CollectionName)
var actualRes output.ResultEvent
err = collection.FindOne(ctx, map[string]interface{}{"request": res.Request}).Decode(&actualRes)
if err != nil {
return fmt.Errorf("failed to find document in MongoDB: %s", err)
}
if actualRes.Request != res.Request || actualRes.Response != res.Response {
return fmt.Errorf("exported result does not match expected result: got %v, want %v", actualRes, res)
}
return nil
}

View File

@ -57,6 +57,7 @@ var (
"flow": flowTestcases, "flow": flowTestcases,
"javascript": jsTestcases, "javascript": jsTestcases,
"matcher-status": matcherStatusTestcases, "matcher-status": matcherStatusTestcases,
"exporters": exportersTestCases,
} }
// flakyTests are run with a retry count of 3 // flakyTests are run with a retry count of 3
flakyTests = map[string]bool{ flakyTests = map[string]bool{

View File

@ -15,12 +15,14 @@ var jsTestcases = []TestCaseInfo{
{Path: "protocols/javascript/ssh-server-fingerprint.yaml", TestCase: &javascriptSSHServerFingerprint{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "protocols/javascript/ssh-server-fingerprint.yaml", TestCase: &javascriptSSHServerFingerprint{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/javascript/net-multi-step.yaml", TestCase: &networkMultiStep{}}, {Path: "protocols/javascript/net-multi-step.yaml", TestCase: &networkMultiStep{}},
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}}, {Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}},
{Path: "protocols/javascript/oracle-auth-test.yaml", TestCase: &javascriptOracleAuthTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/javascript/vnc-pass-brute.yaml", TestCase: &javascriptVncPassBrute{}}, {Path: "protocols/javascript/vnc-pass-brute.yaml", TestCase: &javascriptVncPassBrute{}},
} }
var ( var (
redisResource *dockertest.Resource redisResource *dockertest.Resource
sshResource *dockertest.Resource sshResource *dockertest.Resource
oracleResource *dockertest.Resource
vncResource *dockertest.Resource vncResource *dockertest.Resource
pool *dockertest.Pool pool *dockertest.Pool
defaultRetry = 3 defaultRetry = 3
@ -100,6 +102,39 @@ func (j *javascriptSSHServerFingerprint) Execute(filePath string) error {
return multierr.Combine(errs...) return multierr.Combine(errs...)
} }
type javascriptOracleAuthTest struct{}
func (j *javascriptOracleAuthTest) Execute(filePath string) error {
if oracleResource == nil || pool == nil {
// skip test as oracle is not running
return nil
}
tempPort := oracleResource.GetPort("1521/tcp")
finalURL := "localhost:" + tempPort
defer purge(oracleResource)
errs := []error{}
for i := 0; i < defaultRetry; i++ {
results := []string{}
var err error
_ = pool.Retry(func() error {
//let ssh server start
time.Sleep(3 * time.Second)
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
return nil
})
if err != nil {
return err
}
if err := expectResultsCount(results, 1); err == nil {
return nil
} else {
errs = append(errs, err)
}
}
return multierr.Combine(errs...)
}
type javascriptVncPassBrute struct{} type javascriptVncPassBrute struct{}
func (j *javascriptVncPassBrute) Execute(filePath string) error { func (j *javascriptVncPassBrute) Execute(filePath string) error {
@ -198,6 +233,25 @@ func init() {
log.Printf("Could not expire resource: %s", err) log.Printf("Could not expire resource: %s", err)
} }
// setup a temporary oracle instance
oracleResource, err = pool.RunWithOptions(&dockertest.RunOptions{
Repository: "gvenzl/oracle-xe",
Tag: "latest",
Env: []string{
"ORACLE_PASSWORD=mysecret",
},
Platform: "linux/amd64",
})
if err != nil {
log.Printf("Could not start Oracle resource: %s", err)
return
}
// by default expire after 30 sec
if err := oracleResource.Expire(30); err != nil {
log.Printf("Could not expire Oracle resource: %s", err)
}
// setup a temporary vnc server // setup a temporary vnc server
vncResource, err = pool.RunWithOptions(&dockertest.RunOptions{ vncResource, err = pool.RunWithOptions(&dockertest.RunOptions{
Repository: "dorowu/ubuntu-desktop-lxde-vnc", Repository: "dorowu/ubuntu-desktop-lxde-vnc",

View File

@ -20,6 +20,7 @@ import (
_ "github.com/projectdiscovery/utils/pprof" _ "github.com/projectdiscovery/utils/pprof"
stringsutil "github.com/projectdiscovery/utils/strings" stringsutil "github.com/projectdiscovery/utils/strings"
"github.com/rs/xid" "github.com/rs/xid"
"gopkg.in/yaml.v2"
"github.com/projectdiscovery/goflags" "github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/gologger/levels" "github.com/projectdiscovery/gologger/levels"
@ -263,6 +264,8 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.InputFileMode, "input-mode", "im", "list", fmt.Sprintf("mode of input file (%v)", provider.SupportedInputFormats())), flagSet.StringVarP(&options.InputFileMode, "input-mode", "im", "list", fmt.Sprintf("mode of input file (%v)", provider.SupportedInputFormats())),
flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"), flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"), flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
flagSet.BoolVarP(&options.VarsTextTemplating, "vars-text-templating", "vtt", false, "enable text templating for vars in input file (only for yaml input mode)"),
flagSet.StringSliceVarP(&options.VarsFilePaths, "var-file-paths", "vfp", nil, "list of yaml file contained vars to inject into yaml input", goflags.CommaSeparatedStringSliceOptions),
) )
flagSet.CreateGroup("templates", "Templates", flagSet.CreateGroup("templates", "Templates",
@ -571,6 +574,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
config.DefaultConfig.SetConfigDir(customConfigDir) config.DefaultConfig.SetConfigDir(customConfigDir)
readFlagsConfig(flagSet) readFlagsConfig(flagSet)
} }
if cfgFile != "" { if cfgFile != "" {
if !fileutil.FileExists(cfgFile) { if !fileutil.FileExists(cfgFile) {
options.Logger.Fatal().Msgf("given config file '%s' does not exist", cfgFile) options.Logger.Fatal().Msgf("given config file '%s' does not exist", cfgFile)
@ -579,6 +583,41 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
if err := flagSet.MergeConfigFile(cfgFile); err != nil { if err := flagSet.MergeConfigFile(cfgFile); err != nil {
options.Logger.Fatal().Msgf("Could not read config: %s\n", err) options.Logger.Fatal().Msgf("Could not read config: %s\n", err)
} }
if !options.Vars.IsEmpty() {
// Maybe we should add vars to the config file as well even if they are set via flags?
file, err := os.Open(cfgFile)
if err != nil {
gologger.Fatal().Msgf("Could not open config file: %s\n", err)
}
defer func() {
_ = file.Close()
}()
data := make(map[string]interface{})
err = yaml.NewDecoder(file).Decode(&data)
if err != nil {
gologger.Fatal().Msgf("Could not decode config file: %s\n", err)
}
variables := data["var"]
if variables != nil {
if varSlice, ok := variables.([]interface{}); ok {
for _, value := range varSlice {
if strVal, ok := value.(string); ok {
err = options.Vars.Set(strVal)
if err != nil {
gologger.Warning().Msgf("Could not set variable from config file: %s\n", err)
}
} else {
gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
}
}
} else {
gologger.Warning().Msgf("No 'var' section found in config file: %s", cfgFile)
}
}
}
} }
if options.NewTemplatesDirectory != "" { if options.NewTemplatesDirectory != "" {
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory) config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)

135
go.mod
View File

@ -1,6 +1,8 @@
module github.com/projectdiscovery/nuclei/v3 module github.com/projectdiscovery/nuclei/v3
go 1.24.1 go 1.24.2
toolchain go1.24.4
require ( require (
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
@ -20,12 +22,12 @@ require (
github.com/olekukonko/tablewriter v1.0.8 github.com/olekukonko/tablewriter v1.0.8
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/projectdiscovery/clistats v0.1.1 github.com/projectdiscovery/clistats v0.1.1
github.com/projectdiscovery/fastdialer v0.4.6 github.com/projectdiscovery/fastdialer v0.4.9
github.com/projectdiscovery/hmap v0.0.92 github.com/projectdiscovery/hmap v0.0.93
github.com/projectdiscovery/interactsh v1.2.4 github.com/projectdiscovery/interactsh v1.2.4
github.com/projectdiscovery/rawhttp v0.1.90 github.com/projectdiscovery/rawhttp v0.1.90
github.com/projectdiscovery/retryabledns v1.0.105 github.com/projectdiscovery/retryabledns v1.0.107
github.com/projectdiscovery/retryablehttp-go v1.0.120 github.com/projectdiscovery/retryablehttp-go v1.0.123
github.com/projectdiscovery/yamldoc-go v1.0.6 github.com/projectdiscovery/yamldoc-go v1.0.6
github.com/remeh/sizedwaitgroup v1.0.0 github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.6.0 github.com/rs/xid v1.6.0
@ -35,26 +37,27 @@ require (
github.com/spf13/cast v1.9.2 github.com/spf13/cast v1.9.2
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
github.com/valyala/fasttemplate v1.2.2 github.com/valyala/fasttemplate v1.2.2
github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39 github.com/weppos/publicsuffix-go v0.50.0
go.uber.org/multierr v1.11.0 go.uber.org/multierr v1.11.0
golang.org/x/net v0.41.0 golang.org/x/net v0.43.0
golang.org/x/oauth2 v0.30.0 golang.org/x/oauth2 v0.30.0
golang.org/x/text v0.26.0 golang.org/x/text v0.29.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
require ( require (
code.gitea.io/sdk/gitea v0.21.0 carvel.dev/ytt v0.52.0
code.gitea.io/sdk/gitea v0.17.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0
github.com/DataDog/gostackparse v0.7.0 github.com/DataDog/gostackparse v0.7.0
github.com/Masterminds/semver/v3 v3.4.0 github.com/Masterminds/semver/v3 v3.2.1
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057
github.com/Mzack9999/goja v0.0.0-20250507184235-e46100e9c697 github.com/Mzack9999/goja v0.0.0-20250507184235-e46100e9c697
github.com/Mzack9999/goja_nodejs v0.0.0-20250507184139-66bcbf65c883 github.com/Mzack9999/goja_nodejs v0.0.0-20250507184139-66bcbf65c883
github.com/alitto/pond v1.9.2 github.com/alitto/pond v1.9.2
github.com/antchfx/xmlquery v1.4.4 github.com/antchfx/xmlquery v1.4.4
github.com/antchfx/xpath v1.3.4 github.com/antchfx/xpath v1.3.3
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
github.com/aws/aws-sdk-go-v2 v1.36.5 github.com/aws/aws-sdk-go-v2 v1.36.5
github.com/aws/aws-sdk-go-v2/config v1.29.17 github.com/aws/aws-sdk-go-v2/config v1.29.17
@ -87,49 +90,51 @@ require (
github.com/microsoft/go-mssqldb v1.9.2 github.com/microsoft/go-mssqldb v1.9.2
github.com/ory/dockertest/v3 v3.12.0 github.com/ory/dockertest/v3 v3.12.0
github.com/praetorian-inc/fingerprintx v1.1.15 github.com/praetorian-inc/fingerprintx v1.1.15
github.com/projectdiscovery/dsl v0.5.0 github.com/projectdiscovery/dsl v0.6.0
github.com/projectdiscovery/fasttemplate v0.0.2 github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/gcache v0.0.0-20241015120333-12546c6e3f4c github.com/projectdiscovery/gcache v0.0.0-20241015120333-12546c6e3f4c
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
github.com/projectdiscovery/goflags v0.1.74 github.com/projectdiscovery/goflags v0.1.74
github.com/projectdiscovery/gologger v1.1.54 github.com/projectdiscovery/gologger v1.1.54
github.com/projectdiscovery/gostruct v0.0.2 github.com/projectdiscovery/gostruct v0.0.2
github.com/projectdiscovery/gozero v0.0.3 github.com/projectdiscovery/gozero v0.1.0
github.com/projectdiscovery/httpx v1.7.0 github.com/projectdiscovery/httpx v1.7.2-0.20250911192144-fc425deb041a
github.com/projectdiscovery/mapcidr v1.1.34 github.com/projectdiscovery/mapcidr v1.1.34
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
github.com/projectdiscovery/networkpolicy v0.1.20 github.com/projectdiscovery/networkpolicy v0.1.23
github.com/projectdiscovery/ratelimit v0.0.81 github.com/projectdiscovery/ratelimit v0.0.82
github.com/projectdiscovery/rdap v0.9.0 github.com/projectdiscovery/rdap v0.9.0
github.com/projectdiscovery/sarif v0.0.1 github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.1.9 github.com/projectdiscovery/tlsx v1.2.1
github.com/projectdiscovery/uncover v1.1.0 github.com/projectdiscovery/uncover v1.1.0
github.com/projectdiscovery/useragent v0.0.101 github.com/projectdiscovery/useragent v0.0.101
github.com/projectdiscovery/utils v0.4.24-0.20250823123502-bd7f2849ddb4 github.com/projectdiscovery/utils v0.5.0
github.com/projectdiscovery/wappalyzergo v0.2.36 github.com/projectdiscovery/wappalyzergo v0.2.45
github.com/redis/go-redis/v9 v9.11.0 github.com/redis/go-redis/v9 v9.11.0
github.com/seh-msft/burpxml v1.0.1 github.com/seh-msft/burpxml v1.0.1
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
github.com/stretchr/testify v1.10.0 github.com/sijms/go-ora/v2 v2.9.0
github.com/stretchr/testify v1.11.1
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9 github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
github.com/testcontainers/testcontainers-go v0.38.0
github.com/testcontainers/testcontainers-go/modules/mongodb v0.37.0
github.com/yassinebenaid/godump v0.11.1 github.com/yassinebenaid/godump v0.11.1
github.com/zmap/zgrab2 v0.1.8 github.com/zmap/zgrab2 v0.1.8
gitlab.com/gitlab-org/api/client-go v0.130.1 gitlab.com/gitlab-org/api/client-go v0.130.1
go.mongodb.org/mongo-driver v1.17.4 go.mongodb.org/mongo-driver v1.17.4
golang.org/x/term v0.32.0 golang.org/x/term v0.34.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
moul.io/http2curl v1.0.0 moul.io/http2curl v1.0.0
) )
require ( require (
aead.dev/minisign v0.2.0 // indirect aead.dev/minisign v0.2.0 // indirect
dario.cat/mergo v1.0.0 // indirect dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a // indirect git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a // indirect
github.com/42wim/httpsig v1.2.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
@ -180,27 +185,35 @@ require (
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/cheggaaa/pb/v3 v3.1.4 // indirect github.com/cheggaaa/pb/v3 v3.1.6 // indirect
github.com/cloudflare/cfssl v1.6.4 // indirect github.com/cloudflare/cfssl v1.6.4 // indirect
github.com/cloudflare/circl v1.6.1 // indirect github.com/cloudflare/circl v1.6.1 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
github.com/containerd/continuity v0.4.5 // indirect github.com/containerd/continuity v0.4.5 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/docker/cli v27.4.1+incompatible // indirect github.com/docker/cli v27.4.1+incompatible // indirect
github.com/docker/docker v28.0.0+incompatible // indirect github.com/docker/docker v28.3.3+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-connections v0.6.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fatih/color v1.18.0 // indirect
github.com/felixge/fgprof v0.9.5 // indirect github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gaissmai/bart v0.23.1 // indirect github.com/gaissmai/bart v0.24.0 // indirect
github.com/geoffgarside/ber v1.1.0 // indirect github.com/geoffgarside/ber v1.1.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect github.com/gin-gonic/gin v1.9.1 // indirect
@ -208,20 +221,22 @@ require (
github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.1.4 // indirect github.com/google/certificate-transparency-go v1.3.2 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
@ -244,6 +259,7 @@ require (
github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 // indirect
github.com/kataras/jwt v0.1.10 // indirect github.com/kataras/jwt v0.1.10 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/compress v1.18.0 // indirect
@ -256,8 +272,9 @@ require (
github.com/logrusorgru/aurora/v4 v4.0.0 // indirect github.com/logrusorgru/aurora/v4 v4.0.0 // indirect
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lufia/plan9stats v0.0.0-20250821153705-5981dea3221d // indirect
github.com/mackerelio/go-osstat v0.2.4 // indirect github.com/mackerelio/go-osstat v0.2.4 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
@ -269,12 +286,17 @@ require (
github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/user v0.3.0 // indirect github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect github.com/montanaflynn/stats v0.7.1 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.16.0 // indirect github.com/muesli/termenv v0.16.0 // indirect
github.com/nwaples/rardecode/v2 v2.1.0 // indirect github.com/nwaples/rardecode/v2 v2.1.0 // indirect
@ -283,7 +305,7 @@ require (
github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect github.com/olekukonko/ll v0.0.9 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runc v1.2.3 // indirect github.com/opencontainers/runc v1.2.3 // indirect
github.com/openrdap/rdap v0.9.1 // indirect github.com/openrdap/rdap v0.9.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
@ -292,10 +314,10 @@ require (
github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/projectdiscovery/asnmap v1.1.1 // indirect github.com/projectdiscovery/asnmap v1.1.1 // indirect
github.com/projectdiscovery/blackrock v0.0.1 // indirect github.com/projectdiscovery/blackrock v0.0.1 // indirect
github.com/projectdiscovery/cdncheck v1.1.26 // indirect github.com/projectdiscovery/cdncheck v1.1.35 // indirect
github.com/projectdiscovery/freeport v0.0.7 // indirect github.com/projectdiscovery/freeport v0.0.7 // indirect
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect
github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect
@ -303,6 +325,7 @@ require (
github.com/sashabaranov/go-openai v1.37.0 // indirect github.com/sashabaranov/go-openai v1.37.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shirou/gopsutil/v4 v4.25.7 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect github.com/skeema/knownhosts v1.3.1 // indirect
@ -316,11 +339,11 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tklauser/numcpus v0.10.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect github.com/ulikunitz/xz v0.5.15 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
@ -334,13 +357,18 @@ require (
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/ysmood/fetchup v0.2.3 // indirect github.com/ysmood/fetchup v0.2.3 // indirect
github.com/ysmood/got v0.40.0 // indirect github.com/ysmood/got v0.40.0 // indirect
github.com/yuin/goldmark v1.7.8 // indirect github.com/yuin/goldmark v1.7.13 // indirect
github.com/yuin/goldmark-emoji v1.0.5 // indirect github.com/yuin/goldmark-emoji v1.0.5 // indirect
github.com/zcalusic/sysinfo v1.0.2 // indirect github.com/zcalusic/sysinfo v1.0.2 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect github.com/zeebo/blake3 v0.2.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/sync v0.15.0 // indirect golang.org/x/sync v0.17.0 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect
mellium.im/sasl v0.3.2 // indirect mellium.im/sasl v0.3.2 // indirect
) )
@ -361,16 +389,16 @@ require (
github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect
github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db // indirect github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db // indirect
go.etcd.io/bbolt v1.3.10 // indirect go.etcd.io/bbolt v1.4.0 // indirect
go.uber.org/zap v1.25.0 // indirect go.uber.org/zap v1.27.0 // indirect
goftp.io/server/v2 v2.0.1 // indirect goftp.io/server/v2 v2.0.1 // indirect
golang.org/x/crypto v0.39.0 // indirect golang.org/x/crypto v0.41.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
golang.org/x/mod v0.25.0 // indirect golang.org/x/mod v0.27.0 // indirect
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.35.0 // indirect
golang.org/x/time v0.11.0 // indirect golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.34.0 golang.org/x/tools v0.36.0
google.golang.org/protobuf v1.35.1 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
) )
@ -383,3 +411,10 @@ require (
// https://go.dev/ref/mod#go-mod-file-retract // https://go.dev/ref/mod#go-mod-file-retract
retract v3.2.0 // retract due to broken js protocol issue retract v3.2.0 // retract due to broken js protocol issue
// Fix genproto version conflicts
replace (
google.golang.org/genproto => google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142
google.golang.org/genproto/googleapis/api => google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142
google.golang.org/genproto/googleapis/rpc => google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1
)

1227
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
id: fuzz-body
info:
name: fuzzing error sqli payloads in http req body
author: pdteam
severity: info
description: |
This template attempts to find SQL injection vulnerabilities by fuzzing http body
It automatically handles and parses json,xml,multipart form and x-www-form-urlencoded data
and performs fuzzing on the value of every key
http:
- pre-condition:
- type: dsl
dsl:
- method != "GET"
- method != "HEAD"
condition: and
payloads:
injection:
- "'"
- "\""
- ";"
fuzzing:
- part: body
type: postfix
mode: single
fuzz:
- '{{injection}}'
stop-at-first-match: true
matchers:
- type: word
words:
- "unrecognized token:"
- "null"

View File

@ -25,6 +25,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/workflows" "github.com/projectdiscovery/nuclei/v3/pkg/workflows"
"github.com/projectdiscovery/retryablehttp-go" "github.com/projectdiscovery/retryablehttp-go"
"github.com/projectdiscovery/utils/errkit" "github.com/projectdiscovery/utils/errkit"
mapsutil "github.com/projectdiscovery/utils/maps"
sliceutil "github.com/projectdiscovery/utils/slice" sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings" stringsutil "github.com/projectdiscovery/utils/strings"
syncutil "github.com/projectdiscovery/utils/sync" syncutil "github.com/projectdiscovery/utils/sync"
@ -315,6 +316,8 @@ func (store *Store) LoadTemplatesOnlyMetadata() error {
} }
templatesCache := parserItem.Cache() templatesCache := parserItem.Cache()
loadedTemplateIDs := mapsutil.NewSyncLockMap[string, struct{}]()
for templatePath := range validPaths { for templatePath := range validPaths {
template, _, _ := templatesCache.Has(templatePath) template, _, _ := templatesCache.Has(templatePath)
@ -339,6 +342,12 @@ func (store *Store) LoadTemplatesOnlyMetadata() error {
} }
if template != nil { if template != nil {
if loadedTemplateIDs.Has(template.ID) {
store.logger.Debug().Msgf("Skipping duplicate template ID '%s' from path '%s'", template.ID, templatePath)
continue
}
_ = loadedTemplateIDs.Set(template.ID, struct{}{})
template.Path = templatePath template.Path = templatePath
store.templates = append(store.templates, template) store.templates = append(store.templates, template)
} }
@ -492,8 +501,16 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
templatePathMap := store.pathFilter.Match(includedTemplates) templatePathMap := store.pathFilter.Match(includedTemplates)
loadedTemplates := sliceutil.NewSyncSlice[*templates.Template]() loadedTemplates := sliceutil.NewSyncSlice[*templates.Template]()
loadedTemplateIDs := mapsutil.NewSyncLockMap[string, struct{}]()
loadTemplate := func(tmpl *templates.Template) { loadTemplate := func(tmpl *templates.Template) {
if loadedTemplateIDs.Has(tmpl.ID) {
store.logger.Debug().Msgf("Skipping duplicate template ID '%s' from path '%s'", tmpl.ID, tmpl.Path)
return
}
_ = loadedTemplateIDs.Set(tmpl.ID, struct{}{})
loadedTemplates.Append(tmpl) loadedTemplates.Append(tmpl)
// increment signed/unsigned counters // increment signed/unsigned counters
if tmpl.Verified { if tmpl.Verified {

View File

@ -28,6 +28,12 @@ type InputFormatOptions struct {
// RequiredOnly only uses required fields when generating requests // RequiredOnly only uses required fields when generating requests
// instead of all fields // instead of all fields
RequiredOnly bool RequiredOnly bool
// VarsTextTemplating uses Variables and inject it into the input
// this is used for text templating of variables based on carvel ytt
// Only available for Yaml formats
VarsTextTemplating bool
// VarsFilePaths is the path to the file containing variables
VarsFilePaths []string
} }
// Format is an interface implemented by all input formats // Format is an interface implemented by all input formats

View File

@ -0,0 +1,25 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:json", "json")
#@ def get_value(key, default=""):
#@ if hasattr(data.values, key):
#@ return str(getattr(data.values, key))
#@ else:
#@ return default
#@ end
#@ end
timestamp: 2024-02-20T19:24:13+05:32
url: https://ginandjuice.shop/users/3
request:
#@yaml/text-templated-strings
raw: |+
POST /users/3 HTTP/1.1
Host: ginandjuice.shop
Authorization: Bearer (@= get_value("token", "3x4mpl3t0k3n") @)
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
foo=(@= json.encode(data.values.foo) @)&bar=(@= get_value("bar") @)&debug=(@= get_value("debug", "false") @)

View File

@ -0,0 +1,11 @@
list: pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
input-mode: yaml
templates:
- integration_tests/fuzz/fuzz-body.yaml
var:
- debug=true
- bar=bar
vars-text-templating: true
var-file-paths:
- pkg/input/formats/testdata/ytt/ytt-vars.yaml
dast: true

View File

@ -0,0 +1,3 @@
token: foobar
foo:
bar: baz

View File

@ -1,8 +1,8 @@
package yaml package yaml
import ( import (
"bytes"
"io" "io"
"strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
@ -46,23 +46,41 @@ func (j *YamlMultiDocFormat) SetOptions(options formats.InputFormatOptions) {
// Parse parses the input and calls the provided callback // Parse parses the input and calls the provided callback
// function for each RawRequest it discovers. // function for each RawRequest it discovers.
func (j *YamlMultiDocFormat) Parse(input io.Reader, resultsCb formats.ParseReqRespCallback, filePath string) error { func (j *YamlMultiDocFormat) Parse(input io.Reader, resultsCb formats.ParseReqRespCallback, filePath string) error {
decoder := YamlUtil.NewDecoder(input) finalInput := input
// Apply text templating if enabled
if j.opts.VarsTextTemplating {
data, err := io.ReadAll(input)
if err != nil {
return errors.Wrap(err, "could not read input")
}
tpl := []string{string(data)}
dvs := mapToKeyValueSlice(j.opts.Variables)
finalData, err := ytt(tpl, dvs, j.opts.VarsFilePaths)
if err != nil {
return errors.Wrap(err, "could not apply ytt templating")
}
finalInput = bytes.NewReader(finalData)
}
decoder := YamlUtil.NewDecoder(finalInput)
for { for {
var request proxifyRequest var request proxifyRequest
err := decoder.Decode(&request) if err := decoder.Decode(&request); err != nil {
if err == io.EOF { if err == io.EOF {
break break
} }
if err != nil { return errors.Wrap(err, "could not decode yaml file")
return errors.Wrap(err, "could not decode json file")
} }
if strings.TrimSpace(request.Request.Raw) == "" {
raw := request.Request.Raw
if raw == "" {
continue continue
} }
rawRequest, err := types.ParseRawRequestWithURL(request.Request.Raw, request.URL) rawRequest, err := types.ParseRawRequestWithURL(raw, request.URL)
if err != nil { if err != nil {
gologger.Warning().Msgf("multidoc-yaml: Could not parse raw request %s: %s\n", request.URL, err) gologger.Warning().Msgf("multidoc-yaml: Could not parse raw request %s: %s", request.URL, err)
continue continue
} }
resultsCb(rawRequest) resultsCb(rawRequest)

View File

@ -2,8 +2,10 @@ package yaml
import ( import (
"os" "os"
"strings"
"testing" "testing"
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
"github.com/projectdiscovery/nuclei/v3/pkg/input/types" "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -33,3 +35,48 @@ func TestYamlFormatterParse(t *testing.T) {
require.Len(t, urls, len(expectedUrls), "invalid number of urls") require.Len(t, urls, len(expectedUrls), "invalid number of urls")
require.ElementsMatch(t, urls, expectedUrls, "invalid urls") require.ElementsMatch(t, urls, expectedUrls, "invalid urls")
} }
func TestYamlFormatterParseWithVariables(t *testing.T) {
format := New()
proxifyYttFile := "../testdata/ytt/ginandjuice.ytt.yaml"
expectedUrls := []string{
"https://ginandjuice.shop/users/3",
}
format.SetOptions(formats.InputFormatOptions{
VarsTextTemplating: true,
Variables: map[string]interface{}{
"foo": "catalog",
"bar": "product",
},
})
file, err := os.Open(proxifyYttFile)
require.Nilf(t, err, "error opening proxify ytt input file: %v", err)
defer func() {
_ = file.Close()
}()
var urls []string
err = format.Parse(file, func(request *types.RequestResponse) bool {
urls = append(urls, request.URL.String())
expectedRaw := `POST /users/3 HTTP/1.1
Host: ginandjuice.shop
Authorization: Bearer 3x4mpl3t0k3n
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
foo="catalog"&bar=product&debug=false`
normalised := strings.ReplaceAll(request.Request.Raw, "\r\n", "\n")
require.Equal(t, expectedRaw, strings.TrimSuffix(normalised, "\n"), "request raw does not match expected value")
return false
}, proxifyYttFile)
require.Nilf(t, err, "error parsing yaml file: %v", err)
require.Len(t, urls, len(expectedUrls), "invalid number of urls")
require.ElementsMatch(t, urls, expectedUrls, "invalid urls")
}

View File

@ -0,0 +1,70 @@
package yaml
import (
"fmt"
"strings"
yttcmd "carvel.dev/ytt/pkg/cmd/template"
yttui "carvel.dev/ytt/pkg/cmd/ui"
yttfiles "carvel.dev/ytt/pkg/files"
"gopkg.in/yaml.v2"
)
func ytt(tpl, dvs []string, varFiles []string) ([]byte, error) {
// create and invoke ytt "template" command
templatingOptions := yttcmd.NewOptions()
input, err := templatesAsInput(tpl...)
if err != nil {
return nil, err
}
if len(varFiles) > 0 {
// Load vaarFiles into the templating options.
templatingOptions.DataValuesFlags.FromFiles = varFiles
}
// equivalent to `--data-value-yaml`
templatingOptions.DataValuesFlags.KVsFromYAML = dvs
// for in-memory use, pipe output to "/dev/null"
noopUI := yttui.NewCustomWriterTTY(false, noopWriter{}, noopWriter{})
// Evaluate the template given the configured data values...
output := templatingOptions.RunWithFiles(input, noopUI)
if output.Err != nil {
return nil, output.Err
}
return output.DocSet.AsBytes()
}
// templatesAsInput conveniently wraps one or more strings, each in a files.File, into a template.Input.
func templatesAsInput(tpl ...string) (yttcmd.Input, error) {
var files []*yttfiles.File
for i, t := range tpl {
// to make this less brittle, you'll probably want to use well-defined names for `path`, here, for each input.
// this matters when you're processing errors which report based on these paths.
file, err := yttfiles.NewFileFromSource(yttfiles.NewBytesSource(fmt.Sprintf("tpl%d.yml", i), []byte(t)))
if err != nil {
return yttcmd.Input{}, err
}
files = append(files, file)
}
return yttcmd.Input{Files: files}, nil
}
func mapToKeyValueSlice(m map[string]interface{}) []string {
var result []string
for k, v := range m {
y, _ := yaml.Marshal(v)
result = append(result, fmt.Sprintf("%s=%s", k, strings.TrimSpace(string(y))))
}
return result
}
type noopWriter struct{}
func (w noopWriter) Write(data []byte) (int, error) { return len(data), nil }

View File

@ -116,6 +116,8 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
Variables: generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()), Variables: generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()),
SkipFormatValidation: opts.Options.SkipFormatValidation, SkipFormatValidation: opts.Options.SkipFormatValidation,
RequiredOnly: opts.Options.FormatUseRequiredOnly, RequiredOnly: opts.Options.FormatUseRequiredOnly,
VarsTextTemplating: opts.Options.VarsTextTemplating,
VarsFilePaths: opts.Options.VarsFilePaths,
}, },
}) })
} }

View File

@ -15,12 +15,12 @@ func init() {
module.Set( module.Set(
gojs.Objects{ gojs.Objects{
// Functions // Functions
"IsOracle": lib_oracle.IsOracle,
// Var and consts // Var and consts
// Objects / Classes // Objects / Classes
"IsOracleResponse": gojs.GetClassConstructor[lib_oracle.IsOracleResponse](&lib_oracle.IsOracleResponse{}), "IsOracleResponse": gojs.GetClassConstructor[lib_oracle.IsOracleResponse](&lib_oracle.IsOracleResponse{}),
"OracleClient": gojs.GetClassConstructor[lib_oracle.OracleClient](&lib_oracle.OracleClient{}),
}, },
).Register() ).Register()
} }

View File

@ -1,33 +1,106 @@
/**
* IsOracle checks if a host is running an Oracle server
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const isOracle = oracle.IsOracle('acme.com', 1521);
* log(toJSON(isOracle));
* ```
*/
export function IsOracle(host: string, port: number): IsOracleResponse | null {
return null;
}
/** /**
* IsOracleResponse is the response from the IsOracle function. * IsOracleResponse is the response from the IsOracle function.
* this is returned by IsOracle function. * this is returned by IsOracle function.
* @example * @example
* ```javascript * ```javascript
* const oracle = require('nuclei/oracle'); * const oracle = require('nuclei/oracle');
* const isOracle = oracle.IsOracle('acme.com', 1521); * const client = new oracle.OracleClient();
* const isOracle = client.IsOracle('acme.com', 1521);
* ``` * ```
*/ */
export interface IsOracleResponse { export interface IsOracleResponse {
IsOracle?: boolean, IsOracle?: boolean,
Banner?: string, Banner?: string,
} }
/**
* Client is a client for Oracle database.
* Internally client uses go-ora driver.
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const client = new oracle.OracleClient();
* ```
*/
export class OracleClient {
// Constructor of OracleClient
constructor() {}
/**
* Connect connects to an Oracle database
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const client = new oracle.OracleClient();
* client.Connect('acme.com', 1521, 'XE', 'user', 'password');
* ```
*/
public Connect(host: string, port: number, serviceName: string, username: string, password: string): boolean | null {
return null;
}
/**
* ConnectWithDSN connects to an Oracle database using a DSN string
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const client = new oracle.OracleClient();
* client.ConnectWithDSN('oracle://user:password@host:port/service', 'SELECT @@version');
* ```
*/
public ConnectWithDSN(dsn: string): boolean | null {
return null;
}
/**
* IsOracle checks if a host is running an Oracle server
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const isOracle = oracle.IsOracle('acme.com', 1521);
* ```
*/
public IsOracle(host: string, port: number): IsOracleResponse | null {
return null;
}
/**
* ExecuteQuery connects to Oracle database using given credentials and executes a query.
* It returns the results of the query or an error if something goes wrong.
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const client = new oracle.OracleClient();
* const result = client.ExecuteQuery('acme.com', 1521, 'username', 'password', 'XE', 'SELECT * FROM dual');
* log(to_json(result));
* ```
*/
public ExecuteQuery(host: string, port: number, username: string, password: string, dbName: string, query: string): SQLResult | null {
return null;
}
/**
* ExecuteQueryWithDSN executes a query on an Oracle database using a DSN
* @example
* ```javascript
* const oracle = require('nuclei/oracle');
* const client = new oracle.OracleClient();
* const result = client.ExecuteQueryWithDSN('oracle://user:password@host:port/service', 'SELECT * FROM dual');
* log(to_json(result));
* ```
*/
public ExecuteQueryWithDSN(dsn: string, query: string): SQLResult | null {
return null;
}
}
/**
* SQLResult Interface
*/
export interface SQLResult {
Count?: number,
Columns?: string[],
Rows?: any[],
}

View File

@ -59,7 +59,7 @@ func wrapModuleFunc(runtime *goja.Runtime, fn interface{}) interface{} {
} }
// Only wrap if first parameter is context.Context // Only wrap if first parameter is context.Context
if fnType.NumIn() == 0 || fnType.In(0) != reflect.TypeOf((*context.Context)(nil)).Elem() { if fnType.NumIn() == 0 || fnType.In(0) != reflect.TypeFor[context.Context]() {
return fn // Return original function unchanged if it doesn't have context.Context as first arg return fn // Return original function unchanged if it doesn't have context.Context as first arg
} }

View File

@ -34,7 +34,7 @@ func wrapWithContext(runtime *goja.Runtime, fn interface{}) interface{} {
} }
// Only wrap if first parameter is context.Context // Only wrap if first parameter is context.Context
if fnType.NumIn() == 0 || fnType.In(0) != reflect.TypeOf((*context.Context)(nil)).Elem() { if fnType.NumIn() == 0 || fnType.In(0) != reflect.TypeFor[context.Context]() {
return fn // Return original function unchanged if it doesn't have context.Context as first arg return fn // Return original function unchanged if it doesn't have context.Context as first arg
} }

View File

@ -2,6 +2,7 @@ package oracle
import ( import (
"context" "context"
"database/sql"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
@ -9,7 +10,9 @@ import (
"github.com/praetorian-inc/fingerprintx/pkg/plugins" "github.com/praetorian-inc/fingerprintx/pkg/plugins"
"github.com/praetorian-inc/fingerprintx/pkg/plugins/services/oracledb" "github.com/praetorian-inc/fingerprintx/pkg/plugins/services/oracledb"
"github.com/projectdiscovery/nuclei/v3/pkg/js/utils"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate" "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
goora "github.com/sijms/go-ora/v2"
) )
type ( type (
@ -24,6 +27,16 @@ type (
IsOracle bool IsOracle bool
Banner string Banner string
} }
// Client is a client for Oracle database.
// Internally client uses oracle/godror driver.
// @example
// ```javascript
// const oracle = require('nuclei/oracle');
// const client = new oracle.OracleClient();
// ```
OracleClient struct {
connector *goora.OracleConnector
}
) )
// IsOracle checks if a host is running an Oracle server // IsOracle checks if a host is running an Oracle server
@ -33,7 +46,7 @@ type (
// const isOracle = oracle.IsOracle('acme.com', 1521); // const isOracle = oracle.IsOracle('acme.com', 1521);
// log(toJSON(isOracle)); // log(toJSON(isOracle));
// ``` // ```
func IsOracle(ctx context.Context, host string, port int) (IsOracleResponse, error) { func (c *OracleClient) IsOracle(ctx context.Context, host string, port int) (IsOracleResponse, error) {
executionId := ctx.Value("executionId").(string) executionId := ctx.Value("executionId").(string)
return memoizedisOracle(executionId, host, port) return memoizedisOracle(executionId, host, port)
} }
@ -69,3 +82,129 @@ func isOracle(executionId string, host string, port int) (IsOracleResponse, erro
resp.IsOracle = true resp.IsOracle = true
return resp, nil return resp, nil
} }
func (c *OracleClient) oracleDbInstance(connStr string, executionId string) (*goora.OracleConnector, error) {
if c.connector != nil {
return c.connector, nil
}
connector := goora.NewConnector(connStr)
oraConnector, ok := connector.(*goora.OracleConnector)
if !ok {
return nil, fmt.Errorf("failed to cast connector to OracleConnector")
}
// Create custom dialer wrapper
customDialer := &oracleCustomDialer{
executionId: executionId,
}
oraConnector.Dialer(customDialer)
c.connector = oraConnector
return oraConnector, nil
}
// Connect connects to an Oracle database
// @example
// ```javascript
// const oracle = require('nuclei/oracle');
// const client = new oracle.OracleClient;
// client.Connect('acme.com', 1521, 'XE', 'user', 'password');
// ```
func (c *OracleClient) Connect(ctx context.Context, host string, port int, serviceName string, username string, password string) (bool, error) {
connStr := goora.BuildUrl(host, port, serviceName, username, password, nil)
return c.ConnectWithDSN(ctx, connStr)
}
func (c *OracleClient) ConnectWithDSN(ctx context.Context, dsn string) (bool, error) {
executionId := ctx.Value("executionId").(string)
connector, err := c.oracleDbInstance(dsn, executionId)
if err != nil {
return false, err
}
db := sql.OpenDB(connector)
defer func() {
_ = db.Close()
}()
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(0)
// Test the connection
err = db.Ping()
if err != nil {
return false, err
}
return true, nil
}
// ExecuteQuery connects to MS SQL database using given credentials and executes a query.
// It returns the results of the query or an error if something goes wrong.
// @example
// ```javascript
// const oracle = require('nuclei/oracle');
// const client = new oracle.OracleClient;
// const result = client.ExecuteQuery('acme.com', 1521, 'username', 'password', 'XE', 'SELECT @@version');
// log(to_json(result));
// ```
func (c *OracleClient) ExecuteQuery(ctx context.Context, host string, port int, username, password, dbName, query string) (*utils.SQLResult, error) {
if host == "" || port <= 0 {
return nil, fmt.Errorf("invalid host or port")
}
isOracleResp, err := c.IsOracle(ctx, host, port)
if err != nil {
return nil, err
}
if !isOracleResp.IsOracle {
return nil, fmt.Errorf("not a oracle service")
}
connStr := goora.BuildUrl(host, port, dbName, username, password, nil)
return c.ExecuteQueryWithDSN(ctx, connStr, query)
}
// ExecuteQueryWithDSN executes a query on an Oracle database using a DSN
// @example
// ```javascript
// const oracle = require('nuclei/oracle');
// const client = new oracle.OracleClient;
// const result = client.ExecuteQueryWithDSN('oracle://user:password@host:port/service', 'SELECT @@version');
// log(to_json(result));
// ```
func (c *OracleClient) ExecuteQueryWithDSN(ctx context.Context, dsn string, query string) (*utils.SQLResult, error) {
executionId := ctx.Value("executionId").(string)
connector, err := c.oracleDbInstance(dsn, executionId)
if err != nil {
return nil, err
}
db := sql.OpenDB(connector)
defer func() {
_ = db.Close()
}()
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(0)
rows, err := db.Query(query)
if err != nil {
return nil, err
}
data, err := utils.UnmarshalSQLRows(rows)
if err != nil {
if data != nil && len(data.Rows) > 0 {
return data, nil
}
return nil, err
}
return data, nil
}

View File

@ -0,0 +1,42 @@
package oracle
import (
"context"
"fmt"
"net"
"time"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
)
// oracleCustomDialer implements the dialer interface expected by go-ora
type oracleCustomDialer struct {
executionId string
}
func (o *oracleCustomDialer) dialWithCtx(ctx context.Context, network, address string) (net.Conn, error) {
dialers := protocolstate.GetDialersWithId(o.executionId)
if dialers == nil {
return nil, fmt.Errorf("dialers not initialized for %s", o.executionId)
}
if !protocolstate.IsHostAllowed(o.executionId, address) {
// host is not valid according to network policy
return nil, protocolstate.ErrHostDenied.Msgf(address)
}
return dialers.Fastdialer.Dial(ctx, network, address)
}
func (o *oracleCustomDialer) Dial(network, address string) (net.Conn, error) {
return o.dialWithCtx(context.TODO(), network, address)
}
func (o *oracleCustomDialer) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return o.dialWithCtx(ctx, network, address)
}
func (o *oracleCustomDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
return o.dialWithCtx(ctx, network, address)
}

View File

@ -0,0 +1,29 @@
id: oracle-auth-test
info:
name: Oracle - Authentication Test
author: pdteam
severity: info
tags: js,oracle,network,auth
javascript:
- pre-condition: |
isPortOpen(Host,Port);
code: |
let o = require('nuclei/oracle');
let c = o.OracleClient();
c.Connect(Host, Port, ServiceName, User, Pass);
args:
ServiceName: "XE"
Host: "{{Host}}"
Port: "1521"
User: "system"
Pass: "{{passwords}}"
payloads:
passwords:
- mysecret
matchers:
- type: dsl
dsl:
- "response == true"

View File

@ -1,6 +1,7 @@
package reporting package reporting
import ( import (
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/es" "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/es"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonexporter" "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonexporter"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonl" "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonl"
@ -23,6 +24,8 @@ type Options struct {
AllowList *filters.Filter `yaml:"allow-list"` AllowList *filters.Filter `yaml:"allow-list"`
// DenyList contains a list of denied events for reporting module // DenyList contains a list of denied events for reporting module
DenyList *filters.Filter `yaml:"deny-list"` DenyList *filters.Filter `yaml:"deny-list"`
// ValidatorCallback is a callback function that is called to validate an event before it is reported
ValidatorCallback func(event *output.ResultEvent) bool `yaml:"-"`
// GitHub contains configuration options for GitHub Issue Tracker // GitHub contains configuration options for GitHub Issue Tracker
GitHub *github.Options `yaml:"github"` GitHub *github.Options `yaml:"github"`
// GitLab contains configuration options for GitLab Issue Tracker // GitLab contains configuration options for GitLab Issue Tracker

View File

@ -288,6 +288,10 @@ func (c *ReportingClient) CreateIssue(event *output.ResultEvent) error {
return nil return nil
} }
if c.options.ValidatorCallback != nil && !c.options.ValidatorCallback(event) {
return nil
}
var err error var err error
unique := true unique := true
if c.dedupe != nil { if c.dedupe != nil {

View File

@ -421,6 +421,10 @@ type Options struct {
FormatUseRequiredOnly bool FormatUseRequiredOnly bool
// SkipFormatValidation is used to skip format validation // SkipFormatValidation is used to skip format validation
SkipFormatValidation bool SkipFormatValidation bool
// VarsTextTemplating is used to inject variables into yaml input files
VarsTextTemplating bool
// VarsFilePaths is used to inject variables into yaml input files from a file
VarsFilePaths goflags.StringSlice
// PayloadConcurrency is the number of concurrent payloads to run per template // PayloadConcurrency is the number of concurrent payloads to run per template
PayloadConcurrency int PayloadConcurrency int
// ProbeConcurrency is the number of concurrent http probes to run with httpx // ProbeConcurrency is the number of concurrent http probes to run with httpx