CVE-2024-6387: Critical OpenSSH Vulnerability Allowing Root Access

CODE SECURITY
Jul 1, 2024

Description


The Qualys Threat Research Unit (TRU) found a serious vulnerability in OpenSSH's server on glibc-based Linux systems. This unauthenticated Remote Code Execution (RCE) vulnerability can give attackers full root access and affects the default configuration without needing user interaction. It's a regression of a previously fixed issue (CVE-2006-5051) and was reintroduced in OpenSSH 8.5p1 in October 2020.


Affected OpenSSH Versions


  • Versions earlier than 4.4p1: OpenSSH versions earlier than 4.4p1 are vulnerable to this signal handler race condition unless they have been patched for CVE-2006-5051 and CVE-2008-4109.

  • Versions 4.4p1 to 8.4p1: Versions from 4.4p1 up to, but not including, 8.5p1 are not vulnerable due to a transformative patch for CVE-2006-5051, which made a previously unsafe function secure.

  • Versions 8.5p1 to 9.7p1: The vulnerability resurfaces in versions from 8.5p1 up to, but not including, 9.8p1 due to the accidental removal of a critical component in a function.


Detection


This script enables the scanning of multiple IP addresses, domain names, and CIDR network ranges to detect potential vulnerabilities and ensures rapid security of your infrastructure.

Save this below code as cve_2024-6387_check.py


#!/usr/bin/env python3
import socket
import argparse
import ipaddress
import threading
import time
from queue import Queue
from concurrent.futures import ThreadPoolExecutor

VERSION = "0.5"
BLUE = "\033[94m"
GREEN = "\033[92m"
RED = "\033[91m"
ORANGE = "\033[33m"
ENDC = "\033[0m"

progress_lock = threading.Lock()
progress_counter = 0
total_hosts = 0

def display_banner():
    banner = rf"""{BLUE}
    __   ____________  _____   _______   _   __
   / /  /  _/_  __/  |/ / / | / /  _/ | / | / /
  / /___/ /  / / / /|_/ / /| |/ // / | |/ |/ /
 /____/___/ /_/ /_/  /_/_/ |___/___/ |__/|__/
    {ENDC}
    {RED}Vulnerability Checker{ENDC}
    v{VERSION} / Alex Hagenah / @xaitax / ah@primepage.de
"""
    print(banner)

def get_ssh_banner(ip, port, timeout):
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        sock.connect((ip, port))
        banner = sock.recv(1024).decode('errors'='ignore').strip()
        sock.close()
        return banner
    except Exception as e:
        return None

def check_vulnerability(ip, port, timeout, result_queue):
    global progress_counter
    banner = get_ssh_banner(ip, port, timeout)
    
    if not banner:
        result_queue.put((ip, 'closed', 'Port closed'))
        with progress_lock:
            progress_counter += 1
        return

    if "SSH-2.0-OpenSSH" not in banner:
        result_queue.put((ip, 'unknown', f'Failed to retrieve SSH banner: {banner}'))
        with progress_lock:
            progress_counter += 1
        return
        
    vulnerable_versions = [
        'SSH-2.0-OpenSSH_1',
        'SSH-2.0-OpenSSH_2',
        'SSH-2.0-OpenSSH_3',
        'SSH-2.0-OpenSSH_4.0',
        'SSH-2.0-OpenSSH_4.1',
        'SSH-2.0-OpenSSH_4.2',
        'SSH-2.0-OpenSSH_4.3',
        'SSH-2.0-OpenSSH_8.5',
        'SSH-2.0-OpenSSH_8.6',
        'SSH-2.0-OpenSSH_8.7',
        'SSH-2.0-OpenSSH_8.8',
        'SSH-2.0-OpenSSH_8.9',
        'SSH-2.0-OpenSSH_9.0',
        'SSH-2.0-OpenSSH_9.1',
        'SSH-2.0-OpenSSH_9.2',
        'SSH-2.0-OpenSSH_9.3',
        'SSH-2.0-OpenSSH_9.4',
        'SSH-2.0-OpenSSH_9.5',
        'SSH-2.0-OpenSSH_9.6',
        'SSH-2.0-OpenSSH_9.7',
    ]

    excluded_versions = [
        'SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.10',
        'SSH-2.0-OpenSSH_9.3p1 Ubuntu-3ubuntu3.6',
        'SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3',
    ]

    if any(version in banner for version in vulnerable_versions) and not any(excluded in banner for excluded in excluded_versions):
        result_queue.put((ip, 'vulnerable', banner))
    else:
        result_queue.put((ip, 'not_vulnerable', f'{banner}'))
    
    with progress_lock:
        progress_counter += 1

def process_ip_list(ip_list_file):
    try:
        with open(ip_list_file, 'r') as file:
            ips = [line.strip() for line in file.readlines()]
        return [ip for ip in ips if ip]
    except FileNotFoundError:
        print(f"{RED}[-]{ENDC} Could not find file: {ip_list_file}")
        return []

