CVE-2019-17362 - vulnerability in der_decode_utf8_string #507
Labels
No labels
bug
duplicate
enhancement
feature
help wanted
improve API
invalid
needs documentation
not-planned
rtfm
stale
support
wishlist
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-libtom/libtomcrypt#507
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Description
The
der_decode_utf8_stringfunction (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:
Here the variable
tmpcontains 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
tmpset 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_stringaccepts 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_stringinto reporting a length bigger than the actual size of the encoded string.This works because the function
der_utf8_charsizereturns 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->dataand then compute the length usingder_length_utf8_stringon the decoded data:The computed
lenis later used to move forward some pointers:The variable
inlenpoints 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
*inlenwill 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).
This vulnerability has now been attributed CVE ID: CVE-2019-17362
@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.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.