Esta pagina se ve mejor con JavaScript habilitado

SMTP: Diferencia entre MAIL FROM del envelope y FROM del message

 ·  🎃 kr0m

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:

vi /usr/local/etc/mail/opendkim.conf

SenderHeaders Custom-Header,From
service milter-opendkim restart

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:

vi /usr/local/etc/mail/opendkim.conf

SenderHeaders Custom-Header,From
service milter-opendkim restart

Programamos un sencillo milter que leerá el campo mail from del envelope y añadirá la cabecera Custom-Header con dicha información:

vi kr0mMilterReturnPath.py
#!/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:

cd /etc/mail

Definimos el milter y lo añadimos a la lista confINPUT_MAIL_FILTERS:

vi DrWho.alfaexploit.com.mc

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:

make

Actualizamos la configuración de Sendmail con la nuestra:

cp DrWho.alfaexploit.com.cf sendmail.cf

Reiniciamos el servicio:

service sendmail restart

Postfix:
Editamos su configuración del siguiente modo:

vi /etc/postfix/main.cf

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:

service postfix restart

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:.
Si te ha gustado el artículo puedes invitarme a un RedBull aquí