This week in security: hide your SSH, Polyfill and pack it

The big news this week was that OpenSSH has an unauthorized Remote Code Execution exploit. Or more precisely, it had one that was fixed in 2006, which was inadvertently reintroduced in 2021’s 8.5p1. The flaw is a signal handler race condition, where async-unsafe code is called from the SIGALARM handler. What does that mean?

To understand this, we need to dive into the world of Linux signal processing. Signals are sent by the operating system to individual processes to notify the process of a state change. For example SIGHUPor SIGNnal HangUP, originally referred to the disconnection of the serial line from the terminal on which a program was running. SIGALRM is the SIGNAL ALaRM, which indicates that a timer has expired.

What’s interesting about signal processing in Unix is ​​how it interrupts program execution. The operating system has complete control over the scheduling of execution, so in response to a signal, the scheduler pauses execution and processes the signal immediately. If no signal handler function is defined, that means a default handler provided by the operating system. But if the handler is set, that function is executed immediately. And here’s the dangerous part. Program execution can occur anywhere in the program, when it is paused, the signal handler is executed and execution continues. From Andries Brouwer in The Linux Kernel:

It’s hard to do interesting things in a signal handler, because the process can be interrupted at any point, data structures can be in any state, etc. The three most common things to do in a signal handler are (i) set a flag variable and return immediately, and (ii) (messily) throw away whatever the program was doing and restart it at some convenient point, say the main command loop or something, and (iii) clean up and exit.

The term async-signal-safe describes functions that exhibit predictable behavior even when called from a signal handler, pausing execution in an arbitrary state. How can such a function be unsafe? Let’s take a look at async-signal-unsafe free(). Here, memory sections are marked as free, and then pointers to that memory are added to the free memory table. If program execution is interrupted between these points, we have an undefined state in which memory is both free and still allocated. A second call to free() during execution pause will corrupt the free memory data structure, since the code is not intended to be called in this reentrant manner.

So back to the OpenSSH leak. The SSH daemon sets a timer when a new connection comes in, and if authentication is not completed, the SIGALRM signal is generated when the timer expires. The problem is that this signal handler uses the syslog() system call, which is not an async-safe function, due to the addition of malloc() And free() system calls. The trick is to initiate an SSH connection, wait for the timeout, and send the last bytes of a public-key packet just before the timeout signal is triggered. If the public-key handler happens to be at the right point in a malloc() call, when the SIGALRM handler re-enters malloc()the heap is corrupted. This corruption overwrites a function pointer. Replace the pointer with an address where the incoming key material is stored, and suddenly we have shellcode execution.

There are several problems with turning this into a functional exploit. The first is that it’s a race condition, requiring very tight timing to split the execution of the program at exactly the right spot. The randomness of network timing makes this a high hurdle. Next, all major distros use Address Space Layout Randomization (ASLR), which should make overwriting that pointer very difficult. It turns out that ASLR is broken to some extent on all major distros as well. Okay, on 32-bit installs it’s completely broken. On the Debian system I tested, there is literally one bit of ASLR in play for the glibc library. It can be in one of two possible memory locations.

Assuming the default settings for maximum SSH connections and LoginGraceTime, it takes an average of 3-4 hours to win the race condition to trigger the bug, and then there is a 50% chance of guessing the correct address on the first try. That seems to put the average time at five and a quarter hours to crack a 32-bit Debian machine. A 64-bit machine has ASLR which works slightly better. A working exploit had not yet been demonstrated at the time the vulnerability description was published, but the authors suggest that it could be in the neighborhood of a week of attacks.

So which systems should we really be concerned about? The regression was introduced in 8.5p1 and fixed in 9.8p1. That means that Debian 11, RHEL 8, and their derivatives are safe, as they ship older OpenSSH versions. Debian 12 and RHEL 9 are affected, although both distros now have updates available that fix the issue. If you are running one of those distros, particularly the 32-bit version, it is time to update OpenSSH and restart the service. You can check your OpenSSH version by nc -w1 localhost 22 -i 1to see if you might be vulnerable.

Polyfill

The Polyfill service was once a handy tool for pulling in JavaScript functions to emulate newer browser features on browsers that weren’t quite up to the task. It worked by including the polyfill JS script from polyfill.io. The problem is that a company called Funnull took over the polyfill domain and Github account and started serving malicious scripts instead of the legitimate polyfill function.

The list of domains and companies affected by this supply chain attack is quite extensive, with nearly 400,000 still attempting to link to the domain as of July 3rd. We say “attempted” because providers took notice of Sansec’s report and broke the news. Google has blocked associated domains from ads, Cloudflare is rewriting calls to polyfill to a clean cache, and Namecheap has blocked the domain, effectively ending the attack. It’s a reminder that a domain that may be trustworthy now may not be in the future. Be careful where you link to.

Pack it up

We are no strangers to disagreements over CVE severity drama. There may be a desire to make a discovered vulnerability seem serious, and sometimes this results in wild exaggeration of the impact of a problem. One example is the node-ip project that had a problem, CVE-2023-42282, which originally had a CVSS of 9.8. The author of node-ip has taken the position that it is not a vulnerability at all, because an untrusted input must be passed to node-ip and then used for an authorization check. It seems like a reasonable objection: if an attacker can manipulate the source IP address in this way, then the source IP address is untrustworthy, regardless of this problem in node-ip.

The manager, [Fedor] the decision to simply archive the node-ip project in response to the seemingly false CVE and the endless stream of unintentional harassment about the issue. Auditing tools began alerting developers to the issue and they began pinging the project. Since there was seemingly no way to fight back against the report, archiving the project seemed like the best solution. However, the bug has been fixed and Github has downgraded the severity in their advisory to “low”. As a result, [Fedora] has announced that the project is coming back and it is indeed an active project on Github again.

Bits and bytes

[sam4k] found a remote Use After Free (UAF) in the Linux Transparent Inter Process Communication (TIPC) service, which could potentially be abused to achieve RCE. This is a kind of toy vulnerability, found while preparing a talk about debugging the Linux kernel. It is also not a protocol built into the kernel by default, so the potential impact here is quite low. The problem is fragmentation handling, as the error handling misses a check for the last fragment buffer and tries to free it twice. It was fixed in Kernel version 6.8 in May.

CocaoPods is a dependency manager for Swift/Objective-C projects and had three serious issues. The most interesting was the result of a migration, where many packages lost their connection to the correct maintenance account. Using the CocaoPods API and a maintenance email address, it was possible for arbitrary users to claim those packages and make changes. This and a few other issues were fixed late last year.

Leave a Comment