Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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.

[1] - http://php.net/manual/en/function.mail.php


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.


Opening a socket to a local MTA and dumping a message to it wouldn't take any longer than shelling out to a local sendmail and writing to its stdin.


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.


You're right. I retract the documentation comment.


> In those cases, it really isn't a good idea to send mail in-process anyway due to web-process and SMTP timeouts

Why is sending a message to something like RabbitMQ less likely to timeout then to postfix?


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


exim and sendmail have synchronous options


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.


On most shared hosts, it blocks. The action taken by mail() is dependent upon your php.ini settings.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: