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

CVE-2019-17362 - vulnerability in der_decode_utf8_string #507

Closed
werew opened this issue Oct 3, 2019 · 3 comments
Closed

CVE-2019-17362 - vulnerability in der_decode_utf8_string #507

werew opened this issue Oct 3, 2019 · 3 comments

Comments

@werew
Copy link
Contributor

werew commented Oct 3, 2019

Description

The der_decode_utf8_string function (in der_decode_utf8_string.c) does not properly detect certain invalid UTF-8 sequences.
This allows context-dependent attackers to cause a denial of service (out-of-bounds read and crash) or read information from other memory locations via carefully crafted DER-encoded data.

Attack vectors

To exploit this vulnerability an attacker must be able to provide crafted DER-encoded data to LibTomCrypt (e.g. by importing a X509 certificate).
Information disclosure is made possible by a 2-steps attack where the imported data is later somehow re-encoded and sent to the attacker (e.g. import and then export X509 certificate).

Details

This vulnerability affects LibTomCrypt 1.18.2 and earlier versions.
For the remainder of this issue I will be referring to the code of LibTomCrypt last released version (i.e. version 1.18.2, https://www.libtom.net/news/LTC_1.18.2/).

The cause of the problem lies in the decoding-loop at line 71 of der_decode_utf8_string.c:

   /* proceed to decode */
   for (y = 0; x < inlen; ) {
      /* get first byte */
      tmp = in[x++];

      /* count number of bytes */
      for (z = 0; (tmp & 0x80) && (z <= 4); z++, tmp = (tmp << 1) & 0xFF);

      if (z > 4 || (x + (z - 1) > inlen)) {
         return CRYPT_INVALID_PACKET;
      }

      /* decode, grab upper bits */
      tmp >>= z;

      /* grab remaining bytes */
      if (z > 1) { --z; }
      while (z-- != 0) {
         if ((in[x] & 0xC0) != 0x80) {
            return CRYPT_INVALID_PACKET;
         }
         tmp = (tmp << 6) | ((wchar_t)in[x++] & 0x3F);
      }

      if (y < *outlen) {
         out[y] = tmp;
      }
      y++;
   }

Here the variable tmp contains the value of the first byte of the utf-8 encoded character.
In accordance to utf-8 encoding rules the number of most significant bits of tmp set at 1 (from left to right) prior to a 0, indicates the number of bytes used to encode the utf-8 character (i.e. a sequence starting by 110xxxxx indicates a size of 2 bytes) .

However notice that 10xxxxxx is not a valid 1st byte.
The loop in question fails to detect this case and process a sequence starting with 10xxxxxx as if it was a sequence of two bytes.

A valid utf-8 sequence of two bytes is of the form: 110xxxxx 10xxxxxx and can encode values up to 0x7FF. Yet der_decode_utf8_string accepts sequences of two bytes of the form: 10xxxxxx 10xxxxxx.
This invalid form offers an additional free bit and can therefore encode values up to 0xFFF, hence including a range of values that would normally be encodable only using a sequence of at least 3 bytes.

This behavior can be used to trick der_length_utf8_string into reporting a length bigger than the actual size of the encoded string.
This works because the function der_utf8_charsize returns a number of bytes based on the size of the decoded value.

To see an example of how this can be exploited to crash the program or read data after the DER-buffer, let us consider the function der_decode_sequence_flexi (used to decode X509 certificates).

When an utf-8 entry is encountered this function will first decode it in an array pointed by l->data and then compute the length using der_length_utf8_string on the decoded data:

         case 0x0C: /* UTF8 */

            /* init field */
            l->type = LTC_ASN1_UTF8_STRING;
            l->size = len;

            if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
               err = CRYPT_MEM;
               goto error;
            }

            if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
               goto error;
            }

            if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
               goto error;
            }
            break;

The computed lenis later used to move forward some pointers:

      /* advance pointers */
      totlen  += len;
      in      += len;
      *inlen  -= len;

The variable inlen points to the size of the remaining number of bytes to decode.
Using the aforementioned bug it is possible to craft an input such that len > *inlen.
In this case *inlen will underflow resulting in a much bigger value than the actual size of user's input.

Finally, this can be used to crash the program (e.g. by reading invalid memory location) or to trick the DER-decoder into including adjacent data into the decoded sequence.

PoC

Following I include two profs of concept.

poc1 will likely cause a program to crash by triggering a read of 0xffffffff additional bytes (thus probably ending up in an invalid memory page).
poc2 will add 0xffff bytes of adjacent memory to the decoded sequence. This data can then be accessed, in a 2-steps attack scenario, by exporting the certificate.
Notice that poc2 will very likely NOT cause the program to crash since any invalid DER-type encountered after the leaked data will just cause the decoding to stop gracefully without causing any further error (line 436 of der_decode_sequence_flexi.c).

