Skip to content

Commit 568df31

Browse files
committed
Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3: Fix #80710: imap_mail_compose() header injection
2 parents 2b33462 + 37962c6 commit 568df31

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

ext/imap/php_imap.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3551,6 +3551,23 @@ PHP_FUNCTION(imap_fetch_overview)
35513551
}
35523552
/* }}} */
35533553

3554+
static zend_bool header_injection(zend_string *str, zend_bool adrlist)
3555+
{
3556+
char *p = ZSTR_VAL(str);
3557+
3558+
while ((p = strpbrk(p, "\r\n")) != NULL) {
3559+
if (!(p[0] == '\r' && p[1] == '\n')
3560+
/* adrlists do not support folding, but swallow trailing line breaks */
3561+
&& !((adrlist && p[1] == '\0')
3562+
/* other headers support folding */
3563+
|| !adrlist && (p[1] == ' ' || p[1] == '\t'))) {
3564+
return 1;
3565+
}
3566+
p++;
3567+
}
3568+
return 0;
3569+
}
3570+
35543571
/* {{{ proto string imap_mail_compose(array envelope, array body)
35553572
Create a MIME message based on given envelope and body sections */
35563573
PHP_FUNCTION(imap_mail_compose)
@@ -3571,6 +3588,13 @@ PHP_FUNCTION(imap_mail_compose)
35713588
return;
35723589
}
35733590

3591+
#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \
3592+
if (header_injection(zstr, adrlist)) { \
3593+
php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \
3594+
RETVAL_FALSE; \
3595+
goto done; \
3596+
}
3597+
35743598
#define PHP_RFC822_PARSE_ADRLIST(target, value) \
35753599
str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \
35763600
rfc822_parse_adrlist(target, str_copy, "NO HOST"); \
@@ -3579,46 +3603,57 @@ PHP_FUNCTION(imap_mail_compose)
35793603
env = mail_newenvelope();
35803604
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) {
35813605
convert_to_string_ex(pvalue);
3606+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail");
35823607
env->remail = cpystr(Z_STRVAL_P(pvalue));
35833608
}
35843609
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) {
35853610
convert_to_string_ex(pvalue);
3611+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path");
35863612
PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue);
35873613
}
35883614
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) {
35893615
convert_to_string_ex(pvalue);
3616+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date");
35903617
env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue));
35913618
}
35923619
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) {
35933620
convert_to_string_ex(pvalue);
3621+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from");
35943622
PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue);
35953623
}
35963624
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) {
35973625
convert_to_string_ex(pvalue);
3626+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to");
35983627
PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue);
35993628
}
36003629
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) {
36013630
convert_to_string_ex(pvalue);
3631+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to");
36023632
env->in_reply_to = cpystr(Z_STRVAL_P(pvalue));
36033633
}
36043634
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) {
36053635
convert_to_string_ex(pvalue);
3636+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject");
36063637
env->subject = cpystr(Z_STRVAL_P(pvalue));
36073638
}
36083639
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) {
36093640
convert_to_string_ex(pvalue);
3641+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to");
36103642
PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue);
36113643
}
36123644
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) {
36133645
convert_to_string_ex(pvalue);
3646+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc");
36143647
PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue);
36153648
}
36163649
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) {
36173650
convert_to_string_ex(pvalue);
3651+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc");
36183652
PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue);
36193653
}
36203654
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) {
36213655
convert_to_string_ex(pvalue);
3656+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id");
36223657
env->message_id=cpystr(Z_STRVAL_P(pvalue));
36233658
}
36243659

