GHSA-4C5F-9MJ4-M247

regreSSHion: Time Travel is Real, and It Roots Your Box

Alon Barad
Alon Barad
Software Engineer

Jan 5, 2026·5 min read

Executive Summary (TL;DR)

OpenSSH's `sshd` has a race condition in its `SIGALRM` handler. If a client doesn't authenticate within the `LoginGraceTime` (usually 120s), the handler fires. Unfortunately, the handler calls `syslog()`, which is not async-signal-safe. If this interrupts the heap manager (malloc/free) in the main thread, heap corruption occurs. Attackers can exploit this to gain unauthenticated root access, though it takes ~10,000 attempts (6-8 hours) on average.

A signal handler race condition in OpenSSH's sshd allows unauthenticated remote code execution as root on glibc-based Linux systems. This is a regression of a vulnerability originally fixed in 2006, proving that history doesn't just repeat itself—it recompiles.

The Hook: The Zombie Bug Returns

In the world of software development, we like to think we move forward. We fix bugs, we write tests, we deploy. But CVE-2024-6387, dubbed 'regreSSHion', is a stark reminder that codebases have long memories.

This isn't a new vulnerability. It's a zombie. Specifically, it's a regression of CVE-2006-5051, a signal handler race condition that was patched nearly two decades ago. Somehow, in a refactor around October 2020 (OpenSSH 8.5p1), someone accidentally removed the safety rails.

The target? sshd, the ubiquitous daemon that guards the front door of nearly every Linux server on the planet. The impact? Unauthenticated Remote Code Execution (RCE) as root. If that doesn't make you check your patch levels, nothing will.

The Flaw: Async-Signal-Safety 101

To understand this bug, you need to understand the absolute chaos of UNIX signals. When a signal (like SIGALRM) fires, the OS pauses whatever the main thread is doing—literally anywhere in the execution flow—and jumps to the signal handler.

Because the main thread is frozen, the signal handler must be incredibly careful. It cannot call functions that might be holding locks or modifying global state that the main thread was also using. These safe functions are called Async-Signal-Safe.

Here is the cardinal sin: syslog() is NOT async-signal-safe. It uses malloc() and free() internally to format messages. If the main thread was in the middle of a malloc() (manipulating the heap linked lists) when the signal hit, and the signal handler also calls syslog() (which calls malloc()), you get re-entrancy into a non-reentrant function. The result? The heap metadata gets scrambled like eggs.

The Code: The Smoking Gun

Let's look at the crime scene in sshd.c. The logic is supposed to handle timeouts. If you take too long to type your password (LoginGraceTime), sshd kills the connection.

The vulnerable chain looks like this:

  1. SIGALRM fires.
  2. grace_alarm_handler() is called.
  3. It calls sigdie().
  4. sigdie() calls syslog().

Here is the simplified pseudocode of the disaster:

// The Signal Handler
void grace_alarm_handler(int sig) {
    // ... logic ...
    sigdie("Timeout before authentication");
}
 
void sigdie(const char *fmt, ...) {
    // DOOM: syslog is not safe here!
    syslog(LOG_INFO, fmt, ...);
    _exit(1);
}

The fix is technically simple but conceptually strict: remove the logging from the signal handler. The patch moves the complex logic out of the interrupt context, ensuring we only call async-signal-safe functions (like _exit) directly.

The Exploit: Winning the Race

Exploiting this is not like throwing a payload at a buffer overflow. It's a probabilistic race condition. We are playing a timing game against the CPU scheduler.

To win, the attacker must force sshd to be inside a malloc() or free() call exactly when the SIGALRM timer expires. Since we know the LoginGraceTime is usually 120 seconds, we can attempt to manipulate the timing.

The attack strategy involves:

  1. Open a connection to sshd.
  2. Send specific public key packets to force the server to allocate memory (heap grooming/Feng Shui).
  3. Wait.
  4. Hope the signal fires while the heap is in an inconsistent state.

Qualys (who found this) noted that on a 32-bit system, this is easier because heap structures are predictable. On 64-bit AMD64 with ASLR, it's a nightmare. It takes roughly ~10,000 attempts to succeed. That sounds like a lot, but in a scriptable attack, that's just a few hours of noise. Once the race is won, the heap corruption allows overwriting a struct that contains function pointers, redirecting execution to a ROP chain.

The Impact: Root for Everyone

If an attacker pulls this off, they bypass authentication entirely. They are running code within the context of the unprivileged sshd worker, which is bad, but it gets worse.

Because of the way OpenSSH is architected, exploiting the unprivileged process is often a stepping stone to kernel exploitation or privilege escalation, but in this specific race, we are interfering with the root-owned parent process in some configurations or the pre-auth stage.

The saving grace? This effectively only affects glibc-based Linux systems. Musl libc and others are likely safe because their syslog implementation or heap management differs slightly, or they don't have the specific gadgetry required for the heap exploit to land easily. Windows and macOS are generally unaffected.

The Mitigation: Kill the Grace Period

The official fix is to upgrade to OpenSSH 9.8p1. The developers reorganized the code to ensure syslog is never called from the signal handler.

Immediate Workaround: If you can't patch immediately (and let's be honest, patching sshd on 5,000 servers on a Friday is risky), you can mitigate this by setting LoginGraceTime to 0 in sshd_config.

# /etc/ssh/sshd_config
LoginGraceTime 0

[!WARNING] Setting LoginGraceTime to 0 means connections will never time out. This exposes you to a Denial of Service (DoS) where an attacker opens thousands of connections and just sits there, exhausting your file descriptors. It's a "pick your poison" scenario until you patch.

Technical Appendix

CVSS Score
8.1/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
4.00%
Top 99% most exploited
14,000,000
via Shodan

Affected Systems

OpenSSH 8.5p1 through 9.7p1glibc-based Linux systems

Affected Versions Detail

Product
Affected Versions
Fixed Version
OpenSSH
OpenBSD Foundation
>= 8.5p1, < 9.8p19.8p1
AttributeDetail
CWE IDCWE-364
Attack VectorNetwork (AV:N)
ImpactRoot RCE
CVSS v3.18.1 (High)
Exploit StatusPoC Available / Complex
ComplexityHigh (AC:H)
CWE-364
Signal Handler Race Condition

Signal Handler Race Condition causing memory corruption

Vulnerability Timeline

Original bug (CVE-2006-5051) patched.
2006-09-28
Regression introduced in OpenSSH 8.5p1.
2020-10-01
Qualys discloses CVE-2024-6387.
2024-07-01
OpenSSH 9.8p1 released.
2024-07-01

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.