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

parser.go (11200B)

      1 package cli
      2 
      3 import (
      4 	"fmt"
      5 	"os"
      6 	"strings"
      7 
      8 	"github.com/spf13/cobra"
      9 
     10 	"evil.djnn.sh/djnn/yellow/helpers"
     11 	"evil.djnn.sh/djnn/yellow/osint"
     12 	"evil.djnn.sh/djnn/yellow/prune"
     13 	"evil.djnn.sh/djnn/yellow/scan"
     14 )
     15 
     16 func GetParser(opts *StandardOptions) *cobra.Command {
     17 
     18 	var pruneCmd = &cobra.Command{
     19 		Use:   "prune",
     20 		Short: "filters a file full of domains",
     21 		Long:  "filters a file full of domains to only get the reachable domains",
     22 		Args:  cobra.MinimumNArgs(0),
     23 		Run: func(cmd *cobra.Command, args []string) {
     24 
     25 			if opts.TargetFilePath == "" {
     26 				fmt.Println("[!] Error: target cannot be empty. Please run with --file [something]")
     27 				fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
     28 				os.Exit(1)
     29 			}
     30 
     31 			if opts.OutName == "" {
     32 				fmt.Println("[!] Error: output path cannot be empty. Please run with --out [something]")
     33 				fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
     34 				os.Exit(1)
     35 			}
     36 
     37 			pruneOpts := prune.PruneOpts{
     38 				Proxy:         opts.Proxy,
     39 				DryRun:        opts.RunDry,
     40 				ForceInsecure: opts.UseHttpInsecure,
     41 				InFilePath:    opts.TargetFilePath,
     42 				OutFilePath:   opts.OutName,
     43 			}
     44 
     45 			pruneOpts.Run()
     46 		},
     47 	}
     48 
     49 	var fingerprintCmd = &cobra.Command{
     50 		Use:   "fingerprint",
     51 		Short: "Runs fingerprinting against websites",
     52 		Long:  "Runs active fingerprinting (wappalyzergo then cvemap)",
     53 		Args:  cobra.MinimumNArgs(0),
     54 		Run: func(cmd *cobra.Command, args []string) {
     55 
     56 			if opts.OutName == "" && opts.TargetFilePath == "" {
     57 				fmt.Println("[!] Error: target cannot be empty. Please run with --target [something] or --file [something]")
     58 				fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
     59 				os.Exit(1)
     60 			}
     61 
     62 			helper.CheckProxy(opts.Proxy)
     63 			helper.DisplayNetInfo()
     64 
     65 			if opts.OutName == "" || !helper.Exists(opts.OutName) {
     66 				fmt.Println("[!] collected assets will be sent to current working directory")
     67 			}
     68 
     69 			scanOpts := scan.ScanOpts{
     70 				Domain:        opts.OutName,
     71 				ScanPath:      opts.OutName,
     72 				Proxy:         opts.Proxy,
     73 				DryRun:        opts.RunDry,
     74 				RateLimit:     opts.RateLimit,
     75 				WordlistPath:  opts.WordlistPath,
     76 				ForceInsecure: opts.UseHttpInsecure,
     77 				Gobuster:      opts.Gobuster,
     78 			}
     79 
     80 			if opts.TargetFilePath == "" {
     81 				scanOpts.Fingerprint()
     82 				return
     83 			}
     84 
     85 			scanner := helper.LoadTargetFile(opts.TargetFilePath)
     86 			defer scanner.Close()
     87 
     88 			for target := range scanner.Lines() {
     89 				scanOpts.Domain = target
     90 				scanOpts.Fingerprint()
     91 			}
     92 		},
     93 	}
     94 
     95 	var scanCmd = &cobra.Command{
     96 		Use:   "scan",
     97 		Short: "Run active scanning tools to perform enumeration",
     98 		Long:  "Runs active scanning (sitemap, robots.txt, katana crawl, tlsx, wappalyzergo, cvemap, httpx, gitleaks secret scan, optional gobuster, optional TCP port-scan and optional nuclei)",
     99 		Args:  cobra.MinimumNArgs(0),
    100 		Run: func(cmd *cobra.Command, args []string) {
    101 
    102 			if opts.OutName == "" && opts.TargetFilePath == "" {
    103 				fmt.Println("[!] Error: target cannot be empty. Please run with --target [something] or --file [something]")
    104 				fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
    105 				os.Exit(1)
    106 			}
    107 
    108 			helper.CheckProxy(opts.Proxy)
    109 			helper.DisplayNetInfo()
    110 
    111 			if opts.OutName == "" || !helper.Exists(opts.OutName) {
    112 				fmt.Println("[!] collected assets will be sent to current working directory")
    113 			}
    114 
    115 			scanOpts := scan.ScanOpts{
    116 				Domain:        opts.OutName,
    117 				ScanPath:      opts.OutName,
    118 				Proxy:         opts.Proxy,
    119 				DryRun:        opts.RunDry,
    120 				RateLimit:     opts.RateLimit,
    121 				WordlistPath:  opts.WordlistPath,
    122 				ForceInsecure: opts.UseHttpInsecure,
    123 				Gobuster:      opts.Gobuster,
    124 				PortScan:      opts.PortScan,
    125 				Ports:         opts.Ports,
    126 				Nuclei:        opts.Nuclei,
    127 				NoKatana:      opts.NoKatana,
    128 				KatanaDepth:   opts.KatanaDepth,
    129 				KatanaMaxTime: opts.KatanaMaxTime,
    130 				KatanaMaxURLs: opts.KatanaMaxURLs,
    131 				NoSecrets:     opts.NoSecrets,
    132 			}
    133 
    134 			if opts.TargetFilePath == "" {
    135 				scanOpts.Run()
    136 				return
    137 			}
    138 
    139 			scanner := helper.LoadTargetFile(opts.TargetFilePath)
    140 			defer scanner.Close()
    141 
    142 			for target := range scanner.Lines() {
    143 				scanOpts.Domain = target
    144 				scanOpts.Run()
    145 			}
    146 		},
    147 	}
    148 
    149 	var osintCmd = &cobra.Command{
    150 		Use:   "osint",
    151 		Short: "Run OSINT tools to retrieve IP addresses and interesting assets",
    152 		Long:  "Runs dorks, subfinder, assetfinder, dnsx, gau & alterx to find subdomains, assets & historical URLs",
    153 		Args:  cobra.MinimumNArgs(0),
    154 		Run: func(cmd *cobra.Command, args []string) {
    155 
    156 			if opts.OutName == "" && opts.TargetFilePath == "" {
    157 				fmt.Println("[!] Error: target cannot be empty. Please run with --target [something] or --file [something]")
    158 				fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
    159 				os.Exit(1)
    160 			}
    161 
    162 			helper.CheckProxy(opts.Proxy)
    163 			helper.DisplayNetInfo()
    164 
    165 			if opts.OutName == "" || !helper.Exists(opts.OutName) {
    166 				fmt.Println("[!] collected assets will be sent to current working directory")
    167 			}
    168 
    169 			osintOpts := osint.OsintOpts{
    170 				Domain:     opts.OutName,
    171 				ScanPath:   opts.OutName,
    172 				Proxy:      opts.Proxy,
    173 				DryRun:     opts.RunDry,
    174 				RateLimit:  opts.RateLimit,
    175 				EmailsFile: opts.EmailsFilePath,
    176 			}
    177 
    178 			// if used create subcommand, put the results in scans
    179 			if helper.Exists(opts.OutName + "/scans/") {
    180 				osintOpts.ScanPath = opts.OutName + "/scans"
    181 			}
    182 
    183 			if opts.TargetFilePath == "" {
    184 				osintOpts.Run()
    185 				return
    186 			}
    187 
    188 			scanner := helper.LoadTargetFile(opts.TargetFilePath)
    189 			defer scanner.Close()
    190 
    191 			for target := range scanner.Lines() {
    192 				osintOpts.Domain = target
    193 				osintOpts.Run()
    194 			}
    195 		},
    196 	}
    197 
    198 	var createDirectories = &cobra.Command{
    199 		Use:   "create",
    200 		Short: "Create a work tree to perform scanning, OSINT, and other targets",
    201 		Long:  "Set up a clean-cut architecture at the launch of your assessments",
    202 		Args:  cobra.MinimumNArgs(0),
    203 		Run: func(cmd *cobra.Command, args []string) {
    204 
    205 			if opts.OutName == "" {
    206 				fmt.Println("[!] Error: target cannot be empty. Please run with --target [something]")
    207 				fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
    208 				os.Exit(1)
    209 			}
    210 
    211 			if strings.Contains(opts.OutName, ",") {
    212 				directories := strings.Split(opts.OutName, ",")
    213 				for _, d := range directories {
    214 					helper.SetUpDirectoryArchitecture(d)
    215 				}
    216 			} else {
    217 				helper.SetUpDirectoryArchitecture(opts.OutName)
    218 			}
    219 
    220 			fmt.Println("[+] Done. Happy hunting :)~")
    221 		},
    222 	}
    223 
    224 	defaults := GetDefaultOptions()
    225 	var rootCmd = createDirectories
    226 	rootCmd.Flags().StringVarP(&opts.OutName, "dir-name", "d", defaults.OutName, "Directory name to create (you can also put multiple names and separate them with a ,)")
    227 
    228 	rootCmd.AddCommand(osintCmd)
    229 	osintCmd.Flags().StringVarP(&opts.OutName, "dir-name", "d", defaults.OutName, "Outfile directory name (if no target-file is specified, will also be target domain)")
    230 	osintCmd.Flags().StringVarP(&opts.Proxy, "proxy", "p", defaults.Proxy, "Proxy URL (used for the tools supporting it. Other will prompt a warning msg)")
    231 	osintCmd.Flags().BoolVarP(&opts.RunDry, "dry", "", defaults.RunDry, "Run a dry-run (test mode)")
    232 	osintCmd.Flags().Int32VarP(&opts.RateLimit, "rate-limit", "r", defaults.RateLimit, "Requests rate-limit (used for the tools supporting it. Other will prompt a warning msg)")
    233 	osintCmd.Flags().StringVarP(&opts.TargetFilePath, "file", "f", defaults.TargetFilePath, "File containing list of targets (should be a list of IP Addresses or domains)")
    234 	osintCmd.Flags().StringVarP(&opts.EmailsFilePath, "emails", "e", defaults.EmailsFilePath, "File containing list of emails for credential leak checking")
    235 
    236 	rootCmd.AddCommand(scanCmd)
    237 	scanCmd.Flags().StringVarP(&opts.OutName, "dir-name", "d", defaults.OutName, "Outfile directory name (if no target-file is specified, will also be target domain)")
    238 	scanCmd.Flags().StringVarP(&opts.Proxy, "proxy", "p", defaults.Proxy, "Proxy URL (used for the tools supporting it. Other will prompt a warning msg)")
    239 	scanCmd.Flags().BoolVarP(&opts.RunDry, "dry", "", defaults.RunDry, "Run a dry-run (test mode)")
    240 	scanCmd.Flags().BoolVarP(&opts.Gobuster, "gobuster", "", defaults.Gobuster, "Run gobuster directory bruteforce")
    241 	scanCmd.Flags().BoolVarP(&opts.UseHttpInsecure, "insecure", "k", defaults.UseHttpInsecure, "Ignore SSL warnings and force http")
    242 	scanCmd.Flags().Int32VarP(&opts.RateLimit, "rate-limit", "r", defaults.RateLimit, "Requests rate-limit (used for the tools supporting it. Other will prompt a warning msg)")
    243 	scanCmd.Flags().StringVarP(&opts.WordlistPath, "wordlist", "w", defaults.WordlistPath, "Wordlist to use")
    244 	scanCmd.Flags().StringVarP(&opts.TargetFilePath, "file", "f", defaults.TargetFilePath, "File containing list of targets (should be a list of IP Addresses or domains)")
    245 	scanCmd.Flags().BoolVarP(&opts.PortScan, "port-scan", "", defaults.PortScan, "Run TCP port scan and service fingerprinting")
    246 	scanCmd.Flags().StringVarP(&opts.Ports, "ports", "", defaults.Ports, "Ports to scan, comma-separated or ranges (e.g. 22,80,443,8000-9000)")
    247 	scanCmd.Flags().BoolVarP(&opts.Nuclei, "nuclei", "", defaults.Nuclei, "Run nuclei template-based vulnerability scanning (downloads templates on first run)")
    248 	scanCmd.Flags().BoolVarP(&opts.NoKatana, "no-katana", "", defaults.NoKatana, "Disable the katana headless crawl (runs by default)")
    249 	scanCmd.Flags().IntVarP(&opts.KatanaDepth, "katana-depth", "", defaults.KatanaDepth, "Katana crawl depth")
    250 	scanCmd.Flags().DurationVarP(&opts.KatanaMaxTime, "katana-duration", "", defaults.KatanaMaxTime, "Katana crawl time budget per target")
    251 	scanCmd.Flags().IntVarP(&opts.KatanaMaxURLs, "katana-max-urls", "", defaults.KatanaMaxURLs, "Cap on crawled URLs fed into nuclei/gobuster (0 = unlimited)")
    252 	scanCmd.Flags().BoolVarP(&opts.NoSecrets, "no-secrets", "", defaults.NoSecrets, "Disable gitleaks secret scanning of crawled responses (runs by default)")
    253 
    254 	rootCmd.AddCommand(pruneCmd)
    255 	pruneCmd.Flags().StringVarP(&opts.Proxy, "proxy", "p", defaults.Proxy, "Proxy URL (used for the tools supporting it. Other will prompt a warning msg)")
    256 	pruneCmd.Flags().BoolVarP(&opts.UseHttpInsecure, "insecure", "k", defaults.UseHttpInsecure, "Ignore SSL warnings and force http")
    257 	pruneCmd.Flags().StringVarP(&opts.TargetFilePath, "file", "f", defaults.TargetFilePath, "File containing list of targets (should be a list of IP Addresses or domains)")
    258 	pruneCmd.Flags().StringVarP(&opts.OutName, "out", "o", defaults.OutName, "output file path")
    259 
    260 	rootCmd.AddCommand(fingerprintCmd)
    261 	fingerprintCmd.Flags().StringVarP(&opts.OutName, "dir-name", "d", defaults.OutName, "Outfile directory name (if no target-file is specified, will also be target domain)")
    262 	fingerprintCmd.Flags().StringVarP(&opts.Proxy, "proxy", "p", defaults.Proxy, "Proxy URL (used for the tools supporting it. Other will prompt a warning msg)")
    263 	fingerprintCmd.Flags().BoolVarP(&opts.UseHttpInsecure, "insecure", "k", defaults.UseHttpInsecure, "Ignore SSL warnings and force http")
    264 	fingerprintCmd.Flags().StringVarP(&opts.TargetFilePath, "file", "f", defaults.TargetFilePath, "File containing list of targets (should be a list of IP Addresses or domains)")
    265 
    266 	return rootCmd
    267 }