Exemple #1
0
func commandPrintShort(data interface{}) (idstr, agtname, duration, status string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("commandPrintShort() -> %v", e)
		}
	}()
	cmd, err := client.ValueToCommand(data)
	if err != nil {
		panic(err)
	}
	idstr = fmt.Sprintf("%.0f", cmd.ID)
	if len(idstr) < 20 {
		for i := len(idstr); i < 20; i++ {
			idstr += " "
		}
	}

	agtname = cmd.Agent.Name
	if len(agtname) < 30 {
		for i := len(agtname); i < 30; i++ {
			agtname += " "
		}
	}
	if len(agtname) > 30 {
		agtname = agtname[0:27] + "..."
	}

	duration = cmd.FinishTime.Sub(cmd.StartTime).String()
	if len(duration) > 10 {
		duration = duration[0:8] + duration[len(duration)-3:len(duration)-1]
	}
	if len(duration) < 10 {
		for i := len(duration); i < 10; i++ {
			duration += " "
		}
	}

	status = cmd.Status
	if len(status) > 10 {
		status = status[0:9]
	}
	if len(status) < 10 {
		for i := len(status); i < 10; i++ {
			status += " "
		}
	}

	return
}
Exemple #2
0
func searchCommands(aid float64, show string, cli client.Client) (cmds []mig.Command, err error) {
	defer func() {
		fmt.Printf("\n")
		if e := recover(); e != nil {
			err = fmt.Errorf("searchCommands() -> %v", e)
		}
	}()
	base := fmt.Sprintf("search?type=command&actionid=%.0f", aid)
	switch show {
	case "found":
		base += "&foundanything=true"
	case "notfound":
		base += "&foundanything=false"
	}
	offset := 0
	// loop until all results have been retrieved using paginated queries
	for {
		fmt.Printf(".")
		target := fmt.Sprintf("%s&limit=50&offset=%d", base, offset)
		resource, err := cli.GetAPIResource(target)
		// because we query using pagination, the last query will return a 404 with no result.
		// When that happens, GetAPIResource returns an error which we do not report to the user
		if resource.Collection.Error.Message == "no results found" {
			err = nil
			break
		} else if err != nil {
			panic(err)
		}
		for _, item := range resource.Collection.Items {
			for _, data := range item.Data {
				if data.Name != "command" {
					continue
				}
				cmd, err := client.ValueToCommand(data.Value)
				if err != nil {
					panic(err)
				}
				cmds = append(cmds, cmd)
			}
		}
		// else increase limit and offset and continue
		offset += 50
	}
	return
}
Exemple #3
0
func printAgentLastCommands(agtid float64, limit int, cli client.Client) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("printAgentLastCommands() -> %v", e)
		}
	}()
	target := fmt.Sprintf("search?type=command&agentid=%.0f&limit=%d", agtid, limit)
	resource, err := cli.GetAPIResource(target)
	if err != nil {
		panic(err)
	}
	fmt.Printf("-------  ID  ------- + --------    Action Name ------- + ----    Date    ---- +  -- Status --\n")
	for _, item := range resource.Collection.Items {
		for _, data := range item.Data {
			if data.Name != "command" {
				continue
			}
			cmd, err := client.ValueToCommand(data.Value)
			if err != nil {
				panic(err)
			}
			name := cmd.Action.Name
			if len(name) < 30 {
				for i := len(name); i < 30; i++ {
					name += " "
				}
			}
			if len(name) > 30 {
				name = name[0:27] + "..."
			}
			fmt.Printf("%.0f     %s   %s    %s\n", cmd.ID, name,
				cmd.StartTime.Format(time.RFC3339), cmd.Status)
		}
	}
	return
}
Exemple #4
0
// search runs a search for actions, commands or agents
func search(input string, cli client.Client) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("search() -> %v", e)
		}
	}()
	orders := strings.Split(input, " ")
	if len(orders) < 2 {
		orders = append(orders, "help")
	}
	sType := ""
	switch orders[1] {
	case "action", "agent", "command", "investigator":
		sType = orders[1]
	case "", "help":
		fmt.Printf(`usage: search <action|agent|command|investigator> where <key>=<value> [and <key>=<value>...]

Example:
mig> search command where agentname=%%khazad%% and investigatorname=%%vehent%% and actionname=%%memory%% and after=2015-09-09T17:00:00Z
	----    ID      ---- + ----         Name         ---- + --- Last Updated ---
	       4886304327951   memory -c /home/ulfr/.migrc...   2015-09-09T13:01:03-04:00

The following search parameters are available, per search type:
* action:
	- name=<str>		search actions by name <str>
	- before=<rfc3339>	search actions that expired before <rfc3339 date>
	- after=<rfc3339>	search actions were valid after <rfc3339 date>
	- commandid=<id>	search action that spawned a given command
	- agentid=<id>		search actions that ran on a given agent
	- agentname=<str>	search actions that ran on an agent named <str>
	- investigatorid=<id>	search actions signed by a given investigator
	- investigatorname=<str>search actions signed by investigator named <str>
	- status=<str>		search actions with a given status amongst:
				pending, scheduled, preparing, invalid, inflight, completed
* command:
	- name=<str>		search commands by action name <str>
	- before=<rfc3339>	search commands that started before <rfc3339 date>
	- after=<rfc3339>	search commands that started after <rfc3339 date>
	- actionid=<id>		search commands spawned action <id>
	- actionname=<str>	search commands spawned by an action named <str>
	- agentname=<str>	search commands that ran on an agent named <str>
	- agentid=<id>		search commands that ran on a given agent
	- investigatorid=<id>	search commands signed by investigator <id>
	- investigatorname=<str>search commands signed by investigator named <str>
	- status=<str>		search commands with a given status amongst:
				prepared, sent, success, timeout, cancelled, expired, failed
* agent:
	- name=<str>		search agents by hostname
	- before=<rfc3339>	search agents that have sent a heartbeat before <rfc3339 date>
	- after=<rfc3339>	search agents that have sent a heartbeat after <rfc3339 date>
	- actionid=<id>		search agents that ran action <id>
	- actionname=<str>	search agents that ran action named <str>
	- commandid=<id>	search agents that ran command <id>
	- investigatorid=<id>	search agents that ran an action signed by investigator <id>
	- investigatorname=<str>search agents that ran an action signed by investigator named <str>
	- version=<str>		search agents by version <str>
	- status=<str>		search agents with a given status amongst:
				online, upgraded, destroyed, offline, idle
* investigator:
	- name=<str>		search investigators by name
	- before=<rfc3339>	search investigators created or modified before <rfc3339 date>
	- after=<rfc3339>	search investigators created or modified after <rfc3339 date>
	- actionid=<id>		search investigators that signed action <id>
	- actionname=<str>	search investigators that signed action named <str>
	- commandid=<id>	search investigators that ran command <id>
	- agentid=<id>		search investigators that ran a command on a given agent
	- agentname=<str>	search investigators that ran actions on an agent named <str>,
	- status=<str>		search investigators by status amongst: active, disabled

All searches accept the 'limit=<num>' parameter to limits the number of results returned by a search, defaults to 100
Parameters that accept a <str> can use wildcards * and % (ex: name=jul%veh% ).
No spaces are permitted within parameters. Spaces are used to separate search parameters.
`)
		return nil
	default:
		return fmt.Errorf("Invalid search '%s'. Try `search help`.\n", input)
	}
	p, err := parseSearchQuery(orders)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Searching %s after %s and before %s, limited to %.0f results\n", p.Type,
		p.After.Format(time.RFC3339), p.Before.Format(time.RFC3339), p.Limit)
	resources, err := cli.GetAPIResource("search?" + p.String())
	if err != nil {
		if strings.Contains(fmt.Sprintf("%v", err), "HTTP 404") {
			panic("No results found for search query: " + p.String())
		}
		panic(err)
	}
	switch sType {
	case "agent":
		fmt.Println("---   ID  ---- + ----         Name         ---- + -- Status -- + -- Last Heartbeat --")
	case "action":
		fmt.Println("----- ID ----- + --------   Action Name ------- + ----------- Target  ---------- + ---- Investigators ---- + - Sent - + - Status - + --- Last Updated --- ")
	case "command":
		fmt.Println("----  ID  ---- + ----         Name         ---- + --- Last Updated ---")
	case "investigator":
		fmt.Println("- ID - + ----         Name         ---- + --- Status ---")
	}
	for _, item := range resources.Collection.Items {
		for _, data := range item.Data {
			if data.Name != sType {
				continue
			}
			switch data.Name {
			case "action":
				idstr, name, target, datestr, invs, status, sent, err := actionPrintShort(data.Value)
				if err != nil {
					panic(err)
				}
				fmt.Printf("%s   %s   %s   %s   %8d   %s   %s\n", idstr, name, target, invs, sent,
					status, datestr)
			case "command":
				cmd, err := client.ValueToCommand(data.Value)
				if err != nil {
					panic(err)
				}
				name := cmd.Action.Name
				if len(name) < 30 {
					for i := len(name); i < 30; i++ {
						name += " "
					}
				}
				if len(name) > 30 {
					name = name[0:27] + "..."
				}
				fmt.Printf("%14.0f   %s   %s\n", cmd.ID, name,
					cmd.FinishTime.UTC().Format(time.RFC3339))

			case "agent":
				agt, err := client.ValueToAgent(data.Value)
				if err != nil {
					panic(err)
				}
				name := agt.Name
				if len(name) < 30 {
					for i := len(name); i < 30; i++ {
						name += " "
					}
				}
				if len(name) > 30 {
					name = name[0:27] + "..."
				}
				status := agt.Status
				if len(status) < 12 {
					for i := len(status); i < 12; i++ {
						status += " "
					}
				}
				if len(status) > 12 {
					status = status[0:12]
				}
				fmt.Printf("%20.0f   %s   %s   %s\n", agt.ID, name, status,
					agt.HeartBeatTS.UTC().Format(time.RFC3339))
			case "investigator":
				inv, err := client.ValueToInvestigator(data.Value)
				if err != nil {
					panic(err)
				}
				name := inv.Name
				if len(name) < 30 {
					for i := len(name); i < 30; i++ {
						name += " "
					}
				}
				if len(name) > 30 {
					name = name[0:27] + "..."
				}
				fmt.Printf("%6.0f   %s   %s\n", inv.ID, name, inv.Status)
			}
		}
	}
	return
}