diff --git a/client/command/generate/generate.go b/client/command/generate/generate.go index 09d1a02776..786ce45a79 100644 --- a/client/command/generate/generate.go +++ b/client/command/generate/generate.go @@ -515,6 +515,9 @@ func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) { } for index, arg := range strings.Split(args, ",") { arg = strings.ToLower(arg) + arg = strings.ReplaceAll(arg, "\\", "/") + arg = strings.TrimPrefix(arg, "/") + arg = strings.TrimPrefix(arg, "/") var uri *url.URL var err error if strings.HasPrefix(arg, "namedpipe://") { @@ -531,6 +534,18 @@ func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) { if uri.Scheme != "namedpipe" { return nil, fmt.Errorf("invalid namedpipe scheme: %s", uri.Scheme) } + + if !strings.HasPrefix(uri.Path, "/pipe/") { + prompt := &survey.Confirm{ + Message: fmt.Sprintf("Named pipe '%s' is missing the 'pipe' path prefix\nContinue anyways?", uri), + } + var confirm bool + survey.AskOne(prompt, &confirm) + if !confirm { + return nil, fmt.Errorf("invalid namedpipe path: %s", uri.Path) + } + } + c2s = append(c2s, &clientpb.ImplantC2{ Priority: uint32(index), URL: uri.String(), diff --git a/implant/sliver/pivots/named-pipe_windows.go b/implant/sliver/pivots/named-pipe_windows.go index 42244df244..604fc613a5 100644 --- a/implant/sliver/pivots/named-pipe_windows.go +++ b/implant/sliver/pivots/named-pipe_windows.go @@ -19,6 +19,7 @@ package pivots */ import ( + "strings" "sync" "time" @@ -37,7 +38,7 @@ var ( // CreateNamedPipePivotListener - Starts a named pipe listener func CreateNamedPipePivotListener(address string, upstream chan<- *pb.Envelope) (*PivotListener, error) { - fullName := "\\\\.\\pipe\\" + address + fullName := "\\\\.\\pipe\\" + strings.TrimPrefix(address, "\\\\.\\pipe\\") ln, err := winio.ListenPipe(fullName, &winio.PipeConfig{ //SecurityDescriptor: "", RemoteClientMode: true, diff --git a/implant/sliver/transports/session.go b/implant/sliver/transports/session.go index 8cd7f593eb..0442f3cbbb 100644 --- a/implant/sliver/transports/session.go +++ b/implant/sliver/transports/session.go @@ -753,6 +753,9 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) { case <-pingCtrl: return case <-time.After(time.Minute): + // {{if .Config.Debug}} + log.Printf("[tcp pivot] peer ping...") + // {{end}} data, _ := proto.Marshal(&pb.PivotPing{ Nonce: uint32(time.Now().UnixNano()), }) @@ -760,11 +763,10 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) { Type: pb.MsgPivotPeerPing, Data: data, } - case <-time.After(time.Minute): // {{if .Config.Debug}} log.Printf("[tcp pivot] server ping...") // {{end}} - data, _ := proto.Marshal(&pb.PivotPing{ + data, _ = proto.Marshal(&pb.PivotPing{ Nonce: uint32(time.Now().UnixNano()), }) connection.Send <- &pb.Envelope{ diff --git a/implant/sliver/transports/transports_windows.go b/implant/sliver/transports/transports_windows.go index 5da569d467..a4fdc8e444 100644 --- a/implant/sliver/transports/transports_windows.go +++ b/implant/sliver/transports/transports_windows.go @@ -56,6 +56,7 @@ func namedPipeConnect(uri *url.URL) (*Connection, error) { // {{end}} close(send) ctrl <- struct{}{} + pingCtrl <- struct{}{} close(recv) }, } @@ -80,6 +81,9 @@ func namedPipeConnect(uri *url.URL) (*Connection, error) { case <-pingCtrl: return case <-time.After(time.Minute): + // {{if .Config.Debug}} + log.Printf("[namedpipe] peer ping...") + // {{end}} data, _ := proto.Marshal(&pb.PivotPing{ Nonce: uint32(time.Now().UnixNano()), }) @@ -87,11 +91,10 @@ func namedPipeConnect(uri *url.URL) (*Connection, error) { Type: pb.MsgPivotPeerPing, Data: data, } - case <-time.After(time.Minute): // {{if .Config.Debug}} log.Printf("[namedpipe] server ping...") // {{end}} - data, _ := proto.Marshal(&pb.PivotPing{ + data, _ = proto.Marshal(&pb.PivotPing{ Nonce: uint32(time.Now().UnixNano()), }) connection.Send <- &pb.Envelope{ diff --git a/server/core/pivots.go b/server/core/pivots.go index bf2bc00c66..8d2de34ea4 100644 --- a/server/core/pivots.go +++ b/server/core/pivots.go @@ -197,6 +197,10 @@ func insertImmediateChildren(entry *PivotGraphEntry, depth int) { return true } session := Sessions.FromImplantConnection(pivot.ImplantConn) + if session == nil { + coreLog.Warnf("[graph] session not found for pivot: %v", pivot) + return true + } coreLog.Debugf("[graph] entry: %v, pivot: %v", entry.Name, pivot) if pivot.Peers[1].PeerID == entry.PeerID { child := &PivotGraphEntry{ diff --git a/server/core/sessions.go b/server/core/sessions.go index 84e95e3048..fb788c89f6 100644 --- a/server/core/sessions.go +++ b/server/core/sessions.go @@ -80,6 +80,7 @@ func (s *Session) LastCheckin() time.Time { // IsDead - See if last check-in is within expected variance func (s *Session) IsDead() bool { + sessionsLog.Debugf("Checking health of %s", s.ID) sessionsLog.Debugf("Last checkin was %v", s.Connection.LastMessage) padding := time.Duration(10 * time.Second) // Arbitrary margin of error timePassed := time.Since(s.LastCheckin()) @@ -95,6 +96,12 @@ func (s *Session) IsDead() bool { return false } } + if s.Connection.Transport == "pivot" { + if time.Since(s.Connection.LastMessage) < time.Duration(time.Minute)+padding { + sessionsLog.Debugf("Last message within pivot/server ping interval with padding") + return false + } + } return true } @@ -202,6 +209,7 @@ func (s *sessions) Remove(sessionID string) { for _, child := range children { childSession, ok := s.sessions.LoadAndDelete(child.SessionID) if ok { + PivotSessions.Delete(childSession.(*Session).Connection.ID) EventBroker.Publish(Event{ EventType: consts.SessionClosedEvent, Session: childSession.(*Session), diff --git a/server/handlers/pivot.go b/server/handlers/pivot.go index bd77bb2e48..c7a4cdb149 100644 --- a/server/handlers/pivot.go +++ b/server/handlers/pivot.go @@ -76,8 +76,6 @@ func pivotPeerEnvelopeHandler(implantConn *core.ImplantConnection, data []byte) resp = serverKeyExchange(implantConn, peerEnvelope) case sliverpb.MsgPivotSessionEnvelope: resp = sessionEnvelopeHandler(implantConn, peerEnvelope) - case sliverpb.MsgPivotServerPing: - resp = serverPingHandler(implantConn, peerEnvelope) } return resp @@ -130,6 +128,8 @@ func handlePivotEnvelope(pivot *core.Pivot, envelope *sliverpb.Envelope) { pivot.ImplantConn.Send <- respEnvelope }() } + } else if envelope.Type == sliverpb.MsgPivotServerPing { + pivotServerPingHandler(pivot) } else { pivotLog.Errorf("no pivot handler for envelope type %v", envelope.Type) } @@ -159,26 +159,9 @@ func pivotPeerFailureHandler(implantConn *core.ImplantConnection, data []byte) * return nil } -func serverPingHandler(implantConn *core.ImplantConnection, peerEnvelope *sliverpb.PivotPeerEnvelope) *sliverpb.Envelope { - pivotSessionID := uuid.FromBytesOrNil(peerEnvelope.PivotSessionID).String() - if pivotSessionID == "" { - pivotLog.Errorf("failed to parse pivot session id from peer envelope") - return nil - } - - // Find the pivot session for the server ping - pivotLog.Debugf("origin envelope pivot session ID = %s", pivotSessionID) - pivotEntry, ok := core.PivotSessions.Load(pivotSessionID) - if !ok { - pivotLog.Errorf("pivot session id '%s' not found", pivotSessionID) - return nil - } - pivot := pivotEntry.(*core.Pivot) - - // Update last message time +func pivotServerPingHandler(pivot *core.Pivot) { pivot.ImplantConn.UpdateLastMessage() - - return nil + pivot.ImmediateImplantConn.UpdateLastMessage() } // ------------------------ diff --git a/server/handlers/sessions.go b/server/handlers/sessions.go index b4c2ffbce4..e928ca5ae1 100644 --- a/server/handlers/sessions.go +++ b/server/handlers/sessions.go @@ -111,7 +111,7 @@ func tunnelDataHandler(implantConn *core.ImplantConnection, data []byte) *sliver if session.ID == tunnel.SessionID { tunnel.FromImplant <- tunnelData } else { - sessionHandlerLog.Warnf("Warning: Session %d attempted to send data on tunnel it did not own", session.ID) + sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID) } } else { sessionHandlerLog.Warnf("Data sent on nil tunnel %d", tunnelData.TunnelID) @@ -135,7 +135,7 @@ func tunnelCloseHandler(implantConn *core.ImplantConnection, data []byte) *slive sessionHandlerLog.Infof("Closing tunnel %d", tunnel.ID) core.Tunnels.Close(tunnel.ID) } else { - sessionHandlerLog.Warnf("Warning: Session %d attempted to send data on tunnel it did not own", session.ID) + sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID) } } else { sessionHandlerLog.Warnf("Close sent on nil tunnel %d", tunnelData.TunnelID) @@ -145,7 +145,7 @@ func tunnelCloseHandler(implantConn *core.ImplantConnection, data []byte) *slive func pingHandler(implantConn *core.ImplantConnection, data []byte) *sliverpb.Envelope { session := core.Sessions.FromImplantConnection(implantConn) - sessionHandlerLog.Debugf("ping from session %d", session.ID) + sessionHandlerLog.Debugf("ping from session %s", session.ID) return nil } @@ -166,7 +166,7 @@ func socksDataHandler(implantConn *core.ImplantConnection, data []byte) *sliverp if session.ID == SocksTunne.SessionID { SocksTunne.FromImplant <- socksData } else { - sessionHandlerLog.Warnf("Warning: Session %d attempted to send data on tunnel it did not own", session.ID) + sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID) } } else { sessionHandlerLog.Warnf("Data sent on nil tunnel %d", socksData.TunnelID)