2025-02-06 14:42:06 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"strings"
|
|
|
|
|
"text/tabwriter"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2025-04-01 20:28:14 +02:00
|
|
|
func ListAgents(operatorID string) {
|
2025-02-06 14:42:06 +01:00
|
|
|
var sb strings.Builder
|
|
|
|
|
|
|
|
|
|
operatorConn, _ := GetOperatorConn(operatorID)
|
|
|
|
|
|
|
|
|
|
tw := tabwriter.NewWriter(&sb, 0, 8, 2, ' ', 0) // Initialize a tab writer
|
|
|
|
|
|
|
|
|
|
// Write the header row
|
2025-07-13 19:40:11 +02:00
|
|
|
fmt.Fprintln(tw, "ID\tOS\tUsername\tProcess (PID)\tRemote Address\tLast Seen")
|
2025-07-25 17:28:23 +02:00
|
|
|
fmt.Fprintln(tw, "==========\t==========\t========\t==============\t===============\t==========")
|
2025-02-06 14:42:06 +01:00
|
|
|
|
|
|
|
|
// Iterate over the agents and write their details
|
|
|
|
|
agents.Range(func(key, value interface{}) bool {
|
|
|
|
|
agentID := key.(string)
|
|
|
|
|
agentInfo := value.(*AgentInfo)
|
|
|
|
|
|
|
|
|
|
// Extract OS (only first two parts: "Windows 10" for example)
|
|
|
|
|
osParts := strings.Fields(agentInfo.OSVersion)
|
|
|
|
|
os := ""
|
|
|
|
|
if len(osParts) >= 3 {
|
2025-04-22 23:54:40 +02:00
|
|
|
os = fmt.Sprintf("%s %s", osParts[0], osParts[1]) // e.g., "Windows 10"
|
2025-02-06 14:42:06 +01:00
|
|
|
} else {
|
|
|
|
|
os = agentInfo.OSVersion // Fallback if OS is shorter than expected
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-22 23:54:40 +02:00
|
|
|
// Extract just the executable name from the full path
|
|
|
|
|
// Extract executable name from the full path, handling both Windows and Unix paths
|
|
|
|
|
procPath := agentInfo.Procname
|
|
|
|
|
// Replace backslashes with forward slashes for consistency
|
|
|
|
|
procPath = strings.ReplaceAll(procPath, "\\", "/")
|
|
|
|
|
// Get the last part after the final slash
|
|
|
|
|
parts := strings.Split(procPath, "/")
|
|
|
|
|
procName := parts[len(parts)-1]
|
|
|
|
|
|
2025-02-06 14:42:06 +01:00
|
|
|
// Format the last connection time
|
|
|
|
|
lastMsg := agentInfo.LastConnection.Format("Jan 2 15:04:05")
|
|
|
|
|
timeSinceLast := time.Since(agentInfo.LastConnection).Truncate(time.Second)
|
|
|
|
|
lastMsgWithAgo := fmt.Sprintf("%s (%s ago)", lastMsg, timeSinceLast)
|
|
|
|
|
|
|
|
|
|
// Write a row for each agent
|
2025-07-13 19:40:11 +02:00
|
|
|
fmt.Fprintf(tw, "%s\t%s\t%s\t%s (%s)\t%s\t%s\n",
|
2025-02-06 14:42:06 +01:00
|
|
|
agentID,
|
2025-07-13 19:40:11 +02:00
|
|
|
os,
|
2025-02-06 14:42:06 +01:00
|
|
|
agentInfo.Username,
|
2025-04-22 23:54:40 +02:00
|
|
|
procName,
|
2025-07-13 19:40:11 +02:00
|
|
|
agentInfo.PID,
|
2025-02-06 14:42:06 +01:00
|
|
|
agentInfo.RemoteIP,
|
|
|
|
|
lastMsgWithAgo,
|
|
|
|
|
)
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Flush the tab writer and write to operator connection
|
|
|
|
|
tw.Flush()
|
|
|
|
|
|
|
|
|
|
if sb.Len() == 0 {
|
|
|
|
|
operatorConn.Write([]byte("No agents connected"))
|
|
|
|
|
} else {
|
2025-04-06 09:36:31 +02:00
|
|
|
operatorConn.Write([]byte("Agents:\n" + sb.String()))
|
2025-02-06 14:42:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get information about specific agent
|
|
|
|
|
func ShowAgent(operatorID string, agentID string) {
|
|
|
|
|
operatorConn, exists := GetOperatorConn(operatorID)
|
|
|
|
|
if !exists {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value, exists := agents.Load(agentID)
|
|
|
|
|
if !exists {
|
|
|
|
|
operatorConn.Write([]byte("Agent not found"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
agentInfo := value.(*AgentInfo)
|
|
|
|
|
|
|
|
|
|
// Format last connection time
|
|
|
|
|
lastMsg := agentInfo.LastConnection.Format("Jan 2 15:04:05")
|
|
|
|
|
timeSinceLast := time.Since(agentInfo.LastConnection).Truncate(time.Second)
|
|
|
|
|
lastMsgWithAgo := fmt.Sprintf("%s (%s ago)", lastMsg, timeSinceLast)
|
|
|
|
|
|
|
|
|
|
var sb strings.Builder
|
|
|
|
|
tw := tabwriter.NewWriter(&sb, 0, 8, 2, ' ', 0)
|
|
|
|
|
|
|
|
|
|
// Write agent details in tabular format
|
|
|
|
|
fmt.Fprintln(tw, "Field\tDescription")
|
2025-08-11 19:36:45 +02:00
|
|
|
fmt.Fprintln(tw, "============\t=========================")
|
2025-02-06 14:42:06 +01:00
|
|
|
fmt.Fprintf(tw, "Agent ID\t%s\n", agentID)
|
|
|
|
|
fmt.Fprintf(tw, "OS\t%s\n", agentInfo.OSVersion)
|
|
|
|
|
fmt.Fprintf(tw, "Architecture\t%s\n", agentInfo.Architecture)
|
2025-07-13 19:40:11 +02:00
|
|
|
fmt.Fprintf(tw, "Process\t%s\n", agentInfo.Procname)
|
|
|
|
|
fmt.Fprintf(tw, "PID\t%s\n", agentInfo.PID)
|
2025-02-06 14:42:06 +01:00
|
|
|
fmt.Fprintf(tw, "Hostname\t%s\n", agentInfo.Hostname)
|
|
|
|
|
fmt.Fprintf(tw, "Username\t%s\n", agentInfo.Username)
|
|
|
|
|
fmt.Fprintf(tw, "Local IP\t%s\n", agentInfo.LocalIP)
|
|
|
|
|
fmt.Fprintf(tw, "Remote IP\t%s\n", agentInfo.RemoteIP)
|
|
|
|
|
fmt.Fprintf(tw, "Last Connection\t%s\n", lastMsgWithAgo)
|
|
|
|
|
|
|
|
|
|
// Flush and send response
|
|
|
|
|
tw.Flush()
|
|
|
|
|
operatorConn.Write([]byte(sb.String()))
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-05 15:03:12 +02:00
|
|
|
// ShowTasks lists tasks for a specific agent or all agents if no ID is given
|
2025-04-07 11:09:28 +02:00
|
|
|
func ShowTasks(operatorID string, cmdParts []string) {
|
2025-08-05 15:03:12 +02:00
|
|
|
operatorConn, exists := GetOperatorConn(operatorID)
|
|
|
|
|
if !exists {
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-02-06 14:42:06 +01:00
|
|
|
|
2025-08-05 15:03:12 +02:00
|
|
|
var sb strings.Builder
|
|
|
|
|
tw := tabwriter.NewWriter(&sb, 0, 8, 2, ' ', 0)
|
2025-02-06 14:42:06 +01:00
|
|
|
|
2025-08-05 15:03:12 +02:00
|
|
|
// Write header
|
|
|
|
|
fmt.Fprintln(tw, "Agent\tTask #\tCommand\tArguments")
|
|
|
|
|
fmt.Fprintln(tw, "============\t============\t============\t===============================")
|
2025-02-06 14:42:06 +01:00
|
|
|
|
2025-08-05 15:03:12 +02:00
|
|
|
// Determine if specific agent ID is given
|
|
|
|
|
if len(cmdParts) > 1 {
|
|
|
|
|
agentID := cmdParts[0]
|
|
|
|
|
|
|
|
|
|
if _, agentExists := agents.Load(agentID); !agentExists {
|
|
|
|
|
operatorConn.Write([]byte(fmt.Sprintf("Agent %s not found", agentID)))
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-02-06 14:42:06 +01:00
|
|
|
|
2025-08-05 15:03:12 +02:00
|
|
|
tasks := taskHandler.ListTasks(agentID)
|
|
|
|
|
if len(tasks) == 0 {
|
|
|
|
|
operatorConn.Write([]byte(fmt.Sprintf("No tasks for agent %s", agentID)))
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-02-06 14:42:06 +01:00
|
|
|
|
|
|
|
|
for i, task := range tasks {
|
2025-08-05 15:03:12 +02:00
|
|
|
fmt.Fprintf(tw, "%s\t%d\t%s\t%s\n", agentID, i+1, task.Type, task.Args)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// List tasks for all agents
|
|
|
|
|
hasTasks := false
|
|
|
|
|
|
|
|
|
|
agents.Range(func(key, value interface{}) bool {
|
|
|
|
|
agentID := key.(string)
|
|
|
|
|
tasks := taskHandler.ListTasks(agentID)
|
|
|
|
|
|
|
|
|
|
if len(tasks) == 0 {
|
|
|
|
|
return true // Skip
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hasTasks = true
|
|
|
|
|
for i, task := range tasks {
|
|
|
|
|
fmt.Fprintf(tw, "%s\t%d\t%s\t%s\n", agentID, i+1, task.Type, task.Args)
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if !hasTasks {
|
|
|
|
|
operatorConn.Write([]byte("No tasks for any agents"))
|
|
|
|
|
return
|
2025-02-06 14:42:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-05 15:03:12 +02:00
|
|
|
|
|
|
|
|
// Flush and send output
|
|
|
|
|
tw.Flush()
|
|
|
|
|
operatorConn.Write([]byte("Current tasks:\n" + sb.String()))
|
2025-02-06 14:42:06 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-07 11:09:28 +02:00
|
|
|
// Remove all tasks assigned to a agent
|
2025-02-06 14:42:06 +01:00
|
|
|
func ClearTasks(operatorID string, cmdParts []string) {
|
|
|
|
|
var response string
|
|
|
|
|
agentID := cmdParts[2]
|
|
|
|
|
|
|
|
|
|
operatorConn, _ := GetOperatorConn(operatorID)
|
|
|
|
|
|
|
|
|
|
if _, agentExists := agents.Load(agentID); !agentExists {
|
|
|
|
|
logMessage := fmt.Sprintf("Operator %s requested to clear tasks for non-existent agent: %s", operatorID, agentID)
|
|
|
|
|
log.Print(logMessage)
|
|
|
|
|
response = fmt.Sprintf("Agent %s not found", agentID)
|
|
|
|
|
operatorConn.Write([]byte(response))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logMessage := fmt.Sprintf("Operator %s requested to clear all tasks for agent: %s", operatorID, agentID)
|
|
|
|
|
log.Print(logMessage)
|
|
|
|
|
|
|
|
|
|
taskHandler.ClearTasks(agentID)
|
|
|
|
|
|
|
|
|
|
response = fmt.Sprintf("Cleared task list for agent: %s", agentID)
|
|
|
|
|
operatorConn.Write([]byte(response))
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 11:09:28 +02:00
|
|
|
// Print the list of all loaded modules
|
|
|
|
|
func ShowModules(operatorID string) {
|
|
|
|
|
operatorConn, exists := GetOperatorConn(operatorID)
|
|
|
|
|
if !exists {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(modules) == 0 {
|
|
|
|
|
operatorConn.Write([]byte("No modules loaded"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sb strings.Builder
|
|
|
|
|
tw := tabwriter.NewWriter(&sb, 0, 8, 2, ' ', 0)
|
|
|
|
|
|
|
|
|
|
// Write header
|
|
|
|
|
fmt.Fprintln(tw, "Module\tType\tPath\tDescription")
|
|
|
|
|
fmt.Fprintln(tw, "============\t============\t============\t===============================")
|
|
|
|
|
|
|
|
|
|
// List all modules in tabular format
|
|
|
|
|
for _, module := range modules {
|
|
|
|
|
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n",
|
|
|
|
|
module.Name, module.Type, module.Path, module.Description)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Flush and send response
|
|
|
|
|
tw.Flush()
|
|
|
|
|
operatorConn.Write([]byte("Loaded modules:\n" + sb.String()))
|
|
|
|
|
}
|