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 }