char *poc1 = "\x30\x04"                  // Start DER-sequence of length 4
             "\x0c\x02\xbf\xbf"          // Start UTF8 string of actual length 2 and evaluated length 3
             "\xaa"                      // One byte padding
             "\x30\x84\xff\xff\xff\xff"; // Start DER-sequence of length 0xffffffff (will very likely cause a crash)
char *poc2 = "\x30\x04"                 // Start DER-sequence of length 4
             "\x0c\x02\xbf\xbf"         // Start UTF8 string of actual length 2 and evaluated length 3
             "\xaa"                     // One byte padding
             "\x04\x82\xff\xff";        // Start OCTECT sequence of length 0xffff
                                        // (this will include the adjacent data into the decoded certificate)
sjaeckel added a commit that referenced this issue Oct 8, 2019
sjaeckel added a commit that referenced this issue Oct 8, 2019
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

[joakim bech: Extended commmit message]
Acked-by: Joakim Bech <[email protected]>
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

[Joakim Bech: Extended commmit message]
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

[Joakim Bech: Extended commmit message]
Signed-off-by: Luigi Coniglio <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

[Joakim Bech: Extended commmit message]
Signed-off-by: Luigi Coniglio <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jens Wiklander <[email protected]>
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

Signed-off-by: Luigi Coniglio <[email protected]>
[Joakim Bech: Extended commit message]
Signed-off-by: Joakim Bech <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jerome Forissier <[email protected]>
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

Signed-off-by: Luigi Coniglio <[email protected]>
[Joakim Bech: Extended commit message]
Signed-off-by: Joakim Bech <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jerome Forissier <[email protected]>
jforissier pushed a commit to OP-TEE/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

Signed-off-by: Luigi Coniglio <[email protected]>
[Joakim Bech: Extended commit message]
Signed-off-by: Joakim Bech <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jerome Forissier <[email protected]>
jbech-linaro pushed a commit to jbech-linaro/optee_os that referenced this issue Oct 8, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

Signed-off-by: Luigi Coniglio <[email protected]>
[Joakim Bech: Extended commit message]
Signed-off-by: Joakim Bech <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jerome Forissier <[email protected]>
jforissier pushed a commit to OP-TEE/optee_os that referenced this issue Oct 9, 2019
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

Signed-off-by: Luigi Coniglio <[email protected]>
[Joakim Bech: Extended commit message]
Signed-off-by: Joakim Bech <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jerome Forissier <[email protected]>
@werew
Copy link
Contributor Author

werew commented Oct 9, 2019

This vulnerability has now been attributed CVE ID: CVE-2019-17362

@werew werew changed the title Vulnerability in der_decode_utf8_string CVE-2019-17362 - vulnerability in der_decode_utf8_string Oct 9, 2019
sjaeckel added a commit that referenced this issue Oct 11, 2019
sjaeckel added a commit that referenced this issue Oct 12, 2019
buildroot-auto-update pushed a commit to buildroot/buildroot that referenced this issue Dec 23, 2019
CVE-2019-17362:
"The der_decode_utf8_string function (in der_decode_utf8_string.c) does not
properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds read
and crash) or read information from other memory locations via carefully
crafted DER-encoded data."

Details:
libtom/libtomcrypt#507
https://nvd.nist.gov/vuln/detail/CVE-2019-17362

Signed-off-by: Thomas De Schampheleire <[email protected]>
Signed-off-by: Thomas Petazzoni <[email protected]>
buildroot-auto-update pushed a commit to buildroot/buildroot that referenced this issue Dec 25, 2019
CVE-2019-17362:
"The der_decode_utf8_string function (in der_decode_utf8_string.c) does not
properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds read
and crash) or read information from other memory locations via carefully
crafted DER-encoded data."

Details:
libtom/libtomcrypt#507
https://nvd.nist.gov/vuln/detail/CVE-2019-17362

Signed-off-by: Thomas De Schampheleire <[email protected]>
Signed-off-by: Thomas Petazzoni <[email protected]>
(cherry picked from commit 62b34ed)
Signed-off-by: Peter Korsgaard <[email protected]>
buildroot-auto-update pushed a commit to buildroot/buildroot that referenced this issue Dec 25, 2019
CVE-2019-17362:
"The der_decode_utf8_string function (in der_decode_utf8_string.c) does not
properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds read
and crash) or read information from other memory locations via carefully
crafted DER-encoded data."

Details:
libtom/libtomcrypt#507
https://nvd.nist.gov/vuln/detail/CVE-2019-17362

