Per the writeup, it looks like they were already escaping their arguments, but they didn't know PHP's built-in mail() function was already doing that:
PHPMailer 5.2.17 sanitizes the $Sender variable
by applying escapeshellarg() escaping before the
value is passed to mail() function.
It does not however take into account the clashing
of the escapeshellarg() function with internal
escaping with escapeshellcmd() performed by mail()
function on the 5th parameter.
As a result it is possible to inject an extra quote
that does not get properly escaped and break out of
the escapeshellarg() protection applied by the patch
in PHPMailer 5.2.17.
In most cases, people are using PHP as a server-side language under a web server. In those cases, it really isn't a good idea to send mail in-process anyway due to web-process and SMTP timeouts. Queueing messages with something like Gearman or some other job handler would be a more secure and performant approach.
> It looks like better documentation could have prevented this bug.
Where?
Barring user-submitted comments, PHP has consistently had some of the most complete programming language documentation.
This exact issue is specifically documented with the mail() function[1] so I'm not sure you can blame PHP or ask for better documentation in this case:
"This parameter is escaped by escapeshellcmd() internally to prevent command execution. escapeshellcmd() prevents command execution, but allows to add additional parameters. For security reasons, it is recommended for the user to sanitize this parameter to avoid adding unwanted parameters to the shell command."
Escaping too many times or incorrectly is a pretty common error but it's normally of the PEBKAC variety.
Why is it possible to do command execution in a mailer at all??? Any reasonable language would have abstracted this into an SMTP library where such things are impossible instead of relying on sendmail.
Likely because PHP has to run things while the end user is waiting for a page to download. They rely on sendmail so that the mail can be queued, versus hanging while the email is sent. PHPmailer can be configured in the way you're describing, but it then has this issue.
That's true, but it doesn't typically work out of the box. Postfix on debian and ubuntu, for example, won't allow relay through localhost....unless it's sasl authenticated, which requires work.
So, yes, you can, but software like Wordpress includes a default configuration that works for most people without additional work...piping to /usr/bin/sendmail.
Job queue services have async modes where enqueueing the message returns immediately. Then the jobber can send the message under a more limited account, or even on a different machine in a different language without timeouts.
Last I checked, PHP's mail() function blocks until SMTP connect/auth/submit completes, and with things like SMTP tarpitting, or just ordinary slowness, that can take a very long time.
Sometimes, it takes more time than your server-side web process is alloted for execution, leading to your script being force-terminated prior to completion.
[in reply to skarap]
The action of mail() depends on the mail/sendmail settings in your php.ini, so the behavior could be blocking or non-blocking depending on which client is used and which parameters are passed.
Both postfix and qmail are inherently incapable of blocking their clients on communication with destination/upstream smarthost because of their architecture.
In both cases it works like this:
client: MAIL FROM
server checks whether it makes sense (outgoing smarthost has essentially nothing to check here)
SMTP server: 250 Ok
client: RCPT TO
server checks, again there is nothing expensive to check for smarthost case
SMTP server: 250 Ok
client: DATA ... .
server does its checks on the contents of message (again, nothing meaningful for smarthos), reformats it, adds Received and such and writes it out into queue
SMTP server: 250 Ok: queued
server wakes up the process that handles delivery by IPC and gives it queue ID of just created message
client probably disconnects now
outgoing SMTP daemon starts connecting to somewhere
I'm aware of that. My point is that when sending mail directly from web server process is too slow, correct solution is not building your own bug-ridden implementation of half of SMTP on top of some newfangled message queue, but simply configuring your outgoing mail server correctly.
When you only enqueue event such as "this happened, there should probably be an notification for that" and have some non-trivial application logic in the queue runner it starts to make sense. But queue runner of the kind for(;;) {msg = get_message(); smtp_send(message)} is complete nonsense.
By the way, I know of pretty significant line of bussiness system that has nothing to do with email except the fact that it uses smtp and postfix as it's message bus and the thing seems to just work without issue, for more than decade.
Never said to re-implement SMTP. Just stating that I've been on shared servers where PHP mail() blocks and had to job-out SMTP for responsiveness. If I've encountered it, I'm sure others have as well.
As for the jobber, it was using the same PHP mail() function, it's just that the jobber runs async and does not have a time limit imposed on it.
If you have control over your php.ini to where you can set agent parameters to be non-blocking, then yes, that would be ideal.
The default configuration for PHP (and I guess the most frequently used one) is using sendmail command. That command does just one thing - enqueue the message on the local server. It doesn't handle the delivery of the email.
That is also the case when using the mail server at 127.0.0.1 port 25.
One could have configured a remote SMTP server with authentication and that would be slow and would be affected by network issues, but same would happen with a remote RabbitMQ server.
Quite the contrary: most installs I've seen have a "remote" dedicated SMTP server which is actually on local network (not significantly slower than mail()), and does other useful stuff like DKIM and SPF (which, with appropriate setup, has the added bonus that rogue app-server emails don't just appear out of nowhere, and at the very minimum have to pass through this server, giving you a place to debug). Of course, if you're making My First Blog Server on a shared host, then all of this is moot.