From 5a91d3c683de9b98a96f7c2485247ee7a963eb36 Mon Sep 17 00:00:00 2001 From: Tirefire <84106878+tire-fire@users.noreply.github.com> Date: Sat, 24 Jan 2026 01:27:13 -0600 Subject: [PATCH 1/2] Use random hex strings instead of fortune quotes for SMTP noise Generate random hex content for email subject (16 chars) and body (64 chars) instead of using hardcoded quotes. This provides the unpredictability needed to prevent SMTP check bypass while avoiding any content concerns. --- engine/checks/smtp.go | 60 ++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/engine/checks/smtp.go b/engine/checks/smtp.go index eb66f72..fe98b9e 100644 --- a/engine/checks/smtp.go +++ b/engine/checks/smtp.go @@ -3,22 +3,37 @@ package checks import ( "context" "crypto/tls" + "encoding/hex" "fmt" "log/slog" "math/rand" "net" "net/smtp" - "os" - "strings" "time" ) +// generateRandomContent creates unpredictable email content to prevent +// SMTP check bypass by accepting only known static messages. +func generateRandomContent() (subject string, body string) { + // Generate random bytes for subject and body + subjectBytes := make([]byte, 8) + bodyBytes := make([]byte, 32) + + // #nosec G404 -- non-crypto random for email content noise + rand.Read(subjectBytes) + // #nosec G404 -- non-crypto random for email content noise + rand.Read(bodyBytes) + + subject = hex.EncodeToString(subjectBytes) + body = hex.EncodeToString(bodyBytes) + return +} + type Smtp struct { Service Encrypted bool Domain string RequireAuth bool - Fortunes []string } type unencryptedAuth struct { @@ -34,38 +49,13 @@ func (a unencryptedAuth) Start(server *smtp.ServerInfo) (string, []byte, error) func (c Smtp) Run(teamID uint, teamIdentifier string, roundID uint, resultsChan chan Result) { definition := func(teamID uint, teamIdentifier string, checkResult Result, response chan Result) { - fortunes, err := os.ReadFile("/usr/share/fortune/fortunes") - if err != nil { - checkResult.Error = "failed to load fortune file (/usr/share/fortune/fortunes)" - checkResult.Debug = err.Error() - response <- checkResult - return - } - c.Fortunes = strings.Split(string(fortunes), "\n%\n") - if len(c.Fortunes) == 0 { - checkResult.Error = "failed to load fortune file (/usr/share/fortune/fortunes)" - checkResult.Debug = "no fortunes found" - response <- checkResult - return - } - // Create a dialer dialer := net.Dialer{ Timeout: time.Duration(c.Timeout) * time.Second, } - fortune := c.Fortunes[rand.Intn(len(c.Fortunes))] // #nosec G404 -- non-crypto selection of fortune text - words := strings.Fields(fortune) - subject := "" - if len(words) <= 3 { - subject = fortune - } else { - selected := make([]string, 3) - for i := range 3 { - selected[i] = words[rand.Intn(len(words))] // #nosec G404 -- non-crypto selection of words for subject - } - subject = strings.Join(selected, " ") - } + // Generate random content to prevent bypass via static message acceptance + subject, body := generateRandomContent() // *********************************************** // Set up custom auth for bypassing net/smtp protections @@ -176,20 +166,20 @@ func (c Smtp) Run(teamID uint, teamIdentifier string, roundID uint, resultsChan } }() - body := fmt.Sprintf("Subject: %s\n\n%s\n\n", subject, fortune) + message := fmt.Sprintf("Subject: %s\n\n%s\n\n", subject, body) - // Write the body using Fprint to avoid treating the contents as a + // Write the message using Fprint to avoid treating the contents as a // format string. - _, err = fmt.Fprint(wc, body) + _, err = fmt.Fprint(wc, message) if err != nil { - checkResult.Error = "writing body failed" + checkResult.Error = "writing message failed" checkResult.Debug = err.Error() response <- checkResult return } checkResult.Status = true - checkResult.Debug = "successfully wrote '" + body + "' to " + toUser + " from " + username + checkResult.Debug = "successfully wrote '" + message + "' to " + toUser + " from " + username response <- checkResult } From 8056affc5c3406712b452ef2fde1fff2903b32d9 Mon Sep 17 00:00:00 2001 From: Tirefire <84106878+tire-fire@users.noreply.github.com> Date: Sat, 24 Jan 2026 01:27:13 -0600 Subject: [PATCH 2/2] Remove fortune package from runner container No longer needed since SMTP check now uses generated random content. --- Dockerfile.runner | 2 +- engine/checks/smtp.go | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Dockerfile.runner b/Dockerfile.runner index 78b61a5..6b59304 100644 --- a/Dockerfile.runner +++ b/Dockerfile.runner @@ -13,7 +13,7 @@ RUN go build -o runner FROM alpine:3.21 WORKDIR /app COPY --from=builder /src/runner/runner runner -RUN apk add --no-cache wireguard-tools iproute2 iputils curl git openssh fortune py3-uv python3 proxychains-ng jq file sshpass bind-tools grep chrony krb5 +RUN apk add --no-cache wireguard-tools iproute2 iputils curl git openssh py3-uv python3 proxychains-ng jq file sshpass bind-tools grep chrony krb5 # custom python check scripts COPY custom-checks/requirements.txt /app diff --git a/engine/checks/smtp.go b/engine/checks/smtp.go index fe98b9e..cbf6687 100644 --- a/engine/checks/smtp.go +++ b/engine/checks/smtp.go @@ -3,7 +3,6 @@ package checks import ( "context" "crypto/tls" - "encoding/hex" "fmt" "log/slog" "math/rand" @@ -12,20 +11,12 @@ import ( "time" ) -// generateRandomContent creates unpredictable email content to prevent -// SMTP check bypass by accepting only known static messages. +// generateRandomContent creates random email content for variety. func generateRandomContent() (subject string, body string) { - // Generate random bytes for subject and body - subjectBytes := make([]byte, 8) - bodyBytes := make([]byte, 32) - - // #nosec G404 -- non-crypto random for email content noise - rand.Read(subjectBytes) - // #nosec G404 -- non-crypto random for email content noise - rand.Read(bodyBytes) - - subject = hex.EncodeToString(subjectBytes) - body = hex.EncodeToString(bodyBytes) + // #nosec G404 -- non-crypto random for email content + subject = fmt.Sprintf("%016x", rand.Uint64()) + // #nosec G404 -- non-crypto random for email content + body = fmt.Sprintf("%016x%016x%016x%016x", rand.Uint64(), rand.Uint64(), rand.Uint64(), rand.Uint64()) return } @@ -54,7 +45,6 @@ func (c Smtp) Run(teamID uint, teamIdentifier string, roundID uint, resultsChan Timeout: time.Duration(c.Timeout) * time.Second, } - // Generate random content to prevent bypass via static message acceptance subject, body := generateRandomContent() // ***********************************************