You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
2.9 KiB
107 lines
2.9 KiB
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"github.com/spf13/cobra"
|
|
"shimon/internal/shimon"
|
|
)
|
|
|
|
var (
|
|
domainsPath string
|
|
outFile string
|
|
prefix string
|
|
regexp string
|
|
suffix string
|
|
timeout int
|
|
ulimit int64
|
|
workers int
|
|
|
|
rootCmd = &cobra.Command{
|
|
Use: "shimon",
|
|
Short: "Load a file containing domains then return a list of domains matching a provided regular expression",
|
|
Run: rootRun,
|
|
}
|
|
)
|
|
|
|
// Initialize flags for cobra
|
|
func init() {
|
|
rootCmd.PersistentFlags().StringVarP(&domainsPath, "domains-file", "f", "", "Path to the input file containing domains (Example: './domains.txt')")
|
|
rootCmd.MarkPersistentFlagRequired("file")
|
|
rootCmd.PersistentFlags().StringVarP(&outFile, "output-file", "o", "results.txt", "File to output matching domains to")
|
|
rootCmd.PersistentFlags().StringVarP(&prefix, "prefix", "p", "https://", "Prefix for each domain")
|
|
rootCmd.PersistentFlags().StringVarP(®exp, "regexp", "r", "", "Regular expression for fingerprinting (Example '[g|G]oogle'")
|
|
rootCmd.MarkPersistentFlagRequired("regexp")
|
|
rootCmd.PersistentFlags().StringVarP(&suffix, "suffix", "s", "/", "Suffix for each domain (Example: '/index/login.php'")
|
|
rootCmd.PersistentFlags().IntVarP(&timeout, "timeout", "t", 30, "Timeout (in seconds) for each GET request")
|
|
rootCmd.PersistentFlags().Int64VarP(&ulimit, "ulimit", "u", 1024, "Maximum number of open files allowed by 'ulimit -n'")
|
|
rootCmd.PersistentFlags().IntVarP(&workers, "workers", "w", 1000, "Number of workers to create")
|
|
}
|
|
|
|
// Load all domains (separated by newline) from a file into a slice of strings
|
|
func loadDomains(filePath string) ([]string, error) {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return []string{}, err
|
|
}
|
|
defer file.Close() // Ensure files is closed at the end of the function
|
|
|
|
domains := []string{}
|
|
buf := bufio.NewScanner(file)
|
|
for buf.Scan() {
|
|
domains = append(domains, buf.Text())
|
|
}
|
|
if err := buf.Err(); err != nil {
|
|
return []string{}, err
|
|
}
|
|
|
|
return domains, nil
|
|
}
|
|
|
|
// Function for the root command (shimon)
|
|
func rootRun(cmd *cobra.Command, args []string) {
|
|
domains, err := loadDomains(domainsPath)
|
|
if err != nil {
|
|
log.Fatalf(err.Error())
|
|
}
|
|
|
|
shimon := shimon.ShiMon{
|
|
Domains: domains,
|
|
Prefix: prefix,
|
|
RegExp: regexp,
|
|
Suffix: suffix,
|
|
Timeout: timeout,
|
|
Ulimit: ulimit,
|
|
Workers: workers,
|
|
}
|
|
|
|
// Create results file for writing
|
|
resultsFile, err := os.Create(outFile)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Create a buffered writer to write to this file (allows for partial writes)
|
|
writer := bufio.NewWriter(resultsFile)
|
|
|
|
// Start scan and receive matches then perform a hard exit if it errors
|
|
matches, err := shimon.Scan(writer)
|
|
if err != nil {
|
|
log.Fatalf(err.Error())
|
|
}
|
|
|
|
fmt.Println("\nResults:")
|
|
for _, match := range matches {
|
|
fmt.Println(" ", match)
|
|
}
|
|
|
|
fmt.Println("\nSaving results to:", outFile)
|
|
}
|
|
|
|
// Execute executes the root command.
|
|
func Execute() error {
|
|
return rootCmd.Execute()
|
|
}
|
|
|