@@ -3629,6 +3664,7 @@ PHP_FUNCTION(imap_mail_compose)
36293664
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) {
36303665
custom_headers_param = mail_newbody_parameter();
36313666
convert_to_string_ex(env_data);
3667+
CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers");
36323668
custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1);
36333669
custom_headers_param->attribute = NULL;
36343670
memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1);
@@ -3667,6 +3703,7 @@ PHP_FUNCTION(imap_mail_compose)
36673703
}
36683704
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
36693705
convert_to_string_ex(pvalue);
3706+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset");
36703707
tmp_param = mail_newbody_parameter();
36713708
tmp_param->value = cpystr(Z_STRVAL_P(pvalue));
36723709
tmp_param->attribute = cpystr("CHARSET");
@@ -3679,9 +3716,11 @@ PHP_FUNCTION(imap_mail_compose)
36793716
SEPARATE_ARRAY(pvalue);
36803717
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
36813718
if (key == NULL) continue;
3719+
CHECK_HEADER_INJECTION(key, 0, "body disposition key");
36823720
disp_param = mail_newbody_parameter();
36833721
disp_param->attribute = cpystr(ZSTR_VAL(key));
36843722
convert_to_string_ex(disp_data);
3723+
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value");
36853724
disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
36863725
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
36873726
disp_param->next = tmp_param;
@@ -3692,18 +3731,22 @@ PHP_FUNCTION(imap_mail_compose)
36923731
}
36933732
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
36943733
convert_to_string_ex(pvalue);
3734+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype");
36953735
bod->subtype = cpystr(Z_STRVAL_P(pvalue));
36963736
}
36973737
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
36983738
convert_to_string_ex(pvalue);
3739+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id");
36993740
bod->id = cpystr(Z_STRVAL_P(pvalue));
37003741
}
37013742
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
37023743
convert_to_string_ex(pvalue);
3744+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description");
37033745
bod->description = cpystr(Z_STRVAL_P(pvalue));
37043746
}
37053747
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
37063748
convert_to_string_ex(pvalue);
3749+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type");
37073750
bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
37083751
memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
37093752
}
@@ -3713,9 +3756,11 @@ PHP_FUNCTION(imap_mail_compose)
37133756
SEPARATE_ARRAY(pvalue);
37143757
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
37153758
if (key == NULL) continue;
3759+
CHECK_HEADER_INJECTION(key, 0, "body type.parameters key");
37163760
disp_param = mail_newbody_parameter();
37173761
disp_param->attribute = cpystr(ZSTR_VAL(key));
37183762
convert_to_string_ex(disp_data);
3763+
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value");
37193764
disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
37203765
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
37213766
disp_param->next = tmp_param;
@@ -3746,6 +3791,7 @@ PHP_FUNCTION(imap_mail_compose)
37463791
}
37473792
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
37483793
convert_to_string_ex(pvalue);
3794+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5");
37493795
bod->md5 = cpystr(Z_STRVAL_P(pvalue));
37503796
}
37513797
} else if (Z_TYPE_P(data) == IS_ARRAY && topbod->type == TYPEMULTIPART) {
@@ -3778,6 +3824,7 @@ PHP_FUNCTION(imap_mail_compose)
37783824
}
37793825
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
37803826
convert_to_string_ex(pvalue);
3827+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset");
37813828
tmp_param = mail_newbody_parameter();
37823829
tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
37833830
memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
@@ -3791,9 +3838,11 @@ PHP_FUNCTION(imap_mail_compose)
37913838
SEPARATE_ARRAY(pvalue);
37923839
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
37933840
if (key == NULL) continue;
3841+
CHECK_HEADER_INJECTION(key, 0, "body type.parameters key");
37943842
disp_param = mail_newbody_parameter();
37953843
disp_param->attribute = cpystr(ZSTR_VAL(key));
37963844
convert_to_string_ex(disp_data);
3845+
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value");
37973846
disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1);
37983847
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
37993848
disp_param->next = tmp_param;
@@ -3804,18 +3853,22 @@ PHP_FUNCTION(imap_mail_compose)
38043853
}
38053854
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
38063855
convert_to_string_ex(pvalue);
3856+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype");
38073857
bod->subtype = cpystr(Z_STRVAL_P(pvalue));
38083858
}
38093859
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
38103860
convert_to_string_ex(pvalue);
3861+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id");
38113862
bod->id = cpystr(Z_STRVAL_P(pvalue));
38123863
}
38133864
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
38143865
convert_to_string_ex(pvalue);
3866+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description");
38153867
bod->description = cpystr(Z_STRVAL_P(pvalue));
38163868
}
38173869
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
38183870
convert_to_string_ex(pvalue);
3871+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type");
38193872
bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
38203873
memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
38213874
}
@@ -3825,9 +3878,11 @@ PHP_FUNCTION(imap_mail_compose)
38253878
SEPARATE_ARRAY(pvalue);
38263879
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
38273880
if (key == NULL) continue;
3881+
CHECK_HEADER_INJECTION(key, 0, "body disposition key");
38283882
disp_param = mail_newbody_parameter();
38293883
disp_param->attribute = cpystr(ZSTR_VAL(key));
38303884
convert_to_string_ex(disp_data);
3885+
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value");
38313886
disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
38323887
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
38333888
disp_param->next = tmp_param;
@@ -3858,6 +3913,7 @@ PHP_FUNCTION(imap_mail_compose)
38583913
}
38593914
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
38603915
convert_to_string_ex(pvalue);
3916+
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5");
38613917
bod->md5 = cpystr(Z_STRVAL_P(pvalue));
38623918
}
38633919
}

ext/imap/tests/bug80710_1.phpt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("imap")) die("skip imap extension not available");
6+
?>
7+
--FILE--
8+
<?php
9+
$envelope["from"]= "joe@example.com\n From : X-INJECTED";
10+
$envelope["to"] = "foo@example.com\nFrom: X-INJECTED";
11+
$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED";
12+
$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED";
13+
$envelope["x-remail"] = "bar@example.com\nFrom: X-INJECTED";
14+
$envelope["something"] = "bar@example.com\nFrom: X-INJECTED";
15+
16+
$part1["type"] = TYPEMULTIPART;
17+
$part1["subtype"] = "mixed";
18+
19+
$part2["type"] = TYPEAPPLICATION;
20+
$part2["encoding"] = ENCBINARY;
21+
$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED";
22+
$part2["description"] = "some file\nContent-Type: X-INJECTED";
23+
$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED";
24+
25+
$part3["type"] = TYPETEXT;
26+
$part3["subtype"] = "plain";
27+
$part3["description"] = "description3";
28+
$part3["contents.data"] = "contents.data3\n\n\n\t";
29+
30+
$body[1] = $part1;
31+
$body[2] = $part2;
32+
$body[3] = $part3;
33+
34+
echo imap_mail_compose($envelope, $body);
35+
?>
36+
--EXPECTF--
37+
Warning: imap_mail_compose(): header injection attempt in from in %s on line %d

ext/imap/tests/bug80710_2.phpt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
Bug #80710 (imap_mail_compose() header injection) - Remail
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("imap")) die("skip imap extension not available");
6+
?>
7+
--FILE--
8+
<?php
9+
$envelope["from"]= "joe@example.com\n From : X-INJECTED";
10+
$envelope["to"] = "foo@example.com\nFrom: X-INJECTED";
11+
$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED";
12+
$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED";
13+
$envelope["remail"] = "X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM"; //<--- Injected as first hdr
14+
$envelope["something"] = "bar@example.com\nFrom: X-INJECTED";
15+
16+
$part1["type"] = TYPEMULTIPART;
17+
$part1["subtype"] = "mixed";
18+
19+
$part2["type"] = TYPEAPPLICATION;
20+
$part2["encoding"] = ENCBINARY;
21+
$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED";
22+
$part2["description"] = "some file\nContent-Type: X-INJECTED";
23+
$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED";
24+
25+
$part3["type"] = TYPETEXT;
26+
$part3["subtype"] = "plain";
27+
$part3["description"] = "description3";
28+
$part3["contents.data"] = "contents.data3\n\n\n\t";
29+
30+
$body[1] = $part1;
31+
$body[2] = $part2;
32+
$body[3] = $part3;
33+
34+
echo imap_mail_compose($envelope, $body);
35+
?>
36+
--EXPECTF--
37+
Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d

0 commit comments

Comments
 (0)