
PHPMailer Exploit – Remote Code Execution - dawid_golunski
https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10045-Vuln-Patch-Bypass.html
======
Sanddancer
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
As 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
It'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.

~~~
Sanddancer
I'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.

------
jstewartmobile
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.

~~~
randomdrake
_> 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](http://php.net/manual/en/function.mail.php)

~~~
79d697i6fdif
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.

~~~
tyingq
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.

~~~
kstrauser
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.

~~~
tyingq
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.

------
wila
Claiming it is a responsible disclosure, because of a post at a forum
somewhere does not make it responsible.

Edit: I should probably clarify that it is the 1 day timeline over Christmas
that I think is irresponsible.

------
shimon_e
It's not been patched yet.

Edit: Seems like another exploit found 8 hours ago:
[https://github.com/PHPMailer/PHPMailer/issues/924](https://github.com/PHPMailer/PHPMailer/issues/924)

Probably wise to disable phpmailer on your servers for now.

------
kogepathic
Out of curiosity, why is PHPMailer invoking the command line at all?

It would seem much safer to establish a TCP connection to the local MTA over
port 25 or 587 and send the message that way.

Admins can just use iptables to restrict access to the port to localhost,
and/or do the same in their MTA config.

~~~
0x0
It's using PHP's builtin mail() function, which happens to be a wrapper around
/usr/bin/sendmail, and one of the parameters it takes is used as an
"additional command-line parameter to sendmail". In particular, the "-f"
switch is used to set the SMTP envelope MAIL FROM address. Apparently PHP's
mail() tries to do some automagic shell escaping on the argument but it's
likely not good enough and it also creates a conflict when callers such as
PHPMailer also try to escape the parameter.

~~~
r1ch
Software should never be using -f with user emails, regardless if it's
sanitized or not. -f sets the return path, which will trigger DMARC protection
if the domain doesn't allow it. For example, the yahoo.com policy will reject
all mail if you try to set the return path to the user's yahoo.com address
using -f.

The best way I've found to send mail on behalf of someone else is to leave the
return path (-f) and From header pointing to your own domain, and use the
Reply-To header with the users email.

------
SnaKeZ
[https://github.com/PHPMailer/PHPMailer/wiki/About-the-
CVE-20...](https://github.com/PHPMailer/PHPMailer/wiki/About-the-
CVE-2016-10033-and-CVE-2016-10045-vulnerabilities)

PHPMailer 5.2.21 is out!

------
rompic
PHPMailer is also used by wordpress:
[https://www.wordfence.com/blog/2016/12/phpmailer-
vulnerabili...](https://www.wordfence.com/blog/2016/12/phpmailer-
vulnerability/)

~~~
koheripbal
It's times like this I'm glad I have a country block setup through ipdeny.
Reducing the likelihood of attack by two orders of magnitude is a big help
until there's a patch.

~~~
diegoperini
No it is unfortunately not if there exists at least one company that provides
a VPN service from your country. :)

~~~
koheripbal
You don't think there's any value in reducing penetration attempts by 2-3
orders of magnitude? I went from seeing an attack every few seconds to one per
day/week.

~~~
nkkollaw
How do you monitor attacks?

------
0x0
The advisory says exploitation is not limited to just systems running the
original Sendmail MTA, but Postfix' "sendmail" wrapper apparently ignores the
"-X" parameter... so how can a Postfix-based system be exploited?

~~~
tyingq
I believe it's because the exploit isn't actually exploiting sendmail, it's
expoiting /bin/sh sh -c <cmd>.

Php's implementation of popen() doesn't invoke commands directly with stdlib's
execl() or execle()...it calls stdlib's popen(), which passes it through
/bin/sh -c <cmd>.

That's assuming phpmailer doesn't treat a postfix sendmail wrapper differently
than sendmail.

Edit: As far as I can tell, php doesn't allow any way to spawn a process
without passing it to /bin/sh. That's odd, as other script languages like Perl
and Python provide that. It avoids a whole class of exploits.

Edit2: It seems to be exploiting the "-f" option, not "-X". The postfix
wrapper supports that.

~~~
thaumaturgy
It's exploiting -f to abuse -X to allow it to save a file with PHP tags to an
externally-accessible location. Without -X or some similar capability, it's
not exploitable. Well, it is, but not for the same amount of fun -- all you
get to do is abuse whatever other arguments Postfix makes available to you.

I don't see a whole lot that a non-root user calling Postfix's version of
sendmail can do with this ... maybe get a mail server RBL'd.

~~~
tyingq
Ah, yes, you're right. Maybe the option to use an alternate alias database
could be troublesome, but would require some other hole that allowed local
file creation.

------
jexyru
This discussion is broken by design. Using user input from contact form as
"From" address for emails, sent from your site, is the mistake of your
application - you should use something like "noreply@yoursite.com", why you
put user email there? In addition - most probably such emails will not pass
spam filters.

~~~
prab97
You would probably want to respond to the user, and it is possible only if
they give you their email in the form. Although, this can be solved by
treating the From field in the mail form as just a field of information and
have that in the body of email. But that would make automated replies
difficult.

~~~
manquer
you could use reply-to header instead of from, being another additional header
i guess it has the same problem.

------
ec109685
Isn't this really a vulnerability of php's mail() function (or at least
evidence of bad design). It shouldn't let itself call a shell command with
arguments unescaped.

~~~
tyingq
It appears that it does escape shell commands. The issue is that PHPMailer had
already escaped them. The exploit is exploiting the "double escape".

The real issue to me is that unlike Perl and Python, PHP doesn't provide a way
to spawn a process without invoking /bin/sh. If PHP had support for the
various incantations of exec(), you could pass arguments without needing the
shell.

------
Sephr
I wonder if WordPress SMTP plugins¹ that override normal mail functions
provide any protection from this vulnerability.

[1]: Such as [https://wordpress.org/plugins/wp-mail-
smtp/](https://wordpress.org/plugins/wp-mail-smtp/)

~~~
Piskvorrr
Yes. This is only exploitable if you're using `mail()` to invoke the local
MTA; if you're talking to a SMTP host, this exploit has nothing to work with.

------
disposablezero
My brain instinctively did s/PHP/CVE/, hope it's right.

------
dremos
....

------
annnnd
TL;DR: PHPmailer fails to properly sanitize input. When configured to use CLI
sendmail, this can lead to arbitrary command execution.

But then again, why would you send e-mail to just any address someone enters,
without validating it for correctness? I know it is tough to validate all
addresses according to RFC, but I'd rather block some legitimate users (which
btw. probably know more about RFC than me and I'm sure can find a "nicer"
e-mail address if they want to) than let some attacker use some vulnerability
like this. Always whitelist valid input, never (just) blacklist it.

Also, I am baffled that frameworks I encountered never demanded from developer
to specify _exactly_ what kind of input it expects via POST & co.. It is
trivial to write a set of functions like this:

    
    
        function input_post_email($field_name, $default_value)
        function input_post_string($field_name, $validation_regex, $default_value)
        ...
    

The point here is that framework should _DEMAND_ from developer to specify
format of each and every input var it needs. It should be difficult to bypass
these restrictions, to demotivate developers doing it.

This is a first thing I made in every PHP project I started. Combined with
Content Security Policy and output filtering it's... well, better than most
other solutions. :)

