别让黑客有机可乘!立即了解CVE-2024-6387对OpenSSH的影响与防护措施
概述
CVE-2024-6387
是一个影响OpenSSH的远程代码执行(RCE)漏洞。该漏洞存在于OpenSSH服务器(sshd)的信号处理程序中,由于在处理SIGALRM
信号时的竞争条件,攻击者可以利用该漏洞执行任意代码。该漏洞主要影响基于glibc的Linux系统。
受影响版本8.5p1 <= OpenSSH < 9.8p1
详细的漏洞情况请查阅该篇文章
漏洞原理
当客户端在LoginGraceTime
(默认120秒,旧版本600秒)内未能完成身份验证时,sshd会异步调用SIGALRM处理程序。由于信号处理的竞争条件,攻击者可以通过特定的时间窗口注入恶意代码,实现远程代码执行。表 1 显示了与 CVE-2024-6387 关联的易受攻击版本。
受影响范围
使用 Palo Alto Networks Xpanse 数据,我们观察到 2300 万个 OpenSSH 服务器实例,包括所有版本。截至 2024 年 7 月 1 日,全球有超过 700 万个暴露的 OpenSSH 版本 8.5p1-9.7p1 实例。包括旧版本(4.3p1 及更早版本),我们总共看到 730 万。但是,这可能是对易受攻击版本的过度计算,因为没有可靠的方法来解释向后移植,其中实例正在运行修补版本但显示受影响的版本号。这些数字也不考虑漏洞可能需要的操作系统级规范或配置。表 2 显示了我们对易受攻击版本 8.5p1-9.7p1 的观察结果的地理分布。
漏洞复现
Fofa:protocol="ssh"
quake:app:"OpenSSH"
hunter:app.name="OpenSSH"
该漏洞在github上,大神也发布了poc,如下图:
使用方法也是很简单,不过,该漏洞攻击时间很长,在linux虚拟机环境“平均需要尝试约10,000次才能成功复现,约需3小时左右。
- 把上述的poc克隆到kali主机上,如下图
- 该poc采用C语言编程,所以,我们需要编译。如下图:
- 如何利用该poc,执行如下命令:
./cve-2024-6387 <ip> <port>
例如:
./cve-2024-6387 192.168.31.19 22
执行完命令后,如下图的输出:
批量检查SSH版本脚本
import socket
import argparse
import ipaddress
import threading
from queue import Queue
def is_port_open(ip, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
try:
sock.connect((ip, port))
sock.close()
return True
except:
return False
def get_ssh_banner(ip, port):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
sock.connect((ip, port))
banner = sock.recv(1024).decode().strip()
sock.close()
return banner
except Exception as e:
return str(e)
def check_vulnerability(ip, port, result_queue):
if not is_port_open(ip, port):
result_queue.put((ip, port, 'closed', "Port closed"))
return
banner = get_ssh_banner(ip, port)
if "SSH-2.0-OpenSSH" not in banner:
result_queue.put((ip, port, 'failed', f"Failed to retrieve SSH banner: {banner}"))
return
vulnerable_versions = [
'SSH-2.0-OpenSSH_8.5p1',
'SSH-2.0-OpenSSH_8.6p1',
'SSH-2.0-OpenSSH_8.7p1',
'SSH-2.0-OpenSSH_8.8p1',
'SSH-2.0-OpenSSH_8.9p1',
'SSH-2.0-OpenSSH_9.0p1',
'SSH-2.0-OpenSSH_9.1p1',
'SSH-2.0-OpenSSH_9.2p1',
'SSH-2.0-OpenSSH_9.3p1',
'SSH-2.0-OpenSSH_9.4p1',
'SSH-2.0-OpenSSH_9.5p1',
'SSH-2.0-OpenSSH_9.6p1',
'SSH-2.0-OpenSSH_9.7p1'
]
if any(version in banner for version in vulnerable_versions):
result_queue.put((ip, port, 'vulnerable', f"(running {banner})"))
else:
result_queue.put((ip, port, 'not_vulnerable', f"(running {banner})"))
def main():
parser = argparse.ArgumentParser(description="Check if servers are running a vulnerable version of OpenSSH.")
parser.add_argument("targets", nargs='+', help="IP addresses, domain names, file paths containing IP addresses, or CIDR network ranges.")
parser.add_argument("--port", type=int, default=22, help="Port number to check (default: 22).")
args = parser.parse_args()
targets = args.targets
port = args.port
ips = []
for target in targets:
try:
with open(target, 'r') as file:
ips.extend(file.readlines())
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"❌ [-] Invalid CIDR notation: {target}")
else:
ips.append(target)
result_queue = Queue()
threads = []
for ip in ips:
ip = ip.strip()
thread = threading.Thread(target=check_vulnerability, args=(ip, port, result_queue))
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
total_scanned = len(ips)
closed_ports = 0
not_vulnerable = []
vulnerable = []
while not result_queue.empty():
ip, port, status, message = result_queue.get()
if status == 'closed':
closed_ports += 1
elif status == 'vulnerable':
vulnerable.append((ip, message))
elif status == 'not_vulnerable':
not_vulnerable.append((ip, message))
else:
print(f"⚠️ [!] Server at {ip}:{port} is {message}")
print(f"\n🛡️ Servers not vulnerable: {len(not_vulnerable)}\n")
for ip, msg in not_vulnerable:
print(f" [+] Server at {ip} {msg}")
print(f"\n🚨 Servers likely vulnerable: {len(vulnerable)}\n")
for ip, msg in vulnerable:
print(f" [+] Server at {ip} {msg}")
print(f"\n🔒 Servers with port 22 closed: {closed_ports}")
print(f"\n📊 Total scanned targets: {total_scanned}\n")
if __name__ == "__main__":
main()
修补方案
升级 OpenSSH 到最新版本
要有效解决此漏洞,请升级到最新的 OpenSSH 版本,其中包括必要的修复程序。保持 OpenSSH 安装最新对于安全和防范已知漏洞至关重要。
官方已发布最新版本修复该漏洞,请受影响客户将Openssh更新到安全版本:OpenSSH > 9.8p1。下载链接:
https://www.openssh.com/releasenotes.html
Debian解决方案:
https://security-tracker.debian.org/tracker/CVE-2024-6387
Ubuntu解决方案:
https://ubuntu.com/security/notices/USN-6859-1
Redhat解决方案:
https://access.redhat.com/security/cve/cve-2024-6387
实施临时解决方法
如果无法立即升级,您可以通过在 OpenSSH 配置文件中将 LoginGraceTime 参数设置为 0 来降低风险。这样可以防止未经身份验证的会话保持打开状态并被利用。但是,如果所有连接插槽都被占用,此设置可能会导致拒绝服务。
通过使用seccomp(安全计算模式)
添加额外的安全层,可以进一步减轻风险。seccomp限制了sshd进程可以执行的系统调用,从而限制了攻击面并减少了利用不安全函数(如syslog())的可能性。实现seccomp确保即使触发了漏洞,攻击者执行任意代码的能力也会显著受限。
通过遵循这些缓解策略,您可以保护系统免受此漏洞的影响,并增强OpenSSH配置的整体安全性。
结论
CVE-2024-6387(又名 RegreSSHion)是基于 glibc 的 Linux 系统上 OpenSSH 服务器 (sshd) 中的信号处理程序争用条件漏洞。此漏洞的严重等级为“高”(CVSS 8.1),并可能导致具有 root 权限的未经身份验证的远程代码执行 (RCE)。