From cdfee6510e8d472695f5180ddd727464e5baddb7 Mon Sep 17 00:00:00 2001 From: moloch-- <875022+moloch--@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:41:39 -0600 Subject: [PATCH 1/4] fix issue #590, and improper named pivot peer ping cleanup --- implant/sliver/pivots/named-pipe_windows.go | 3 ++- implant/sliver/transports/transports_windows.go | 1 + server/core/pivots.go | 4 ++++ server/core/sessions.go | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) 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/transports_windows.go b/implant/sliver/transports/transports_windows.go index 5da569d467..763754baf8 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) }, } 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..c6b03840c0 100644 --- a/server/core/sessions.go +++ b/server/core/sessions.go @@ -231,6 +231,7 @@ func (s *sessions) FromImplantConnection(conn *ImplantConnection) *Session { s.sessions.Range(func(key, value interface{}) bool { if value.(*Session).Connection.ID == conn.ID { found = value.(*Session) + PivotSessions.Delete(conn.ID) return false } return true From 41669ed41f9e5224d4a7babf6a8ca7210ccc6e69 Mon Sep 17 00:00:00 2001 From: moloch-- <875022+moloch--@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:43:35 -0600 Subject: [PATCH 2/4] fix pivotsession cleanup --- server/core/sessions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/core/sessions.go b/server/core/sessions.go index c6b03840c0..35aaaeb5fa 100644 --- a/server/core/sessions.go +++ b/server/core/sessions.go @@ -201,6 +201,7 @@ func (s *sessions) Remove(sessionID string) { coreLog.Debugf("Removing %d children of session %d (%v)", len(children), parentSession.ID, children) for _, child := range children { childSession, ok := s.sessions.LoadAndDelete(child.SessionID) + PivotSessions.Delete(childSession.(*Session).Connection.ID) if ok { EventBroker.Publish(Event{ EventType: consts.SessionClosedEvent, @@ -231,7 +232,6 @@ func (s *sessions) FromImplantConnection(conn *ImplantConnection) *Session { s.sessions.Range(func(key, value interface{}) bool { if value.(*Session).Connection.ID == conn.ID { found = value.(*Session) - PivotSessions.Delete(conn.ID) return false } return true From 4b2b80b2f8ecb0525383d163c433090d0e9900bd Mon Sep 17 00:00:00 2001 From: moloch-- <875022+moloch--@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:45:07 -0600 Subject: [PATCH 3/4] fix pivot session cleanup --- server/core/sessions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/core/sessions.go b/server/core/sessions.go index 35aaaeb5fa..b5b4f83af7 100644 --- a/server/core/sessions.go +++ b/server/core/sessions.go @@ -201,8 +201,8 @@ func (s *sessions) Remove(sessionID string) { coreLog.Debugf("Removing %d children of session %d (%v)", len(children), parentSession.ID, children) for _, child := range children { childSession, ok := s.sessions.LoadAndDelete(child.SessionID) - PivotSessions.Delete(childSession.(*Session).Connection.ID) if ok { + PivotSessions.Delete(childSession.(*Session).Connection.ID) EventBroker.Publish(Event{ EventType: consts.SessionClosedEvent, Session: childSession.(*Session), From f71a066ffc6a6021e9d2d0851a6f923f281fe0a9 Mon Sep 17 00:00:00 2001 From: moloch-- <875022+moloch--@users.noreply.github.com> Date: Sat, 12 Feb 2022 13:45:00 -0600 Subject: [PATCH 4/4] fix pivot/server ping interval, and calculation of pivot health --- client/command/generate/generate.go | 15 +++++++++++ implant/sliver/transports/session.go | 6 +++-- .../sliver/transports/transports_windows.go | 6 +++-- server/core/sessions.go | 7 ++++++ server/handlers/pivot.go | 25 +++---------------- server/handlers/sessions.go | 8 +++--- 6 files changed, 38 insertions(+), 29 deletions(-) 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/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 763754baf8..a4fdc8e444 100644 --- a/implant/sliver/transports/transports_windows.go +++ b/implant/sliver/transports/transports_windows.go @@ -81,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()), }) @@ -88,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/sessions.go b/server/core/sessions.go index b5b4f83af7..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 } 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)