README.md
Rendering markdown...
package main
import (
"bufio"
"encoding/csv"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net"
"os"
"path"
"strings"
"sync"
"time"
)
type csvWriter struct {
locker *sync.Mutex
writer *csv.Writer
}
const letterRunes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func initCSVWriter(fname string) (*csvWriter, error) {
csvf, err := os.Create(fname)
if err != nil {
return nil, err
}
wr := csv.NewWriter(csvf)
return &csvWriter{
locker: &sync.Mutex{},
writer: wr,
}, nil
}
func (wr *csvWriter) writeRow(row []string) {
wr.locker.Lock()
wr.writer.Write(row)
wr.locker.Unlock()
}
func (wr *csvWriter) FlushBuffer() {
wr.locker.Lock()
wr.writer.Flush()
wr.locker.Unlock()
}
// checks if a specific item is in a slice
func isItemIn(item string, allitems *[]string) bool {
for x := range *allitems {
if item == (*allitems)[x] {
return true
}
}
return false
}
func genRandStr(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func getLocalAddr() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Fatalln(err)
}
conn.Close()
return conn.LocalAddr().String()
}
func sendPacket(hostport string, payload string, deadline int, termConn bool) (net.Conn, error) {
conn, err := net.DialTimeout("udp", hostport, time.Duration(dialTimeout)*time.Second)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(time.Duration(deadline) * time.Second))
_, err = conn.Write([]byte(payload))
if err != nil {
return nil, err
}
if termConn {
err = conn.Close()
if err != nil {
return nil, err
}
}
return conn, nil
}
func readExtensionsFromFile(fname string) *[]string {
var exts []string
file, err := os.Open(fname)
if err != nil {
log.Fatalln(err.Error())
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
exts = append(exts, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatalln(err.Error())
}
return &exts
}
func readCsvFile(filePath string) [][]string {
f, err := os.Open(filePath)
if err != nil {
log.Fatal("Unable to read input file "+filePath, err)
}
defer f.Close()
csvReader := csv.NewReader(f)
records, err := csvReader.ReadAll()
if err != nil {
log.Fatal("Unable to parse file as CSV for "+filePath, err)
}
return records
}
func checkAlive(targets *[]string) map[string]bool {
var dmap = make(map[string]bool)
for _, targ := range *targets {
dmap[targ] = false
conn, err := net.DialTimeout("udp", targ, time.Duration(dialTimeout)*time.Second)
if err != nil {
log.Println(err.Error())
continue
}
defer conn.Close()
var payload string
payload += fmt.Sprintf("OPTIONS sip:1000@%s;transport=UDP SIP/2.0\r\n", targ)
payload += fmt.Sprintf("Via: SIP/2.0/UDP %s;branch=z9hG4bK001b84f6;rport\r\n", conn.LocalAddr().String())
payload += "Max-Forwards: 70\r\n"
payload += "To: \"PewSWITCH\" <sip:[email protected]>\r\n"
payload += "From: \"PewSWITCH\" <sip:[email protected]>;tag=61633638380343437\r\n"
payload += "User-Agent: pewswitch\r\n"
payload += "Call-ID: AABkh3bjAZ3k2j3br5920I0\r\n"
payload += fmt.Sprintf("Contact: sip:1000@%s\r\n", conn.LocalAddr().String())
payload += "CSeq: 1 OPTIONS\r\n"
payload += "Accept: application/sdp\r\n"
payload += "Content-Length: 0\r\n"
payload += "\r\n"
conn.SetDeadline(time.Now().Add(5 * time.Second))
_, err = conn.Write([]byte(payload))
if err != nil {
continue
}
xbuf := make([]byte, 8192)
_, err = conn.Read(xbuf)
if err != nil {
continue
}
if strings.HasPrefix(string(xbuf), "SIP/2.0") {
dmap[targ] = true
log.Printf("Host %s is up and responding to SIP.", targ)
}
server := serverHead.FindAllSubmatch(xbuf, -1)
if server != nil {
servstr := strings.ToLower(string(server[0][1]))
if !strings.Contains(servstr, "freeswitch") {
log.Println("Heuristics indicate that the server might not be FreeSWITCH!")
} else {
log.Println("Heuristics indicate that the server is FreeSWITCH.")
}
} else {
log.Println("No server header found. Skipping heuristic checks...")
}
}
return dmap
}
func postProcess(obj *[]fResult) *[]fResult {
var (
uniqhosts []string
xresult fResult
count = 0
newObj = make([]fResult, 0)
)
for _, x := range *obj {
uniqhosts = append(uniqhosts, x.Host)
}
uniqhosts = *sortUnique(&uniqhosts)
for _, mhost := range uniqhosts {
xflag := false
for _, res := range *obj {
if res.Host == mhost {
if !xflag {
if count > 0 {
newObj = append(newObj, xresult)
}
xresult = res
xflag = true
continue
}
xresult.Details.CVE202137624.ExploitDetails = append(xresult.Details.
CVE202137624.ExploitDetails, res.Details.CVE202137624.ExploitDetails...)
xresult.Details.CVE202141157.ExploitDetails = append(xresult.Details.
CVE202141157.ExploitDetails, res.Details.CVE202141157.ExploitDetails...)
count++
}
}
}
newObj = append(newObj, xresult)
return &newObj
}
// writeToJSON writes the results of a scan to the specified directory
func writeToJSON(obj *[]fResult) error {
obj = postProcess(obj)
for _, res := range *obj {
xdata, err := json.MarshalIndent(res, "", " ")
if err != nil {
return err
}
if err = ioutil.WriteFile(path.Join(outdir,
fmt.Sprintf("%s-report.json", res.Host)), xdata, 0644); err != nil {
return err
}
}
return nil
}
func writeToCSV(obj *[]fResult) error {
var uniqhosts []string
for _, x := range *obj {
uniqhosts = append(uniqhosts, x.Host)
}
uniqhosts = *sortUnique(&uniqhosts)
for _, xhost := range uniqhosts {
xwriter, err := initCSVWriter(path.Join(outdir, fmt.Sprintf("%s-report.csv", xhost)))
if err != nil {
return err
}
xwriter.writeRow([]string{
"extension",
"host",
"cve",
"is_vulnerable",
"message",
"timestamp",
})
for _, res := range *obj {
if xhost == res.Host {
xdets := res.Details.CVE202137624.ExploitDetails
if len(res.Details.CVE202137624.ExploitDetails) > 0 {
for _, msg := range res.Details.CVE202137624.ExploitDetails[0].SentMessages {
xwriter.writeRow([]string{
xdets[0].Extension,
xhost,
"CVE-2021-37624",
fmt.Sprint(res.Details.CVE202137624.IsVulnerable),
msg.Message,
time.Time(msg.Timestamp).Format(time.RFC3339),
})
}
}
xdetx := res.Details.CVE202141157.ExploitDetails
if len(res.Details.CVE202141157.ExploitDetails) > 0 {
for _, msg := range res.Details.CVE202141157.ExploitDetails[0].NotifsRecvd {
xwriter.writeRow([]string{
xdetx[0].Extension,
xhost,
"CVE-2021-41157",
fmt.Sprint(res.Details.CVE202137624.IsVulnerable),
// santizing the CSV so it doesn't span across lines
sanitiseRex.ReplaceAllLiteralString(msg.Message, "\\n"),
time.Time(msg.Timestamp).Format(time.RFC3339),
})
}
}
}
}
xwriter.FlushBuffer()
}
return nil
}
func sortUnique(sSlice *[]string) *[]string {
var keys = make(map[string]bool)
var list []string
for _, entry := range *sSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return &list
}