Signed-off-by: Thomas De Schampheleire <[email protected]>
Signed-off-by: Thomas Petazzoni <[email protected]>
(cherry picked from commit 62b34ed)
Signed-off-by: Peter Korsgaard <[email protected]>
andyzsh68 pushed a commit to andyzsh68/optee_os that referenced this issue Apr 21, 2020
Fix a vulnerability in der_decode_utf8_string as specified here:
libtom/libtomcrypt#507

Patch manually picked from:
  libtom/libtomcrypt@25c26a3

Signed-off-by: Luigi Coniglio <[email protected]>
[Joakim Bech: Extended commit message]
Signed-off-by: Joakim Bech <[email protected]>
Acked-by: Joakim Bech <[email protected]>
Tested-by: Joakim Bech <[email protected]> (QEMU v7)
Acked-by: Jerome Forissier <[email protected]>
@jamuir
Copy link
Contributor

jamuir commented Dec 23, 2020

@werew : your write-up on this issue is really good. Thanks!

One thing that seems unusual about the test vectors you provide (poc1, poc2) is that they begin with "\x30\x04..." but they are followed by more than four bytes. However, it doesn't seem like the der sequence length matters in this exploit.

What is important is the value of "inlen", which is the input length that is passed in to der_decode_sequence_flexi(). That is the value that is subject to underflow.

jamuir added a commit to jamuir/libtomcrypt that referenced this issue Dec 24, 2020
Description:
Minor changes to help test and clarify the way utf8 strings are
decoded.  This originated from my misunderstanding of the fix for
issue libtom#507.

Testing:

  $ make clean
  $ make CFLAGS="-DUSE_LTM -DLTM_DESC -I../libtommath" EXTRALIBS="../libtommath/libtommath.a" test
  $ ./test

You can confirm that the new utf8 test data is correct using python:

  >>> s="\xD7\xA9\xD7\x9C\xD7\x95\xD7\x9D"
  >>> s.decode("utf-8")
  u'\u05e9\u05dc\u05d5\u05dd'
jamuir added a commit to jamuir/libtomcrypt that referenced this issue Dec 24, 2020
Description:
Minor changes to help test and clarify the way utf8 strings are
decoded.  This originated from my misunderstanding of the fix for
issue libtom#507.  The new test-vector uses two bytes to encode each
wide-char.

Testing:

  $ make clean
  $ make CFLAGS="-DUSE_LTM -DLTM_DESC -I../libtommath" EXTRALIBS="../libtommath/libtommath.a" test
  $ ./test

You can confirm that the new utf8 test data is correct using python:

  >>> s="\xD7\xA9\xD7\x9C\xD7\x95\xD7\x9D"
  >>> s.decode("utf-8")
  u'\u05e9\u05dc\u05d5\u05dd'
jamuir added a commit to jamuir/libtomcrypt that referenced this issue Jan 4, 2021
Description:
Minor changes to help test and clarify the way utf8 strings are
decoded.  This originated from my misunderstanding of the fix for
issue libtom#507.  The new test-vector uses two bytes to encode each
wide-char.

Testing:

  $ make clean
  $ make CFLAGS="-DUSE_LTM -DLTM_DESC -I../libtommath" EXTRALIBS="../libtommath/libtommath.a" test
  $ ./test

You can confirm that the new utf8 test data is correct using python:

  >>> s="\xD7\xA9\xD7\x9C\xD7\x95\xD7\x9D"
  >>> s.decode("utf-8")
  u'\u05e9\u05dc\u05d5\u05dd'
jamuir added a commit to jamuir/libtomcrypt that referenced this issue Jan 16, 2021
Description:
Minor changes to help test and clarify the way utf8 strings are
decoded.  This originated from my misunderstanding of the fix for
issue libtom#507.  The new test-vector uses two bytes to encode each
wide-char.

The utf8 format is described here:

  https://tools.ietf.org/html/rfc3629#section-3

Testing:

  $ make clean
  $ make CFLAGS="-DUSE_LTM -DLTM_DESC -I../libtommath" EXTRALIBS="../libtommath/libtommath.a" test
  $ ./test

You can confirm that the new utf8 test data is correct using python:

  >>> s="\xD7\xA9\xD7\x9C\xD7\x95\xD7\x9D"
  >>> s.decode("utf-8")
  u'\u05e9\u05dc\u05d5\u05dd'
jamuir added a commit to jamuir/libtomcrypt that referenced this issue Jan 16, 2021
Description:
Minor changes to help test and clarify the way utf8 strings are
decoded.  This originated from my misunderstanding of the fix for
issue libtom#507.  The new test-vector uses two bytes to encode each
wide-char.

The utf8 format is described here:

  https://tools.ietf.org/html/rfc3629#section-3

