diff --git a/server/core/tunnels.go b/server/core/tunnels.go index 8ae1d39a7a..7f95c5b9a2 100644 --- a/server/core/tunnels.go +++ b/server/core/tunnels.go @@ -44,11 +44,16 @@ var ( // with an identifier, these tunnels are full duplex. The server doesn't really // care what data gets passed back and forth it just facilitates the connection type Tunnel struct { - ID uint64 - SessionID uint32 - ToImplant chan []byte - FromImplant chan []byte - Client rpcpb.SliverRPC_TunnelDataServer + ID uint64 + SessionID uint32 + + ToImplant chan []byte + ToImplantSequence uint64 + + FromImplant chan *sliverpb.TunnelData + FromImplantSequence uint64 + + Client rpcpb.SliverRPC_TunnelDataServer } type tunnels struct { @@ -63,7 +68,7 @@ func (t *tunnels) Create(sessionID uint32) *Tunnel { ID: tunnelID, SessionID: session.ID, ToImplant: make(chan []byte), - FromImplant: make(chan []byte), + FromImplant: make(chan *sliverpb.TunnelData), } t.mutex.Lock() defer t.mutex.Unlock() diff --git a/server/handlers/sessions.go b/server/handlers/sessions.go index b688194c16..8357aeddd9 100644 --- a/server/handlers/sessions.go +++ b/server/handlers/sessions.go @@ -89,7 +89,7 @@ func tunnelDataHandler(session *core.Session, data []byte) { tunnel := core.Tunnels.Get(tunnelData.TunnelID) if tunnel != nil { if session.ID == tunnel.SessionID { - tunnel.FromImplant <- tunnelData.GetData() + tunnel.FromImplant <- tunnelData } else { handlerLog.Warnf("Warning: Session %d attempted to send data on tunnel it did not own", session.ID) } diff --git a/server/rpc/rpc-tunnel.go b/server/rpc/rpc-tunnel.go index 20e5711bd5..256d266694 100644 --- a/server/rpc/rpc-tunnel.go +++ b/server/rpc/rpc-tunnel.go @@ -32,6 +32,8 @@ import ( var ( tunnelLog = log.NamedLogger("rpc", "tunnel") + + fromImplantCache = map[uint64]map[uint64]*sliverpb.TunnelData{} ) // CreateTunnel - Create a new tunnel on the server, however based on only this request there's @@ -46,6 +48,7 @@ func (s *Server) CreateTunnel(ctx context.Context, req *sliverpb.Tunnel) (*slive if tunnel == nil { return nil, ErrTunnelInitFailure } + fromImplantCache[tunnel.ID] = map[uint64]*sliverpb.TunnelData{} return &sliverpb.Tunnel{ SessionID: session.ID, TunnelID: tunnel.ID, @@ -55,6 +58,11 @@ func (s *Server) CreateTunnel(ctx context.Context, req *sliverpb.Tunnel) (*slive // CloseTunnel - Client requests we close a tunnel func (s *Server) CloseTunnel(ctx context.Context, req *sliverpb.Tunnel) (*commonpb.Empty, error) { err := core.Tunnels.Close(req.TunnelID) + + if _, ok := fromImplantCache[req.TunnelID]; ok { + delete(fromImplantCache, req.TunnelID) + } + if err != nil { return nil, err } @@ -89,15 +97,22 @@ func (s *Server) TunnelData(stream rpcpb.SliverRPC_TunnelDataServer) error { }) go func() { - for data := range tunnel.FromImplant { - tunnelLog.Debugf("Tunnel %d: From implant %d byte(s)", tunnel.ID, len(data)) - tunnel.Client.Send(&sliverpb.TunnelData{ - TunnelID: tunnel.ID, - SessionID: tunnel.SessionID, - Data: data, - Closed: false, - }) - tunnelLog.Debugf("Sent data to client %v", tunnel.Client) + for tunnelData := range tunnel.FromImplant { + tunnelLog.Debugf("Tunnel %d: From implant %d byte(s)", tunnel.ID, len(tunnelData.Data)) + cache, ok := fromImplantCache[tunnel.ID] + if ok { + cache[tunnelData.Sequence] = tunnelData + } + for recv, ok := cache[tunnel.FromImplantSequence]; ok; recv, ok = cache[tunnel.FromImplantSequence] { + tunnel.Client.Send(&sliverpb.TunnelData{ + TunnelID: tunnel.ID, + SessionID: tunnel.SessionID, + Data: recv.Data, + Closed: false, + }) + delete(cache, tunnel.FromImplantSequence) + tunnel.FromImplantSequence++ + } } tunnelLog.Debugf("Closing tunnel %d (To Client)", tunnel.ID) tunnel.Client.Send(&sliverpb.TunnelData{ @@ -112,18 +127,22 @@ func (s *Server) TunnelData(stream rpcpb.SliverRPC_TunnelDataServer) error { for data := range tunnel.ToImplant { tunnelLog.Debugf("Tunnel %d: To implant %d byte(s)", tunnel.ID, len(data)) data, _ := proto.Marshal(&sliverpb.TunnelData{ + Sequence: tunnel.ToImplantSequence, TunnelID: tunnel.ID, SessionID: tunnel.SessionID, Data: data, Closed: false, }) + tunnel.ToImplantSequence++ session.Send <- &sliverpb.Envelope{ Type: sliverpb.MsgTunnelData, Data: data, } + } tunnelLog.Debugf("Closing tunnel %d (To Implant) ...", tunnel.ID) data, _ := proto.Marshal(&sliverpb.TunnelData{ + Sequence: tunnel.ToImplantSequence, // Shouldn't need to increment since this will close the tunnel TunnelID: tunnel.ID, SessionID: tunnel.SessionID, Data: make([]byte, 0), diff --git a/sliver/handlers/generic-tun-handlers.go b/sliver/handlers/generic-tun-handlers.go index 9141951c38..025d4c204c 100644 --- a/sliver/handlers/generic-tun-handlers.go +++ b/sliver/handlers/generic-tun-handlers.go @@ -104,7 +104,7 @@ func tunnelDataHandler(envelope *sliverpb.Envelope, connection *transports.Conne cache := tunnelDataCache[tunnel.ID] for recv, ok := cache[tunnel.ReadSequence]; ok; recv, ok = cache[tunnel.ReadSequence] { // {{if .Config.Debug}} - log.Printf("[tunnel] Write %d bytes to tunnel %d (read seq: %d)", recv.TunnelID, recv.Sequence) + log.Printf("[tunnel] Write %d bytes to tunnel %d (read seq: %d)", len(recv.Data), recv.TunnelID, recv.Sequence) // {{end}} tunnel.Writer.Write(recv.Data)