4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / main.go GO
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

func processHostExt(host string) {
	var pResult fResult
	for vuln, runner := range vulnToModule {
		if isItemIn(vuln, &allvulns) {
			runner.(func(string, *fResult))(host, &pResult)
		}
	}
	pResult.Host = strings.Split(strings.Split(host, "@")[1], ":")[0]
	finalResults = append(finalResults, pResult)
}

func initScan(allhosts, allexts *[]string) {
	log.Println("Checking if hosts are alive and responding to SIP...")

	var alivehosts []string
	xmap := checkAlive(allhosts)
	for target, alive := range xmap {
		if alive {
			alivehosts = append(alivehosts, target)
		} else {
			log.Fatalf("Looks like '%s' is down / not responding to SIP.", target)
		}
	}

	hosts := make(chan string, maxConcurrent)
	maxProcs := new(sync.WaitGroup)
	maxProcs.Add(maxConcurrent)

	cwd, _ := os.Getwd()
	log.Printf("Using output directory %s under %s...", outdir, cwd)
	_, err := os.Stat(outdir)
	if err != nil {
		if os.IsNotExist(err) {
			log.Println("Output directory doesn't exist. Creating one...")
			if err = os.Mkdir(outdir, 0777); err != nil {
				log.Fatalln(err.Error())
			}
		}
	}

	startTime := time.Now()
	log.Println("Starting scan at:", startTime.String())
	for i := 0; i < maxConcurrent; i++ {
		go func() {
			for {
				host := <-hosts
				if host == "" {
					break
				}
				processHostExt(host)
			}
			maxProcs.Done()
		}()
	}

	if len(extFile) < 1 {
		for _, xhost := range alivehosts {
			for _, ext := range *allexts {
				hosts <- fmt.Sprintf("%s@%s", ext, xhost)
			}
		}
	} else {
		for _, host := range *readExtensionsFromFile(extFile) {
			*allhosts = append(*allhosts, host)
			if !strings.Contains(host, ":") {
				host = fmt.Sprintf("%s:5060", host)
			}
			hosts <- host
		}
	}

	close(hosts)
	maxProcs.Wait()

	if outFormat == "json" {
		log.Println("Writing results to destination directory as JSON...")
		if err = writeToJSON(&finalResults); err != nil {
			log.Panicln(err)
		}
	} else if outFormat == "csv" {
		log.Println("Writing results to destination directory as CSV...")
		if err = writeToCSV(&finalResults); err != nil {
			log.Panicln(err)
		}
	}

	log.Println("Scan finished at:", time.Now().String())
	log.Printf("Total %d hosts scanned in %s.", len(*allhosts), time.Since(startTime).String())
}

func main() {
	flag.IntVar(&delay, "delay", 0, "Delay in seconds between subsequent requests.")
	flag.IntVar(&maxConcurrent, "threads", 2, "Number of threads to use while scanning.")
	flag.IntVar(&maxExpires, "expires", 60, "Maximum value of the 'Expires' header for SUBSCRIBE requests.")
	flag.StringVar(&monEvents, "events", "", "Comma-separated list of events to be subscribed to. All events are monitored by default.")
	flag.StringVar(&userAgent, "user-agent", fmt.Sprintf("pewswitch/%s", version), "Custom user-agent string to use.")
	flag.StringVar(&cveToScan, "cve", "", "Specify a specific CVE to scan. Both vulns are tested by default.")
	flag.StringVar(&extensions, "exts", "", "Comma separated list of extensions to scan.")
	flag.StringVar(&extFile, "ext-file", "", "Specify a file containing extensions instead of '-exts'.")
	flag.StringVar(&sendmsgs, "msg-file", "", "Specify a CSV file containing messages to be sent (if found vulnerable to CVE-2021-37624).")
	flag.StringVar(&outdir, "out-dir", "./pewswitch-results/", "Output directory to write the results to.")
	flag.StringVar(&outFormat, "out-format", "json", "Output format type of the results. Can be either 'json' or 'csv'.")

	mainUsage := func() {
		fmt.Fprint(os.Stdout, lackofart, "\n\n")
		fmt.Fprintf(os.Stdout, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Usage = mainUsage
	flag.Parse()
	fmt.Print(lackofart, "\n\n")
	targets := flag.Args()
	if (len(targets) < 1 || len(extensions) < 1) && len(extFile) < 1 {
		log.Println("You need to supply at least a valid target & extension to scan!\n\nUsage:")
		flag.PrintDefaults()
		os.Exit(1)
	}
	if outFormat != "json" && outFormat != "csv" {
		log.Println("The only output formats allowed are json and csv.")
		flag.PrintDefaults()
		os.Exit(1)
	}
	if len(cveToScan) != 0 {
		allvulns = []string{strings.ToLower(cveToScan)}
	}
	xflag := false
	for x := range targets {
		if !strings.Contains(targets[x], ":") {
			xflag = true
			targets[x] = fmt.Sprintf("%s:5060", targets[x])
		}
	}
	// just letting the user know we're defaulting to 5060.
	if xflag {
		log.Println("No port supplied, using default port 5060 for targets...")
	}
	for _, ext := range strings.Split(extensions, ",") {
		allexts = append(allexts, strings.TrimSpace(ext))
	}
	if len(sendmsgs) > 0 {
		msgstosend = append(msgstosend, readCsvFile(sendmsgs)...)
	} else {
		msgstosend = append(msgstosend, defaultMsgText)
	}
	if len(monEvents) > 0 {
		for _, x := range strings.Split(monEvents, ",") {
			allEvents = append(allEvents, strings.TrimSpace(x))
		}
	} else {
		allEvents = events
	}
	initScan(&targets, &allexts)
}