// PrintResults() is an *optional* method that returns results in a human-readable format. // if matchOnly is set, only results that have at least one match are returned. // If matchOnly is not set, all results are returned, along with errors and statistics. func (r *run) PrintResults(result modules.Result, matchOnly bool) (prints []string, err error) { var ( el elements stats statistics ) err = result.GetElements(&el) if err != nil { panic(err) } if el.Hostname != "" { prints = append(prints, fmt.Sprintf("hostname is %s", el.Hostname)) } for _, addr := range el.Addresses { prints = append(prints, fmt.Sprintf("address is %s", addr)) } for host, addrs := range el.LookedUpHost { for _, addr := range addrs { prints = append(prints, fmt.Sprintf("lookedup host %s has IP %s", host, addr)) } } if matchOnly { return } for _, e := range result.Errors { prints = append(prints, fmt.Sprintf("error: %v", e)) } err = result.GetStatistics(&stats) if err != nil { panic(err) } prints = append(prints, fmt.Sprintf("stat: %d stuff found", stats.StuffFound)) return }
func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) { var ( elem elements stats Statistics ) err = result.GetElements(&elem) if err != nil { panic(err) } err = result.GetStatistics(&stats) if err != nil { panic(err) } for _, x := range elem.Packages { resStr := fmt.Sprintf("pkgmatch name=%v version=%v type=%v", x.Name, x.Version, x.Type) prints = append(prints, resStr) } if !foundOnly { for _, we := range result.Errors { prints = append(prints, we) } stats := fmt.Sprintf("Statistics: runtime %v", stats.ExecRuntime) prints = append(prints, stats) } return }
func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) { var ( elem ScribeElements stats statistics ) err = result.GetElements(&elem) if err != nil { panic(err) } err = result.GetStatistics(&stats) if err != nil { panic(err) } for _, x := range elem.Results { if elem.HumanOutput { prints = append(prints, x.String()) } else if elem.JSONOutput { prints = append(prints, x.JSON()) } else { for _, y := range x.SingleLineResults() { prints = append(prints, y) } } } if !foundOnly { for _, we := range result.Errors { prints = append(prints, we) } s := fmt.Sprintf("Statistics: runtime %v", stats.ExecRuntime) prints = append(prints, s) } return }
// PrintResults() returns results in a human-readable format. if foundOnly is set, // only results that have at least one match are returned. // If foundOnly is not set, all results are returned, along with errors and // statistics. func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) { var ( el searchResults stats statistics ) err = result.GetElements(&el) if err != nil { panic(err) } err = result.GetStatistics(&stats) if err != nil { panic(err) } for label, sr := range el { for _, mps := range sr { var out string if mps.Process.Name == "" { if foundOnly { continue } out = fmt.Sprintf("0 match found in search '%s'", label) } else { out = fmt.Sprintf("%s [pid:%.0f] in search '%s'", mps.Process.Name, mps.Process.Pid, label) } if mps.Search.Options.MatchAll { prints = append(prints, out) continue } out += " on checks" // if matchany, print the detail of the checks that matched with the filename for _, v := range mps.Search.Names { out += fmt.Sprintf(" name='%s'", v) } for _, v := range mps.Search.Libraries { out += fmt.Sprintf(" library='%s'", v) } for _, v := range mps.Search.Contents { out += fmt.Sprintf(" content='%s'", v) } for _, v := range mps.Search.Bytes { out += fmt.Sprintf(" byte='%s'", v) } prints = append(prints, out) } } if !foundOnly { for _, e := range stats.Failures { prints = append(prints, fmt.Sprintf("Failure: %v", e)) } for _, e := range result.Errors { prints = append(prints, e) } stat := fmt.Sprintf("Statistics: %.0f processes checked, %.0f matched, %d failures, ran in %s.", stats.ProcessCount, stats.TotalHits, len(stats.Failures), stats.Exectime) prints = append(prints, stat) } return }
func buildResults(e elements, r *modules.Result) (buf []byte, err error) { r.Success = true r.Elements = e if len(e.Packages) > 0 { r.FoundAnything = true } endCounters() r.Statistics = stats buf, err = json.Marshal(r) return }
func evalResults(jsonresults []byte, expectedfiles []string) error { var ( mr modules.Result sr SearchResults ) err := json.Unmarshal(jsonresults, &mr) if err != nil { return err } if !mr.Success { return fmt.Errorf("failed to run file search") } if !mr.FoundAnything { return fmt.Errorf("should have found %d files in '%s' but didn't", len(expectedfiles), basedir) } if mr.GetElements(&sr) != nil { return fmt.Errorf("failed to retrieve search results") } if len(expectedfiles) == 1 && expectedfiles[0] == "" { // should not have found anything to succeed if len(sr["s1"]) != 1 { return fmt.Errorf("expected to find nothing but found %d files", len(sr["s1"])) } else if sr["s1"][0].File != "" { return fmt.Errorf("expected to find nothing but found file '%s'", sr["s1"][0].File) } } if len(sr["s1"]) != len(expectedfiles) { if len(sr["s1"]) == 1 && sr["s1"][0].File == "" { return fmt.Errorf("expected to find %d files but found nothing", len(expectedfiles)) } return fmt.Errorf("expected to find %d files but found %d", len(expectedfiles), len(sr["s1"])) } for _, found := range sr["s1"] { for i, expectedfile := range expectedfiles { if filepath.Clean(found.File) == filepath.Clean(expectedfile) { // good result, remove expected file from list of expected files expectedfiles = expectedfiles[:i+copy(expectedfiles[i:], expectedfiles[i+1:])] } } } if len(expectedfiles) != 0 { return fmt.Errorf("did not find %d files: %s", len(expectedfiles), expectedfiles) } return nil }
func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) { var el elements defer func() { if e := recover(); e != nil { err = fmt.Errorf("Print Error: %v", e) } }() err = result.GetElements(&el) if err != nil { panic(err) } if result.FoundAnything { prints = append(prints, fmt.Sprintf("%s ping of %s succeeded. Target is reachable.", el.Protocol, el.ResolvedHost, ), ) } // if we don't care about results where the target was not reachable, stop here if foundOnly { return } if !result.FoundAnything { prints = append(prints, fmt.Sprintf("%s ping of %s failed. Target is no reachable.", el.Protocol, el.ResolvedHost, ), ) } for i, lat := range el.Latencies { switch lat { case -1: prints = append(prints, fmt.Sprintf("ping #%d failed, target was unreachable", i+1)) case 0: prints = append(prints, fmt.Sprintf("ping #%d failed, reason unknown", i+1)) case 9999999: if el.Protocol == "udp" { prints = append(prints, fmt.Sprintf("ping #%d may have succeeded (no udp response)", i+1)) } else { prints = append(prints, fmt.Sprintf("ping #%d failed, connection timed out", i+1)) } default: prints = append(prints, fmt.Sprintf("ping #%d succeeded in %.0fms", i+1, lat)) } } return }
func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) { var ( el elements stats statistics ) err = result.GetElements(&el) if err != nil { return } prints = append(prints, "local time is "+el.LocalTime) if el.HasCheckedDrift { if el.IsWithinDrift { prints = append(prints, "local time is within acceptable drift from NTP servers") } else { prints = append(prints, "local time is out of sync from NTP servers") for _, drift := range el.Drifts { prints = append(prints, drift) } } } // stop here if foundOnly is set, we don't want to see errors and stats if foundOnly { return } for _, e := range result.Errors { prints = append(prints, "error:", e) } err = result.GetStatistics(&stats) if err != nil { panic(err) } prints = append(prints, "stat: execution time was "+stats.ExecTime) for _, ntpstat := range stats.NtpStats { if ntpstat.Reachable { prints = append(prints, "stat: "+ntpstat.Host+" responded in "+ntpstat.Latency+" with time "+ntpstat.Time.UTC().String()+". local time drifts by "+ntpstat.Drift) } else { prints = append(prints, "stat: "+ntpstat.Host+" was unreachable") } } if result.Success { prints = append(prints, fmt.Sprintf("timedrift module has succeeded")) } else { prints = append(prints, fmt.Sprintf("timedrift module has failed")) } return }
func buildResults(e ScribeElements, r *modules.Result) (buf []byte, err error) { r.Success = true r.Elements = e if len(e.Results) > 0 { r.FoundAnything = true } // If any tests resulted in an error, store them as errors in the command. for _, x := range e.Results { if x.IsError { es := fmt.Sprintf("Error: %v in \"%v\"", x.Error, x.TestID) r.Errors = append(r.Errors, es) } } endCounters() r.Statistics = stats buf, err = json.Marshal(r) return }
// This function is used to call the file module from this module. In order to // avoid exporting types from the file module, we construct parameters for the // file module using the parameter creation functions (passing command line // arguments). // // We use the file modules file system location functions here to avoid // duplicating functionality in this module. func fileModuleLocator(pattern string, regex bool, root string, depth int) ([]string, error) { ret := make([]string, 0) // Build a pseudo-run struct to let us call the file module. run := modules.Available["file"].NewRun() args := make([]string, 0) args = append(args, "-path", root) args = append(args, "-name", pattern) args = append(args, "-maxdepth", strconv.Itoa(depth)) param, err := run.(modules.HasParamsParser).ParamsParser(args) buf, err := modules.MakeMessage(modules.MsgClassParameters, param, false) if err != nil { return ret, nil } rdr := bytes.NewReader(buf) res := run.Run(rdr) var modresult modules.Result var sr file.SearchResults err = json.Unmarshal([]byte(res), &modresult) if err != nil { return ret, err } err = modresult.GetElements(&sr) if err != nil { return ret, err } p0, ok := sr["s1"] if !ok { return ret, fmt.Errorf("result in file module call was missing") } for _, x := range p0 { ret = append(ret, x.File) } return ret, nil }
func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) { var statusMsg string err = result.GetElements(&statusMsg) if err != nil { prints = append(prints, "[error] failed to retrieve status message from results") } if statusMsg != "" { prints = append(prints, statusMsg) } if foundOnly { return } for _, e := range result.Errors { prints = append(prints, "[error] "+e) } if result.Success { prints = append(prints, fmt.Sprintf("agentdestroy module has succeeded")) } else { prints = append(prints, fmt.Sprintf("agentdestroy module has failed")) } return }
func makeComplianceItem(cmd mig.Command, conf Config) (items []gozdef.ComplianceItem, err error) { var ci gozdef.ComplianceItem ci.Utctimestamp = time.Now().UTC().Format(time.RFC3339Nano) ci.Target = cmd.Agent.Name ci.Policy.Name = cmd.Action.Threat.Type ci.Policy.URL = cmd.Action.Description.URL ci.Policy.Level = cmd.Action.Threat.Level ci.Check.Ref = cmd.Action.Threat.Ref ci.Check.Description = cmd.Action.Name ci.Link = fmt.Sprintf("%s/command?commandid=%.0f", conf.API.Host, cmd.ID) if cmd.Agent.Tags != nil { operator := "" if _, ok := cmd.Agent.Tags.(map[string]interface{})["operator"]; ok { operator = cmd.Agent.Tags.(map[string]interface{})["operator"].(string) } team := getTeam(cmd.Agent, conf) ci.Tags = struct { Operator string `json:"operator"` Team string `json:"team"` }{ Operator: operator, Team: team, } } for i, result := range cmd.Results { buf, err := json.Marshal(result) if err != nil { return items, err } if i > (len(cmd.Action.Operations) - 1) { // skip this entry if the lookup fails continue } switch cmd.Action.Operations[i].Module { case "file": var r modules.Result var el file.SearchResults err = json.Unmarshal(buf, &r) if err != nil { return items, err } err = r.GetElements(&el) if err != nil { return items, err } for label, sr := range el { for _, mf := range sr { ci.Check.Location = mf.File ci.Check.Name = label ci.Check.Test.Type = "file" ci.Check.Test.Value = "" for _, v := range mf.Search.Names { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("name='%s'", v) } for _, v := range mf.Search.Sizes { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("size='%s'", v) } for _, v := range mf.Search.Modes { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("mode='%s'", v) } for _, v := range mf.Search.Mtimes { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("mtime='%s'", v) } for _, v := range mf.Search.Contents { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("content='%s'", v) } for _, v := range mf.Search.MD5 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("md5='%s'", v) } for _, v := range mf.Search.SHA1 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha1='%s'", v) } for _, v := range mf.Search.SHA256 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha256='%s'", v) } for _, v := range mf.Search.SHA384 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha384='%s'", v) } for _, v := range mf.Search.SHA512 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha512='%s'", v) } for _, v := range mf.Search.SHA3_224 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha3_224='%s'", v) } for _, v := range mf.Search.SHA3_256 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha3_256='%s'", v) } for _, v := range mf.Search.SHA3_384 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha3_384='%s'", v) } for _, v := range mf.Search.SHA3_512 { if len(ci.Check.Test.Value) > 0 { ci.Check.Test.Value += " and " } ci.Check.Test.Value += fmt.Sprintf("sha3_512='%s'", v) } if mf.File == "" { for i, p := range mf.Search.Paths { if i > 0 { ci.Check.Location += ", " } ci.Check.Location += p } ci.Compliance = false } else { ci.Compliance = true } items = append(items, ci) } } } } return }
func (r *run) PrintResults(result modules.Result, matchOnly bool) (prints []string, err error) { var ( el elements stats statistics ) defer func() { if e := recover(); e != nil { err = fmt.Errorf("PrintResults() -> %v", e) } }() el = *newElements() err = result.GetElements(&el) if err != nil { panic(err) } for val, res := range el.LocalMAC { if matchOnly && len(res) < 1 { continue } for _, el := range res { resStr := fmt.Sprintf("found local mac %s for netstat localmac:'%s'", el.LocalMACAddr, val) resStr += printNamespaceId(el.Namespace) prints = append(prints, resStr) } } for val, res := range el.NeighborMAC { if matchOnly && len(res) < 1 { continue } for _, el := range res { resStr := fmt.Sprintf("found neighbor mac %s %s for netstat neighbormac:'%s'", el.RemoteMACAddr, el.RemoteAddr, val) resStr += printNamespaceId(el.Namespace) prints = append(prints, resStr) } if len(res) == 0 { resStr := fmt.Sprintf("did not find anything for netstat neighbormac:'%s'", val) prints = append(prints, resStr) } } for val, res := range el.LocalIP { if matchOnly && len(res) < 1 { continue } for _, el := range res { resStr := fmt.Sprintf("found local ip %s for netstat localip:'%s'", el.LocalAddr, val) resStr += printNamespaceId(el.Namespace) prints = append(prints, resStr) } if len(res) == 0 { resStr := fmt.Sprintf("did not find anything for netstat localip:'%s'", val) prints = append(prints, resStr) } } for val, res := range el.ConnectedIP { if matchOnly && len(res) < 1 { continue } for _, el := range res { resStr := fmt.Sprintf("found connected tuple %s:%.0f with local tuple %s:%.0f for netstat connectedip:'%s'", el.RemoteAddr, el.RemotePort, el.LocalAddr, el.LocalPort, val) resStr += printNamespaceId(el.Namespace) prints = append(prints, resStr) } if len(res) == 0 { resStr := fmt.Sprintf("did not find anything for netstat connectedip:'%s'", val) prints = append(prints, resStr) } } for val, res := range el.ListeningPort { if matchOnly && len(res) < 1 { continue } for _, el := range res { resStr := fmt.Sprintf("found listening port %.0f for netstat listeningport:'%s'", el.LocalPort, val) resStr += printNamespaceId(el.Namespace) prints = append(prints, resStr) } if len(res) == 0 { resStr := fmt.Sprintf("did not find anything for netstat listeningport:'%s'", val) prints = append(prints, resStr) } } if matchOnly { return } for _, e := range result.Errors { prints = append(prints, fmt.Sprintf("error: %v", e)) } err = result.GetStatistics(&stats) if err != nil { panic(err) } resStr := fmt.Sprintf("Statistics: total hits %.0f examined %.0f items exectime %s", stats.Totalhits, stats.Examined, stats.Exectime) prints = append(prints, resStr) return }
func commandsToComplianceItems(commands []mig.Command) (items []ComplianceItem, err error) { for _, cmd := range commands { var bitem ComplianceItem bitem.Utctimestamp = cmd.FinishTime.UTC().Format(time.RFC3339Nano) bitem.Target = cmd.Agent.Name bitem.Policy.Name = cmd.Action.Threat.Type bitem.Policy.URL = cmd.Action.Description.URL bitem.Policy.Level = cmd.Action.Threat.Level bitem.Check.Ref = cmd.Action.Threat.Ref bitem.Check.Description = cmd.Action.Name bitem.Link = fmt.Sprintf("%s/command?commandid=%.0f", ctx.Server.BaseURL, cmd.ID) if _, ok := cmd.Agent.Tags.(map[string]interface{})["operator"]; ok { var t ComplianceTags t.Operator = cmd.Agent.Tags.(map[string]interface{})["operator"].(string) bitem.Tags = t } for i, result := range cmd.Results { buf, err := json.Marshal(result) if err != nil { return items, err } if i > (len(cmd.Action.Operations) - 1) { // skip this entry if the lookup fails continue } switch cmd.Action.Operations[i].Module { case "file": var el file.SearchResults var r modules.Result err = json.Unmarshal(buf, &r) if err != nil { return items, err } err = r.GetElements(&el) if err != nil { return items, err } for label, sr := range el { for _, mf := range sr { bitem.Check.Location = mf.File bitem.Check.Name = label bitem.Check.Test.Type = "file" bitem.Check.Test.Value = "" for _, v := range mf.Search.Names { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("name='%s'", v) } for _, v := range mf.Search.Sizes { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("size='%s'", v) } for _, v := range mf.Search.Modes { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("mode='%s'", v) } for _, v := range mf.Search.Mtimes { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("mtime='%s'", v) } for _, v := range mf.Search.Contents { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("content='%s'", v) } for _, v := range mf.Search.MD5 { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("md5='%s'", v) } for _, v := range mf.Search.SHA1 { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("sha1='%s'", v) } for _, v := range mf.Search.SHA2 { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("sha2='%s'", v) } for _, v := range mf.Search.SHA3 { if len(bitem.Check.Test.Value) > 0 { bitem.Check.Test.Value += " and " } bitem.Check.Test.Value += fmt.Sprintf("sha3='%s'", v) } if mf.File == "" { for i, p := range mf.Search.Paths { if i > 0 { bitem.Check.Location += ", " } bitem.Check.Location += p } bitem.Compliance = false } else { bitem.Compliance = true } items = append(items, bitem) } } } } } return }