regreSSHion: The Ghost of Vulnerabilities Past Haunts OpenSSH
Jan 6, 2026·6 min read
Executive Summary (TL;DR)
OpenSSH's sshd server has a race condition in its SIGALRM handler. If a client disconnects precisely when the LoginGraceTime expires, the signal handler calls non-async-signal-safe functions (syslog). This corrupts the glibc heap, leading to potential RCE as root. It affects versions 8.5p1 through 9.7p1.
A signal handler race condition in OpenSSH's server (sshd) allows unauthenticated remote code execution (RCE) as root on glibc-based Linux systems. This is a regression of a vulnerability originally fixed in 2006 (CVE-2006-5051).
The Hook: We've Been Here Before
OpenSSH is the bedrock of the internet. It is the digital equivalent of the locks on your front door. We trust it implicitly to manage remote access to servers, routers, and IoT devices across the globe. When a vulnerability drops in OpenSSH, it’s not just a bad day; it’s a potential catastrophe. But what makes CVE-2024-6387—dubbed 'regreSSHion'—particularly stinging isn't just the severity; it's the irony.
This bug is a regression. We literally solved this problem in 2006 (CVE-2006-5051). Back then, the security community learned a valuable, blood-written lesson: do not perform complex operations inside a signal handler. Specifically, stay away from the heap.
Fast forward to October 2020, OpenSSH 8.5p1 is released. Somewhere in the refactoring chaos, a developer accidentally removed the guardrails preventing this specific race condition. For nearly four years, millions of servers have been exposing a root-level RCE window, waiting for someone with enough patience to win the race. It’s a stark reminder that in software development, history doesn't just repeat itself; it recompiles itself.
The Flaw: A fatal signal
To understand this flaw, you need to understand UNIX signals and 'async-signal-safety'. When a program receives a signal (like SIGALRM when a timer expires), the OS pauses the program's normal execution and jumps to a 'signal handler' function. This is like a rudely interrupted phone call; you stop talking to your friend and answer the intruder immediately.
The problem arises when the interrupted code and the signal handler try to use the same shared resources—specifically, the memory allocator (malloc/free). The glibc memory allocator is not re-entrant. If the main program is in the middle of a malloc() call, messing with internal heap structures (linked lists, size headers), and a signal interrupts it, the signal handler must not call malloc() or free(). If it does, it will try to modify those same inconsistent structures, leading to heap corruption.
In sshd, the LoginGraceTime setting (default 120 seconds) sets an alarm. If the user doesn't authenticate in time, SIGALRM fires. The handler for this signal, sigdie(), is supposed to clean up and exit. However, in vulnerable versions, sigdie() calls syslog(). Here is the kicker: syslog() is not async-signal-safe. Internally, syslog() allocates memory to format the log message. Boom. We have a race condition.
The Code: The Smoking Gun
Let's look at the logic flow that creates the disaster. The vulnerability exists in the sshd.c file's signal handling logic. The signal handler is registered to catch SIGALRM.
// The Vulnerable Logic Pattern
void
sigdie(int sig)
{
// ERROR: syslog() uses malloc() internally!
syslog(LOG_INFO, "Timeout before authentication for %s", user);
_exit(1);
}The exploit requires a precise timing window. The attacker creates an SSH connection but doesn't complete authentication. They wait. On the server, sshd is processing public keys or handling packet parsing code which utilizes malloc() or free().
If the SIGALRM fires exactly while the main thread is inside a heap function (manipulating the tcache or fastbins in glibc), the signal handler interrupts it. The handler calls syslog(), which calls malloc(). The heap state, currently in a half-modified flux, gets shredded.
[!NOTE] Why is this hard? Hitting this window is probabilistic. We are talking about interrupting a specific instruction sequence within
malloc. However, becausesshdforks a new process for every incoming connection, an attacker can retry millions of times without crashing the main daemon. It's a brute-force race.
The Exploit: Winning the Race
Exploiting this on 64-bit systems with modern glibc (with ASLR and NX) is non-trivial but feasible. The goal is to corrupt the glibc heap structures to overwrite a function pointer or a return address.
Here is the high-level attack strategy:
- Heap Feng Shui: The attacker sends specific packets to force the heap into a predictable layout. This might involve sending large public keys to trigger allocations of specific sizes.
- The Trigger: The attacker waits for the
LoginGraceTime(usually 120s, but can be configured lower) to nearly expire. - The Race: Just as the alarm is about to go off, the attacker sends a packet that triggers a
free()ormalloc()in the main loop (e.g., sending a packet with a parsing error). - Corruption: The signal handler interrupts the heap operation.
syslog()allocates memory, utilizing the corrupted metadata.
The Qualys researchers identified that by targeting the _IO_2_1_stdout_ structure (which resides in the data segment or heap depending on the version), they could fake a vtable. By overwriting the vtable pointer, the next time glibc tries to flush stdout (or during exit), it jumps to our shellcode (or ROP chain).
The Impact: Root for Everyone
The impact is absolute. Because sshd runs as root (to bind port 22 and handle privilege separation), successful exploitation yields a root shell. The attacker does not need valid credentials. They just need network access to the SSH port.
While the race condition is hard to win (taking ~10,000 attempts on average in lab conditions), the consequence is a total system compromise. This is particularly dangerous for enterprise environments where automated scanning and exploitation tools can run 24/7. If you have a fleet of Linux servers, this is a 'drop everything and patch' event.
However, there is a silver lining: OpenBSD is not affected. The OpenBSD team developed syslog_r (a re-entrant, async-signal-safe version of syslog) specifically to avoid this class of bugs. This vulnerability specifically targets Linux systems using glibc where syslog is not safe.
The Fix: Back to Basics
The remediation is conceptually simple: Don't call syslog in the signal handler. The patch moves the logging logic out of the async-signal context or uses a safe alternative.
Immediate Mitigation:
If you cannot patch immediately, you can set LoginGraceTime to 0 in sshd_config. This disables the alarm entirely, preventing the signal handler from firing.
# /etc/ssh/sshd_config
LoginGraceTime 0[!WARNING] DoS Risk Setting
LoginGraceTime 0means connections that get stuck during authentication will hang forever. An attacker could exhaust all available connection slots (MaxStartups) by opening connections and doing nothing, causing a Denial of Service. This is a stop-gap, not a permanent fix.
The Real Fix:
Upgrade to OpenSSH 9.8p1. The vendors (Ubuntu, Debian, RedHat) have backported the fix to older versions, so apt update && apt upgrade is your best friend here.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenSSH OpenBSD | >= 8.5p1, < 9.8p1 | 9.8p1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-364 |
| Attack Vector | Network |
| CVSS v3.1 | 8.1 |
| Impact | Remote Code Execution (Root) |
| Exploit Status | High Complexity PoC |
| Architecture | x86 (glibc) |
MITRE ATT&CK Mapping
Signal Handler Race Condition
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.