Doc #78958 [Com]: FILTER_VALIDATE_EMAIL fails on a long email address

From: Date: Sat, 14 Dec 2019 15:45:43 +0000
Subject: Doc #78958 [Com]: FILTER_VALIDATE_EMAIL fails on a long email address
References: 1  Groups: php.doc.bugs 
Request: Send a blank email to doc-bugs+get-17121@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=78958&edit=1

 ID:                 78958
 Comment by:         drtechno at mail dot com
 Reported by:        kaulkwappe dot php-bugs at prvy dot eu
 Summary:            FILTER_VALIDATE_EMAIL fails on a long email address
 Status:             Open
 Type:               Documentation Problem
 Package:            Filter related
 Operating System:   Debian Buster 10.2
 PHP Version:        7.3.11
 Block user comment: N
 Private report:     N

 New Comment:

Keep in mind mail() has a critical flaw: a nested parameter. very bad practice, as the nested
parameter can be filled even though the program didn't use it. lets look at mail():
bool mail(	
	string $to, 
	string $subject,
	string $message [, 
	string $additional_headers [, 
	string $additional_parameters ]]
)
$additional_parameters is the weak code and the exploit in the MTA (mail transfer agent)...

When PHP is configured with the second option, calls to the mail() function will result in the
execution of the configured MTA program. Although PHP internally applies escapeshellcmd() to the
program call which prevents an injection of new shell commands, the 5th argument
$additional_parameters in mail() allows the addition of new program arguments to the MTA. Thus, an
attacker can append program flags which in some MTA’s enables the creation of a file with
user-controlled content.
vilnerable code:
mail("myfriend@example.com", "subject", "message", "",
"-f" . $_GET['from']);
The code shown above is prone to a remote command execution that is easily overlooked. The GET
parameter from is used unsanitized and allows an attacker to pass additional parameters to the mail
program. For example, in sendmail, the parameter -O can be used to reconfigure sendmail options and
the parameter -X specifies the location of a log file.
Proof of concept:
example@example.com -OQueueDirectory=/tmp -X/var/www/html/rce.php
The proof of concept will drop a PHP shell in the web directory of the application. This file
contains log information that can be tainted with PHP code. Thus, an attacker is able to execute
arbitrary PHP code on the web server when accessing the rce.php file.


Another intuitive approach is to use PHP’s email filter in order to ensure that only a valid
email address is used in the 5th parameter of mail().
filter_var($email, FILTER_VALIDATE_EMAIL)
However, not all characters that are necessary to exploit the security issue in mail() are forbidden
by this filter. It allows the usage of escaped whitespaces nested in double quotes. Due to the
nature of the underlying regular expression it is possible to overlap single and double quotes and
trick filter_var() into thinking we are inside of double quotes, although mail()s internal
escapeshellcmd() thinks we are not.
Toxic code:
'a."'\ -OQueueDirectory=\%0D<?=eval($_GET[c])?>\ -X/var/www/html/"@a.php
For the here given url-encoded input, the filter_var() function returns true and rates the payload
as a valid email address. This has a critical impact when using this function as a sole security
measure: Similar as in our original attack, our malicious "email address" would cause
sendmail to print the following error into our newly generated shell "@a.php in our webroot.

<?=eval($_GET[c])?>\/): No such file or directory

Remember that filter_var() is not appropriate to be used for user-input sanitization and was never
designed for such cases, as it is too loose regarding several characters.


Previous Comments:
------------------------------------------------------------------------
[2019-12-14 15:28:41] drtechno at mail dot com

CORRECTION:
FORGOT THAT UNDERSCORE, AND MINUS SIGN IS USED IN EMAILS


#define EMAIL_ADDR "@._-"

------------------------------------------------------------------------
[2019-12-14 15:21:26] drtechno at mail dot com

But I would do a #define EMAIL_ADDR "@." so that the function would look like:
#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="
#define EMAIL_ADDR "@."
void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT EMAIL_ADDR;
filter_map map;
filter_map_init(&map);
filter_map_update(&map, 1, allowed_list);
filter_map_apply(value, &map);
}

This file (sanitizing_filters.c),has a lot of extra space characters. They should be removed so
white space injection isn't a possibility....

------------------------------------------------------------------------
[2019-12-14 15:11:06] drtechno at mail dot com

looking at the source code:
#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="

void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{

	const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT
"!#$%&'*+-=?^_`{|}~@.[]";
	filter_map     map;

	filter_map_init(&map);
	filter_map_update(&map, 1, allowed_list);
	filter_map_apply(value, &map);
}

it appears to be not correct.... I would think it would be:

#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="

void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{
	/* Check section 6 of rfc 822 http://www.faqs.org/rfcs/rfc822.html */
	const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT "@.";
	filter_map     map;

	filter_map_init(&map);
	filter_map_update(&map, 1, allowed_list);
	filter_map_apply(value, &map);
}

------------------------------------------------------------------------
[2019-12-13 19:49:23] requinix@php.net

Maybe NAB is a bit too aggressive a reaction.

The thing with SMTP is that servers do whatever they want. The standards themselves even acknowledge
this in a few places. So while 64 octets is supposed to be the maximum, the actual emailing industry
will kinda just do whatever it wants.

Some documentation about exactly what rules PHP uses to validate emails (and maybe URLs too?) would
be nice. More than just a link to an RFC. A summary of the rules enforced.
But I think the real bug here is with PHP's listserv. exim, I believe.

------------------------------------------------------------------------
[2019-12-13 18:46:14] kaulkwappe dot php-bugs at prvy dot eu

I think a strict mode would make sense since developers may want to

a) prevent users from entering a new, not RFC valid email address, but
b) also prevent pseudo false positives from foreign email addresses.

E.g. when an user answers an email the system would check if the recipient email address you entered
is valid; however, the replying user cannot influence its RFC validness because it is an foreign
email address. Not RFC conform, but still valid. But the same user may not choose a RFC invalid
email address if he wants to create an email alias for himself.

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=78958


--
Edit this bug report at https://bugs.php.net/bug.php?id=78958&edit=1


Thread (8 messages)

« previous php.doc.bugs (#17121) next »