OpenSSL punycode – with hindsight

The real scare that happened right after Halloween

 By Yali Sela and Gili Yankovitch Technology Leaders and Security Experts, Check Point IoT Protect

November 1st, 2022. Everyone in the cybersecurity world was sitting at the edge of his or her seat, waiting for the update from OpenSSL. The tension was palpable. The next Heartbleeds were about to be announced, two critical vulnerabilities that affect everyone and everything, everywhere.

And then they were released.

And everyone was let down.

Ever since the recent OpenSSL CVEs were released (CVE-2022-3602 and CVE-2022-3786), we’ve had many posts pop up all across the internet discussing them:

  • Snyk, giving a great technical breakdown of the CVEs and the commits that fixed them (CVE-2022-3602, CVE-2022-3786).
  • Datadog, which also explains how to detect exploitation of the vulnerability.
  • Filippo Valsorda, explaining how the stars aligned so that these vulnerabilities came to be, and how we could have very easily detected these bugs before committing them to code.
  • A million others: individual researchers or other companies, all pretty much saying the same facts, presenting their own analyses, and reaching the same conclusions (spoiler alert: the CVEs are not a big deal).

We’ll give you the highlights. We’ll present our own technical analysis. We’ll cap this with an interesting technology that is doing a different thing that vulnerability management to give you the security you want.

Here are the highlights:

  1. The CVEs were hyped-up before their release.
  2. They were downgraded in severity as they were released.
  3. The bugs behind them are very simple and straightforward.
  4. The conditions required for them to even be enabled, and the difficulty in actually exploiting them meaningfully, ended up causing them to be a huge let-down.

Now let’s get down to business.

Technical analysis

The two discovered vulnerabilities are some types of “buffer overflow”. A buffer overflow means that a certain amount of space was allocated for data, but someone accidentally wrote more than that amount, causing data to “overflow” and overwrite whatever happened to be nearby in memory. Carefully controlling what is overwritten and the data with which we overwrite it, we could achieve extreme results – even remote code execution.

CVE-2022-3062: Punycode off-by-one (or – the more meaningful CVE)

Screenshot of the commit fixing CVE-2022-3062

This vulnerability in the ossl_punycode_decode function was fixed by the commit screenshotted above. We can see that the only change was “>” turning into “>=” on line 184; a memory size check that makes sure we’re not writing past the buffer we allocated. The check was just… off by 1. This is a buffer overflow again.

An interlude for Punycode

This vulnerability manifested in a “Punycode decode” function. “What even is Punycode?” you might ask – and rightfully so. Punycode is a representation of the huge Unicode character set (which includes English, emojis, Chinese, Klingon, and pretty much anything you can think of) using ASCII subset, which is much more limited. Punycode generally consists of letters, numbers, and hyphens. This is used also for Internet hostnames. This is how you can have domain names in any language you want, and not just English.

Here is an example table from Wikipedia to demonstrate the concept:

Just imagine someone naming their website “😉.com”

Back to the CVE

Our off-by-one vulnerability corrupts data that sits next to it. So then, what is that data? Running this with a debugger shows that a seed array (see below) is partially overwritten. In the general worst case, what could be written is a useful control-flow artifact such as a function return address or a function pointer, but luckily this is not our case.

As you can see from the assembly analysis of the ossl_a2ulabel function, a stack frame of at least 0x838 bytes is opened:

Comparing with the crypto/punycode.c source file, stack analysis shows the local variables are mapped to the following offsets:

The CVE-2022-3062 off-by-one vulnerability in the ossl_punycode_decode  function, exploits the buf array, allowing an additional unsigned int (4 whole bytes!) beyond the array boundaries. This is, by definition, a buffer overflow.

The seed array now contains some data that it didn’t intend to have. However…

Looking at codepoint2utf8, one can clearly see that the out buffer (which points to the outer seed variable), is immediately overwritten by some value as part of normal flow, therefore rendering the off-by-one unusable.

CVE-2022-3786: a classic buffer overflow (or – the less meaningful CVE)

This vulnerability exists in a function called ossl_a2ulabel. It might allow another buffer overflow, however the nature of this specific CVE limits us to only be able to write dots – “.” (ASCII 46). This makes the CVE rather unusable for serious attacks.

What is this function and why is it there? There’s no need to explain the context in-depth, but it’s there as part of verifying an X.509 certificate is valid. That’s generally what happens – for example – automatically when you go to google.com and your browser wants to make sure whichever server answered you really is Google (and not just pretending and secretly recording your Google searches).