~~~
thaumaturgy
Misguided developers incorrectly "validating" email addresses is the reason
that one of my clients couldn't use one of the newer TLDs, ".place", and ended
up scrapping it and trying to find something they wanted a lot less in the
much more crowded .com space.

It's also why I far-too-often run into forms that won't let me use a "+" in
the username part of my email address, which I use to track who's responsible
for sending my email account off to third parties (e.g., "rob+paypal@....").

Some kinds of email validation are better than others. Using regular
expressions and strictly adhering to the RFC is the one that developers are
usually talking about when they say not to do it. filter_var(...,
FILTER_VALIDATE_EMAIL) is sort of okay, although there are lots of edge cases
that it doesn't handle correctly.

~~~
annnnd
Genuinly curious: does '+' trick work? I would imagine any infringing parties
would learn to remove plus sign and all after it before selling the database
of addresses by now...

Other than that: true, I hate incorrect validation. But I hate sloppy security
practices even more.

~~~
thaumaturgy
Not as much as it used to. You're right, they've caught on to it. I need to
stand up another mail server pretty soon, I want to try making it easy to
generate random recipient aliases, so e.g. qti3XZ@mydomain.com is an alias for
rob+someservice@mydomain.com and gdUTgp@mydomain.com is an alias for
rob+otherservice@mydomain.com. That oughtta stump 'em for a while.

------
cdevs
We're jerks and just strip everything down to a-Z space .- and @ _ anything
beyond that f u, extensions and 3rd party library or even core filters come
out with these vulnerabilities all the time, at least we will know for sure
what characters were passed in from the start though I'm sure most business
NEED to support every wacky combination but I'll take the complaint over the
hack any day.

~~~
hartz
So you are one of those sites that reject email addresses with "+" in it?

