From 9b34a5d26fda441e892becec5acda31a04994c8a Mon Sep 17 00:00:00 2001 From: Ralf Date: Fri, 26 Dec 2025 22:16:05 +0300 Subject: [PATCH] TsTerminal API upgrade --- AdaptixServer/core/extender/ex_agent.go | 2 +- AdaptixServer/core/extender/utils.go | 2 +- AdaptixServer/core/server/ts_terminal.go | 127 +++++++++++++----- AdaptixServer/core/server/utils.go | 8 +- .../extenders/beacon_agent/pl_agent.go | 19 ++- .../extenders/beacon_agent/pl_main.go | 17 ++- .../extenders/gopher_agent/pl_agent.go | 6 +- .../extenders/gopher_agent/pl_main.go | 10 +- .../extenders/gopher_listener_tcp/pl_main.go | 2 +- .../extenders/gopher_listener_tcp/pl_tcp.go | 2 +- 10 files changed, 134 insertions(+), 61 deletions(-) diff --git a/AdaptixServer/core/extender/ex_agent.go b/AdaptixServer/core/extender/ex_agent.go index b68febf5..eaf7390b 100644 --- a/AdaptixServer/core/extender/ex_agent.go +++ b/AdaptixServer/core/extender/ex_agent.go @@ -64,7 +64,7 @@ func (ex *AdaptixExtender) ExAgentTunnelCallbacks(agentData adaptix.AgentData, t return module.AgentTunnelCallbacks() } -func (ex *AdaptixExtender) ExAgentTerminalCallbacks(agentData adaptix.AgentData) (func(int, string, int, int) (adaptix.TaskData, error), func(int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) { +func (ex *AdaptixExtender) ExAgentTerminalCallbacks(agentData adaptix.AgentData) (func(int, string, int, int, int) (adaptix.TaskData, error), func(int, int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) { module, ok := ex.agentModules[agentData.Name] if !ok { diff --git a/AdaptixServer/core/extender/utils.go b/AdaptixServer/core/extender/utils.go index a1f4a056..dc2ed110 100644 --- a/AdaptixServer/core/extender/utils.go +++ b/AdaptixServer/core/extender/utils.go @@ -64,7 +64,7 @@ type ExtAgent interface { AgentPivotPackData(pivotId string, data []byte) (adaptix.TaskData, error) AgentTunnelCallbacks() (func(int, int, int, string, int) adaptix.TaskData, func(int, int, int, string, int) adaptix.TaskData, func(int, []byte) adaptix.TaskData, func(int, []byte) adaptix.TaskData, func(int) adaptix.TaskData, func(int, int) adaptix.TaskData, error) - AgentTerminalCallbacks() (func(int, string, int, int) (adaptix.TaskData, error), func(int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) + AgentTerminalCallbacks() (func(int, string, int, int, int) (adaptix.TaskData, error), func(int, int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) } type AdaptixExtender struct { diff --git a/AdaptixServer/core/server/ts_terminal.go b/AdaptixServer/core/server/ts_terminal.go index f6035e0c..bd2befba 100644 --- a/AdaptixServer/core/server/ts_terminal.go +++ b/AdaptixServer/core/server/ts_terminal.go @@ -1,6 +1,7 @@ package server import ( + "context" "encoding/base64" "errors" "fmt" @@ -80,7 +81,7 @@ func (ts *Teamserver) TsAgentTerminalCreateChannel(terminalData string, wsconn * return err } - taskData, err := terminal.handlerStart(terminal.TerminalId, program, sizeH, sizeW) + taskData, err := terminal.handlerStart(terminal.TerminalId, program, sizeH, sizeW, OemCP) if err != nil { return err } @@ -115,7 +116,7 @@ func (ts *Teamserver) TsTerminalGetPipe(AgentId string, terminalId string) (*io. return terminal.prSrv, terminal.pwTun, nil } -func (ts *Teamserver) TsTerminalConnResume(agentId string, terminalId string) { +func (ts *Teamserver) TsTerminalConnResume(agentId string, terminalId string, ioDirect bool) { agent, err := ts.getAgent(agentId) if err != nil { return @@ -130,7 +131,26 @@ func (ts *Teamserver) TsTerminalConnResume(agentId string, terminalId string) { return } - relayWebsocketToTerminal(ts, agent, terminal, terminalId) + relayWebsocketToTerminal(ts, agent, terminal, terminalId, ioDirect) +} + +func (ts *Teamserver) TsTerminalConnData(terminalId string, data []byte) { + value, ok := ts.terminals.Get(terminalId) + if !ok { + return + } + terminal, ok := value.(*Terminal) + if !ok { + return + } + + terminal.mu.Lock() + defer terminal.mu.Unlock() + + if terminal.closed || terminal.pwTun == nil { + return + } + _, _ = terminal.pwTun.Write(data) } func (ts *Teamserver) TsTerminalConnClose(terminalId string, status string) error { @@ -151,31 +171,41 @@ func closeTerminalResources(terminal *Terminal) { if terminal == nil { return } + + terminal.mu.Lock() + if terminal.closed { + terminal.mu.Unlock() + return + } + terminal.closed = true + terminal.mu.Unlock() + if terminal.wsconn != nil { _ = terminal.wsconn.Close() } - if terminal.prSrv != nil { - _ = terminal.prSrv.Close() - } - if terminal.pwSrv != nil { - _ = terminal.pwSrv.Close() + if terminal.pwTun != nil { + _ = terminal.pwTun.Close() } if terminal.prTun != nil { _ = terminal.prTun.Close() } - if terminal.pwTun != nil { - _ = terminal.pwTun.Close() + if terminal.pwSrv != nil { + _ = terminal.pwSrv.Close() + } + if terminal.prSrv != nil { + _ = terminal.prSrv.Close() } } /// -func relayWebsocketToTerminal(ts *Teamserver, agent *Agent, terminal *Terminal, terminalId string) { - var closeOnce sync.Once +func relayWebsocketToTerminal(ts *Teamserver, agent *Agent, terminal *Terminal, terminalId string, direct bool) { + ctx, cancel := context.WithCancel(context.Background()) + var once sync.Once var wsWriteMu sync.Mutex - - closeAll := func() { - closeOnce.Do(func() { + finish := func() { + once.Do(func() { + cancel() ts.terminals.Delete(terminalId) closeTerminalResources(terminal) @@ -187,42 +217,67 @@ func relayWebsocketToTerminal(ts *Teamserver, agent *Agent, terminal *Terminal, } go func() { - defer closeAll() + defer finish() + if terminal.wsconn == nil || terminal.pwSrv == nil { + return + } for { _, msg, err := terminal.wsconn.ReadMessage() if err != nil { - return + break } - if terminal.pwSrv == nil { - return - } - if _, err = terminal.pwSrv.Write(msg); err != nil { - return + if _, err := terminal.pwSrv.Write(msg); err != nil { + break } } + _ = terminal.pwSrv.Close() }() go func() { - defer closeAll() + defer finish() + if terminal.wsconn == nil || terminal.prTun == nil { + return + } buf := ts.TunnelManager.GetBuffer() defer ts.TunnelManager.PutBuffer(buf) - for { - if terminal.prTun == nil { - return - } n, err := terminal.prTun.Read(buf) - if err != nil { - return + if n > 0 { + wsWriteMu.Lock() + writeErr := terminal.wsconn.WriteMessage(websocket.BinaryMessage, buf[:n]) + wsWriteMu.Unlock() + if writeErr != nil { + break + } } - - wsWriteMu.Lock() - writeErr := terminal.wsconn.WriteMessage(websocket.BinaryMessage, buf[:n]) - wsWriteMu.Unlock() - - if writeErr != nil { - return + if err != nil { + break } } }() + + if !direct { + go func() { + buf := ts.TunnelManager.GetBuffer() + defer ts.TunnelManager.PutBuffer(buf) + for { + select { + case <-ctx.Done(): + return + default: + n, err := terminal.prSrv.Read(buf) + if n > 0 { + taskData, writeErr := terminal.handlerWrite(terminal.TerminalId, terminal.CodePage, buf[:n]) + if writeErr == nil { + tunnelManageTask(agent, taskData) + } + relayPipeToTaskData(agent, terminal.TerminalId, taskData) + } + if err != nil { + return + } + } + } + }() + } } diff --git a/AdaptixServer/core/server/utils.go b/AdaptixServer/core/server/utils.go index 6b83b5dc..93d63436 100644 --- a/AdaptixServer/core/server/utils.go +++ b/AdaptixServer/core/server/utils.go @@ -159,7 +159,9 @@ type Terminal struct { TerminalId int CodePage int - agent *Agent + agent *Agent + mu sync.Mutex + closed bool wsconn *websocket.Conn @@ -169,8 +171,8 @@ type Terminal struct { pwTun *io.PipeWriter prTun *io.PipeReader - handlerStart func(terminalId int, program string, sizeH int, sizeW int) (adaptix.TaskData, error) - handlerWrite func(terminalId int, data []byte) (adaptix.TaskData, error) + handlerStart func(terminalId int, program string, sizeH int, sizeW int, oemCP int) (adaptix.TaskData, error) + handlerWrite func(terminalId int, oemCP int, data []byte) (adaptix.TaskData, error) handlerClose func(terminalId int) (adaptix.TaskData, error) } diff --git a/AdaptixServer/extenders/beacon_agent/pl_agent.go b/AdaptixServer/extenders/beacon_agent/pl_agent.go index d32d6d4c..b1f298d0 100644 --- a/AdaptixServer/extenders/beacon_agent/pl_agent.go +++ b/AdaptixServer/extenders/beacon_agent/pl_agent.go @@ -2004,14 +2004,23 @@ func TunnelReverse(tunnelId int, port int) ([]byte, error) { /// TERMINAL -func TerminalStart(terminalId int, program string, sizeH int, sizeW int) ([]byte, error) { - return nil, errors.New("Function Remote Terminal not supported") +func TerminalStart(terminalId int, program string, sizeH int, sizeW int, oemCP int) ([]byte, error) { + programArgs := ModuleObject.ts.TsConvertUTF8toCp(program, oemCP) + array := []interface{}{COMMAND_SHELL_START, terminalId, programArgs} + return PackArray(array) } -func TerminalWrite(terminalId int, data []byte) ([]byte, error) { - return nil, errors.New("Function Remote Terminal not supported") +func TerminalWrite(terminalId int, oemCP int, data []byte) ([]byte, error) { + dataEncode := ModuleObject.ts.TsConvertUTF8toCp(string(data), oemCP) + if oemCP > 0 { + dataEncode = strings.ReplaceAll(dataEncode, "\n", "\r\n") + } + + array := []interface{}{COMMAND_SHELL_WRITE, terminalId, len(dataEncode), []byte(dataEncode)} + return PackArray(array) } func TerminalClose(terminalId int) ([]byte, error) { - return nil, errors.New("Function Remote Terminal not supported") + array := []interface{}{COMMAND_JOBS_KILL, terminalId} + return PackArray(array) } diff --git a/AdaptixServer/extenders/beacon_agent/pl_main.go b/AdaptixServer/extenders/beacon_agent/pl_main.go index 742f9719..1e52326c 100644 --- a/AdaptixServer/extenders/beacon_agent/pl_main.go +++ b/AdaptixServer/extenders/beacon_agent/pl_main.go @@ -3,6 +3,7 @@ package main import ( "encoding/hex" "encoding/json" + "io" "math/rand" "time" @@ -99,6 +100,12 @@ type Teamserver interface { TsTunnelConnectionData(channelId int, data []byte) TsTunnelConnectionAccept(tunnelId int, channelId int) + TsTerminalConnExists(terminalId string) bool + TsTerminalGetPipe(AgentId string, terminalId string) (*io.PipeReader, *io.PipeWriter, error) + TsTerminalConnResume(agentId string, terminalId string, ioDirect bool) + TsTerminalConnData(terminalId string, data []byte) + TsTerminalConnClose(terminalId string, status string) error + TsConvertCpToUTF8(input string, codePage int) string TsConvertUTF8toCp(input string, codePage int) string TsWin32Error(errorCode uint) string @@ -318,12 +325,12 @@ func TunnelMessageReverse(tunnelId int, port int) adaptix.TaskData { /// TERMINAL -func (m *ModuleExtender) AgentTerminalCallbacks() (func(int, string, int, int) (adaptix.TaskData, error), func(int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) { +func (m *ModuleExtender) AgentTerminalCallbacks() (func(int, string, int, int, int) (adaptix.TaskData, error), func(int, int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) { return TerminalMessageStart, TerminalMessageWrite, TerminalMessageClose, nil } -func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int) (adaptix.TaskData, error) { - packData, err := TerminalStart(terminalId, program, sizeH, sizeW) +func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int, oemCP int) (adaptix.TaskData, error) { + packData, err := TerminalStart(terminalId, program, sizeH, sizeW, oemCP) if err != nil { return adaptix.TaskData{}, err } @@ -337,8 +344,8 @@ func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int) return taskData, nil } -func TerminalMessageWrite(channelId int, data []byte) (adaptix.TaskData, error) { - packData, err := TerminalWrite(channelId, data) +func TerminalMessageWrite(terminalId int, oemCP int, data []byte) (adaptix.TaskData, error) { + packData, err := TerminalWrite(terminalId, oemCP, data) if err != nil { return adaptix.TaskData{}, err } diff --git a/AdaptixServer/extenders/gopher_agent/pl_agent.go b/AdaptixServer/extenders/gopher_agent/pl_agent.go index 217f08d9..d87d3f45 100644 --- a/AdaptixServer/extenders/gopher_agent/pl_agent.go +++ b/AdaptixServer/extenders/gopher_agent/pl_agent.go @@ -1545,14 +1545,14 @@ func TunnelReverse(tunnelId int, port int) ([]byte, error) { /// TERMINAL -func TerminalStart(terminalId int, program string, sizeH int, sizeW int) ([]byte, error) { +func TerminalStart(terminalId int, program string, sizeH int, sizeW int, oemCP int) ([]byte, error) { packerData, _ := msgpack.Marshal(ParamsTerminalStart{TermId: terminalId, Program: program, Height: sizeH, Width: sizeW}) cmd := Command{Code: COMMAND_TERMINAL_START, Data: packerData} return msgpack.Marshal(cmd) } -func TerminalWrite(terminalId int, data []byte) ([]byte, error) { - return nil, nil +func TerminalWrite(terminalId int, oemCP int, data []byte) ([]byte, error) { + return data, nil } func TerminalClose(terminalId int) ([]byte, error) { diff --git a/AdaptixServer/extenders/gopher_agent/pl_main.go b/AdaptixServer/extenders/gopher_agent/pl_main.go index 0ed617e1..6b9316a7 100644 --- a/AdaptixServer/extenders/gopher_agent/pl_main.go +++ b/AdaptixServer/extenders/gopher_agent/pl_main.go @@ -331,12 +331,12 @@ func TunnelMessageReverse(tunnelId int, port int) adaptix.TaskData { /// TERMINAL -func (m *ModuleExtender) AgentTerminalCallbacks() (func(int, string, int, int) (adaptix.TaskData, error), func(int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) { +func (m *ModuleExtender) AgentTerminalCallbacks() (func(int, string, int, int, int) (adaptix.TaskData, error), func(int, int, []byte) (adaptix.TaskData, error), func(int) (adaptix.TaskData, error), error) { return TerminalMessageStart, TerminalMessageWrite, TerminalMessageClose, nil } -func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int) (adaptix.TaskData, error) { - packData, err := TerminalStart(terminalId, program, sizeH, sizeW) +func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int, oemCP int) (adaptix.TaskData, error) { + packData, err := TerminalStart(terminalId, program, sizeH, sizeW, oemCP) if err != nil { return adaptix.TaskData{}, err } @@ -350,8 +350,8 @@ func TerminalMessageStart(terminalId int, program string, sizeH int, sizeW int) return taskData, nil } -func TerminalMessageWrite(channelId int, data []byte) (adaptix.TaskData, error) { - packData, err := TerminalWrite(channelId, data) +func TerminalMessageWrite(terminalId int, oemCP int, data []byte) (adaptix.TaskData, error) { + packData, err := TerminalWrite(terminalId, oemCP, data) if err != nil { return adaptix.TaskData{}, err } diff --git a/AdaptixServer/extenders/gopher_listener_tcp/pl_main.go b/AdaptixServer/extenders/gopher_listener_tcp/pl_main.go index 682545ab..7ad8ea9d 100644 --- a/AdaptixServer/extenders/gopher_listener_tcp/pl_main.go +++ b/AdaptixServer/extenders/gopher_listener_tcp/pl_main.go @@ -41,7 +41,7 @@ type Teamserver interface { TsAgentTerminalCloseChannel(terminalId string, status string) error TsTerminalConnExists(terminalId string) bool - TsTerminalConnResume(agentId string, terminalId string) + TsTerminalConnResume(agentId string, terminalId string, ioDirect bool) TsTerminalGetPipe(AgentId string, terminalId string) (*io.PipeReader, *io.PipeWriter, error) TsTunnelGetPipe(AgentId string, channelId int) (*io.PipeReader, *io.PipeWriter, error) diff --git a/AdaptixServer/extenders/gopher_listener_tcp/pl_tcp.go b/AdaptixServer/extenders/gopher_listener_tcp/pl_tcp.go index 0357ccfa..44add64f 100644 --- a/AdaptixServer/extenders/gopher_listener_tcp/pl_tcp.go +++ b/AdaptixServer/extenders/gopher_listener_tcp/pl_tcp.go @@ -401,7 +401,7 @@ func (handler *TCP) handleConnection(conn net.Conn, ts Teamserver) { return } - ts.TsTerminalConnResume(agentId, terminalId) + ts.TsTerminalConnResume(agentId, terminalId, true) pr, pw, err := ModuleObject.ts.TsTerminalGetPipe(agentId, terminalId) if err != nil {