Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile.runner
Original file line number Diff line number Diff line change
Expand Up @@ -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 tini 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
Expand Down
50 changes: 15 additions & 35 deletions engine/checks/smtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ import (
"math/rand"
"net"
"net/smtp"
"os"
"strings"
"time"
)

// generateRandomContent creates random email content for variety.
func generateRandomContent() (subject string, body string) {
// #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
}

type Smtp struct {
Service
Encrypted bool
Domain string
RequireAuth bool
Fortunes []string
}

type unencryptedAuth struct {
Expand All @@ -34,38 +40,12 @@ 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, " ")
}
subject, body := generateRandomContent()

// ***********************************************
// Set up custom auth for bypassing net/smtp protections
Expand Down Expand Up @@ -176,20 +156,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
}

Expand Down