python / python/cpython

CRLF Injection vulnerability in "email.mime.multipart" > "MIMEMultipart" > "add_header()"

Open
#100,612 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

topic-email type-bug type-security
Dominant language
Python
Stars
77.2k
Forks
36k
PR merge metrics
PR metrics pending

Description

Summary

I found CRLF Injection ( File Content Injection / (Potential) Tampering file extension ) Vulnerability in email.mime.multipart > class MIMEMultipart > add_header().

This problem is caused by the lack of escaping of "filename" in Multipart > Mail.
Normally, the following three characters are escaped

  • \r --> \\r
  • \n --> \\n
  • " --> \"
    However, the method in question does not escape \r\n
    ( " (double-quote) is escaped. " --> \" )

Therefore, if a crafted file name is inserted, CRLF Injection will occur in the Content-Disposition header of multipart body.

My calculated CVSS:
Score: 3.1 (Low)
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N


PoC:

OS: macOS Monterey (v12.6.1)
Python ver: v3.10.3
PoC Code:
(please edit filepath)

from email.mime.application import MIMEApplication
def main():
  filepath = "/Users/XXXXXXXXXX/Desktop/example.txt"
  # If \r\n (CRLF) is present, the file will fail to load (on mac OS).
  with open(filepath, "rb") as f:
    mb = MIMEApplication(f.read())
  disposition_filename = "malicious_test.sh\r\n.txt"
  # If \r\n (CRLF) is present, the contents of the file can be Injected.
  mb.add_header("Content-Disposition", "attachment", filename=disposition_filename)
  print(mb)
if __name__ == '__main__':
  main()

Output:

Content-Type: application/octet-stream
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="malicious_test.sh
.txt"
IyEvYmluL2Jhc2gKCmVjaG8gImhlbGxvIg==

Injected Line:

Content-Disposition: attachment; filename="malicious_test.sh
.txt"


Affect

This problem is very limited.
The reason for this is that if [ \r, \n ] are included when a file is opened, an Exception will be thrown.

with open(filepath, "rb") as f:

However, it is not always safe to do so, since the file name may be given by an external parameter, DB, etc.
In addition, data can be added to the header content within Multipart, allowing for a variety of attacks.

It may be possible to insert multiple Content-Dispositions, falsify the filename, or inject malicious shell code after making the file .sh .


Reference:

As far as I can tell, the following service systems escape [ \r \n " ] to [ \\r \\n \" ]


The Python PSRT team has agreed to published this information.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the email.mime.multipart MIMEMultipart.add_header() path and reproduce the provided PoC with a filename containing CRLF. Trace how the filename is serialized into the Content-Disposition header, then add regression coverage for the reported behavior; done means crafted CRLF cannot create additional header lines while existing MIME behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.