From 37436e138601bc9e2df87f8cdb23add3c15d3d81 Mon Sep 17 00:00:00 2001 From: ALLAI Date: Sat, 14 Mar 2026 23:34:51 -0400 Subject: [PATCH 1/3] fix: indefinite hangs during TLS handshake and cipher enumeration --- internal/pdcp/writer.go | 8 ++++++-- pkg/tlsx/tls/tls.go | 4 +++- pkg/tlsx/ztls/ztls.go | 21 ++++++++++++--------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/internal/pdcp/writer.go b/internal/pdcp/writer.go index 3adf91b6..c9c364d0 100644 --- a/internal/pdcp/writer.go +++ b/internal/pdcp/writer.go @@ -65,7 +65,7 @@ func NewUploadWriterCallback(ctx context.Context, creds *pdcpauth.PDCPCredential u := &UploadWriter{ creds: creds, done: make(chan struct{}, 1), - data: make(chan *clients.Response, 8), // default buffer size + data: make(chan *clients.Response, 1000), // increased buffer size TeamID: "", } var err error @@ -91,7 +91,11 @@ func NewUploadWriterCallback(ctx context.Context, creds *pdcpauth.PDCPCredential // GetWriterCallback returns the writer callback func (u *UploadWriter) GetWriterCallback() func(*clients.Response) { return func(resp *clients.Response) { - u.data <- resp + select { + case u.data <- resp: + default: + gologger.Warning().Msgf("PDCP upload buffer full, skipping result") + } } } diff --git a/pkg/tlsx/tls/tls.go b/pkg/tlsx/tls/tls.go index c07a5ed2..2f15e66d 100644 --- a/pkg/tlsx/tls/tls.go +++ b/pkg/tlsx/tls/tls.go @@ -236,10 +236,12 @@ func (c *Client) EnumerateCiphers(hostname, ip, port string, options clients.Con conn := tls.Client(baseConn, baseCfg) - if err := conn.Handshake(); err == nil { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(c.options.Timeout)*time.Second) + if err := conn.HandshakeContext(ctx); err == nil { ciphersuite := conn.ConnectionState().CipherSuite enumeratedCiphers = append(enumeratedCiphers, tls.CipherSuiteName(ciphersuite)) } + cancel() _ = conn.Close() // close baseConn internally } return enumeratedCiphers, nil diff --git a/pkg/tlsx/ztls/ztls.go b/pkg/tlsx/ztls/ztls.go index a03b7267..f89265cd 100644 --- a/pkg/tlsx/ztls/ztls.go +++ b/pkg/tlsx/ztls/ztls.go @@ -257,10 +257,12 @@ func (c *Client) EnumerateCiphers(hostname, ip, port string, options clients.Con conn := tls.Client(baseConn, baseCfg) baseCfg.CipherSuites = []uint16{ztlsCiphers[v]} - if err := c.tlsHandshakeWithTimeout(conn, context.TODO()); err == nil { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(c.options.Timeout)*time.Second) + if err := c.tlsHandshakeWithTimeout(conn, ctx); err == nil { h1 := conn.GetHandshakeLog() enumeratedCiphers = append(enumeratedCiphers, h1.ServerHello.CipherSuite.String()) } + cancel() _ = conn.Close() // also closes baseConn internally } return enumeratedCiphers, nil @@ -323,17 +325,18 @@ func (c *Client) getConfig(hostname, ip, port string, options clients.ConnectOpt // tlsHandshakeWithCtx attempts tls handshake with given timeout func (c *Client) tlsHandshakeWithTimeout(tlsConn *tls.Conn, ctx context.Context) error { errChan := make(chan error, 1) - defer close(errChan) + + go func() { + errChan <- tlsConn.Handshake() + }() select { case <-ctx.Done(): return errorutil.NewWithTag("ztls", "timeout while attempting handshake") //nolint - case errChan <- tlsConn.Handshake(): - } - - err := <-errChan - if err == tls.ErrCertsOnly { - err = nil + case err := <-errChan: + if err == tls.ErrCertsOnly { + err = nil + } + return err } - return err } From 27c1b5da2cbc4a8cd127e5d92e43986b1d98094d Mon Sep 17 00:00:00 2001 From: allornothingai Date: Mon, 16 Mar 2026 22:26:03 -0400 Subject: [PATCH 2/3] fix: Add timeout validation to EnumerateCiphers Guard against Timeout == 0 causing immediate context expiration. Co-authored-by: Paperclip --- pkg/tlsx/tls/tls.go | 10 ++++++++-- pkg/tlsx/ztls/ztls.go | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pkg/tlsx/tls/tls.go b/pkg/tlsx/tls/tls.go index 2f15e66d..c3bddd8e 100644 --- a/pkg/tlsx/tls/tls.go +++ b/pkg/tlsx/tls/tls.go @@ -236,12 +236,18 @@ func (c *Client) EnumerateCiphers(hostname, ip, port string, options clients.Con conn := tls.Client(baseConn, baseCfg) - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(c.options.Timeout)*time.Second) + ctx := context.Background() + var cancel context.CancelFunc + if c.options.Timeout != 0 { + ctx, cancel = context.WithTimeout(ctx, time.Duration(c.options.Timeout)*time.Second) + } if err := conn.HandshakeContext(ctx); err == nil { ciphersuite := conn.ConnectionState().CipherSuite enumeratedCiphers = append(enumeratedCiphers, tls.CipherSuiteName(ciphersuite)) } - cancel() + if cancel != nil { + cancel() + } _ = conn.Close() // close baseConn internally } return enumeratedCiphers, nil diff --git a/pkg/tlsx/ztls/ztls.go b/pkg/tlsx/ztls/ztls.go index f89265cd..67685139 100644 --- a/pkg/tlsx/ztls/ztls.go +++ b/pkg/tlsx/ztls/ztls.go @@ -257,12 +257,18 @@ func (c *Client) EnumerateCiphers(hostname, ip, port string, options clients.Con conn := tls.Client(baseConn, baseCfg) baseCfg.CipherSuites = []uint16{ztlsCiphers[v]} - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(c.options.Timeout)*time.Second) + ctx := context.Background() + var cancel context.CancelFunc + if c.options.Timeout != 0 { + ctx, cancel = context.WithTimeout(ctx, time.Duration(c.options.Timeout)*time.Second) + } if err := c.tlsHandshakeWithTimeout(conn, ctx); err == nil { h1 := conn.GetHandshakeLog() enumeratedCiphers = append(enumeratedCiphers, h1.ServerHello.CipherSuite.String()) } - cancel() + if cancel != nil { + cancel() + } _ = conn.Close() // also closes baseConn internally } return enumeratedCiphers, nil From 679cf13346d86a75a368b66f8e1f5c339e38f73c Mon Sep 17 00:00:00 2001 From: allornothingai Date: Mon, 16 Mar 2026 22:27:25 -0400 Subject: [PATCH 3/3] chore: Address CodeRabbit nitpicks - Add dropped results counter to PDCP UploadWriter\n- Reorder parameters of tlsHandshakeWithTimeout to follow Go conventions\n\nCo-authored-by: Paperclip --- internal/pdcp/writer.go | 5 +++++ pkg/tlsx/ztls/ztls.go | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/pdcp/writer.go b/internal/pdcp/writer.go index c9c364d0..9fe8f219 100644 --- a/internal/pdcp/writer.go +++ b/internal/pdcp/writer.go @@ -52,6 +52,7 @@ type UploadWriter struct { assetGroupID string assetGroupName string counter atomic.Int32 + droppedCounter atomic.Int32 closed atomic.Bool TeamID string } @@ -94,6 +95,7 @@ func (u *UploadWriter) GetWriterCallback() func(*clients.Response) { select { case u.data <- resp: default: + u.droppedCounter.Add(1) gologger.Warning().Msgf("PDCP upload buffer full, skipping result") } } @@ -129,6 +131,9 @@ func (u *UploadWriter) autoCommit(ctx context.Context) { } else { gologger.Info().Msgf("Found %v results, View found results in dashboard : %v", u.counter.Load(), getAssetsDashBoardURL(u.assetGroupID, u.TeamID)) } + if dropped := u.droppedCounter.Load(); dropped > 0 { + gologger.Warning().Msgf("Dropped %v results due to upload buffer overflow", dropped) + } }() // temporary buffer to store the results buff := &bytes.Buffer{} diff --git a/pkg/tlsx/ztls/ztls.go b/pkg/tlsx/ztls/ztls.go index 67685139..be09a8e4 100644 --- a/pkg/tlsx/ztls/ztls.go +++ b/pkg/tlsx/ztls/ztls.go @@ -140,7 +140,7 @@ func (c *Client) ConnectWithOptions(hostname, ip, port string, options clients.C // new tls connection tlsConn := tls.Client(conn, config) - err = c.tlsHandshakeWithTimeout(tlsConn, ctx) + err = c.tlsHandshakeWithTimeout(ctx, tlsConn) if err != nil { if clients.IsClientCertRequiredError(err) { clientCertRequired = true @@ -262,7 +262,7 @@ func (c *Client) EnumerateCiphers(hostname, ip, port string, options clients.Con if c.options.Timeout != 0 { ctx, cancel = context.WithTimeout(ctx, time.Duration(c.options.Timeout)*time.Second) } - if err := c.tlsHandshakeWithTimeout(conn, ctx); err == nil { + if err := c.tlsHandshakeWithTimeout(ctx, conn); err == nil { h1 := conn.GetHandshakeLog() enumeratedCiphers = append(enumeratedCiphers, h1.ServerHello.CipherSuite.String()) } @@ -329,7 +329,7 @@ func (c *Client) getConfig(hostname, ip, port string, options clients.ConnectOpt } // tlsHandshakeWithCtx attempts tls handshake with given timeout -func (c *Client) tlsHandshakeWithTimeout(tlsConn *tls.Conn, ctx context.Context) error { +func (c *Client) tlsHandshakeWithTimeout(ctx context.Context, tlsConn *tls.Conn) error { errChan := make(chan error, 1) go func() {