/src/nighthawkresponse/audit/manifest.go
https://github.com/biggiesmallsAG/nightHawkResponse · Go · 257 lines · 178 code · 52 blank · 27 comment · 49 complexity · 9343e650cc01aa57cdd9da52e9ccbc1b MD5 · raw file
- /*
- *@package nighthawkresponse
- *@file manifest.go
- *@author roshan maskey <roshanmaskey@gmail.com>
- *
- *@description This file contains structure and functions to process Redline audit manifest file
- */
-
- //package nighthawkresponse
- package audit
-
- import (
- "encoding/json"
- "encoding/xml"
- "errors"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "regexp"
- "strings"
-
- nhlog "nighthawkresponse/log"
- nhs "nighthawkresponse/nhstruct"
- )
-
- type AuditResult struct {
- Payload string `json:"payload"`
- PayloadType string `json:"type"`
- }
-
- type AuditGenerator struct {
- Generator string `json:"generator"`
- GeneratorVersion string `json:"generatorVersion"`
- AuditResults []AuditResult `json:"results"`
- }
-
- type RlManifest struct {
- SysInfo nhs.RlSystemInfo `json:"sysinfo"`
- Type string `json:"type"`
- Version string `json:"version"`
- Audits []AuditGenerator `json:"audits"`
- }
-
- type RlAudit struct {
- AuditGenerator string
- AuditFile string
- }
-
- func (rlman *RlManifest) ParseAuditManifest(filename string) error {
- manifestData, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- json.Unmarshal(manifestData, &rlman)
- return nil
- }
-
- /// This function returns the filename for the give audit generator
- /// It does not return full file path.
- /// This function ignore any file containing audit issues
- func (rlman *RlManifest) Payload(generator string) []string {
- var payload []string
-
- for _, auditgenerator := range rlman.Audits {
- if auditgenerator.Generator == generator {
- for _, p := range auditgenerator.AuditResults {
- // Only append the files without issue. We are going to ignore issue file
- if !strings.Contains(p.Payload, "issue") {
- payload = append(payload, p.Payload)
- }
- }
- }
- }
- return payload
- }
-
- /// This function returns all the payloads file from manifest
- func (rlman *RlManifest) Payloads(session_dir string) []string {
- var payload []string
- var w32system_file string
-
- for _, ag := range rlman.Audits {
- for _, p := range ag.AuditResults {
- if !strings.Contains(p.Payload, "issue") {
- payload = append(payload, p.Payload)
-
- if ag.Generator == "w32system" {
- w32system_file = p.Payload
- }
- }
- }
- }
-
- xmlData, _ := ioutil.ReadFile(filepath.Join(session_dir, w32system_file))
- xml.Unmarshal(xmlData, &rlman.SysInfo)
-
- return payload
- }
-
- func (rlman *RlManifest) Payloads2(session_dir string) []RlAudit {
- var rlaudits []RlAudit
- var w32system_file string = ""
- var sysinfo_file string = ""
-
- for _, ag := range rlman.Audits {
- for _, p := range ag.AuditResults {
- if !strings.Contains(p.Payload, "issue") && !strings.Contains(p.PayloadType, "issue") {
- var r = RlAudit{AuditGenerator: ag.Generator, AuditFile: p.Payload}
- rlaudits = append(rlaudits, r)
-
- if ag.Generator == "w32system" {
- w32system_file = p.Payload
- }
-
- if ag.Generator == "sysinfo" {
- sysinfo_file = p.Payload
- }
- }
- }
- }
-
- // Starting with HX3.5 w32system is replaced by sysinfo
- if w32system_file == "" && sysinfo_file != "" {
- w32system_file = sysinfo_file
- }
-
- xmlData, _ := ioutil.ReadFile(filepath.Join(session_dir, w32system_file))
- xml.Unmarshal(xmlData, &rlman.SysInfo)
-
- return rlaudits
- }
-
- /// Load SystemInformation
-
- /// This function returns manifest file in given session directory
- func GetAuditManifestFile(session_dir string) (string, error) {
- filelist, err := filepath.Glob(filepath.Join(session_dir, "*"))
- if err != nil {
- return "", err
- }
-
- var manifest_file string = ""
- for _, file := range filelist {
- manifest_file = ""
- _, filename := filepath.Split(file)
-
- lwrFilename := strings.ToLower(filename)
- // Checking keyword manifest in filename and file extension .json
- if strings.Contains(lwrFilename, "manifest") && strings.HasSuffix(lwrFilename, "json") {
- manifest_file = filename
- break
- } else if strings.HasSuffix(lwrFilename, "json") {
- // This is loose checking for manifest file. Just checking for json file if keyword is not found
- manifest_file = filename
- }
- }
-
- /// Something to do in future. Validate that json file is correct auditmanifest file by unmarshaling
- if len(manifest_file) > 2 {
- return manifest_file, nil
- }
-
- return manifest_file, errors.New("Error no manifest file")
- }
-
- /// This function generates manifest file. This function is
- /// typically used for audits generated using MIR (Mandiant Intelligence Response)
- /// The manifest file created by this function is different that Redline/HX manifest
-
- func GenerateAuditManifestFile(session_dir string) string {
- var manfilename string = "nh_manifest.json"
-
- var rlman RlManifest
- rlman.Type = "audit_manifest"
- rlman.Version = "1.0"
-
- filelist, err := filepath.Glob(filepath.Join(session_dir, "*"))
- if err != nil {
- panic(err.Error())
- }
-
- for _, file := range filelist {
- if IsRegularFile(file) {
-
- fh, err := os.Open(file)
- if err != nil {
- panic(err.Error())
- }
- defer fh.Close()
-
- buf := make([]byte, 500)
- fh.Read(buf)
-
- strbuf := string(buf)
-
- // No processing file containig Redline or MIR issues
- if strings.Contains(strbuf, "issue.xsd") {
- continue
- }
-
- /// Begin creating manifest audits
- var ar AuditResult
- var ag AuditGenerator
-
- ar.Payload = filepath.Base(file)
- ar.PayloadType = "application/xml"
-
- re := regexp.MustCompile("generator=\"(.*)\" generatorVersion=\"([0-9.]+)\" ")
- match := re.FindStringSubmatch(strbuf)
-
- if len(match) > 2 {
- ag.Generator = match[1]
- ag.GeneratorVersion = match[2]
-
- // HX audit failed audit contains "FireEye Agent" as generator.
- // Ignoring audits with issue.
- if ag.Generator != "FireEye Agent" {
- ag.AuditResults = append(ag.AuditResults, ar)
- rlman.Audits = append(rlman.Audits, ag)
- }
-
- }
-
- }
- }
-
- manJsonData, _ := json.MarshalIndent(&rlman, "", " ")
-
- nhlog.LogMessage("GenerateAuditManifestFile", "INFO", fmt.Sprintf("Generating manifest file %s", manfilename))
-
- err = ioutil.WriteFile(filepath.Join(session_dir, manfilename), manJsonData, 0644)
- if err != nil {
- nhlog.LogMessage("GenerateAuditManifestFile", "WARNING", fmt.Sprintf("Failed to write %s to session directory %s", manfilename, session_dir))
- return ""
- }
-
- return manfilename
- }
-
- //
- func IsRegularFile(file string) bool {
- fh, err := os.Open(file)
- if err != nil {
- nhlog.LogMessage("IsRegularFile", "WARNING", fmt.Sprintf("Failed to open file %s", file))
- return false
- }
-
- defer fh.Close()
-
- fi, _ := fh.Stat()
-
- if fi.Mode().IsRegular() {
- return true
- }
- return false
- }