integer overflow in mutt_convert_string()
I noticed the routine mutt_convert_string()
is vulnerable to an integer overflow, but I think it is not exploitable on most platforms. I thought I would report it anyway to see what you think.
The function is used to decode MIME parameter values into the correct charset, using the syntax specified in RFC2231. An example parameter that needs to be converted would look like this:
Content-Disposition: attachment; filename*=us-ascii'en-us'file%20name%2etxt
This logic is used to allocate buffers and pass it to iconv()
to convert (simplified for clarity):
int len;
size_t ibl, obl;
len = strlen (s); // The attacker controlled MIME parameter
ibl = len + 1;
obl = MB_LEN_MAX * ibl;
ob = buf = safe_malloc (obl + 1);
mutt_iconv (cd, &ib, &ibl, &ob, &obl, inrepls, outrepl);
Here len
should clearly be size_t
, but I think through luck this logic is not exploitable.
We can sign extend a negative len
to a very large ibl
. If we could then make ibl
(2^64-1) / MB_LEN_MAX
, then the safe_malloc()
parameters will wrap, but MB_LEN_MAX
is 16 on Linux, and so it's not perfectly divisible. If MB_LEN_MAX
had been 15, this would have been exploitable, because (2^64-1) % 15
is 0.
That would have caused ob
to be a very small buffer, and obl
to be very large, allowing mutt_iconv()
to overflow the heap buffer with attacker controlled data.
We can make obl
really big and make malloc()
fail, causing mutt to terminate. This doesn't seem very useful to an attacker though, other than a minor DoS.
You might be ask whether integer wrapping is really relevant for mutt, because it seems implausible that an attacker can send gigabyte-scale messages. This is actually trivially possible because application/pgp-encrypted
parts can be compressed.
For example, we can create a very small PGP message that contains gigabytes of data:
$ perl -e 'print "A"x(512 * 1024 * 1024)' | gpg --compress-algo bzip2 --store --armor
-----BEGIN PGP MESSAGE-----
owNCWmg2MUFZJlNZwwAuWgOq4nclwAABBCAAIABAABAAAEAACAACAAggAHBANNNA
UqgwmmcKoK10lIk4BVBWuKoK7jxVJSJMeZ+xv6VBXNpFUFfmKCskymsoySxtgBbw
xIAwAIQAAABAAQQACgzTQKSmmFUFdAqgrpUFam8RSkScqgrFFUFfMUFZJlNZhE5M
NQBp6CQBgAQgAAACAAggAHAzTQTUppqBVHFCUl2qJSKtBVHlURKS4FUYlBVHzFBW
SZTWSyffJwA9w0kAYAEIAAAAgAIIABQZpoFJTTCqCugVQV0qCtTeIpSJOVQViiqC
vmKCskyms0bozpIBRLJIAwAIQAAABAAQQACgzTQKSmmFUFdAqgrpUFam8RSkScqg
rFFUFfMUFZJlNZ03C3qABUuaQBgAQgAAACAAggAHAzTQTUppqBVHFCUl2qJSKtBV
HlURKS4FUYlBVHzFBWSZTWcCdr6EA4eAkAYAEIAAAAgAIIABQZpoFJTTCqCugVQV
0qCtTeIpSJOVQViiqCvmKCskymszsZ4rgBGlhIAwAIQAAABAAQQACgzTQKSmmFUF
dAqgrpUFam8RSkScqgrFFUFfMUFZJlNZoFOiDwA/iyQBgAQgAAACAAggAHAzTQTU
ppqBVHFCUl2qJSKtBVHlURKS4FUYlBVHzFBWSZTWYa/skAAzLMkAYAEIAAAAgAII
ABQZpoFJTTCqCugVQV0qCtTeIpSJOVQViiqCvmKCskymsmMLM6IA7/5IAwAIQAAA
BAAQQACgzTQKSmmFUFdAqgrpUFam8RSkScqgrFFUFfMUFZJlNZr47YcgAqXKQBgA
QgAAACAAggAHAzTQTUppqBVHFCUl2qJSKtBVHlURKS4FUYlBVHzFBWSZTWUZJY2w
At4YkAYAEIAAAAgAIIABQZpoFJTTCqCugVQV0qCtTeIpSJOVQViiqCvmKCskymsw
icmGoA09BIAwAIQAAABAAQQADgZpoJqU01AqjihKS7VEpFWgqjyqIlJcCqMSgqj5
igrJMprJZPvk4Ae4aSAMACEAAAAQAEEAAoM00CkpphVBXQKoK6VBWpvEUpEnKoKx
RVBXzFBWSZTWaN0Z0kAolkkAYAEIAAAAgAIIABQZpoFJTTCqCugVQV0qCtTeIpSJ
OVQViiqCvmKCskyms6bhb1AAqXNIAwAIQAAABAAQQADgZpoJqU01AqjihKS7VEpF
WgqjyqIlJcCqMSgqj5igrJMprOBO19CAcPASAMACEAAAAQAEEAAoM00CkpphVBXQ
KoK6VBWpvEUpEnKoKxRVBXzFBWSZTWVfLjr0AE53kAZEAAAQgAAACAAggAFBgAmq
U9NTdwgjeQQPYUBOQj1UqKLkIyqIR+LuSKcKEgPOLcuA
=Q40j
-----END PGP MESSAGE-----
Here 500MB of data is compressed to just a short PGP message. If we create the relevant x-action
parameters, mutt will automatically try to decrypt this, allowing us to send very small messages that can hit integer overflows.
Here is a sample mail that will cause mutt to automatically decrypt gigabytes of data.
From taviso Thu Mar 31 16:53:55 2022
From: mutt@test.test
Subject: Very Large Message
Content-Type: multipart/encrypted; protocol=application/pgp-encrypted; boundary=hello
--hello
Content-Disposition: inline
Content-Type: text/plain; action=pgp-encrypt
-----BEGIN PGP MESSAGE-----
[copy data from above]
-----END PGP MESSAGE-----
I guess if you wanted to mitigate this, you could add max-output 104857600
or similar to your ~/.gnupg/gpg.conf
. This prevents a trivial DoS, and likely makes integer wrap issues unexploitable in practice.