mirror of
https://github.com/lunchcat/sif.git
synced 2026-06-12 19:11:25 -07:00
d0bdcf1690
every scanner spun up its own &http.Client, so there was no single place to apply a proxy, custom headers, a cookie or a rate limit. add an internal/httpx package that builds one configured transport at startup and hand it to every scanner via httpx.Client(timeout), keeping behavior identical when nothing is set (plain client when Configure was never called). - httpx.Configure wires -proxy (http/https/socks5), -H/--header, -cookie and -rate-limit into a package-level RoundTripper that paces via a rate.Limiter and only sets headers the caller hasn't already, so a scanner's explicit api key still wins. - route the scan/wordlist downloads that used http.DefaultClient through the shared client too; ports tcp dialing is left untouched. - clamp -threads to a floor of 1: it feeds wg.Add across the scanners, so 0 was a silent no-op and a negative value panicked the waitgroup. document the new flags in the readme, usage docs and man page.
151 lines
7.0 KiB
Go
151 lines
7.0 KiB
Go
/*
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
: :
|
|
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
|
|
: ▄█ █ █▀ · BSD 3-Clause License :
|
|
: :
|
|
: (c) 2022-2026 vmfunc, xyzeva, :
|
|
: lunchcat alumni & contributors :
|
|
: :
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
*/
|
|
|
|
package config
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/charmbracelet/log"
|
|
"github.com/projectdiscovery/goflags"
|
|
)
|
|
|
|
type Settings struct {
|
|
Dirlist string
|
|
Dnslist string
|
|
Debug bool
|
|
LogDir string
|
|
NoScan bool
|
|
Ports string
|
|
Dorking bool
|
|
Git bool
|
|
Whois bool
|
|
Threads int
|
|
Nuclei bool
|
|
JavaScript bool
|
|
Timeout time.Duration
|
|
URLs goflags.StringSlice
|
|
File string
|
|
ApiMode bool
|
|
Template string
|
|
CMS bool
|
|
Headers bool
|
|
SecurityHeaders bool
|
|
CloudStorage bool
|
|
SubdomainTakeover bool
|
|
Shodan bool
|
|
SecurityTrails bool
|
|
SQL bool
|
|
LFI bool
|
|
Framework bool
|
|
Modules string // Comma-separated list of module IDs to run
|
|
ModuleTags string // Run modules matching these tags
|
|
AllModules bool // Run all loaded modules
|
|
ListModules bool // List available modules and exit
|
|
Proxy string
|
|
Header goflags.StringSlice // custom request headers ("Key: Value")
|
|
Cookie string
|
|
RateLimit int
|
|
}
|
|
|
|
// minThreads is the floor for the worker count. Threads feeds wg.Add across the
|
|
// scanners, so 0 silently runs nothing and a negative value panics with
|
|
// "negative WaitGroup counter"; clamp the parsed value up to this.
|
|
const minThreads = 1
|
|
|
|
const (
|
|
Nil goflags.EnumVariable = iota
|
|
|
|
// list sizes
|
|
Small
|
|
Medium
|
|
Large
|
|
|
|
// port scan scopes
|
|
Common
|
|
Full
|
|
)
|
|
|
|
func Parse() *Settings {
|
|
settings := &Settings{}
|
|
|
|
flagSet := goflags.NewFlagSet()
|
|
flagSet.SetDescription("a blazing-fast pentesting (recon/exploitation) suite")
|
|
|
|
flagSet.CreateGroup("target", "Targets",
|
|
flagSet.StringSliceVarP(&settings.URLs, "urls", "u", nil, "List of URLs to check (comma-separated)", goflags.FileCommaSeparatedStringSliceOptions),
|
|
flagSet.StringVarP(&settings.File, "file", "f", "", "File that includes URLs to check"),
|
|
)
|
|
|
|
listSizes := goflags.AllowdTypes{"small": Small, "medium": Medium, "large": Large, "none": Nil}
|
|
portScopes := goflags.AllowdTypes{"common": Common, "full": Full, "none": Nil}
|
|
flagSet.CreateGroup("scans", "Scans",
|
|
flagSet.EnumVar(&settings.Dirlist, "dirlist", Nil, "Directory fuzzing scan size (small/medium/large)", listSizes),
|
|
flagSet.EnumVar(&settings.Dnslist, "dnslist", Nil, "DNS fuzzing scan size (small/medium/large)", listSizes),
|
|
flagSet.EnumVar(&settings.Ports, "ports", Nil, "Port scanning scope (common/full)", portScopes),
|
|
flagSet.BoolVar(&settings.Dorking, "dork", false, "Enable Google dorking"),
|
|
flagSet.BoolVar(&settings.Git, "git", false, "Enable git repository scanning"),
|
|
flagSet.BoolVar(&settings.Nuclei, "nuclei", false, "Enable scanning using nuclei templates"),
|
|
flagSet.BoolVar(&settings.NoScan, "noscan", false, "Do not perform base URL (robots.txt, etc) scanning"),
|
|
flagSet.BoolVar(&settings.Whois, "whois", false, "Enable WHOIS lookup"),
|
|
flagSet.BoolVar(&settings.JavaScript, "js", false, "Enable JavaScript scans"),
|
|
flagSet.BoolVar(&settings.CMS, "cms", false, "Enable CMS detection"),
|
|
flagSet.BoolVar(&settings.Headers, "headers", false, "Enable HTTP Header Analysis"),
|
|
flagSet.BoolVarP(&settings.SecurityHeaders, "security-headers", "sh", false, "Enable security header analysis (missing/weak headers)"),
|
|
flagSet.BoolVar(&settings.CloudStorage, "c3", false, "Enable C3 Misconfiguration Scan"),
|
|
flagSet.BoolVar(&settings.SubdomainTakeover, "st", false, "Enable Subdomain Takeover Check"),
|
|
flagSet.BoolVar(&settings.Shodan, "shodan", false, "Enable Shodan lookup (requires SHODAN_API_KEY env var)"),
|
|
flagSet.BoolVar(&settings.SecurityTrails, "securitytrails", false, "Enable SecurityTrails domain discovery (requires SECURITYTRAILS_API_KEY env var)"),
|
|
flagSet.BoolVar(&settings.SQL, "sql", false, "Enable SQL reconnaissance (admin panels, error disclosure)"),
|
|
flagSet.BoolVar(&settings.LFI, "lfi", false, "Enable LFI (Local File Inclusion) reconnaissance"),
|
|
flagSet.BoolVar(&settings.Framework, "framework", false, "Enable framework detection"),
|
|
)
|
|
|
|
flagSet.CreateGroup("runtime", "Runtime",
|
|
flagSet.BoolVarP(&settings.Debug, "debug", "d", false, "Enable debug logging"),
|
|
flagSet.DurationVarP(&settings.Timeout, "timeout", "t", 10*time.Second, "HTTP request timeout"),
|
|
flagSet.StringVarP(&settings.LogDir, "log", "l", "", "Directory to store logs in"),
|
|
flagSet.IntVar(&settings.Threads, "threads", 10, "Number of threads to run scans on"),
|
|
flagSet.StringVar(&settings.Template, "template", "", "Sif runtime template to use"),
|
|
)
|
|
|
|
flagSet.CreateGroup("http", "HTTP",
|
|
flagSet.StringVar(&settings.Proxy, "proxy", "", "Proxy for all requests (http/https/socks5 url)"),
|
|
flagSet.StringSliceVarP(&settings.Header, "header", "H", nil, "Custom header to send (repeatable or comma-separated, \"Key: Value\")", goflags.CommaSeparatedStringSliceOptions),
|
|
flagSet.StringVar(&settings.Cookie, "cookie", "", "Cookie header to send with every request"),
|
|
flagSet.IntVar(&settings.RateLimit, "rate-limit", 0, "Max requests per second (0 = unlimited)"),
|
|
)
|
|
|
|
flagSet.CreateGroup("api", "API",
|
|
flagSet.BoolVar(&settings.ApiMode, "api", false, "Enable API mode. Only useful for internal lunchcat usage"),
|
|
)
|
|
|
|
flagSet.CreateGroup("modules", "Modules",
|
|
flagSet.StringVarP(&settings.Modules, "modules", "m", "", "Comma-separated list of module IDs to run"),
|
|
flagSet.StringVarP(&settings.ModuleTags, "module-tags", "mt", "", "Run modules matching these tags"),
|
|
flagSet.BoolVarP(&settings.AllModules, "all-modules", "am", false, "Run all loaded modules"),
|
|
flagSet.BoolVarP(&settings.ListModules, "list-modules", "lm", false, "List available modules and exit"),
|
|
)
|
|
|
|
if err := flagSet.Parse(); err != nil {
|
|
log.Fatalf("Could not parse flags: %s", err)
|
|
}
|
|
|
|
// threads feeds wg.Add directly; floor it so 0 isn't a silent no-op and a
|
|
// negative value can't panic the waitgroup.
|
|
if settings.Threads < minThreads {
|
|
settings.Threads = minThreads
|
|
}
|
|
|
|
return settings
|
|
}
|