mirror of
https://github.com/lunchcat/sif.git
synced 2026-06-12 19:11:25 -07:00
d0bdcf1690
every scanner spun up its own &http.Client, so there was no single place to apply a proxy, custom headers, a cookie or a rate limit. add an internal/httpx package that builds one configured transport at startup and hand it to every scanner via httpx.Client(timeout), keeping behavior identical when nothing is set (plain client when Configure was never called). - httpx.Configure wires -proxy (http/https/socks5), -H/--header, -cookie and -rate-limit into a package-level RoundTripper that paces via a rate.Limiter and only sets headers the caller hasn't already, so a scanner's explicit api key still wins. - route the scan/wordlist downloads that used http.DefaultClient through the shared client too; ports tcp dialing is left untouched. - clamp -threads to a floor of 1: it feeds wg.Add across the scanners, so 0 was a silent no-op and a negative value panicked the waitgroup. document the new flags in the readme, usage docs and man page.
141 lines
4.4 KiB
Go
141 lines
4.4 KiB
Go
/*
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
: :
|
|
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
|
|
: ▄█ █ █▀ · BSD 3-Clause License :
|
|
: :
|
|
: (c) 2022-2026 vmfunc, xyzeva, :
|
|
: lunchcat alumni & contributors :
|
|
: :
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
*/
|
|
|
|
// Package scan provides various security scanning functionalities for web applications.
|
|
// This file handles Google dorking operations.
|
|
|
|
package scan
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/charmbracelet/log"
|
|
"github.com/dropalldatabases/sif/internal/httpx"
|
|
"github.com/dropalldatabases/sif/internal/logger"
|
|
"github.com/dropalldatabases/sif/internal/output"
|
|
googlesearch "github.com/rocketlaunchr/google-search"
|
|
)
|
|
|
|
const (
|
|
dorkURL = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/dork/"
|
|
dorkFile = "dork.txt"
|
|
)
|
|
|
|
// DorkResult represents the result of a Google dork search.
|
|
type DorkResult struct {
|
|
Url string `json:"url"` // The URL found by the dork
|
|
Count int `json:"count"` // The number of times this URL was found
|
|
}
|
|
|
|
// Dork performs Google dorking operations on the target URL.
|
|
// It uses a predefined list of dorks to search for potentially sensitive information.
|
|
//
|
|
// Parameters:
|
|
// - url: The target URL to dork
|
|
// - timeout: Maximum duration for each dork search
|
|
// - threads: Number of concurrent threads to use
|
|
// - logdir: Directory to store log files (empty string for no logging)
|
|
//
|
|
// Returns:
|
|
// - []DorkResult: A slice of results from the dorking operation
|
|
// - error: Any error encountered during the dorking process
|
|
func Dork(url string, timeout time.Duration, threads int, logdir string) ([]DorkResult, error) {
|
|
output.ScanStart("URL dorking")
|
|
|
|
spin := output.NewSpinner("Running Google dorks")
|
|
spin.Start()
|
|
|
|
sanitizedURL := stripScheme(url)
|
|
|
|
if logdir != "" {
|
|
if err := logger.WriteHeader(sanitizedURL, logdir, "URL dorking"); err != nil {
|
|
spin.Stop()
|
|
output.Error("Error creating log file: %v", err)
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, dorkURL+dorkFile, http.NoBody)
|
|
if err != nil {
|
|
spin.Stop()
|
|
output.Error("Error creating dork list request: %s", err)
|
|
return nil, err
|
|
}
|
|
resp, err := httpx.Client(timeout).Do(req)
|
|
if err != nil {
|
|
spin.Stop()
|
|
output.Error("Error downloading dork list: %s", err)
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
var dorks []string
|
|
scanner := bufio.NewScanner(resp.Body)
|
|
scanner.Split(bufio.ScanLines)
|
|
for scanner.Scan() {
|
|
dorks = append(dorks, scanner.Text())
|
|
}
|
|
|
|
// util.InitProgressBar()
|
|
var wg sync.WaitGroup
|
|
var mu sync.Mutex
|
|
wg.Add(threads)
|
|
|
|
dorkResults := []DorkResult{}
|
|
for thread := 0; thread < threads; thread++ {
|
|
go func(thread int) {
|
|
defer wg.Done()
|
|
|
|
for i, dork := range dorks {
|
|
|
|
if i%threads != thread {
|
|
continue
|
|
}
|
|
|
|
results, err := googlesearch.Search(context.TODO(), fmt.Sprintf("%s %s", dork, sanitizedURL))
|
|
if err != nil {
|
|
log.Debugf("error searching for dork %s: %v", dork, err)
|
|
continue
|
|
}
|
|
if len(results) > 0 {
|
|
spin.Stop()
|
|
output.Success("%s dork results found for dork %s", output.Status.Render(strconv.Itoa(len(results))), output.Highlight.Render(dork))
|
|
spin.Start()
|
|
if logdir != "" {
|
|
_ = logger.Write(sanitizedURL, logdir, strconv.Itoa(len(results))+" dork results found for dork ["+dork+"]\n")
|
|
}
|
|
|
|
result := DorkResult{
|
|
Url: dork,
|
|
Count: len(results),
|
|
}
|
|
|
|
mu.Lock()
|
|
dorkResults = append(dorkResults, result)
|
|
mu.Unlock()
|
|
}
|
|
}
|
|
}(thread)
|
|
}
|
|
wg.Wait()
|
|
spin.Stop()
|
|
|
|
output.ScanComplete("URL dorking", len(dorkResults), "found")
|
|
return dorkResults, nil
|
|
}
|