Testing:

  $ make clean
  $ make CFLAGS="-DUSE_LTM -DLTM_DESC -I../libtommath" EXTRALIBS="../libtommath/libtommath.a" test
  $ ./test

You can confirm that the new utf8 test data is correct using python:

  >>> s="\xD7\xA9\xD7\x9C\xD7\x95\xD7\x9D"
  >>> s.decode("utf-8")
  u'\u05e9\u05dc\u05d5\u05dd'
@0-wiz-0 0-wiz-0 mentioned this issue Jul 27, 2024
ynezz pushed a commit to ynezz/dropbear that referenced this issue Aug 21, 2024
[ cherry pick of upstream commit 64d1153e5a515740ab56f39c46baf4cf6991a9d3 ]

The der_decode_utf8_string function (in der_decode_utf8_string.c) does
not properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds
read and crash) or read information from other memory locations via
carefully crafted DER-encoded data.

To exploit this vulnerability an attacker must be able to provide
crafted DER-encoded data to LibTomCrypt (e.g. by importing a X509
certificate).  Information disclosure is made possible by a 2-steps
attack where the imported data is later somehow re-encoded and sent to
the attacker (e.g. import and then export X509 certificate).

Fixes: CVE-2019-17362
References: libtom/libtomcrypt#507
Signed-off-by: werew <[email protected]>
Signed-off-by: Petr Štetiar <[email protected]> [backport]
ynezz added a commit to ynezz/openwrt that referenced this issue Aug 22, 2024
…E-2019-17362

[ cherry pick of upstream commit 64d1153e5a515740ab56f39c46baf4cf6991a9d3 ]

The der_decode_utf8_string function (in der_decode_utf8_string.c) does
not properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds
read and crash) or read information from other memory locations via
carefully crafted DER-encoded data.

To exploit this vulnerability an attacker must be able to provide
crafted DER-encoded data to LibTomCrypt (e.g. by importing a X509
certificate).  Information disclosure is made possible by a 2-steps
attack where the imported data is later somehow re-encoded and sent to
the attacker (e.g. import and then export X509 certificate).

Fixes: CVE-2019-17362
References: libtom/libtomcrypt#507
Upstream-Status: Submitted [mkj/dropbear#319]
Signed-off-by: werew <[email protected]>
Signed-off-by: Petr Štetiar <[email protected]>
ynezz added a commit to ynezz/openwrt that referenced this issue Aug 22, 2024
…E-2019-17362

[ cherry pick of upstream commit 64d1153e5a515740ab56f39c46baf4cf6991a9d3 ]

The der_decode_utf8_string function (in der_decode_utf8_string.c) does
not properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds
read and crash) or read information from other memory locations via
carefully crafted DER-encoded data.

To exploit this vulnerability an attacker must be able to provide
crafted DER-encoded data to LibTomCrypt (e.g. by importing a X509
certificate).  Information disclosure is made possible by a 2-steps
attack where the imported data is later somehow re-encoded and sent to
the attacker (e.g. import and then export X509 certificate).

Fixes: CVE-2019-17362
References: libtom/libtomcrypt#507
Upstream-Status: Submitted [mkj/dropbear#319]
Signed-off-by: werew <[email protected]>
Signed-off-by: Petr Štetiar <[email protected]>
@Neustradamus
Copy link

Dear @libtom team,

We are in 2024, the latest release build is 1.18.2 (2018-07-02) - 6 years, 2 moths soon:

Thanks to @kloczek for this ticket from 2021-04-19 - 3 years, 4 months already:

It is time to create a new release build with CVE-2019-17362 fix!

Thanks in advance.

ynezz added a commit to ynezz/openwrt that referenced this issue Aug 27, 2024
…E-2019-17362

[ cherry pick of upstream commit 64d1153e5a515740ab56f39c46baf4cf6991a9d3 ]

The der_decode_utf8_string function (in der_decode_utf8_string.c) does
not properly detect certain invalid UTF-8 sequences.  This allows
context-dependent attackers to cause a denial of service (out-of-bounds
read and crash) or read information from other memory locations via
carefully crafted DER-encoded data.

To exploit this vulnerability an attacker must be able to provide
crafted DER-encoded data to LibTomCrypt (e.g. by importing a X509
certificate).  Information disclosure is made possible by a 2-steps
attack where the imported data is later somehow re-encoded and sent to
the attacker (e.g. import and then export X509 certificate).

Fixes: CVE-2019-17362
References: libtom/libtomcrypt#507
Upstream-Status: Denied [mkj/dropbear#319]
Signed-off-by: werew <[email protected]>
Signed-off-by: Petr Štetiar <[email protected]>
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

3 participants