mirror of
https://github.com/Vyntral/god-eye.git
synced 2026-02-12 16:52:45 +00:00
- Implement 8 specialized AI agents (XSS, SQLi, Auth, API, Crypto, Secrets, Headers, General) - Add fast type-based routing for finding classification - Include OWASP-aligned knowledge bases per agent - Add agent handoff logic for cross-vulnerability detection - Optimize timeouts and parallelism for local LLM - Add new modules: cache, network, fingerprint, secrets, cloud, API, discovery - Update documentation with multi-agent feature
277 lines
6.2 KiB
Go
277 lines
6.2 KiB
Go
package scanner
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
"god-eye/internal/config"
|
|
gohttp "god-eye/internal/http"
|
|
"god-eye/internal/progress"
|
|
"god-eye/internal/ratelimit"
|
|
"god-eye/internal/security"
|
|
"god-eye/internal/stealth"
|
|
)
|
|
|
|
// ProbeConfig contains configuration for HTTP probing
|
|
type ProbeConfig struct {
|
|
Timeout int
|
|
Concurrency int
|
|
Silent bool
|
|
JsonOutput bool
|
|
Verbose bool
|
|
}
|
|
|
|
// ProbeResults contains the results from HTTP probing
|
|
type ProbeResults struct {
|
|
RateLimitStats struct {
|
|
Hosts int
|
|
Requests int
|
|
Errors int
|
|
}
|
|
}
|
|
|
|
// RunHTTPProbe performs HTTP probing on all resolved subdomains
|
|
func RunHTTPProbe(ctx context.Context, results map[string]*config.SubdomainResult,
|
|
resultsMu *sync.Mutex, cfg ProbeConfig, stealthMgr *stealth.Manager) *ProbeResults {
|
|
|
|
if len(results) == 0 {
|
|
return &ProbeResults{}
|
|
}
|
|
|
|
probeResults := &ProbeResults{}
|
|
|
|
// Create progress bar and rate limiter
|
|
httpBar := progress.New(len(results), "HTTP", cfg.Silent || cfg.JsonOutput)
|
|
httpLimiter := ratelimit.NewHostRateLimiter(ratelimit.DefaultConfig())
|
|
pool := NewWorkerPool(ctx, cfg.Concurrency)
|
|
|
|
for sub := range results {
|
|
subdomain := sub // capture for closure
|
|
pool.Submit(func() error {
|
|
// Check context cancellation
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
}
|
|
|
|
defer httpBar.Increment()
|
|
|
|
// Apply stealth delays
|
|
if stealthMgr != nil {
|
|
stealthMgr.Wait()
|
|
stealthMgr.WaitForHost(subdomain)
|
|
}
|
|
|
|
// Apply adaptive rate limiting
|
|
limiter := httpLimiter.Get(subdomain)
|
|
limiter.Wait()
|
|
|
|
// Use shared client
|
|
client := gohttp.GetSharedClient(cfg.Timeout)
|
|
|
|
// Primary HTTP probe
|
|
result := gohttp.ProbeHTTP(subdomain, cfg.Timeout)
|
|
|
|
// Run all HTTP checks in parallel
|
|
var checkWg sync.WaitGroup
|
|
var checkMu sync.Mutex
|
|
|
|
var robotsTxt, sitemapXml bool
|
|
var faviconHash string
|
|
var openRedirect bool
|
|
var corsMisconfig string
|
|
var allowedMethods, dangerousMethods []string
|
|
var adminPanels, backupFiles, apiEndpoints []string
|
|
var gitExposed, svnExposed bool
|
|
var s3Buckets, tlsAltNames []string
|
|
var jsFiles, jsSecrets []string
|
|
|
|
// Check robots.txt
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
r := CheckRobotsTxtWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
robotsTxt = r
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check sitemap.xml
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
s := CheckSitemapXmlWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
sitemapXml = s
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check favicon
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
f := GetFaviconHashWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
faviconHash = f
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check open redirect
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
o := security.CheckOpenRedirectWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
openRedirect = o
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check CORS
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
c := security.CheckCORSWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
corsMisconfig = c
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check HTTP methods
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
a, d := security.CheckHTTPMethodsWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
allowedMethods = a
|
|
dangerousMethods = d
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check admin panels
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
p := security.CheckAdminPanelsWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
adminPanels = p
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check Git/SVN exposure
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
g, s := security.CheckGitSvnExposureWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
gitExposed = g
|
|
svnExposed = s
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check backup files
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
b := security.CheckBackupFilesWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
backupFiles = b
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check API endpoints
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
e := security.CheckAPIEndpointsWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
apiEndpoints = e
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Check S3 buckets
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
b := CheckS3BucketsWithClient(subdomain, client)
|
|
checkMu.Lock()
|
|
s3Buckets = b
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Get TLS alt names
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
t := GetTLSAltNames(subdomain, cfg.Timeout)
|
|
checkMu.Lock()
|
|
tlsAltNames = t
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Analyze JavaScript files
|
|
checkWg.Add(1)
|
|
go func() {
|
|
defer checkWg.Done()
|
|
f, s := AnalyzeJSFiles(subdomain, client)
|
|
checkMu.Lock()
|
|
jsFiles = f
|
|
jsSecrets = s
|
|
checkMu.Unlock()
|
|
}()
|
|
|
|
// Wait for all checks
|
|
checkWg.Wait()
|
|
|
|
// Update results
|
|
resultsMu.Lock()
|
|
if r, ok := results[subdomain]; ok {
|
|
r.StatusCode = result.StatusCode
|
|
r.ContentLength = result.ContentLength
|
|
r.RedirectURL = result.RedirectURL
|
|
r.Title = result.Title
|
|
r.Server = result.Server
|
|
r.Tech = result.Tech
|
|
r.Headers = result.Headers
|
|
r.WAF = result.WAF
|
|
r.TLSVersion = result.TLSVersion
|
|
r.TLSIssuer = result.TLSIssuer
|
|
r.TLSExpiry = result.TLSExpiry
|
|
r.ResponseMs = result.ResponseMs
|
|
r.RobotsTxt = robotsTxt
|
|
r.SitemapXml = sitemapXml
|
|
r.FaviconHash = faviconHash
|
|
r.SecurityHeaders = result.SecurityHeaders
|
|
r.MissingHeaders = result.MissingHeaders
|
|
r.OpenRedirect = openRedirect
|
|
r.CORSMisconfig = corsMisconfig
|
|
r.AllowedMethods = allowedMethods
|
|
r.DangerousMethods = dangerousMethods
|
|
r.AdminPanels = adminPanels
|
|
r.GitExposed = gitExposed
|
|
r.S3Buckets = s3Buckets
|
|
r.TLSAltNames = tlsAltNames
|
|
r.SvnExposed = svnExposed
|
|
r.BackupFiles = backupFiles
|
|
r.APIEndpoints = apiEndpoints
|
|
r.JSFiles = jsFiles
|
|
r.JSSecrets = jsSecrets
|
|
}
|
|
resultsMu.Unlock()
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
pool.Wait()
|
|
httpBar.Finish()
|
|
|
|
// Collect rate limiting stats
|
|
h, r, e := httpLimiter.GetStats()
|
|
probeResults.RateLimitStats.Hosts = int(h)
|
|
probeResults.RateLimitStats.Requests = int(r)
|
|
probeResults.RateLimitStats.Errors = int(e)
|
|
|
|
return probeResults
|
|
}
|