After iterating over the ossl_punycode_decode output using the codepoint2utf8 function, the ossl_a2ulabel function tries to write the ‘.’ character to the output decoded buffer outptr. In this case, we need to find what’s behind this variable. A quick look presents two functions:

1. ossl_a2ucompare():

2. nc_email_eai() under crypto/x509/v3_ncons.c:

In both cases, outptr points to a local buffer. Therefore, an overflow over this buffer will result in a stack-based buffer overflow. Taking a closer look at the vulnerable code under ossl_a2ulabel we find the function is indeed vulnerable to an overflow:

It seems the function will continue writing the ‘.’ character to the buffer, regardless of its maximum size. This allows an attacker to overflow the stack with an arbitrary number of the ‘.’ character, which will cause the program to crash.

How and when can we use this?

The client is at risk in a scenario where a client – such as your home browser – connects to a malicious server.  For example, if someone hacked your favorite forum or online vendor which you then visit, or if you click an untrusted link. There are a few extra conditions here and there which can be considered mitigating factors, but we won’t delve into details as they’re not very effective mitigating factors.

The server is at risk when it is configured to accept client certificates, which is rare.

What is the risk?

Probably nothing. This is by no means a guarantee, and there is no proof that this cannot be exploited successfully. Experienced researchers explored exploitation of this CVE and it seems difficult, and even impractical when considering modern security mechanisms.

The mentioned OpenSSL CVEs don’t put you at any real risk. So as promised, calm down, and let the experts keep you safe; this is literally just another Tuesday.

What’s the deal with software vulnerabilities?

The vulnerabilities in OpenSSL got unusual attention, probably because of the heads-up about 2 critical vulnerabilities before sharing the full information. However, these sorts of publications come out all the time. Every day, dozens of new CVEs are published. This year, we have already 21871 CVEs and number is counting on. Last year ended up with 20171 CVEs. Most of them are generally harmless or irrelevant, only around 15% of vulnerabilities are exploitable. In recent years, vulnerability assessments and publishing CVEs became more popular (compared to, say, 2005). Looking at the last few years, just the Linux kernel gets over 200 new CVEs every year, which we can average out as a bit more than 1 CVE every 2 days. With the kernel being the main component of the operating system, you can imagine how many systems are affected by new CVEs every day.

Vulnerabilities are a big issue, because the minority that are really dangerous may be used as a successful attack vector. In most sectors this is either the main attack vector, or the second one after social engineering.

As a user, you might be not fully aware of the heavy process for a software vendor to cope the numerous vulnerabilities in software components. Any new vulnerability, harmful or harmless, required security hotfix to be released in a certain timeframe. Users are required to patch their devices and systems with the new hotfixes, but most of users actually don’t do it.

Vulnerability management has become somewhat of a buzzword in the cybersecurity field. It appears as a mandatory requirement in standards and regulations; it’s a common approach for security experts to mitigate risks when securing the organization.

How do we suggest managing your vulnerabilities?

As a cybersecurity company we must tell you keep doing strict vulnerability management policy. However, life shows that vulnerability management as a strategy for security is inefficient and hard to maintain. It is hard to keep it practical and efficient. As more and more external dependencies are added to your projects, and each of them brings a “ball and chain” of known vulnerabilities and yet-unknown vulnerabilities, and creates an impossible burden on both developers and users. You cannot patch 20,000 vulnerabilities every year, and keep your teams developing features. The teams do not have the skills to analyze each CVE and decide what is relevant and what can be ignored and to deal with the occasional functional break when a dependency is updated.

We suggest a solution that pre-emptively blocks cyberattacks even on vulnerable software. It gives you a safety net for even zero-day vulnerabilities.

Check Point Software Technologies experts develop a technology that is able to protect vulnerable systems and devices.

We focus on IoT devices, as those are mostly vulnerable and in many cases, are missing basic concepts of security by design.

IoT Protect’s Nano Agent identifies malicious behavior and blocks exploitation of vulnerabilities, known and unknown. This is, in a way, future-proofing. We do not tout machine learning or “AI”, we simply analyze the assembly – much like industry-standard disassemblers do – and recognize (in runtime, by hooking system calls and applying control flow integrity) deviations of the software’s behavior from the compiled expected behavior. By using cutting edge technology, the Nano Agent helps you avoid an urgent need to patch and update your software – whether you’re an end user or the software vendor – keeping the burden of vulnerability maintenance orders of magnitude smaller.