osq-exts/tables/crowdstrikefalconagent/crowdstrikefalconagent_darwin.go (180 lines of code) (raw):

package crowdstrikefalconagent import ( "context" "fmt" "os" "os/exec" "regexp" "github.com/groob/plist" "github.com/osquery/osquery-go/plugin/table" ) const ( _DARWIN_FALCONCTL = "/Applications/Falcon.app/Contents/Resources/falconctl" _DARWIN_FALCONCTL_STATS = "stats" _DARWIN_FALCONCTL_PLIST = "--plist" _AGENTID = "agentID" _CUSTOMERID = "customerID" _SENOR_OPERATIONAL = "sensor_operational" _VERSION = "version" _BW_FILTER_CALLED = "bw_filter_called" _BW_FILTER_FALSE = "bw_filter_false" _BW_FILTER_SATISFIED = "bw_filter_satisfied" _BW_FILTER_TIMEOUTS = "bw_filter_timeouts" _BW_FILTER_TRUE = "bw_filter_true" _BW_LATERESPONSE = "bw_lateresponse" _BW_RECEIVER_CALLED = "bw_receiver_called" _BW_RECEIVER_SATISFIED = "bw_receiver_satisfied" _DC_ENABLED = "dc_enabled" _DC_FSAUTH = "dc_fsauth" _DC_RULECOUNT = "dc_rulecount" _ES_AUTH = "es_auth" _ES_NOTIFY = "es_notify" _SA_AVG = "sa_avg" _SA_MAX = "sa_max" _SA_READY = "sa_ready" _SA_REQUESTS = "sa_requests" _SA_SUCCESSES = "sa_successes" _ERR_NOT_LOADED = "not_loaded" _ERR_NOT_FOUND = "not_found" _ERR_PARSE_ERROR = "parse_error" _REGEX_FILTER = "[^0-9a-zA-Z-]+" ) var ( m = regexp.MustCompile(_REGEX_FILTER) ) type TopLevel struct { AgentInfo AgentInfo `plist:"agent_info"` DeviceControl DeviceControl `plist:"device_control"` EndpointSecurity EndpointSecurity `plist:"EndpointSecurity"` StaticAnalysis StaticAnalysis `plist:"StaticAnalysis"` BlockWait BlockWait `plist:"block_wait"` } type AgentInfo struct { AgentID string `plist:"agentID"` CustomerID string `plist:"customerID"` SensorOperational string `plist:"sensor_operational"` Version string `plist:"version"` } type DeviceControl struct { Enabled int `plist:"enabled"` FSAuth int `plist:"fs_auth"` RuleCount int `plist:"rule_count"` } type EndpointSecurity struct { Auth int `plist:"auth"` Notify int `plist:"notify"` } type StaticAnalysis struct { Avg int `plist:"avg"` Max int `plist:"max"` Ready bool `plist:"ready"` Requests int `plist:"requests"` Successes int `plist:"successes"` } type BlockWait struct { FilterCalled int `plist:"filter_called"` FilterFalse int `plist:"filter_false"` FilterSatisfied int `plist:"filter_satisfied"` FilterTimeouts int `plist:"filter_timeouts"` FilterTrue int `plist:"filter_true"` LateResponse int `plist:"late_response"` ReceiverCalled int `plist:"receiver_called"` ReceiverSatisfied int `plist:"receiver_satisfied"` } func (c *CrowdStrikeFalconAgent) osCompat() error { return nil } func (c *CrowdStrikeFalconAgent) osColumns() []table.ColumnDefinition { return []table.ColumnDefinition{ table.TextColumn(_AGENTID), table.TextColumn(_CUSTOMERID), table.TextColumn(_SENOR_OPERATIONAL), table.TextColumn(_VERSION), table.BigIntColumn(_DC_ENABLED), table.BigIntColumn(_DC_FSAUTH), table.BigIntColumn(_DC_RULECOUNT), table.BigIntColumn(_ES_AUTH), table.BigIntColumn(_ES_NOTIFY), table.BigIntColumn(_SA_AVG), table.BigIntColumn(_SA_MAX), table.TextColumn(_SA_READY), table.BigIntColumn(_SA_REQUESTS), table.BigIntColumn(_SA_SUCCESSES), table.BigIntColumn(_BW_FILTER_CALLED), table.BigIntColumn(_BW_FILTER_FALSE), table.BigIntColumn(_BW_FILTER_SATISFIED), table.BigIntColumn(_BW_FILTER_TIMEOUTS), table.BigIntColumn(_BW_FILTER_TRUE), table.BigIntColumn(_BW_LATERESPONSE), table.BigIntColumn(_BW_RECEIVER_CALLED), table.BigIntColumn(_BW_RECEIVER_SATISFIED), } } func (c *CrowdStrikeFalconAgent) osGenerate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { err := checkFalconCtl(_DARWIN_FALCONCTL) if err != nil { return prepareError(_ERR_NOT_FOUND) } stats, err := getStatsOutput(_DARWIN_FALCONCTL, _DARWIN_FALCONCTL_STATS, _DARWIN_FALCONCTL_PLIST) if err != nil { return prepareError(_ERR_NOT_LOADED) } parsed, err := parseRead(stats) if err != nil { return prepareError(_ERR_PARSE_ERROR) } return prepareResults(parsed) } func prepareError(reason string) ([]map[string]string, error) { return []map[string]string{ { _SENOR_OPERATIONAL: reason, }, }, nil } func prepareResults(in *TopLevel) ([]map[string]string, error) { return []map[string]string{ { _AGENTID: in.AgentInfo.AgentID, _CUSTOMERID: in.AgentInfo.CustomerID, _SENOR_OPERATIONAL: in.AgentInfo.SensorOperational, _VERSION: in.AgentInfo.Version, _DC_ENABLED: fmt.Sprintf("%v", in.DeviceControl.Enabled), _DC_FSAUTH: fmt.Sprintf("%v", in.DeviceControl.FSAuth), _DC_RULECOUNT: fmt.Sprintf("%v", in.DeviceControl.RuleCount), _ES_AUTH: fmt.Sprintf("%v", in.EndpointSecurity.Auth), _ES_NOTIFY: fmt.Sprintf("%v", in.EndpointSecurity.Notify), _SA_AVG: fmt.Sprintf("%v", in.StaticAnalysis.Avg), _SA_MAX: fmt.Sprintf("%v", in.StaticAnalysis.Max), _SA_READY: fmt.Sprintf("%v", in.StaticAnalysis.Ready), _SA_REQUESTS: fmt.Sprintf("%v", in.StaticAnalysis.Requests), _SA_SUCCESSES: fmt.Sprintf("%v", in.StaticAnalysis.Successes), _BW_FILTER_CALLED: fmt.Sprintf("%v", in.BlockWait.FilterCalled), _BW_FILTER_FALSE: fmt.Sprintf("%v", in.BlockWait.FilterFalse), _BW_FILTER_SATISFIED: fmt.Sprintf("%v", in.BlockWait.FilterSatisfied), _BW_FILTER_TIMEOUTS: fmt.Sprintf("%v", in.BlockWait.FilterTimeouts), _BW_FILTER_TRUE: fmt.Sprintf("%v", in.BlockWait.FilterTrue), _BW_LATERESPONSE: fmt.Sprintf("%v", in.BlockWait.LateResponse), _BW_RECEIVER_CALLED: fmt.Sprintf("%v", in.BlockWait.ReceiverCalled), _BW_RECEIVER_SATISFIED: fmt.Sprintf("%v", in.BlockWait.ReceiverSatisfied), }, }, nil } func parseRead(in []byte) (out *TopLevel, err error) { err = plist.Unmarshal(in, &out) return } func checkFalconCtl(path string) (err error) { _, err = os.Stat(path) return } func filterString(val string) string { // keep alphanumeric and dash return m.ReplaceAllString(val, "") } func getStatsOutput(path string, opts ...string) ([]byte, error) { for _, v := range opts { v = filterString(v) } cmd := exec.Command(path, opts...) return cmd.Output() }