yellow.git


yellow

~ opinionated web scanning pipeline for pentesters in a hurry
git clone https://github.com/djnnvx/yellow.git
log | files | refs | archive | README | LICENSE

run.go (2344B)

      1 package scan
      2 
      3 import (
      4 	"fmt"
      5 	"os"
      6 	"time"
      7 
      8 	"evil.djnn.sh/djnn/yellow/core"
      9 	"evil.djnn.sh/djnn/yellow/helpers"
     10 )
     11 
     12 type ScanOpts struct {
     13 	Domain        string
     14 	ScanPath      string
     15 	Proxy         string
     16 	DryRun        bool
     17 	RateLimit     int32
     18 	WordlistPath  string
     19 	ForceInsecure bool
     20 	Gobuster      bool
     21 	PortScan      bool
     22 	Ports         string
     23 	Nuclei        bool
     24 	NoKatana      bool
     25 	KatanaDepth   int
     26 	KatanaMaxTime time.Duration
     27 	KatanaMaxURLs int
     28 	NoSecrets     bool
     29 }
     30 
     31 // context builds a per-target Context from the current options.
     32 func (opts *ScanOpts) context() *core.Context {
     33 	return &core.Context{
     34 		Domain:    opts.Domain,
     35 		ScanPath:  opts.ScanPath,
     36 		Proxy:     opts.Proxy,
     37 		DryRun:    opts.DryRun,
     38 		RateLimit: opts.RateLimit,
     39 		Wordlist:  opts.WordlistPath,
     40 		Insecure:  opts.ForceInsecure,
     41 	}
     42 }
     43 
     44 // webModules is the ordered web-scan pipeline. Gobuster is appended unless
     45 // directory bruteforcing was disabled.
     46 func (opts *ScanOpts) webModules() []core.Module {
     47 	modules := []core.Module{
     48 		&Sitemap{},
     49 		&RobotsTxt{},
     50 	}
     51 	if !opts.NoKatana {
     52 		modules = append(modules, &Katana{Depth: opts.KatanaDepth, Duration: opts.KatanaMaxTime})
     53 	}
     54 	if !opts.NoSecrets {
     55 		modules = append(modules, &Secrets{MaxURLs: opts.KatanaMaxURLs})
     56 	}
     57 	modules = append(modules, &Tlsx{}, &WappalyzerGo{}, &Cvemap{}, &Httpx{})
     58 
     59 	if opts.Nuclei {
     60 		modules = append(modules, &Nuclei{MaxURLs: opts.KatanaMaxURLs})
     61 	}
     62 	if opts.Gobuster {
     63 		modules = append(modules, &Gobuster{MaxURLs: opts.KatanaMaxURLs})
     64 	}
     65 	return modules
     66 }
     67 
     68 func (opts *ScanOpts) Run() {
     69 	fmt.Printf("\n[SCAN] domain: %s\n", opts.Domain)
     70 
     71 	if opts.PortScan {
     72 		opts.runPortScan()
     73 	}
     74 
     75 	fullDomain, ok := helper.ResolveWebTarget(opts.Domain, opts.ForceInsecure)
     76 	if !ok {
     77 		fmt.Printf("[SCAN %s] => no web panel online. skipping\n", opts.Domain)
     78 		return
     79 	}
     80 
     81 	fmt.Printf("[SCAN %s] web panel online (%s)....running web scans\n", opts.Domain, fullDomain)
     82 
     83 	/* per-domain output dir; setting opts.ScanPath directly would nest dirs */
     84 	pathForDomain := opts.ScanPath + "/" + opts.Domain
     85 	if err := os.MkdirAll(pathForDomain, 0755); err != nil {
     86 		fmt.Printf("[!] scan: could not create %s, skipping %s: %v\n", pathForDomain, opts.Domain, err)
     87 		return
     88 	}
     89 
     90 	ctx := opts.context()
     91 	ctx.Domain = fullDomain
     92 	ctx.ScanPath = pathForDomain
     93 
     94 	core.RunModules(ctx, opts.webModules())
     95 }