Files
osmedeus/execution/clean.go
T
2023-09-07 21:21:14 +07:00

528 lines
13 KiB
Go

package execution
import (
"bufio"
"fmt"
"net/url"
"os"
"path"
"path/filepath"
"sort"
"strings"
"github.com/flosch/pongo2/v6"
"github.com/spf13/cast"
"github.com/thoas/go-funk"
"github.com/Jeffail/gabs/v2"
"github.com/j3ssie/osmedeus/libs"
"github.com/j3ssie/osmedeus/utils"
)
// Cleaning the execution directory
func Cleaning(folder string, reports []string) {
utils.DebugF("Cleaning result: %v", folder)
// list all the file
items, err := filepath.Glob(fmt.Sprintf("%v/*", folder))
if err != nil {
return
}
for _, item := range items {
item = utils.NormalizePath(item)
utils.DebugF("Check Cleaning: %v", item)
if funk.Contains(reports, item) {
utils.DebugF("Skip cleaning file: %v", item)
continue
}
fi, err := os.Stat(item)
if err != nil {
continue
}
switch mode := fi.Mode(); {
case mode.IsDir():
DeleteFolder(item)
continue
case mode.IsRegular():
DeleteFile(item)
}
}
}
// CleanGoBuster clean output for gobuster
func CleanGoBuster(src string, output string) {
data := utils.GetFileContent(src)
if data == "" {
return
}
result := strings.Replace(data, "Found: ", "", -1)
utils.WriteToFile(output, result)
}
// CleanMassdns clean result of massdns to get IP address
func CleanMassdns(filename string, output string) {
file, err := os.Open(utils.NormalizePath(filename))
if err != nil {
return
}
defer file.Close()
outputFile, err := os.OpenFile(utils.NormalizePath(output), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return
}
defer outputFile.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
continue
}
if strings.Contains(line, " A ") {
data := strings.Split(line, " A ")
host := strings.Trim(data[0], ".")
ip := strings.Trim(data[1], ".")
outputFile.WriteString(fmt.Sprintf("%v,%v\n", host, ip))
} else if strings.Contains(line, " CNAME ") {
data := strings.Split(line, " CNAME ")
host := strings.Trim(data[0], ".")
ip := strings.Trim(data[1], ".")
outputFile.WriteString(fmt.Sprintf("%v,%v\n", host, ip))
}
}
}
// CleanAmass get IP range and ASN from Amass result
func CleanAmass(filename string, output string) {
content := utils.ReadingLines(filename)
if len(content) <= 0 {
return
}
var result []string
for _, line := range content {
jsonParsed, err := gabs.ParseJSON([]byte(line))
if err != nil {
continue
}
asn := jsonParsed.Path("asn").String()
cidr := jsonParsed.Path("cidr").String()
desc := jsonParsed.Path("desc").String()
if cidr != "" && cidr != "null" {
result = append(result, fmt.Sprintf("AS%v,%v,%v", asn, cidr, desc))
}
}
if len(result) > 0 {
utils.WriteToFile(output, strings.Join(result, "\n"))
}
}
// CleanSWebanalyze get to get formatted report
func CleanSWebanalyze(filename string, output string) {
content := utils.ReadingLines(filename)
if len(content) <= 0 {
return
}
result := make(map[string][]string)
var finalResult []string
for _, line := range content {
if strings.TrimSpace(line) == "" {
continue
}
if !strings.Contains(line, "tech~") || !strings.Contains(line, "|") {
continue
}
data := strings.Split(line, "|")
domain, _ := utils.GetDomain(strings.TrimLeft(data[1], "~"))
tech := data[2]
if strings.HasSuffix(tech, "/") {
tech = strings.Trim(tech, "/")
}
result[domain] = append(result[domain], tech)
}
// join summary result
for k, v := range result {
v = funk.UniqString(v)
sort.Strings(v)
techs := strings.Join(v, ",")
data := fmt.Sprintf("domain|%v;;techs|%v", k, strings.Trim(techs, ","))
finalResult = append(finalResult, data)
}
if len(result) > 0 {
utils.WriteToFile(output, strings.Join(finalResult, "\n"))
}
}
// CleanWebanalyze get to get formatted report
func CleanWebanalyze(filename string, output string, sum string) {
content := utils.ReadingLines(filename)
if len(content) <= 0 {
return
}
result := make(map[string][]string)
var finalResult []string
var techSum []string
for _, line := range content {
jsonParsed, err := gabs.ParseJSON([]byte(line))
if err != nil {
continue
}
URL := strings.Trim(jsonParsed.S("hostname").String(), `"`)
u, err := url.Parse(URL)
if err != nil {
continue
}
matches := jsonParsed.S("matches").Children()
for _, child := range matches {
techs := ""
app := strings.Trim(child.S("app_name").String(), `"`)
version := strings.Trim(child.S("version").String(), `"`)
if version != "" {
techs += fmt.Sprintf("%v/%v,", app, version)
} else {
techs += fmt.Sprintf("%v,", app)
}
// ignore blank techs
if techs == "" || strings.Trim(techs, ",") == "" || strings.Trim(techs, ",") == " " {
continue
}
techSum = append(techSum, strings.Trim(app, ","))
techs = strings.TrimSpace(strings.Trim(techs, ","))
result[u.Hostname()] = append(result[u.Hostname()], techs)
}
}
// join summary result
for k, v := range result {
techs := strings.Join(funk.UniqString(v), ",")
data := fmt.Sprintf("domain|%v;;techs|%v", k, strings.Trim(techs, ","))
finalResult = append(finalResult, data)
}
if len(techSum) > 0 {
utils.WriteToFile(sum, strings.Join(funk.UniqString(techSum), "\n"))
}
if len(result) > 0 {
utils.WriteToFile(output, strings.Join(finalResult, "\n"))
}
}
// CleanArjun clean output of Arjun
func CleanArjun(src string, dest string) {
src = utils.NormalizePath(src)
if !utils.FolderExists(src) {
return
}
if !strings.HasSuffix(src, "/") {
src += "/"
}
src = path.Join(src, "*")
outputs, err := filepath.Glob(src)
if err != nil {
return
}
var data []string
for _, output := range outputs {
content := utils.GetFileContent(output)
jsonParsed, err := gabs.ParseJSON([]byte(content))
if err != nil {
continue
}
prefix := "[GET]"
if strings.HasPrefix(output, "post") {
prefix = "[POST]"
}
for URL, child := range jsonParsed.ChildrenMap() {
if len(child.Children()) <= 0 {
continue
}
for _, query := range child.Children() {
line := fmt.Sprintf("%v %v?%v=FUZZ", prefix, URL, query.Data())
data = append(data, line)
}
}
}
if len(data) > 0 {
utils.WriteToFile(dest, strings.Join(data, "\n"))
}
}
// CleanJSONDnsx get to get formatted report
func CleanJSONDnsx(filename string, dest string) {
content := utils.ReadingLines(filename)
if len(content) <= 0 {
utils.WarnF("File not found: %s", filename)
return
}
var results []string
for _, line := range content {
jsonParsed, err := gabs.ParseJSON([]byte(line))
if err != nil {
continue
}
domain, ok := jsonParsed.S("host").Data().(string)
if !ok {
continue
}
a := jsonParsed.S("a")
if a != nil {
for _, record := range a.Children() {
data := fmt.Sprintf("%s A %s", domain, cast.ToString(record.Data()))
results = append(results, data)
}
}
cname := jsonParsed.S("cname")
if cname != nil {
for _, record := range cname.Children() {
data := fmt.Sprintf("%s CNAME %s", domain, cast.ToString(record.Data()))
results = append(results, data)
}
}
mx := jsonParsed.S("mx")
if mx != nil {
for _, record := range mx.Children() {
data := fmt.Sprintf("%s MX %s", domain, cast.ToString(record.Data()))
results = append(results, data)
}
}
ns := jsonParsed.S("ns")
if ns != nil {
for _, record := range ns.Children() {
data := fmt.Sprintf("%s NS %s", domain, cast.ToString(record.Data()))
results = append(results, data)
}
}
}
if len(results) > 0 {
utils.WriteToFile(dest, strings.Join(results, "\n"))
}
}
// CleanRustScan make rustscan data to flat format ip:port
func CleanRustScan(src string, dest string) {
src = utils.NormalizePath(src)
dest = utils.NormalizePath(dest)
content := utils.ReadingLines(src)
if len(content) <= 0 {
utils.WarnF("File not found: %s", src)
return
}
var results []string
for _, line := range content {
// 103.247.207.76 -> [80,80,443,443]
if !strings.Contains(line, " -> ") {
continue
}
ip := strings.Split(line, " -> ")[0]
rPorts := strings.Split(line, " -> ")[1]
rPorts = rPorts[1 : len(rPorts)-1]
if !strings.Contains(rPorts, ",") {
results = append(results, fmt.Sprintf("%s:%s", ip, rPorts))
}
ports := strings.Split(rPorts, ",")
ports = funk.UniqString(ports)
for _, port := range ports {
results = append(results, fmt.Sprintf("%s:%s", ip, port))
}
}
utils.WriteToFile(dest, strings.Join(results, "\n"))
}
type Vulnerability struct {
SignID string
SignPath string
URL string
Risk string
Confidence string
Request string
ModalID string
ReportPath string
ReportFile string
Status string
Length string
Words string
Time string
}
func GenNucleiReport(opt libs.Options, src string, dest string, templateFile string) {
if templateFile == "" {
templateFile = path.Join(opt.Env.DataFolder, "nuclei-report.html")
}
if !utils.FileExists(src) {
utils.WarnF("file not found: %v", src)
return
}
content := utils.ReadingLines(src)
var vulns []Vulnerability
for index, line := range content {
if strings.TrimSpace(line) == "" {
continue
}
jsonParsed, err := gabs.ParseJSON([]byte(line))
if err != nil {
utils.WarnF("Error parse JSON Data")
continue
}
modalID, err := utils.GetDomain(cast.ToString(jsonParsed.S("host").Data()))
if err != nil {
continue
}
modalID = fmt.Sprintf("%s-%d", strings.ReplaceAll(modalID, ".", "-"), index)
vulns = append(vulns, Vulnerability{
Request: cast.ToString(jsonParsed.S("request").Data()),
URL: cast.ToString(jsonParsed.S("matched-at").Data()),
SignID: cast.ToString(jsonParsed.S("template-id").Data()),
Risk: cast.ToString(jsonParsed.S("info", "severity").Data()),
ModalID: modalID,
Confidence: "Tentative",
})
}
utils.DebugF("Reading vuln %v from: %v ", len(vulns), src)
if len(vulns) == 0 {
utils.WarnF("No Vulnerability found %v", src)
return
}
// read template file
tmpl := utils.GetFileContent(templateFile)
if strings.TrimSpace(tmpl) == "" {
utils.WarnF("empty template data: %v", templateFile)
return
}
variable := make(map[string]interface{})
variable["Title"] = "Nuclei Summary Report"
variable["Vulnerabilities"] = vulns
variable["CurrentDay"] = utils.GetCurrentDay()
variable["Version"] = libs.VERSION
variable["Src"] = filepath.Base(src)
tpl, err := pongo2.FromString(tmpl)
if err != nil {
utils.WarnF("error render data: %v", err)
return
}
out, ok := tpl.Execute(variable)
if ok == nil {
utils.DebugF("Writing Nuclei HTML report to: %v", dest)
utils.WriteToFile(dest, out)
}
}
// CleanJSONHttpx get to get formatted report
func CleanJSONHttpx(filename string, dest string) {
content := utils.ReadingLines(filename)
if len(content) <= 0 {
utils.WarnF("File not found: %s", filename)
return
}
var results []string
for _, line := range content {
jsonParsed, err := gabs.ParseJSON([]byte(line))
if err != nil {
continue
}
URL := cast.ToString(jsonParsed.S("url").Data())
//domain, _ := utils.GetDomain(URL)
bodyHash := cast.ToString(jsonParsed.S("body-sha256").Data())
headerHash := cast.ToString(jsonParsed.S("header-sha256").Data())
hash := utils.GenHash(fmt.Sprintf("%s-%s", headerHash, bodyHash))
title := "No-Title"
rawTitle := jsonParsed.S("title")
if rawTitle != nil {
title = cast.ToString(rawTitle.Data())
}
rawTechs := jsonParsed.S("tech")
techs := "No-Tech"
if rawTechs != nil {
techs = strings.Join(cast.ToStringSlice(rawTechs.Data()), ";;")
}
data := fmt.Sprintf("%s,%s,%s,%s", URL, hash, title, techs)
results = append(results, data)
}
if len(results) > 0 {
utils.WriteToFile(dest, strings.Join(results, "\n"))
}
}
// CleanFFUFJson get to get formatted report
func CleanFFUFJson(filename string, dest string) {
content := utils.ReadingLines(filename)
if len(content) <= 0 {
utils.WarnF("File not found: %s", filename)
return
}
var results []string
for _, line := range content {
jsonParsed, err := gabs.ParseJSON([]byte(line))
if err != nil {
continue
}
resultsJson := jsonParsed.S("results")
if resultsJson == nil {
continue
}
for _, item := range resultsJson.Children() {
//.url,.status,.length,.words,.lines,.redirectlocation
endpoint := cast.ToString(item.S("url").Data())
status := cast.ToString(item.S("status").Data())
length := cast.ToString(item.S("length").Data())
words := cast.ToString(item.S("words").Data())
lines := cast.ToString(item.S("lines").Data())
redirectLocation := cast.ToString(item.S("redirectlocation").Data())
data := fmt.Sprintf("%s,%s,%s,%s,%s,%s", endpoint, status, length, words, lines, redirectLocation)
results = append(results, data)
}
}
if len(results) > 0 {
utils.WriteToFile(dest, strings.Join(results, "\n"))
}
}