Saturday, August 23, 2008

Diseccionando un envío de Correo en Gmail

El envío del correo electrónico se lleva a cabo por medio del protocolo SMTP, sin embargo debido a cuestiones de seguridad, políticas, etc. se ha dividido el envío del correo electrónico, de la transmisión. Entiéndase como envío la comunicación entre el MUA -> MTA y como transmisión la comunicación entre MTA -> MTA.

De manera, que para cada uno de estos tipos de comunicación tenemos lo siguiente:

* Para la transmisión del correo se ocupa SMTP por el puerto 25 [RFC 2821].
* Para el envío del correo se ocupa SMTP por el puerto 587 [RFC 4409].

Para hacer la disección del envío de correo ocuparemos Gmail, por lo que la dirección del servidor SMTP que ocuparemos es smtp.gmail.com. (De aquí en adelante S-Servidor C-Cliente).

$ telnet smtp.gmail.com 587
S: 220 mx.google.com ESMTP m29sm12092147poh.3

Si vemos los servicios (extendidos) que nos ofrece este servidor obtenemos:
C: ehlo
S: 250-mx.google.com at your service, [w.x.y.z]
S: 250-SIZE 28311552
S: 250-8BITMIME
S: 250-STARTTLS
S: 250 ENHANCEDSTATUSCODES

Lo que nos importa es la línea que dice "250-STARTTLS", ya que en este punto si introducimos cualquier comando de SMTP obtendremos.

S: 530 5.7.0 Must issue a STARTTLS command first m29sm12092147poh.3

Es decir, tenemos que iniciar una comunicación "segura", ocupando SMTP sobre TLS [RFC 2487], que tiene que ser algo como lo siguiente:

S: <waits for connection on SMTP port>
C: <opens connection>
S: 220 mail.imc.org SMTP service ready
C: EHLO mail.ietf.org
S: 250-mail.imc.org offers a warm hug of welcome
S: 250 STARTTLS
C: STARTTLS
S: 220 Go ahead
C: <starts TLS negotiation>
C & S: <negotiate a TLS session>
C & S: <check result of negotiation>
C: <continues by sending an SMTP command>
. . .
(El estándar específica que el primer comando que DEBERÍA enviar el cliente después de haber establecido la negociación de TLS, es un EHLO)

Para la comunicación con el servidor ocuparemos Ruby.

=begin
Al parecer estas líneas no son necesarias en Windows
require 'socket'
require 'openssl' -> Si ocupas Lnx, tienes que tener instalado libssl-ruby
=end

require 'base64'

smtpSocket = TCPSocket.new("smtp.gmail.com",587)
S: 220 mx.google.com ESMTP z15sm18510036pod.11\r\n

smtpSocket.puts "ehlo"
S: 250-mx.google.com at your service, [w.x.y.z]
S: 250-SIZE 28311552
S: 250-8BITMIME
S: 250-STARTTLS
S: 250 ENHANCEDSTATUSCODES

smtpSocket.puts "starttls"
S: 220 2.0.0 Ready to start TLS\r\n

ssl=OpenSSL::SSL::SSLSocket.new(smtpSocket)
ssl.connect
ssl.puts "ehlo"
S: 250-mx.google.com at your service, [w.x.y.z]\r\n
S: 250-SIZE 28311552\r\n
S: 250-8BITMIME\r\n
S: 250-AUTH LOGIN PLAIN\r\n
S: 250 ENHANCEDSTATUSCODES\r\n

Y es en este punto donde encontramos algo interesante: "250-AUTH LOGIN PLAIN", esta línea nos dice la forma en la que podemos autenticarnos; toda esta autenticación se lleva en base a SASL (Simple Authentication and Security Layer) [RFC 4422]. ¿En algún lugar has escuchado SASL?, efectivamente es un framework para autenticación que es usado por varios protocolos y entre esos protocolos se encuentra LDAP y si alguna vez has ocupado Active Directory sabras que la autenticación (por default) se lleva a cabo ocupando Kerberos [RFC 4752]. En nuestro caso ocuparemos PLAIN [RFC 4616], que lo que nos dice es que tenemos que enviar un mensaje de la siguiente forma:

[authorization_identity] UTF8NUL authentication_identity UTF8NUL passwd

Como se especifica en el estándar no enviaremos el campo authorization_identity ("el cliente no provee una identidad de autorización [authorization identity] cuando quiere que el servidor derive una identidad de las credenciales proporcionadas"). De forma que nuestro mensaje queda:

\x00user\x00passwd

Pero antes, de poder enviarlo es necesario saber que tiene ir codificado en Base64.

#Continuando con el código de Ruby
autenticacion = "\x00" + "user" + "\x00" + "passwd"
autenticacion = Base64.encode64(autenticacion)
ssl.puts "auth plain" + autenticacion
S: 235 Accept

# Y ya que estamos adentro, ¿por qué no enviarnos un correo?
ssl.puts "mail from:<user@gmail.com>"
ssl.puts "rcpt to:<user@gmail.com>"
ssl.puts "data"
ssl.puts "From: <user@gmail.com>
To:<user@gmail.com>
Subject: Hola Mundo
Hola Mundo desde Ruby!"
ssl.puts "\r\n.\r\n"
ssl.puts "quit"

Referencias

[RFC 2821] Simple Mail Transfer Protocol, Abril 2001
[RFC 4409] Message Submission for Mail, Abril 2006
[RFC 2487] Secure SMTP over TLS, Enero 1999
[RFC 4422] Simple Authentication and Security Layer, Junio 2006
[RFC 4752] The Kerberos V5 (GSSAPI), SASL Mechanism, Noviembre 2006
[RFC 4616] The PLAIN SASL Mechanism, Agosto 2006

Advertencia

Antes de empezar a poner letras ... y más letras en este blog, he de hacer una pequeña ADVERTENCIA.

Puede que en algún momento que este en trance escriba sobre el "underground", así que, mi estimado lector si tu perteneces a algún grupo de este Universo y te ofenden mis comentarios, siente la completa libertad de apretar las maravillosas teclas Ctrl+W, Ctrl +C, Alt+F4 (o la combinación que aplique para tu browser) . O bien, si tienes un argumento lógico y racional ---> puedes intentar convencerme de que estoy equivocado.
¿Por qué esta advertencia?, porque no pertenezco a ese gran, fenomenal y maravilloso Universo y realmente no me gustaria ofender a alguien que sí forma parte de él. =D

$ sed -e "s/\(.\)\(.\)/\2\1/g" | tr [az] [za]

oLz tnreoi rztbmei npzilzcz c zuqliure zuq eess eitn zfoneidodp rom sic moneztirso ,lcrz,os iseq eup eued selree ts.o