3 ms·
The root cause of this is that PHP's mail function is broken by design. Instead of parameterized values for everything, it passes the entirety of the "additiona
by Sanddancer 10y ago
The root cause of this is that PHP's mail function is broken by design. Instead of parameterized values for everything, it passes the entirety of the "additional" options, which includes the from address, as one string for the shell to parse. If the flags were pulled out to individual options to be passed to the command instead, it wouldn't be possible to exploit things in the way it does. So, instead of:
mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
it would be something like:
mail ( string $to , string $subject , string $message [string $additional_headers], [string $additional_parameter, string $parameter values ] )
With the result passed to sendmail via the underlying functions, not relying on the shell to separate options for you. Any sort of user-supplied data should be parameterized and treated differently than data you provide. We've mostly learned our lessons from SQL injection, the rest of the stack still has a problem.
- tyingq 10y agoAs far as I can tell, PHP doesn't have any way to spawn a subprocess without passing it to /bin/sh for evaluation. PHPMailer (not core php) apparently either calls php's popen(), which passes to the shell...or calls php's mail(), which uses popen(). There are other options in php, like proc_open(), but they also call /bin/sh. TLDR: There isn't any way in PHP to avoid "relying on the shell to separate options for you".
- ajsalminen 10y agoIt's possible with pcntl_fork() and pcntl_exec() but that's not compatible with apache's mod_php which is probably still pretty widely used even though it's getting replaced by php-fpm.
- tyingq 10y agoI believe many distributions disable pcntl_* functions even in a php-fpm environment. You can make it work, of course, but it's not the default.
- Sanddancer 10y agoI've read reports on the incompatibilities, but the odd part is that you can popen which, under FreeBSD at least, is a fairly thin wrapper around vfork() and execve() makes that feel suspect. It may be a bit more work, but commands like this still should be treated as special.