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

commit 8e6e0f3cb4b30eee240e8e3dcb6b4fe7ff13c1ce
parent 24c8c7d6a90fb4cc6cdeb7c9a45e82bc3822c803
Author: djnn <[email protected]>
Date: Tue, 3 Dec 2024 18:18:42 +0900

feat(osint): assetfinder

Diffstat:
Mgo.mod | 1+
Mgo.sum | 2++
Aosint/assetfinder.go | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mosint/run.go | 18++++++++++++++++++

4 files changed, 119 insertions(+), 0 deletions(-)

diff --git a/go.mod b/go.mod
@@ -5,6 +5,7 @@ go 1.23
 require (
 	github.com/bogdzn/gork v0.0.5
 	github.com/spf13/cobra v1.8.1
+	github.com/spiral-sec/assetfinder v0.2.0
 )
 
 require (
diff --git a/go.sum b/go.sum
@@ -38,6 +38,8 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
 github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spiral-sec/assetfinder v0.2.0 h1:Z49ze7/sVZ6ZjuCRDqFpQt3T78VGW3P+SPzC57/HnAI=
+github.com/spiral-sec/assetfinder v0.2.0/go.mod h1:Btbw+b0afgtwSL+YcFXdyrq9cHm46v3bimm4sJyHi/M=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
diff --git a/osint/assetfinder.go b/osint/assetfinder.go
@@ -0,0 +1,98 @@
+package osint
+
+import (
+	"fmt"
+	"os"
+	"sync"
+	"time"
+
+	// old fork that dissociates main from runner
+	// (i deleted the repo but the code still exists, and the tool has not
+	// been update in 4 years so...)
+	assetfinder "github.com/spiral-sec/assetfinder/scanner"
+)
+
+type fetchFn func(string) ([]string, error)
+
+type AssetfinderConfig struct {
+	scanPath string
+	outfile  string
+}
+
+type Assetfinder struct {
+	outfile   string
+	functions []fetchFn
+	scanPath  string
+}
+
+func (a *Assetfinder) Info(url string) {
+	fmt.Println("[+] Running Assetfinder on %s", url)
+}
+
+func (a *Assetfinder) Configure(c interface{}) {
+	a.scanPath = c.(map[string]interface{})["scanPath"].(string)
+	a.outfile = c.(map[string]interface{})["outfile"].(string)
+
+	a.functions = []fetchFn{
+		assetfinder.CertSpotter,
+		assetfinder.HackerTarget,
+		assetfinder.ThreatCrowd,
+		assetfinder.CrtSh,
+		assetfinder.Facebook,
+		assetfinder.VirusTotal,
+		assetfinder.FindSubDomains,
+		assetfinder.Urlscan,
+		assetfinder.BufferOverrun,
+	}
+}
+
+func (a *Assetfinder) Run(url string) {
+	var wg sync.WaitGroup
+
+	rl := assetfinder.NewRateLimiter(time.Second)
+	out := make(chan string)
+
+	for _, f := range a.functions {
+		wg.Add(1)
+		fn := f
+
+		go func() {
+			defer wg.Done()
+
+			rl.Block(fmt.Sprintf("%#v", fn))
+			names, err := fn(url)
+
+			if err != nil {
+				return
+			}
+
+			for _, n := range names {
+				n = assetfinder.CleanDomain(n)
+				out <- n
+			}
+		}()
+	}
+
+	go func() {
+		wg.Wait()
+		close(out)
+	}()
+
+	printed := make(map[string]bool)
+	file, err := os.OpenFile(a.outfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+	if err != nil {
+		return
+	}
+	defer file.Close()
+
+	for n := range out {
+		if _, ok := printed[n]; ok {
+			continue
+		}
+		printed[n] = true
+		fmt.Println(n)
+		file.WriteString(n + string('\n'))
+	}
+
+	fmt.Printf("[OSINT %s] Assetfinder done.", url, a.outfile)
+}
diff --git a/osint/run.go b/osint/run.go
@@ -43,8 +43,25 @@ func (opts OsintOpts) runGoogleDorks() {
 	}
 }
 
+func (opts OsintOpts) runSubfinder() {
+
+}
+
 func (opts OsintOpts) runAssetfinder() {
+	asf := Assetfinder{}
+	asfCfg := make(map[string]interface{})
+
+	asfOutfile := fmt.Sprintf("%s/assetfinder_%s.txt", opts.scanPath, opts.domain)
 
+	asfCfg["scanPath"] = opts.scanPath
+	asfCfg["outfile"] = asfOutfile
+
+	asf.Configure(asfCfg)
+	asf.Info(opts.domain)
+
+	if !opts.dryRun {
+		asf.Run(opts.domain)
+	}
 }
 
 func (opts OsintOpts) runDnsx() {
@@ -63,6 +80,7 @@ func (opts OsintOpts) Run() {
 	fmt.Printf("\n[OSINT] domain: %s\n\n", opts.domain)
 
 	opts.runGoogleDorks()
+	opts.runSubfinder()
 	opts.runAssetfinder()
 	opts.runDnsx()
 	opts.runHttpx()