Muchos sysadmins no entienden la diferencia entre el campo Mail From: y la cabecera From: de un email, esto les lleva a configuraciones erróneas de los registros SPF y DKIM de la zona DNS. En este artÃculo despejaremos todas las dudas mediante una breve explicación y un caso práctico para cada escenario.
Un email se compone de dos partes:
- Envelope: PodrÃamos decir que es el sobre, si hay algún problema de entrega se devolverá a este remitente.
- Message: PodrÃamos decir que es el contenido de la carta donde se indica a quien va dirigida, quienes somos, el asunto y el resto de la carta.
Como ocurre con las cartas fÃsicas el sobre puede pasar por distintas oficinas de correos e ir sellando el sobre y cambiando la información pero el message siempre será el original, las oficinas de correos no alteran nunca el contenido de la carta.
En el Envelope se definen tres campos:
- Received: Cada vez que el email pasa por un servidor se añade un Received distinto indicando el origen del email y quién lo recibe, un ejemplo puede ser este email recibido por GMail desde DrWho.alfaexploit.com:
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id h21si1891479wmc.162.2021.09.08.03.01.34
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 08 Sep 2021 03:01:34 -0700 (PDT)
- MAIL FROM: A quien se debe informar en caso de fallo de entrega del email, esta información aparece en el primer Received como envelope-from, además esta dirección será copiada a un campo nuevo llamado Return-Path:
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A0gJH000912 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:00:51 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
Return-Path: <kr0m@alfaexploit.com>
Debemos tener en cuenta que en caso de fallo de entrega del email los avisos bounceds pueden ser notificados a la dirección de Return-Path de dos maneras distintas dependiendo del proveedor de mailing.
Si utilizamos un servidor de email para enviar correos(como ocurre en la mayorÃa de los casos), pueden darse dos escenarios:
Hotmail/GMail… delega en nuestro servidor | Hotmail/GMail… responde directamente |
---|---|
El servidor(SendMail/Postfix…) conecta con Hotmail/GMail… | El servidor(SendMail/Postfix…) conecta con Hotmail/GMail… |
La dirección no existe o el buzón está lleno | La dirección no existe o el buzón está lleno |
Hotmail/GMail… responde por la conexión SMTP que está lleno | Hotmail/GMail… acepta el email |
El servidor inicial(SendMail/Postfix…) envÃa el bounced a la dirección de Return-Path | Hotmail/GMail… envÃa el bounced a la dirección de Return-Path |
En cambio si realizamos la conexión directamente contra los servidores de Hotmail/GMail sin montar un SendMail/Postfix, pueden darse dos escenarios:
Hotmail/GMail… delega en el cliente | Hotmail/GMail… responde directamente |
---|---|
El cliente conecta con Hotmail/GMail… | El cliente conecta con Hotmail/GMail… |
La dirección no existe o el buzón está lleno | La dirección no existe o el buzón está lleno |
Hotmail/GMail… responde por la conexión SMTP que está lleno | Hotmail/GMail… acepta el email |
Hotmail/GMail… envÃa el bounce a la dirección de Return-Path |
- RCPT TO: Destinatario del email, se trata del for que aparezca en el primer Received:
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A0gJH000912 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:00:51 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
En el Message tenemos dos partes:
- Headers: Estas cabeceras pueden ser de distinta Ãndole, las mas comunes son Subject, Date, From y To, pero también pueden ser datos utilizados por cierto software como SpamAssasin, el tipo de contenido del body del email entre otras muchas opciones, lo que quiero decir es que puede ser muy variable.
From: Indica quién es el autor del email.
- Body: Es el propio contenido del email.
Podemos comprobar el propósito de estos campos en sus respectivas RFCs:
RFC5321.MailFrom
RFC5322.From
Una sesión Telnet de envÃo de email podrÃa ser la siguiente, a la derecha indico una breve descripción.
-- ENVELOPE:-------------------------
helo localhost
mail from: kr0m@alfaexploit.com -> Return-Path -> SPF comprobado a partir de este dominio
rcpt to: jjivarspoquet@gmail.com -> Destinatario real del email
-------------------------------------
-- MESSAGE:--------------------------
data
Subject: SPF: ok DKIM: ok
From: kr0m@alfaexploit.com -> Origen mostrado al cliente -> DKIM generado a partir de este dominio
To: to_mostrado@inventado.com -> Destinatario mostrado al cliente
-------------------------------------
123
.
quit
Lo mejor es probar las cosas por uno mismo asà que voy a enviar diferentes emails:
- Uno con todos los campos correctos.
- Otro con el mail from: de un dominio inventado, por lo tanto el SPF resultará incorrecto.
- Otro con el From: de un dominio inventado, por lo tanto no firmaremos DKIM.
- Y otro con el mail from: y el From: de un dominio inventado, de este modo el SPF resultará incorrecto y no firmaremos DKIM.
De este modo veremos el efecto en el SPF/DKIM al cambiar cada uno de los campos del email.
Todo correcto:
telnet localhost 25
helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com
data
Subject: SPF: ok DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com
123
.
quit
Podemos ver los distintos campos en el email recibido por el cliente:
Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=IgeEfQnE;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id h21si1891479wmc.162.2021.09.08.03.01.34
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 08 Sep 2021 03:01:34 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=IgeEfQnE;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A0gJH000912 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:00:51 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631095271; bh=Afm/S7SaxS19en1h955RwsupTF914DQUPqYU8Nh7kpw=; h=Subject:From:To; b=IgeEfQnEwaalsc+P0hFiwUykYniP5ulRbLYNiMzbY7dF606Af3W6miP1xst4dPzXI
TKTMzNjUBUvIG6bO92hxbwnz41vG9u+g0GH75An78OKC9LfH68pIHeewmiqwbsxoDE
8Yg1Z9gVqjhlZOkwSI8mNwOkuS+67wYM9vBISWVY=
Date: Wed, 8 Sep 2021 12:00:42 +0200 (CEST)
Message-Id: <202109081000.188A0gJH000912@DrWho.alfaexploit.com>
Subject: SPF: ok DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.5 required=5.0 tests=ALL_TRUSTED,MISSING_DATE, MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com
123
Como podemos ver tanto el SPF como el DKIM son correctos:
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=IgeEfQnE;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
En la interfaz del cliente veremos:
Mail from: de un dominio inventado, por lo tanto SPF incorrecto:
telnet localhost 25
helo localhost
mail from: kr0m@inventado.com
rcpt to: jjivarspoquet@gmail.com
data
Subject: SPF: ko DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com
123
.
quit
Podemos ver los distintos campos en el email recibido por el cliente:
Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=VCercMLI;
spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Return-Path: <kr0m@inventado.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id l66si1586854wml.114.2021.09.08.03.04.55
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 08 Sep 2021 03:04:55 -0700 (PDT)
Received-SPF: neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=VCercMLI;
spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A4D8C076084 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:04:19 +0200 (CEST) (envelope-from kr0m@inventado.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631095473; bh=Afm/S7SaxS19en1h955RwsupTF914DQUPqYU8Nh7kpw=; h=Subject:From:To; b=VCercMLIzh9ROm9NxxbVEdjNrZWhPRzNerCD5TXpf9hX2J1+BaDeBLw/SU7nXckXH
ZeC6wNNfZsvEPeHl1De4xDH5yarUswH5Smcb83biCvnjrF+UDB+C8eq2CZxX8m5vjd
DXLzjRVNb3OaBEEWjeY90bEm0AkL/g0+uW2lGXWk=
Date: Wed, 8 Sep 2021 12:04:13 +0200 (CEST)
Message-Id: <202109081004.188A4D8C076084@DrWho.alfaexploit.com>
Subject: SPF: ko DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com
123
El dominio inventado.com es bastante permisivo ya que no considera nuestra ip como permitida ni denegada, de este modo GMail considera el SPF como neutral:
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=VCercMLI;
spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
En la interfaz del cliente veremos:
From: de un dominio inventado, por lo tanto no firmamos DKIM:
telnet localhost 25
helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com
data
Subject: SPF: ok DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com
123
.
quit
Podemos ver los distintos campos en el email recibido por el cliente:
Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id 68si1534562wmz.123.2021.09.08.03.09.08
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 08 Sep 2021 03:09:08 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A8ReQ052051 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:08:33 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
Date: Wed, 8 Sep 2021 12:08:27 +0200 (CEST)
Message-Id: <202109081008.188A8ReQ052051@DrWho.alfaexploit.com>
Subject: SPF: ok DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com
123
Vemos que no hay cabecera DKIM.
El DKIM es tan importante para GMail que para ver el email he tenido que ir a la sección “Todo” porque no lo encontraba ni en la bandeja de entrada ni en Spam.
En la interfaz del cliente veremos:
Mail from: de un dominio inventado y From: también inventado, por lo tanto SPF incorrecto y sin firma DKIM:
telnet localhost 25
helo localhost
mail from: kr0m@inventado.com
rcpt to: jjivarspoquet@gmail.com
data
Subject: SPF: ko DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com
123
.
quit
Podemos ver los distintos campos en el email recibido por el cliente:
Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com
Return-Path: <kr0m@inventado.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id n13si1998533wri.475.2021.09.08.03.12.42
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 08 Sep 2021 03:12:42 -0700 (PDT)
Received-SPF: neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188AC1uc019244 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:12:08 +0200 (CEST) (envelope-from kr0m@inventado.com)
Date: Wed, 8 Sep 2021 12:12:01 +0200 (CEST)
Message-Id: <202109081012.188AC1uc019244@DrWho.alfaexploit.com>
Subject: SPF: ko DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.5 required=5.0 tests=ALL_TRUSTED,MISSING_DATE, MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com
123
Vemos que no hay cabecera DKIM y que el SPF no pasa:
spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com
En la interfaz del cliente veremos:
Curiosamente en esta ocasión el email estaba en la bandeja de entrada, sin DKIM hay que buscarlo en “Todos” pero sin SPF ni DKIM entra en bandeja de entrada, cosas de Google…
En mi caso utilizo OpenDkim que por defecto mira la cabecer From: del message pero se puede configurar para que lea cualquier otra mediante el parámetro SenderHeaders, la configuración es una lista de cabeceras que recorrer en orden hasta encontrar una de ellas.
Si necesitamos firmar en base a algún campo del envelope como lo es Mail From:(Return-Path) tenemos un problema ya que Opendkim está limitado a las cabeceras del message, no puede acceder a los campos del envelope.
Para solventar dicha limitación podemos:
- Inyectar directamente en el email una cabecera con la dirección del campo Mail From:(Return-Path)
- Escribir un milter que lea la información del campo MailFrom:(Return-Path) y nos genere una cabecera con dicha información en el message.
Inyectando cabecera:
Primero configuramos OpenDkim de tal manera que si encuentra la cabecera Custom-Header la leerá para obtener el dominio con el que debe firmar el email, si no la encuentra lo hará con el dominio de la cabecera From:
SenderHeaders Custom-Header,From
Para probarlo enviaremos un email vÃa telnet:
telnet localhost 25
helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com
data
Subject: Test OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
Custom-Header: kr0m@alfaexploit.com
123
.
quit
El resultado es el siguiente:
Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=gL9fSNRb;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id r9si895119wru.150.2021.09.08.23.47.51
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 08 Sep 2021 23:47:52 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=gL9fSNRb;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 1896kuWO076701 for jjivarspoquet@gmail.com; Thu, 9 Sep 2021 08:47:08 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631170048; bh=Afm/S7SaxS19en1h955RwsupTF914DQUPqYU8Nh7kpw=; h=Subject:From:To; b=gL9fSNRb6ovDOSOC+01X2F29evKpDQ7Rnr50ZDxocA3bgWopsa8v2WMci5U8PFAxq
6prYxfHIQad77IbZaRy7pca4+wi3rjILFE6lcZKssHcc5LpZjTLlikxmJmKWLjg6PF
QGFiJeoHFzrsEIHcgm6oX71nZ1uflG3nTyEB1UAY=
Date: Thu, 9 Sep 2021 08:46:56 +0200 (CEST)
Message-Id: <202109090647.1896kuWO076701@DrWho.alfaexploit.com>
Subject: Test OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
Custom-Header: kr0m@alfaexploit.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID,TVD_SPACE_RATIO autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com
123
Como podemos ver OpenDkim ha leÃdo la cabecera custom y no From, si hubiese leÃdo la cabecera From habrÃa intentado firmar el email con el dominio inventado.com que no es de mi propiedad y el email habrÃa llegado sin firma DKIM, pero como ha leÃdo la cabecera Custom-Header, si que lo ha firmado correctamente con alfaexploit.com.
Mediante milter:
Primero configuramos OpenDkim de tal manera que si encuentra la cabecera Custom-Header la leerá para obtener el dominio con el que debe firmar el email, si no la encuentra lo hará con el dominio de la cabecera From:
SenderHeaders Custom-Header,From
Programamos un sencillo milter que leerá el campo mail from del envelope y añadirá la cabecera Custom-Header con dicha información:
#!/usr/bin/env python
# https://pythonhosted.org/pymilter/classMilter_1_1Base.html
import Milter
import time
import sys
import os
import logging
import logging.handlers
from configparser import ConfigParser
__version__ = '0.5b' # version
CONFIG = os.path.join(os.path.dirname(__file__),"config.ini")
if os.path.isfile(CONFIG):
config = ConfigParser()
config.read(CONFIG)
SOCKET = config.get('Milter', 'SOCKET')
try:
UMASK = int(config.get('Milter', 'UMASK'), base=0)
except:
UMASK = 0o0077
TIMEOUT = config.getint('Milter', 'TIMEOUT')
MAX_FILESIZE = config.getint('Milter', 'MAX_FILESIZE')
LOGFILE_DIR = config.get('Logging', 'LOGFILE_DIR')
LOGFILE_NAME = config.get('Logging', 'LOGFILE_NAME')
LOGLEVEL = config.getint('Logging', 'LOGLEVEL')
else:
sys.exit("Please check the config file! Config path: %s" % CONFIG)
# =============================================================================
LOGFILE_PATH = os.path.join(LOGFILE_DIR, LOGFILE_NAME)
log = logging.getLogger('kr0mMilter')
log.setLevel(logging.CRITICAL+1)
class kr0mMilter(Milter.Base):
def __init__(self):
self.id = Milter.uniqueID()
self.return_path_domain = None
def envfrom(self, mailfrom, *str):
self.return_path_domain = mailfrom
return Milter.CONTINUE
def eom(self):
self.addheader('Custom-Header', self.return_path_domain)
return Milter.CONTINUE
# =============================================================================
def main():
try:
os.makedirs(LOGFILE_DIR,0o0027)
except:
pass
oldumask = os.umask(0o0026)
handler = logging.handlers.WatchedFileHandler(LOGFILE_PATH, encoding='utf8')
formatter = logging.Formatter('%(asctime)s - %(levelname)8s: %(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
os.umask(oldumask)
if LOGLEVEL == 2:
log.setLevel(logging.INFO)
elif LOGLEVEL == 3:
log.setLevel(logging.WARNING)
else:
log.setLevel(logging.DEBUG)
Milter.factory = kr0mMilter
flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
flags += Milter.ADDRCPT
flags += Milter.DELRCPT
Milter.set_flags(flags)
print("%s kr0mMilter startup - Version %s" % (time.strftime('%Y-%m-%d %H:%M:%S'), __version__ ))
print('logging to file %s' % LOGFILE_PATH)
log.info('Starting kr0mMilter v%s - listening on %s' % (__version__, SOCKET))
log.debug('Python version: %s' % sys.version)
sys.stdout.flush()
os.umask(UMASK)
Milter.set_exception_policy(Milter.ACCEPT)
Milter.runmilter("kr0mMilter", SOCKET, TIMEOUT)
print("%s kr0mMilter shutdown" % time.strftime('%Y-%m-%d %H:%M:%S'))
if __name__ == "__main__":
main()
Configuramos nuestro MTA para que utilice el milter.
SendMail:
Definimos el milter y lo añadimos a la lista confINPUT_MAIL_FILTERS:
MAIL_FILTER(`kr0mMilter', `S=/var/run/kr0mMilter.sock, F=T, T=R:2m')
define(`confINPUT_MAIL_FILTERS', `kr0mMilter, spamassassin, dkim-filter')
NOTA: El orden de los milters es importante, primero debemos ejecutar nuestro milter y luego OpenDkim.
Compilamos a M4 la nueva configuración:
Actualizamos la configuración de Sendmail con la nuestra:
Reiniciamos el servicio:
Postfix:
Editamos su configuración del siguiente modo:
smtpd_milters = unix:/var/run/kr0mMilter.sock, unix:/var/run/opendkim/opendkim.sock
NOTA: El orden de los milters es importante, primero debemos ejecutar nuestro milter y luego OpenDkim.
Reiniciamos el servicio:
Para probarlo enviaremos un email vÃa telnet:
telnet localhost 25
helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com
data
Subject: Test2 OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
123
.
quit
El resultado es el siguiente:
Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=oP11og1A;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
by mx.google.com with ESMTPS id l26si993677wmi.106.2021.09.09.00.09.57
for <jjivarspoquet@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Thu, 09 Sep 2021 00:09:57 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=oP11og1A;
spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 1897974Z026004 for jjivarspoquet@gmail.com; Thu, 9 Sep 2021 09:09:15 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631171373; bh=osFg1QXCH8704iYyd9cTTQI3SShRGx5igJ1ovGCgJ4s=; h=Subject:From:To; b=oP11og1ArQj5GSBPoX9nV6/sBL7a3tkGGPS55fiBh2pTN42C3sFirKZ4SFiWcw6Hy
U1OxNrNQdVeQ0TIc7N2qE1hiNdXPBhfMtX77lXdsNJBW7KmFzJ9R8oHz+k4ikw4kS+
kcMRcqanDvkXqBNwqetk2qffkr5WQ2kV+J5kxLSQ=
Date: Thu, 9 Sep 2021 09:09:07 +0200 (CEST)
Message-Id: <202109090709.1897974Z026004@DrWho.alfaexploit.com>
Subject: Test2 OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
Custom-Header: kr0m@alfaexploit.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com
data
123
Como podemos ver OpenDkim ha leÃdo la cabecera custom y no From, si hubiese leÃdo la cabecera From habrÃa intentado firmar el email con el dominio inventado.com que no es de mi propiedad y el email habrÃa llegado sin firma DKIM, pero como ha leÃdo la cabecera Custom-Header, si que lo ha firmado correctamente con alfaexploit.com.
Como conclusión final podemos asegurar que SPF y DKIM leen distintos datos para evaluar la validez del email:
- SPF: Lee el dominio del Mail From: del envelope.
- DKIM: Lee el dominio de la cabecera del message que le indiquemos mediante el parámetro de configuración SenderHeaders, por defecto From:.