fix(smtp_relay): inject From: header if absent so attacker address shows in client
Relay-test scripts send minimal DATA with no headers. Without a From: header the mail client falls back to displaying the envelope sender (upstream_sender). Inject From: <attacker MAIL FROM> before forwarding when the message has no existing From: header.
This commit is contained in:
@@ -8,6 +8,7 @@ Called by the realism worker's smtp probe listener, not the main tick loop.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import email
|
||||||
import smtplib
|
import smtplib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -15,6 +16,19 @@ from typing import Any
|
|||||||
_ARTIFACTS_ROOT_DEFAULT = "/var/lib/decnet/artifacts"
|
_ARTIFACTS_ROOT_DEFAULT = "/var/lib/decnet/artifacts"
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_from_header(body: bytes, mail_from: str) -> bytes:
|
||||||
|
"""Return body with a From: header added if one is absent."""
|
||||||
|
try:
|
||||||
|
msg = email.message_from_bytes(body)
|
||||||
|
except Exception:
|
||||||
|
return body
|
||||||
|
if msg["From"]:
|
||||||
|
return body
|
||||||
|
# Prepend the header before the existing content.
|
||||||
|
header_line = f"From: {mail_from}\r\n".encode()
|
||||||
|
return header_line + body
|
||||||
|
|
||||||
|
|
||||||
def forward_probe(
|
def forward_probe(
|
||||||
*,
|
*,
|
||||||
svc_cfg: dict[str, Any],
|
svc_cfg: dict[str, Any],
|
||||||
@@ -47,6 +61,11 @@ def forward_probe(
|
|||||||
upstream_pass = (svc_cfg.get("upstream_pass") or "").strip()
|
upstream_pass = (svc_cfg.get("upstream_pass") or "").strip()
|
||||||
envelope_from = (svc_cfg.get("upstream_sender") or "").strip() or mail_from
|
envelope_from = (svc_cfg.get("upstream_sender") or "").strip() or mail_from
|
||||||
|
|
||||||
|
# Ensure the message has a From: header so mail clients show the attacker's
|
||||||
|
# address rather than falling back to the envelope sender (upstream_sender).
|
||||||
|
# Minimal relay-test scripts often omit headers entirely.
|
||||||
|
body = _ensure_from_header(body, mail_from)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with smtplib.SMTP(upstream_host, upstream_port, timeout=15) as conn:
|
with smtplib.SMTP(upstream_host, upstream_port, timeout=15) as conn:
|
||||||
conn.ehlo()
|
conn.ehlo()
|
||||||
|
|||||||
Reference in New Issue
Block a user