git » chasquid » commit 8c8e64d

smtpsrv: Reject HTTP commands

author Alberto Bertogli
2021-06-10 17:42:56 UTC
committer Alberto Bertogli
2021-06-11 09:35:51 UTC
parent 85305f4bd9320d68cb96be100fd60d6a43a25c87

smtpsrv: Reject HTTP commands

To help with defense-in-depth on cross-protocol attacks (e.g.
https://alpaca-attack.com/), this patch makes chasquid reject HTTP
commands.

docs/monitoring.md +2 -0
internal/smtpsrv/conn.go +10 -0
test/t-12-minor_dialogs/wrong_proto.cmy +15 -0

diff --git a/docs/monitoring.md b/docs/monitoring.md
index 1b13a88..21db2a2 100644
--- a/docs/monitoring.md
+++ b/docs/monitoring.md
@@ -66,6 +66,8 @@ List of exported variables:
   count of SPF checks, by result.
 - **chasquid/smtpIn/tlsCount** (tls status -> counter)  
   count of TLS statuses (plain/tls) for incoming SMTP connections.
+- **chasquid/smtpIn/wrongProtoCount** (command -> counter)  
+  count of commands for other protocols (e.g. HTTP commands).
 - **chasquid/smtpOut/securityLevelChecks** (result -> counter)  
   count of security level checks on outgoing connections, by result.
 - **chasquid/smtpOut/sts/mode** (mode -> counter)  
diff --git a/internal/smtpsrv/conn.go b/internal/smtpsrv/conn.go
index e6d3d54..66f8c74 100644
--- a/internal/smtpsrv/conn.go
+++ b/internal/smtpsrv/conn.go
@@ -51,6 +51,8 @@ var (
 		"result", "incoming security level check results")
 	hookResults = expvarom.NewMap("chasquid/smtpIn/hookResults",
 		"result", "count of hook invocations, by result")
+	wrongProtoCount = expvarom.NewMap("chasquid/smtpIn/wrongProtoCount",
+		"command", "count of commands for other protocols")
 )
 
 var (
@@ -272,6 +274,14 @@ loop:
 		case "QUIT":
 			_ = c.writeResponse(221, "2.0.0 Be seeing you...")
 			break loop
+		case "GET", "POST", "CONNECT":
+			// HTTP protocol detection, to prevent cross-protocol attacks
+			// (e.g. https://alpaca-attack.com/).
+			wrongProtoCount.Add(cmd, 1)
+			c.tr.Errorf("http command, closing connection")
+			_ = c.writeResponse(502,
+				"5.7.0 You hear someone cursing shoplifters")
+			break loop
 		default:
 			// Sanitize it a bit to avoid filling the logs and events with
 			// noisy data. Keep the first 6 bytes for debugging.
diff --git a/test/t-12-minor_dialogs/wrong_proto.cmy b/test/t-12-minor_dialogs/wrong_proto.cmy
new file mode 100644
index 0000000..1f451c7
--- /dev/null
+++ b/test/t-12-minor_dialogs/wrong_proto.cmy
@@ -0,0 +1,15 @@
+
+c tcp_connect localhost:1025
+c <~ 220
+c -> GET /evil HTTP/1.1
+c <- 502 5.7.0 You hear someone cursing shoplifters
+
+c tcp_connect localhost:1025
+c <~ 220
+c -> POST /evil HTTP/1.1
+c <- 502 5.7.0 You hear someone cursing shoplifters
+
+c tcp_connect localhost:1025
+c <~ 220
+c -> CONNECT www.evil.com:80 HTTP/1.1
+c <- 502 5.7.0 You hear someone cursing shoplifters