main
1package cmd
2
3import (
4 "bufio"
5 "context"
6 "fmt"
7 "mysh/pkg/mythic"
8 "mysh/pkg/mythic/api"
9 "os"
10 "strconv"
11 "strings"
12
13 "github.com/spf13/cobra"
14)
15
16var interactCmd = &cobra.Command{
17 Use: "interact <callback_id>",
18 Short: "Interact with a specific callback",
19 Long: "Start an interactive session with a callback, equivalent to right-clicking and selecting 'Interact' in the UI.",
20 Args: cobra.ExactArgs(1),
21 RunE: runInteract,
22}
23
24func init() {
25 rootCmd.AddCommand(interactCmd)
26}
27
28func runInteract(cmd *cobra.Command, args []string) error {
29 if err := validateConfig(); err != nil {
30 return err
31 }
32
33 callbackID, err := strconv.Atoi(args[0])
34 if err != nil {
35 return fmt.Errorf("invalid callback ID: %s", args[0])
36 }
37
38 client := mythic.NewClient(mythicURL, token, insecure, socksProxy)
39 ctx := context.Background()
40
41 // Verify callback exists and is active
42 targetCallback, err := api.FindActiveCallback(ctx, client, callbackID)
43 if err != nil {
44 return err
45 }
46
47 agentType := targetCallback.Payload.PayloadType.Name
48 if agentType == "" {
49 agentType = "agent" // fallback if payload type is not available
50 }
51
52 fmt.Printf("Interacting with callback %d (%s@%s - %s [%s])\n",
53 targetCallback.DisplayID,
54 targetCallback.User,
55 targetCallback.Host,
56 targetCallback.ProcessName,
57 agentType)
58 fmt.Println("Type 'exit' to quit the interactive session")
59 fmt.Println("---")
60
61 scanner := bufio.NewScanner(os.Stdin)
62 for {
63 fmt.Printf("%s[%d]> ", agentType, callbackID)
64 if !scanner.Scan() {
65 break
66 }
67
68 input := strings.TrimSpace(scanner.Text())
69 if input == "" {
70 continue
71 }
72
73 if input == "exit" {
74 fmt.Println("Exiting interactive session")
75 break
76 }
77
78 if err := executeCommand(ctx, client, targetCallback.ID, input); err != nil {
79 fmt.Printf("Error: %v\n", err)
80 }
81 }
82
83 return scanner.Err()
84}
85
86func executeCommand(ctx context.Context, client *mythic.Client, callbackID int, input string) error {
87 parts := strings.Fields(input)
88 if len(parts) == 0 {
89 return nil
90 }
91
92 command := parts[0]
93 params := ""
94 if len(parts) > 1 {
95 params = strings.Join(parts[1:], " ")
96 }
97
98 // Configure polling for interactive mode
99 config := api.TaskPollConfig{
100 TimeoutSeconds: int(api.DefaultTaskTimeout.Seconds()),
101 PollInterval: api.DefaultPollInterval,
102 ShowProgress: true,
103 RawOutput: false,
104 }
105
106 // Execute task and wait for response
107 updatedTask, err := api.ExecuteTaskAndWait(ctx, client, callbackID, command, params, config)
108 if err != nil {
109 fmt.Printf("\n%v\n", err)
110 return nil
111 }
112
113 if updatedTask.Response != "" {
114 fmt.Printf("\nResponse:\n%s\n", updatedTask.Response)
115 } else {
116 fmt.Printf("\nTask completed with status: %s\n", updatedTask.Status)
117 }
118 return nil
119}