If you’re an OpenSSL user, you’re probably aware of the latest high-level bugfix release, which was released in March 2022.
This patch brought us OpenSSS 3.0.2 and 1.1.1nupdates for the two current fully supported versions of the product.
(There is a legacy version, 1.0.2, but updates to this version are only available to customers paying for premium support, and given the changes and improvements made to the product since the days of 1.0.2 , we strongly urge you to upgrade to a consumer version even – perhaps especially – if you plan to continue paying for support.)
The March 2022 update was a vital reminder that deeply buried code with unusual bugs can end up being neglected for years, especially if that code is part of a complex, specialized, low-level function.
The bug fixed at the time concerned a special algorithm for calculating what is called modular square rootswhich are more complicated to calculate than regular square roots.
Unfortunately, the code to perform this calculation, using an algorithm first discovered in the 1890s, was clumsily coded, tortuously written, poorly commented, and difficult to follow.
However, since it was not an obvious “outside” part of OpenSSL, and since rewriting it would have been a daunting task, we assume it has been carefully tested for correctness. of its responses when presented with well-formed numbers, but whose robustness has not been tested against improbable input.
Because, faced with digital certificates that had been tricked into producing malformed numbers, OpenSSL
BN_mod_sqrt() The function could be caused to loop indefinitely, trying to get closer to an answer that didn’t exist.
When you work only with whole numbers and forbid fractions of all kinds, you find that many numbers do not have modular square roots, just as you find that many whole numbers do not have regular square roots . So 7×7 = 49, so 49 has a square root which is an integer, namely 7. But there is no integer which can be multiplied by itself to give 50, or 51, because the next “perfect square” is 8×8 = 64. You can try as long as you want, but you will never find an integer answer for √51.
Never really incorrect, just incomplete
In other words, although OpenSSL’s BigNumber code (many encryption algorithms rely on working with numbers consisting of hundreds or even thousands of digits) has never yielded Wrong answer, he sometimes didn’t realize that there was no answer to be found and got stuck in an infinite loop.
This infinite loop, which could be abused to cause what is called a Denied service (DoS), could be triggered if a malicious website sends a booby-trapped digital certificate.
This meant, ironically, that software scrupulous about validating digital certificates could be brought to their knees via this bug, dubbed CVE-2022-0778while programs that didn’t care about certificate validation at all were unaffected by it.
Given the significant “teachable moments” revealed by this bug, we covered it in detail not only on Naked Security, where we covered how to write better style code, but also on Sophos News, where SophosLabs showed the gory details of how a booby-trapped certificate could trigger the flaw, and how to debug the code to understand the bug.
Two other security flaws in the meantime
The next OpenSSL update was 3.0.3Where 1.1.1o for users of the previous version, which fixed a bug that wasn’t considered a major flaw (at least we didn’t cover it on Naked Security), mainly because the bug wasn’t in the code of the OpenSSL encryption library itself.
Instead of affecting all software that relied on OpenSSL as the cryptographic provider, CVE-2022-1292 just affected a utility script, written in Perl, that comes with the OpenSSL toolkit.
This script, known as
c_rehash (short for certificate directory rehash) is a little-known tool that takes a directory of cryptographic certificate files, such as those managed as trusted certificate authorities (CAs) by Mozilla, and creates a list of file hashes that can help software find specific certificates faster than searching an alphabetical list of names.
For example, Mozilla’s CA certificate directory looks like this…
$ ls -l /usr/share/ca-certificates/mozilla -rw-r--r-- 1 duck duck 2772 2022-06-23 05:32 ACCVRAIZ1.crt -rw-r--r-- 1 duck duck 1972 2022-06-23 05:32 AC_RAIZ_FNMT-RCM.crt -rw-r--r-- 1 duck duck 904 2022-06-23 05:32 AC_RAIZ_FNMT-RCM_SERVIDORES_SEGUROS.crt [. . .] -rw-r--r-- 1 duck duck 1302 2022-06-23 05:32 emSign_Root_CA_-_G1.crt -rw-r--r-- 1 duck duck 774 2022-06-23 05:32 vTrus_ECC_Root_CA.crt -rw-r--r-- 1 duck duck 1911 2022-06-23 05:32 vTrus_Root_CA.crt
c_rehash generates a list of symbolic links that allow individual certificates to be located via hashes based on the issuer’s name in the certificate itself, rather than its filename:
lrwxrwxrwx 1 duck duck 23 2022-06-24 13:41 002c0b4f.0 -> GlobalSign_Root_R46.crt lrwxrwxrwx 1 duck duck 45 2022-06-24 13:41 02265526.0 -> Entrust_Root_Certification_Authority_-_G2.crt lrwxrwxrwx 1 duck duck 36 2022-06-24 13:41 03179a64.0 -> Staat_der_Nederlanden_EV_Root_CA.crt [. . .] lrwxrwxrwx 1 duck duck 19 2022-06-24 13:41 fe8a2cd8.0 -> SZAFIR_ROOT_CA2.crt lrwxrwxrwx 1 duck duck 23 2022-06-24 13:41 feffd413.0 -> GlobalSign_Root_E46.crt lrwxrwxrwx 1 duck duck 49 2022-06-24 13:41 ff34af3f.0 -> TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.crt
Some software relies on these “hash links” to act as a sort of base database system for indexing and searching for specific certificates.
Additionally, some operating system distributions automatically invoke the
c_rehash background script to keep these special links up to date.
Shell metacharacters considered harmful
Unfortunately, the script relied on Perl
system() function (or an equivalent command) to calculate file hashes, and the
system() system automatically launches a command shell, such as Bash, to launch all necessary subroutines.
And, as you probably know, command shells don’t always treat their command-line arguments literally, so if you put special characters in those arguments, the shell handles them in potentially dangerous ways.
For example, the command
echo runthis literally prints the text
runthisbut the command
echo $(runthis) does not print characters directly
Instead, the so-called metacommand
$(runthis) means order replacementso it says, “Run the command
runthis and replace the
$(...) part with the output of this command when it completes”:
# argument treated literally, no metacharacters found $ echo runthis runthis # tries to execute 'runthis', but no such command exists $ echo $(runthis) -bash: runthis: command not found # runs two commands, collects output of both $ echo $(whoami; uname -s -r) duck Linux 5.18.6
If the risk posed by
$(...) This sounds familiar, that’s because it’s the metacommand vulnerability that was exploited in the recent “Follina” bug on Windows. To learn more and see this bug in action, you can watch our recorded webinar. Just click on the image below. [Registration required, access is immedidate thereafter.]
What has been fixed?
Scripts that accept untrusted input from someone else – whether it’s a string typed into a web form or a made-up filename supplied from outside – must be very careful about don’t let these special metacommands leak out as shell arguments when relying on the shell command to run external utilities.
Below you can see the code that was changed from 1.1.1n at 1.1.1o:
A Perl command of the form
`...` (a command between backticks, like
`runthis`is simply an old-fashioned way of writing the
$(runthis) command substitution) has been replaced by a dedicated internal function called
compute_hash which pays more attention to weird metacharacters in the constructed command string.
Well, it turns out the maintainers didn’t quite catch all the places in this utility script where an external command was run without due care and attention.
So this week saw the output of OpenSSL 3.0.4 and 1.1.1pto fix another risky system command in the
This time it was a call to
cp (copy file) via shell based command
system() function which has been replaced by a more secure dedicated internal function called
This patch has the official ID CVE-2022-2068.
As the OpenSSL changelog warns:
c_rehash] The script is distributed by some operating systems to run automatically. On such operating systems, an attacker could execute arbitrary commands with script privileges.
What to do?
- Update OpenSSL as soon as possible. If you rely on your Linux distribution to maintain a centrally installed copy, consult your distribution’s manufacturer for details. If you rely on your own version of OpenSSL instead of (or in addition to) a system-wide version, remember to update that copy as well. You look for 3.0.4 Where 1.1.1p. To run
openssl versionto see which version you have.
- Consider removing the
c_rehashutility if you use it. The all-in-one utility
opensslwhich is commonly used to generate and sign certificates in the first place, now includes a built-in subcommand called
rehashdo the same job. Try
openssl rehash -helpfor more information.
- Disinfect your entrances and exits. Never assume that the input you receive is safe to use as is, and be careful with the data you pass as output to other parts of your code.
- Be alert for multiple errors when reviewing code for specific bug types. A programmer who was careless with a
system()command in one place in the code may have made similar errors elsewhere.
Programmers often produce (or reproduce) the same type of bug multiple times, usually for perfectly innocent and understandable reasons.
Either they weren’t aware of this class of bugs at the time they worked on the code, or they took a “temporary shortcut” to speed up the prototype work but never came back and put away later, or they have copy-pasted someone else’s faulty code and made it their own…