Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email content tampering vulnerability due to crafted file names #1590

Open
motoyasu-saburi opened this issue Oct 18, 2023 · 0 comments
Open

Comments

@motoyasu-saburi
Copy link

I have been trying to contact them for several months in several ways, but have not been able to get in touch with them successfully. Therefore, I am reporting here.


Vulnerability summary

mikel/mail has a problem with lack "filename" escaping in the Attachment File when sending an Email.
This allows "CRLF Injection within a multipart/mixed > part > header" and "file name/extension tampering".

Essentially, the following characters must be escaped when generating Content-Disposition headers in multipart/mixed

  • \r --> \\r or %0D
  • \n --> \\n or %0A
  • " --> \" or %22 (Not Escaped)

These are also defined as requirements in RFCs and HTTP Requests for Multipart/form-data (What's WG - HTML Spec) where Content-Disposition is used.

RFC 6266:
https://tools.ietf.org/html/rfc6266#appendix-D

Avoid including the "" character in the quoted-string form of the filename parameter, as escaping is not implemented by some user agents, and "" can be considered an illegal path character.

What's WG HTML Spec:
https://html.spec.whatwg.org/#multipart-form-data

For field names and filenames for file fields, the result of the encoding in the previous bullet point must be escaped by replacing any 0x0A (LF) bytes with the byte sequence %0A, 0x0D (CR) with %0D and 0x22 (") with %22. The user agent must not perform any other escapes.

As an example, I describe the normal case and the case where a crafted file is processed.


normal case:
Input Filename:

example.txt

Output Content-Disposition:

Content-Disposition: attachment; filename="example.txt"

Crafted file case:
Input Filename:

a.sh";\r\n\r\ndummy.txt

Output Content-Disposition:

Content-Disposition: attachment; filename="a.sh";

ndummy.txt"

Attack Scenario

if " is not escaped, additional fields can be added,
so that filenames can be tampered with,
Content-Disposition size, modification-date, etc fields can be inserted, and so on.

I think there are two main cases of abuse.

  1. Cases where integrity is destroyed by rewriting emails sent by the victim by file name.
  2. Cases that pass validation such as file extension at the time of upload and are converted
    to malware (extension is changed) at the time of email transmission

(1)
This case requires "strong" involvement of the victim, which I believe is a problem that is quite difficult to exploit.

The condition of the attack is that the filename of the attachment
in the e-mail sent by the victim must be set to the string entered by the attacker.

However, since it is up to the system implementer to decide how to use this package and how to send the mail, we do not believe that it is absolutely certain.

(2)
I believe this is the more likely case.

For example, let's say you have a system that uses this package behind a system such as ChatBot that receives customer communications and transfers files.

Since it is unlikely that customers will always send the correct file, file extension validation should be performed at the time of file upload, and those with no problems should be forwarded via email.

However, if this vulnerability exists, it is possible to rewrite
the File Extension to .txt when uploading and .sh when sending mail.

Remediation

As far as I have been able to find, the following services are escaping by \.

example code:

def escapeContentDispositionFilename(filename: String): String = {
  return filename.replaceAll("\r", "\\r")
                 .replaceAll("\n", "\\n")
                 .replaceAll("\"", "\\\"")
}

example response:


> Before
> Content-Disposition: attachment; filename="malicious.sh";\r\ndummy=.txt

> After
> Content-Disposition: attachment; filename="\"malicious.sh\";\\r\\ndummy=.txt"

Also, eliminating CLRF or Double-Quote characters blocking them with Validation can be effective.

Reference

Golang Impliments (safe code)
https://github.com/golang/go/blob/e0e0c8fe9881bbbfe689ad94ca5dddbb252e4233/src/mime/multipart/writer.go#L144

PoC

PoC Environment

OS: macOS Monterey(12.3)
Ruby ver: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21]
mail ver: v2.8.0


  1. install package
$ gem install mail
  1. Generate PoC Code & PoC Dummy File

create dummy file

$ touch dummy_file.txt

create code & edit file path line.

require 'mail'

mail = Mail.new do
  from     '[email protected]'
  to       '[email protected]'
  subject  'Here is the image you wanted'
  add_file :filename => "malicious.sh\"; dummy=\"abc.txt", :content => File.read('./dummy_file.txt')
end

puts mail.to_s
  1. Run
$ ruby main.rb

Output:

Date: Tue, 20 Dec 2022 21:23:14 +0900
From: [email protected]
To: [email protected]
Message-ID: <[email protected]>
Subject: Here is the image you wanted
Mime-Version: 1.0
Content-Type: multipart/mixed;
 boundary="--==_mimepart_63a1a93216419_a649294-4cd"
Content-Transfer-Encoding: 7bit


----==_mimepart_63a1a93216419_a649294-4cd
Content-Type: text/plain;
 charset=UTF-8;
 dummy=abc.txt;
 filename=malicious.sh
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 dummy=abc.txt;
 filename=malicious.sh

abc

----==_mimepart_63a1a93216419_a649294-4cd--

Expected Content-Disposition:

Content-Disposition: attachment; filename="malicious.sh\"; dummy=\"abc.txt"

Actual Content-Disposition

Content-Disposition: attachment;
 dummy=abc.txt;
 filename=malicious.sh

Reference:

Relate RFC:
https://datatracker.ietf.org/doc/html/rfc2231
https://datatracker.ietf.org/doc/html/rfc2616
https://datatracker.ietf.org/doc/html/rfc5987
https://datatracker.ietf.org/doc/html/rfc6266
https://datatracker.ietf.org/doc/html/rfc7578
https://datatracker.ietf.org/doc/html/rfc8187

WhatWG HTML Spec > multipart/form-data escape requirements:
https://html.spec.whatwg.org/#multipart-form-data

Golang Impliments:
https://github.com/golang/go/blob/561a5079057e3a660ab638e1ba957a96c4ff3fd1/src/mime/multipart/writer.go#L132-L136

Symphony (PHP Webframework) Impliments:
https://github.com/symfony/symfony/blob/123b1651c4a7e219ba59074441badfac65525efe/src/Symfony/Component/Mime/Header/ParameterizedHeader.php#L128-L133

Spring (Java Webframework) Impliments:
https://github.com/spring-projects/spring-framework/blob/4cc91e46b210b4e4e7ed182f93994511391b54ed/spring-web/src/main/java/org/springframework/http/ContentDisposition.java#L259-L267

Similar problem with another HTTP Client:

httparty: GHSA-5pq7-52mg-hr42
Playframework WS: playframework/playframework#11571
Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1556711
OWASP ASVS v5 > Content-Disposition escape disscussion:
OWASP/ASVS#1390

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant