From 66e720d34ddbdf961005486493baf036556aad39 Mon Sep 17 00:00:00 2001 From: Zachary Wasserman Date: Tue, 18 Sep 2018 12:12:46 -0400 Subject: [PATCH] Reduce port scanning possibilities via SMTP configuration The SMTP configuration could be used by an admin user to port scan the network the Fleet server was running on. This commit reduces the information possible to determine via this technique. A malicious admin can no longer determine whether any TCP server is listening on a given port/address. They can only determine ports and addresses where SMTP servers are running. Thanks to 'quikke' for reporting this vulnerability. --- server/mail/mail.go | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/server/mail/mail.go b/server/mail/mail.go index 0bfb1b1426..345b51ab83 100644 --- a/server/mail/mail.go +++ b/server/mail/mail.go @@ -147,8 +147,19 @@ func (m mailService) sendMail(e kolide.Email, msg []byte) error { // dialTimeout sets a timeout on net.Dial to prevent email from attempting to // send indefinitely. -func dialTimeout(addr string) (*smtp.Client, error) { - conn, err := net.DialTimeout("tcp", addr, 15*time.Second) +func dialTimeout(addr string) (client *smtp.Client, err error) { + // Ensure that errors are always returned after at least 5s to + // eliminate (some) timing attacks (in which a malicious user tries to + // port scan using the email functionality in Fleet) + c := time.After(5 * time.Second) + defer func() { + if err != nil { + // Wait until timer has elapsed to return anything + <-c + } + }() + + conn, err := net.DialTimeout("tcp", addr, 2*time.Second) if err != nil { return nil, errors.Wrap(err, "dialing with timeout") } @@ -156,5 +167,17 @@ func dialTimeout(addr string) (*smtp.Client, error) { if err != nil { return nil, errors.Wrap(err, "split host port") } - return smtp.NewClient(conn, host) + + // Set a deadline to ensure we time out quickly when there is a TCP + // server listening but it's not an SMTP server (otherwise this seems + // to time out in 20s) + _ = conn.SetDeadline(time.Now().Add(2 * time.Second)) + client, err = smtp.NewClient(conn, host) + if err != nil { + return nil, errors.New("SMTP connection error") + } + // Clear deadlines + _ = conn.SetDeadline(time.Time{}) + + return client, nil }