diff --git a/Changelog.md b/Changelog.md
@@ -4,6 +4,7 @@
- feat(scan): adding cvemap module ~ @djnnvx
- fix(scan): adding --no-dirbusting ~ @djnnvx
- feat(meta): adding run-web-recon script ~ @djnnvx
+- feat(cmd): adding fingerprint subcommand ~ @djnnvx
## v0.0.3
diff --git a/README.md b/README.md
@@ -1,5 +1,7 @@
# yellow
+mirror available here: https://github.com/djnnvx/yellow
+
```
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣤⣤⣤⣤⣤⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
@@ -44,10 +46,7 @@ Please use at your own risk, in a controlled environnement. Thanks<3
For next version, i want to take care of at least two items described here:
-* `scan`: add toolbox scan script to automatically integrate it with
- nmap and other CLI tools
* `scan`: integrate browser-dependant tools (katana, ...) (still TBD),
-
* `osint`: add support for more dorks
* `osint`: shodan API integration
diff --git a/cli/parser.go b/cli/parser.go
@@ -14,6 +14,52 @@ import (
func GetParser(opts *StandardOptions) *cobra.Command {
+ var fingerprintCmd = &cobra.Command{
+ Use: "fingerprint",
+ Short: "Runs fingerprinting against websites",
+ Long: "Runs active fingerprinting (wappalyzergo then cvemap)",
+ Args: cobra.MinimumNArgs(0),
+ Run: func(cmd *cobra.Command, args []string) {
+
+ if opts.OutDirName == "" && opts.TargetFilePath == "" {
+ fmt.Println("[!] Error: target cannot be empty. Please run with --target [something] or --file [something]")
+ fmt.Println("\nIf you're confused, feel free to use --help option. :)~")
+ os.Exit(1)
+ }
+
+ helper.CheckProxy(opts.Proxy)
+ helper.DisplayNetInfo()
+
+ if opts.OutDirName == "" || !helper.Exists(opts.OutDirName) {
+ println("[!] collected assets will be sent to current working directory")
+ }
+
+ scanOpts := scan.ScanOpts{}
+ scanOpts.SetDomain(opts.OutDirName)
+ scanOpts.SetScanPath(opts.OutDirName)
+ scanOpts.SetProxy(opts.Proxy)
+ scanOpts.SetDryRun(opts.RunDry)
+ scanOpts.SetRateLimit(opts.RateLimit)
+ scanOpts.SetWordlistPath(opts.WordlistPath)
+ scanOpts.SetForceInsecure(opts.UseHttpInsecure)
+ scanOpts.SetNoGobuster(opts.NoGobuster)
+
+ if opts.TargetFilePath == "" {
+ scanOpts.Run()
+ return
+ }
+
+ scanner := helper.LoadTargetFile(opts.TargetFilePath)
+ defer scanner.Close()
+
+ for scanner.Scan() {
+ targetDomain := scanner.Text()
+ scanOpts.SetDomain(targetDomain)
+ scanOpts.Fingerprint()
+ }
+ },
+ }
+
var scanCmd = &cobra.Command{
Use: "scan",
Short: "Run active scanning tools to perform enumeration",
@@ -149,11 +195,17 @@ func GetParser(opts *StandardOptions) *cobra.Command {
scanCmd.Flags().StringVarP(&opts.OutDirName, "dir-name", "d", defaults.OutDirName, "Outfile directory name (if no target-file is specified, will also be target domain)")
scanCmd.Flags().StringVarP(&opts.Proxy, "proxy", "p", defaults.Proxy, "Proxy URL (used for the tools supporting it. Other will prompt a warning msg)")
scanCmd.Flags().BoolVarP(&opts.RunDry, "dry", "", defaults.RunDry, "Run a dry-run (test mode)")
- scanCmd.Flags().BoolVarP(&opts.NoGobuster, "no-dirbusting", "", defaults.NoGobuster, "Disable directory bruteforce (sometimes you don't need it yk...)")
+ scanCmd.Flags().BoolVarP(&opts.NoGobuster, "disable-dirbusting", "", defaults.NoGobuster, "Disable directory bruteforce (sometimes you don't need it yk...)")
scanCmd.Flags().BoolVarP(&opts.UseHttpInsecure, "insecure", "k", defaults.UseHttpInsecure, "Ignore SSL warnings and force http")
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)")
scanCmd.Flags().StringVarP(&opts.WordlistPath, "wordlist", "w", defaults.WordlistPath, "Wordlist to use")
scanCmd.Flags().StringVarP(&opts.TargetFilePath, "file", "f", defaults.TargetFilePath, "File containing list of targets (should be a list of IP Addresses or domains)")
+ rootCmd.AddCommand(fingerprintCmd)
+ fingerprintCmd.Flags().StringVarP(&opts.OutDirName, "dir-name", "d", defaults.OutDirName, "Outfile directory name (if no target-file is specified, will also be target domain)")
+ fingerprintCmd.Flags().StringVarP(&opts.Proxy, "proxy", "p", defaults.Proxy, "Proxy URL (used for the tools supporting it. Other will prompt a warning msg)")
+ fingerprintCmd.Flags().BoolVarP(&opts.UseHttpInsecure, "insecure", "k", defaults.UseHttpInsecure, "Ignore SSL warnings and force http")
+ fingerprintCmd.Flags().StringVarP(&opts.TargetFilePath, "file", "f", defaults.TargetFilePath, "File containing list of targets (should be a list of IP Addresses or domains)")
+
return rootCmd
}
diff --git a/scan/fingerprint.go b/scan/fingerprint.go
@@ -0,0 +1,41 @@
+package scan
+
+import (
+ "fmt"
+ "os"
+
+ helper "evil.djnn.sh/djnn/yellow/helpers"
+)
+
+/*
+ This is a sub-command, based on the scan command.
+
+ However, all it does is to run wappalyzer-go then cvemap on it
+ for quick wins.
+*/
+
+func (opts *ScanOpts) Fingerprint() {
+ fmt.Printf("\n[SCAN] domain: %s\n", opts.domain)
+
+ fullDomain := "https://" + opts.domain
+ if opts.forceInsecure {
+ fullDomain = "http://" + opts.domain
+ }
+
+ if !helper.HasUnavailableWebInterface(fullDomain) {
+ pathForDomain := opts.scanPath + "/" + opts.domain
+ opts.SetScanPath(pathForDomain)
+
+ err := os.MkdirAll(opts.scanPath, 0755)
+ if err != nil {
+ panic(err)
+ }
+
+ opts.SetDomain(fullDomain)
+
+ opts.RunWappalyzerGo()
+ opts.RunCvemap()
+ } else {
+ fmt.Printf("[FINGERPRINT %s] => no web panel online. skipping\n", opts.domain)
+ }
+}
diff --git a/scan/run.go b/scan/run.go
@@ -19,9 +19,7 @@ type ScanOpts struct {
}
/*
- save in shared memory to avoid having to read a write from files
-
-all the time
+save in shared memory to avoid having to read a write from files all the time
*/
var (
wappalyzerResults []string
@@ -73,7 +71,7 @@ func (opts ScanOpts) runRobots() {
}
}
-func (opts ScanOpts) runWappalyzerGo() {
+func (opts ScanOpts) RunWappalyzerGo() {
wappalyzerResults = make([]string, 0)
wp := WappalyzerGo{}
@@ -89,7 +87,7 @@ func (opts ScanOpts) runWappalyzerGo() {
}
}
-func (opts ScanOpts) runCvemap() {
+func (opts ScanOpts) RunCvemap() {
cv := Cvemap{}
cvCfg := make(map[string]any)
@@ -165,7 +163,6 @@ func (opts *ScanOpts) Run() {
if !helper.HasUnavailableWebInterface(fullDomain) {
- initialPath := opts.scanPath
fmt.Printf("[SCAN %s] web panel online....running web scans\n", opts.domain)
pathForDomain := opts.scanPath + "/" + opts.domain
@@ -179,15 +176,13 @@ func (opts *ScanOpts) Run() {
opts.runSitemap()
opts.runRobots()
- opts.runWappalyzerGo()
- opts.runCvemap()
+ opts.RunWappalyzerGo()
+ opts.RunCvemap()
opts.runHttpx()
if !opts.noGoBuster {
opts.runGobusterDir()
}
-
- opts.SetScanPath(initialPath)
} else {
fmt.Printf("[SCAN %s] => no web panel online. skipping\n", opts.domain)
}
| | | | |