def main():
    global total_hosts
    display_banner()
    parser = argparse.ArgumentParser(description="Check running versions of OpenSSH (CVE-2024-6387).")
    parser.add_argument("targets", nargs='*', help="IP addresses, domain names, CIDR networks, or file paths.")
    parser.add_argument("-t", "--timeout", type=float, default=1.0, help="Connection timeout in seconds (default: 1.0).")
    parser.add_argument("-l", "--list", help="File containing a list of IP addresses to check.")
    parser.add_argument("--port", type=int, default=22, help="Connection timeout in seconds (default: 1 second).")

    args = parser.parse_args()
    targets = args.targets
    port = args.port
    timeout = args.timeout

    ips = []

    if args.list:
        ips.extend(process_ip_list(args.list))

    for target in targets:
        try:
            with open(target, 'r') as file:
                ips.extend(file.read().splitlines())
        except IOError:
            if '/' in target:
                try:
                    network = ipaddress.ip_network(target, strict=False)
                    ips.extend([str(ip) for ip in network.hosts()])
                except ValueError:
                    print(f"{RED}[-]{ENDC} Invalid CIDR notation: {target}")
            else:
                ips.append(target)
    
    result_queue = Queue()
    total_hosts = len(ips)

    max_workers = 100
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(check_vulnerability, ip, port, timeout, result_queue) for ip in ips]
        
        while any(future.running() for future in futures):
            with progress_lock:
                print(f"\rProgress: {progress_counter}/{total_hosts} hosts scanned", end="")
            time.sleep(0.1)

    print(f"\rProgress: {progress_counter}/{total_hosts} hosts scanned")
    
    total_scanned = len(ips)
    closed_ports = []
    unknown = []
    not_vulnerable = []
    vulnerable = []

    while not result_queue.empty():
        ip, status, message = result_queue.get()
        if status == 'closed':
            closed_ports += [1]
        elif status == 'unknown':
            unknown.append((ip, message))
        elif status == 'vulnerable':
            vulnerable.append((ip, message))
        else:
            not_vulnerable.append((ip, message))
    
    print(f"\n{BLUE}[*]{ENDC} Servers not vulnerable: {len(not_vulnerable)}")
    for ip, msg in not_vulnerable:
        print(f"{GREEN}[+]{ENDC} Server at {ip}: {msg}")
    print(f"\n{RED}[+]{ENDC} Servers likely vulnerable: {len(vulnerable)}")
    for ip, msg in vulnerable:
        print(f"{RED}[+]{ENDC} Server at {ip}: {msg}")
    print(f"\n{ORANGE}[+]{ENDC} Servers with unknown SSH Version: {len(unknown)}")
    for ip, msg in unknown:
        print(f"{ORANGE}[+]{ENDC} Server at {ip}: {msg}")
    print(f"\n{BLUE}[*]{ENDC} Servers with port {port} closed: {len(closed_ports)}")
    print(f"{BLUE}[*]{ENDC} Total scanned targets: {total_scanned}\n")

if __name__ == "__main__":
    main()


Usage


Running script for individual IP address

python cve-2024-6387_Check.py <targets> [--port PORT]


Examples


Single IP

python cve-2024-6387_Check.py 192.168.1.1


Running script for multiple IPs

python cve-2024-6387_Check.py -l ip_list.txt


Running script for multiple IPs and domains

python cve-2024-6387_Check.py example.com 192.168.1.2


Running script for CIDR range

python cve-2024-6387_Check.py 192.168.1.0/24


Running script with custom port

python cve-2024-6387_Check.py example.com --port 2222


What all it will check


  • Rapid Scanning: Quickly scan multiple IP addresses, domain names, and CIDR ranges for the CVE-2024-6387 vulnerability.

  • Multi-threading: Uses threading for concurrent checks, significantly reducing scan times.

  • Banner Retrieval: Efficiently retrieves SSH banners without authentication.

  • Port Check: Identifies closed ports and provides a summary of non-responsive hosts.

  • Detailed Output: Provides clear, emoji-coded output summarizing scan results.


Scan Results


The script will provide a summary of the scanned targets:

  • Vulnerable: Servers running a vulnerable version of OpenSSH.

  • Not Vulnerable: Servers running a non-vulnerable version of OpenSSH.

  • Closed Ports: Total number of targets with port 22 (or specified port) closed.


Sample Output



Check out best code review tools


Credit


Credits to Alexander Hagenah, Cybersecurity Leader, for rapidly developing the detection script for the CVE-2024-6387 vulnerability. With over two decades of experience in cybersecurity, he has evolved from an ethical hacker to an international cybersecurity strategist.

https://primepage.de/


On this page

Label

Ship clean & secure code faster

Avoid 5 different tools. Get one unified AI platform for code reviews, quality, and security.

Ship clean & secure code faster

Avoid 5 different tools. Get one unified AI platform for code reviews, quality, and security.

Ship clean & secure code faster

Avoid 5 different tools. Get one unified AI platform for code reviews, quality, and security.