mirror of
https://github.com/lunchcat/sif.git
synced 2026-06-12 19:11:25 -07:00
Merge branch 'main' into feat/builtin-shodan
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
||||
: :
|
||||
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
|
||||
: ▄█ █ █▀ · BSD 3-Clause License :
|
||||
: :
|
||||
: (c) 2022-2025 vmfunc, xyzeva, :
|
||||
: lunchcat alumni & contributors :
|
||||
: :
|
||||
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
||||
*/
|
||||
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/dropalldatabases/sif/internal/modules"
|
||||
"github.com/dropalldatabases/sif/internal/scan"
|
||||
)
|
||||
|
||||
type NucleiModule struct{}
|
||||
|
||||
func (m *NucleiModule) Info() modules.Info {
|
||||
return modules.Info{
|
||||
ID: "nuclei-scan",
|
||||
Name: "Nuclei Vulnerability Scanner",
|
||||
Author: "sif",
|
||||
Severity: "high",
|
||||
Description: "Runs Nuclei vulnerability scanning templates against target",
|
||||
Tags: []string{"vuln", "nuclei", "cve"},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *NucleiModule) Type() modules.ModuleType {
|
||||
return modules.TypeScript
|
||||
}
|
||||
|
||||
func (m *NucleiModule) Execute(ctx context.Context, target string, opts modules.Options) (*modules.Result, error) {
|
||||
// Call existing legacy scan.Nuclei function
|
||||
nucleiResults, err := scan.Nuclei(target, opts.Timeout, opts.Threads, opts.LogDir)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &modules.Result{
|
||||
ModuleID: m.Info().ID,
|
||||
Target: target,
|
||||
Findings: make([]modules.Finding, 0, len(nucleiResults)),
|
||||
}
|
||||
|
||||
// Process nuclei results into module findings
|
||||
for _, event := range nucleiResults {
|
||||
severity := "info"
|
||||
|
||||
switch event.Info.SeverityHolder.Severity.String() {
|
||||
case "critical":
|
||||
severity = "critical"
|
||||
case "high":
|
||||
severity = "high"
|
||||
case "medium":
|
||||
severity = "medium"
|
||||
case "low":
|
||||
severity = "low"
|
||||
}
|
||||
|
||||
evidence := fmt.Sprintf("[%s] %s", event.TemplateID, event.Info.Name)
|
||||
if event.Matched != "" {
|
||||
evidence = fmt.Sprintf("[%s] %s - matched: %s", event.TemplateID, event.Info.Name, event.Matched)
|
||||
}
|
||||
|
||||
finding := modules.Finding{
|
||||
URL: event.Host,
|
||||
Severity: severity,
|
||||
Evidence: evidence,
|
||||
Extracted: map[string]string{
|
||||
"template_id": event.TemplateID,
|
||||
"template_name": event.Info.Name,
|
||||
"severity": event.Info.SeverityHolder.Severity.String(),
|
||||
},
|
||||
}
|
||||
|
||||
// Template info
|
||||
if event.Type != "" {
|
||||
finding.Extracted["type"] = event.Type
|
||||
}
|
||||
|
||||
// Matcher name
|
||||
if event.MatcherName != "" {
|
||||
finding.Extracted["matcher_name"] = event.MatcherName
|
||||
}
|
||||
|
||||
// Extractor name
|
||||
if event.ExtractorName != "" {
|
||||
finding.Extracted["extractor_name"] = event.ExtractorName
|
||||
}
|
||||
|
||||
// Matched line/data
|
||||
if event.Matched != "" {
|
||||
finding.Extracted["matched"] = event.Matched
|
||||
}
|
||||
|
||||
// Metadata
|
||||
if len(event.Info.Metadata) > 0 {
|
||||
for key, value := range event.Info.Metadata {
|
||||
finding.Extracted[fmt.Sprintf("metadata_%s", key)] = fmt.Sprintf("%v", value)
|
||||
}
|
||||
}
|
||||
|
||||
// Tags
|
||||
if !event.Info.Tags.IsEmpty() {
|
||||
tagStr := ""
|
||||
for _, tag := range event.Info.Tags.ToSlice() {
|
||||
if tagStr != "" {
|
||||
tagStr += ", "
|
||||
}
|
||||
tagStr += tag
|
||||
}
|
||||
|
||||
finding.Extracted["tags"] = tagStr
|
||||
}
|
||||
|
||||
// Reference
|
||||
if event.Info.Reference != nil && !event.Info.Reference.IsEmpty() {
|
||||
refStr := ""
|
||||
for _, ref := range event.Info.Reference.ToSlice() {
|
||||
if refStr != "" {
|
||||
refStr += "; "
|
||||
}
|
||||
refStr += ref
|
||||
}
|
||||
|
||||
finding.Extracted["references"] = refStr
|
||||
}
|
||||
|
||||
result.Findings = append(result.Findings, finding)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -18,4 +18,5 @@ import "github.com/dropalldatabases/sif/internal/modules"
|
||||
// Allows complex Go scans to participate in the module system
|
||||
func Register() {
|
||||
modules.Register(&ShodanModule{})
|
||||
modules.Register(&NucleiModule{})
|
||||
}
|
||||
|
||||
+17
-8
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/dropalldatabases/sif/internal/nuclei/format"
|
||||
"github.com/dropalldatabases/sif/internal/nuclei/templates"
|
||||
sifoutput "github.com/dropalldatabases/sif/internal/output"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/disk"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
|
||||
@@ -59,6 +60,12 @@ func Nuclei(url string, timeout time.Duration, threads int, logdir string) ([]ou
|
||||
options.TemplateThreads = threads
|
||||
options.Timeout = int(timeout.Seconds())
|
||||
|
||||
if logdir != "" {
|
||||
options.ProjectPath = logdir
|
||||
}
|
||||
|
||||
options.Headless = false
|
||||
|
||||
// Get templates
|
||||
templates.Install(nucleilog)
|
||||
pwd, err := os.Getwd()
|
||||
@@ -101,14 +108,16 @@ func Nuclei(url string, timeout time.Duration, threads int, logdir string) ([]ou
|
||||
protocolinit.Init(options)
|
||||
|
||||
executorOpts := protocols.ExecutorOptions{
|
||||
Output: outputWriter,
|
||||
Progress: progressClient,
|
||||
Catalog: catalog,
|
||||
Options: options,
|
||||
IssuesClient: reportingClient,
|
||||
RateLimiter: ratelimit.New(context.Background(), 150, time.Second),
|
||||
Interactsh: interactClient,
|
||||
ResumeCfg: types.NewResumeCfg(),
|
||||
Colorizer: aurora.NewAurora(false),
|
||||
Output: outputWriter,
|
||||
Progress: progressClient,
|
||||
Catalog: catalog,
|
||||
Options: options,
|
||||
IssuesClient: reportingClient,
|
||||
RateLimiter: ratelimit.New(context.Background(), 150, time.Second),
|
||||
Interactsh: interactClient,
|
||||
HostErrorsCache: cache,
|
||||
ResumeCfg: types.NewResumeCfg(),
|
||||
}
|
||||
engine := core.New(options)
|
||||
engine.SetExecuterOptions(executorOpts)
|
||||
|
||||
Reference in New Issue
Block a user