Skip to content

Commit 33758f7

Browse files
authored
Merge pull request #26 from mandiant/kerberos-proxy-leak
kerberos, dcerpc: tunnel KDC traffic through pkg/transport
2 parents 5d927b8 + 8eea029 commit 33758f7

113 files changed

Lines changed: 11381 additions & 193 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

KNOWN_ISSUES.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,27 @@ When reporting, please include:
9494

9595
**Status:** By design. UDP tunneling over SOCKS5 is not a gopacket goal. If your workflow genuinely needs UDP over a proxy, use `proxychains` (which hooks libc at a lower level and can intercept UDP sockets) or a full VPN instead of `-proxy`.
9696

97+
### Kerberos KDC traffic under `-proxy`
98+
99+
All Kerberos KDC traffic (AS-REQ/AS-REP, TGS-REQ/TGS-REP, kpasswd) is tunneled through `-proxy` alongside the rest of the tool. This is enforced two ways:
100+
101+
1. The embedded gokrb5 library has been forked in-tree at `pkg/third_party/gokrb5`. Every client constructor (`NewWithPassword`, `NewWithKeytab`, `NewFromCCache`) takes a required `KDCDialer` as its first argument, making proxy-bypass a compile error rather than a runtime leak. Production call sites all pass `kerberos.TransportKDCDialer{}`, which delegates to `pkg/transport`.
102+
2. The synthesized krb5 config in `pkg/kerberos` sets `udp_preference_limit = 1` unconditionally, so KRB5 never even attempts UDP/88 — direct and proxied paths behave identically. Modern KRB5 already needs TCP for PAC-bearing TGS responses; the legacy UDP "optimization" is dropped.
103+
104+
`/etc/krb5.conf` and `$KRB5_CONFIG` are intentionally not consulted; the in-memory config is the only one used. A misconfigured host cannot subvert the proxy/DNS guarantees by re-enabling `dns_lookup_kdc` or lowering `udp_preference_limit`.
105+
106+
If you add a new code path that constructs a gokrb5 client, the type system will require a `KDCDialer`. Use `kerberos.TransportKDCDialer{}`; the alternative `client.DirectDialer{}` exists only as an explicit escape hatch.
107+
108+
### DCERPC Kerberos traffic under `-proxy` (secretsdump DCSync, wmiexec, wmiquery, wmipersist, dcomexec)
109+
110+
The DCERPC Kerberos auth path uses a separate Kerberos library (`oiweiwei/gokrb5.fork/v9` reached via `oiweiwei/go-msrpc/ssp/krb5`) because go-msrpc's RPC machinery embeds it. Three things are required to keep that path leak-free, and the codebase enforces all three at every call site:
111+
112+
1. **KDC dialer on the krb5 config.** `pkg/dcerpc/auth_kerberos.go` and the four DCOM tools set `krbConfig.KDCDialer = kerberos.TransportKDCDialer{}` on every `krb5.Config` they construct. Same dialer, same proxy guarantee as the rest of Kerberos.
113+
2. **DCERPC transport dialer.** Every `dcerpc.Dial(...)` is passed `dcerpc.WithDialer(transport.ContextDialer{})` so the TCP step honors the proxy.
114+
3. **StringBinding form for the OXID-pivot dial.** The second `dcerpc.Dial` per tool uses `"ncacn_ip_tcp:" + target.Host`, not the bare hostname. The prefix forces go-msrpc to parse the address as a StringBinding instead of triggering its hard-coded pre-dial `net.LookupIP`, which would otherwise leak the target hostname to the operator's local resolver. The FQDN is then handed verbatim to the SOCKS5 dialer so resolution stays proxy-side.
115+
116+
Operator-visible behavior under `-proxy`: every byte of AD attack traffic (Kerberos, SMB, DCERPC, kpasswd, DCSync DRSUAPI, DCOM activation, WMI) is sent through the configured SOCKS5 proxy. Tcpdump on the operator host shows no traffic to the AD subnet at all — only SOCKS5 frames to the proxy. Verified end-to-end in a GOAD lab with secretsdump DCSync extracting `krbtgt`, wmiexec returning `whoami` output, and getTGT/getST/GetUserSPNs/GetNPUsers exchanging with the KDC — all silent on the wire, while the same getTGT without `-proxy` immediately emits direct SYN packets to the KDC.
117+
97118
---
98119

99120
## 7. Remaining Gaps (Low Priority)

NOTICE

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,15 @@ the full license text.
3535
A vendored SMB2/SMB3 client library originally authored by Hiroshi Ioka
3636
and contributors, distributed under the BSD 3-Clause License.
3737
Upstream: https://github.com/hirochachacha/go-smb2
38+
39+
* pkg/third_party/gokrb5/
40+
A vendored Kerberos 5 client library originally authored by Jonathan
41+
Turner and contributors, distributed under the Apache License, Version
42+
2.0. See pkg/third_party/gokrb5/LICENSE for the full text. The vendored
43+
copy has been modified by this project: the gokrb5 client constructors
44+
(NewWithPassword, NewWithKeytab, NewFromCCache) now require a KDCDialer
45+
as their first argument, KDC TCP/UDP I/O routes through the supplied
46+
dialer instead of net.DialTimeout, and unused subpackages (service/,
47+
spnego/) have been removed. See the commit log and KNOWN_ISSUES.md for
48+
the full change record.
49+
Upstream: https://github.com/jcmturner/gokrb5

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ require (
99
github.com/go-ldap/ldap/v3 v3.4.12
1010
github.com/google/gopacket v1.1.19
1111
github.com/google/uuid v1.6.0
12+
github.com/hashicorp/go-uuid v1.0.3
13+
github.com/jcmturner/aescts/v2 v2.0.0
14+
github.com/jcmturner/dnsutils/v2 v2.0.0
1215
github.com/jcmturner/gofork v1.7.6
13-
github.com/jcmturner/gokrb5/v8 v8.4.4
16+
github.com/jcmturner/rpc/v2 v2.0.3
1417
github.com/oiweiwei/go-msrpc v1.2.12
1518
github.com/oiweiwei/gokrb5.fork/v9 v9.0.6
1619
github.com/rs/zerolog v1.32.0
@@ -23,12 +26,9 @@ require (
2326

2427
require (
2528
github.com/Azure/go-ntlmssp v0.1.1 // indirect
26-
github.com/hashicorp/go-uuid v1.0.3 // indirect
2729
github.com/indece-official/go-ebcdic v1.2.0 // indirect
28-
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
29-
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
3030
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
31-
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
31+
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
3232
github.com/mattn/go-colorable v0.1.13 // indirect
3333
github.com/mattn/go-isatty v0.0.19 // indirect
3434
github.com/oiweiwei/go-smb2.fork v1.0.0 // indirect

pkg/dcerpc/auth_kerberos.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/oiweiwei/gokrb5.fork/v9/iana/flags"
3434

3535
"github.com/mandiant/gopacket/internal/build"
36+
"github.com/mandiant/gopacket/pkg/kerberos"
3637
"github.com/mandiant/gopacket/pkg/session"
3738
)
3839

@@ -70,6 +71,14 @@ func NewKerberosAuthHandler(creds *session.Credentials, target session.Target, d
7071
krbConfig := krb5.NewConfig()
7172
krbConfig.DCEStyle = true // Required for DCE/RPC
7273

74+
// Route every KDC call this auth handler makes through pkg/transport.
75+
// Without this, go-msrpc's krb5 SSP calls oiweiwei/gokrb5.fork/v9's
76+
// client which falls back to net.Dial and leaks the operator IP to the
77+
// KDC — see KNOWN_ISSUES.md §8 (Kerberos KDC traffic under -proxy).
78+
// kerberos.TransportKDCDialer structurally satisfies the v9 KDCDialer
79+
// interface (same Dial signature).
80+
krbConfig.KDCDialer = kerberos.TransportKDCDialer{}
81+
7382
// Check if we should use ccache (no password provided)
7483
if creds.Password == "" && creds.Hash == "" {
7584
// First check KRB5CCNAME environment variable
@@ -195,6 +204,8 @@ func NewKerberosAuthHandlerMultiRealm(creds *session.Credentials, target session
195204

196205
krbConfig := krb5.NewConfig()
197206
krbConfig.DCEStyle = true
207+
// Same proxy-routing requirement as NewKerberosAuthHandler.
208+
krbConfig.KDCDialer = kerberos.TransportKDCDialer{}
198209

199210
// Use ccache-based credential
200211
ccachePath := os.Getenv("KRB5CCNAME")

pkg/kerberos/asrep.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ import (
2020

2121
"github.com/mandiant/gopacket/pkg/transport"
2222

23-
"github.com/jcmturner/gokrb5/v8/config"
24-
"github.com/jcmturner/gokrb5/v8/iana/nametype"
25-
"github.com/jcmturner/gokrb5/v8/messages"
26-
"github.com/jcmturner/gokrb5/v8/types"
23+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/config"
24+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/iana/nametype"
25+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/messages"
26+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/types"
2727
)
2828

2929
// GetASREP fetches the AS-REP for a user and returns the hash.
@@ -39,6 +39,11 @@ func GetASREP(username, domain, kdcHost string, format ...string) (string, error
3939

4040
cfg := config.New()
4141
cfg.LibDefaults.DefaultRealm = realm
42+
// Defense-in-depth: this file dials the KDC via transport.Dial directly
43+
// (gokrb5's sendToKDC is never invoked), so the opsec keys are currently
44+
// no-ops here. Stamp them anyway so a future refactor introducing a
45+
// gokrb5 client.Client to this path inherits the proxy/DNS guarantees.
46+
ApplyKrb5OpsecDefaults(cfg)
4247
// Request RC4 (etype 23) for faster cracking - matches Impacket behavior
4348
cfg.LibDefaults.DefaultTktEnctypes = []string{"rc4-hmac"}
4449
cfg.LibDefaults.DefaultTktEnctypeIDs = []int32{23}
@@ -62,7 +67,7 @@ func GetASREP(username, domain, kdcHost string, format ...string) (string, error
6267
}
6368

6469
// Connect to KDC (Port 88)
65-
conn, err := transport.Dial("tcp", fmt.Sprintf("%s:%d", kdcHost, 88))
70+
conn, err := transport.Dial("tcp", FormatKDC(kdcHost, "88"))
6671
if err != nil {
6772
return "", fmt.Errorf("failed to connect to KDC: %v", err)
6873
}

pkg/kerberos/client.go

Lines changed: 111 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,119 @@ import (
2121
"encoding/binary"
2222
"encoding/hex"
2323
"fmt"
24+
"net"
2425
"os"
2526
"strings"
2627

27-
"github.com/jcmturner/gokrb5/v8/client"
28-
"github.com/jcmturner/gokrb5/v8/config"
29-
"github.com/jcmturner/gokrb5/v8/credentials"
30-
"github.com/jcmturner/gokrb5/v8/gssapi"
31-
"github.com/jcmturner/gokrb5/v8/keytab"
32-
"github.com/jcmturner/gokrb5/v8/messages"
33-
"github.com/jcmturner/gokrb5/v8/types"
3428
"github.com/mandiant/gopacket/internal/build"
3529
"github.com/mandiant/gopacket/pkg/session"
30+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/client"
31+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/config"
32+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/credentials"
33+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/gssapi"
34+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/keytab"
35+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/messages"
36+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/types"
37+
"github.com/mandiant/gopacket/pkg/transport"
3638
)
3739

40+
// TransportKDCDialer routes every KDC connection (AS, TGS, kpasswd) through
41+
// pkg/transport, so a configured -proxy / ALL_PROXY tunnels Kerberos traffic
42+
// in lockstep with the rest of the tool. Without this, gokrb5's default path
43+
// uses raw net.Dial and leaks the operator's real source IP to the KDC.
44+
//
45+
// Every gokrb5 client constructor in our fork (NewWithPassword, NewWithKeytab,
46+
// NewFromCCache) requires a KDCDialer; passing this type is how the rest of
47+
// the codebase satisfies that contract while keeping the proxy guarantee.
48+
type TransportKDCDialer struct{}
49+
50+
func (TransportKDCDialer) Dial(network, address string) (net.Conn, error) {
51+
return transport.DialTimeout(network, address, 10)
52+
}
53+
54+
// The opsec invariants every gokrb5 config in this project must enforce:
55+
//
56+
// - dns_lookup_realm / dns_lookup_kdc = false → no SRV lookups via the OS
57+
// resolver, which would bypass our KDCDialer.
58+
// - udp_preference_limit = 1 → TCP-only KDC. Modern KRB5 already requires
59+
// TCP for PAC-bearing TGS responses >1500 bytes; forcing it uniformly
60+
// deletes a code path and keeps direct vs proxied behavior identical.
61+
//
62+
// /etc/krb5.conf and $KRB5_CONFIG are intentionally never consulted; the
63+
// in-memory cfg is the only source. ApplyKrb5OpsecDefaults is the choke point
64+
// for programmatic callers; SynthesizeKrb5Config is the choke point for
65+
// string-template callers. Anything else risks drift.
66+
67+
// ApplyKrb5OpsecDefaults stamps the proxy-/DNS-safety invariants onto a
68+
// programmatically-built *config.Config. Call it after config.New() and
69+
// before constructing a gokrb5 client. Safe to call repeatedly.
70+
func ApplyKrb5OpsecDefaults(cfg *config.Config) {
71+
cfg.LibDefaults.UDPPreferenceLimit = 1
72+
cfg.LibDefaults.DNSLookupKDC = false
73+
cfg.LibDefaults.DNSLookupRealm = false
74+
}
75+
76+
// FormatKDC normalizes a "host" or "host:port" string into a canonical
77+
// "host:port" using net.JoinHostPort, which correctly brackets IPv6 literals.
78+
// Required so that callers passing "[::1]:88", bare "::1", "10.0.0.1:8888",
79+
// or "dc.example.com" all produce valid krb5.conf entries — the naïve
80+
// fmt.Sprintf("%s:88", kdc) form mangles every IPv6 case.
81+
//
82+
// A user-supplied port is preserved: "10.0.0.1:8888" stays on 8888. The
83+
// defaultPort applies only when input has no port (bare host) or a malformed
84+
// trailing-colon form ("host:"). This matches operator expectation for
85+
// lab/tunnel routing where the KDC may not be on the canonical 88/464.
86+
func FormatKDC(kdc, defaultPort string) string {
87+
host, port, err := net.SplitHostPort(kdc)
88+
if err != nil {
89+
// Bare host: IPv4 ("10.0.0.1"), hostname ("dc.example.com"),
90+
// unbracketed IPv6 ("::1"), or bracketed-but-portless IPv6 ("[::1]").
91+
// Strip wrapping brackets before re-joining so JoinHostPort doesn't
92+
// double-bracket ("[::1]" → "[[::1]]:88"). TrimPrefix/TrimSuffix is
93+
// idempotent if the brackets aren't present.
94+
host = strings.TrimSuffix(strings.TrimPrefix(kdc, "["), "]")
95+
port = defaultPort
96+
} else if port == "" {
97+
// "host:" — port-less colon-suffix form.
98+
port = defaultPort
99+
}
100+
return net.JoinHostPort(host, port)
101+
}
102+
103+
// SynthesizeKrb5Config builds the in-memory krb5.conf text for callers that
104+
// need only the KDC. For kpasswd callers, use SynthesizeKrb5ConfigWithKpasswd.
105+
// kdc may be a bare host, host:port, or bracketed IPv6 — FormatKDC normalizes.
106+
func SynthesizeKrb5Config(realm, kdc string) string {
107+
return fmt.Sprintf(`
108+
[libdefaults]
109+
default_realm = %s
110+
dns_lookup_realm = false
111+
dns_lookup_kdc = false
112+
udp_preference_limit = 1
113+
[realms]
114+
%s = {
115+
kdc = %s
116+
}
117+
`, realm, realm, FormatKDC(kdc, "88"))
118+
}
119+
120+
// SynthesizeKrb5ConfigWithKpasswd is SynthesizeKrb5Config plus a kpasswd_server
121+
// per-realm line. Both kdc and kpasswdServer accept the same input forms.
122+
func SynthesizeKrb5ConfigWithKpasswd(realm, kdc, kpasswdServer string) string {
123+
return fmt.Sprintf(`
124+
[libdefaults]
125+
default_realm = %s
126+
dns_lookup_realm = false
127+
dns_lookup_kdc = false
128+
udp_preference_limit = 1
129+
[realms]
130+
%s = {
131+
kdc = %s
132+
kpasswd_server = %s
133+
}
134+
`, realm, realm, FormatKDC(kdc, "88"), FormatKDC(kpasswdServer, "464"))
135+
}
136+
38137
// OID for Kerberos V5 (GSSAPI)
39138
var oidKerberos = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
40139

@@ -102,18 +201,7 @@ func NewClientFromSession(creds *session.Credentials, target session.Target, dcI
102201
realm = ccacheRealm
103202
}
104203

105-
// Create config with the correct realm from ccache
106-
cfgStr := fmt.Sprintf(`
107-
[libdefaults]
108-
default_realm = %s
109-
dns_lookup_realm = false
110-
dns_lookup_kdc = false
111-
[realms]
112-
%s = {
113-
kdc = %s:88
114-
}
115-
`, realm, realm, kdc)
116-
cfg, err := config.NewFromString(cfgStr)
204+
cfg, err := config.NewFromString(SynthesizeKrb5Config(realm, kdc))
117205
if err != nil {
118206
return nil, fmt.Errorf("failed to create krb5 config: %v", err)
119207
}
@@ -126,7 +214,7 @@ func NewClientFromSession(creds *session.Credentials, target session.Target, dcI
126214
}
127215

128216
// Try to create client from ccache (requires TGT)
129-
cl, err := client.NewFromCCache(ccache, cfg)
217+
cl, err := client.NewFromCCache(TransportKDCDialer{}, ccache, cfg)
130218
if err == nil {
131219
krbClient.KrbClient = cl
132220
}
@@ -136,18 +224,7 @@ func NewClientFromSession(creds *session.Credentials, target session.Target, dcI
136224
}
137225
}
138226

139-
// Create config for non-ccache cases
140-
cfgStr := fmt.Sprintf(`
141-
[libdefaults]
142-
default_realm = %s
143-
dns_lookup_realm = false
144-
dns_lookup_kdc = false
145-
[realms]
146-
%s = {
147-
kdc = %s:88
148-
}
149-
`, realm, realm, kdc)
150-
cfg, err := config.NewFromString(cfgStr)
227+
cfg, err := config.NewFromString(SynthesizeKrb5Config(realm, kdc))
151228
if err != nil {
152229
return nil, fmt.Errorf("failed to create krb5 config: %v", err)
153230
}
@@ -164,7 +241,7 @@ func NewClientFromSession(creds *session.Credentials, target session.Target, dcI
164241
if err != nil {
165242
return nil, fmt.Errorf("failed to load keytab %s: %v", creds.Keytab, err)
166243
}
167-
krbClient.KrbClient = client.NewWithKeytab(creds.Username, realm, kt, cfg, client.DisablePAFXFAST(true))
244+
krbClient.KrbClient = client.NewWithKeytab(TransportKDCDialer{}, creds.Username, realm, kt, cfg, client.DisablePAFXFAST(true))
168245
return krbClient, nil
169246
}
170247

@@ -173,7 +250,7 @@ func NewClientFromSession(creds *session.Credentials, target session.Target, dcI
173250
// Check if it's an AES key (64 hex chars)?
174251
// Note: Manual Keytab construction is blocked by unexported keytab.entry in gokrb5 v8.
175252
// For now, treat everything as a password.
176-
krbClient.KrbClient = client.NewWithPassword(creds.Username, realm, creds.Password, cfg, client.DisablePAFXFAST(true))
253+
krbClient.KrbClient = client.NewWithPassword(TransportKDCDialer{}, creds.Username, realm, creds.Password, cfg, client.DisablePAFXFAST(true))
177254
return krbClient, nil
178255
}
179256
return nil, fmt.Errorf("no valid kerberos credentials found (set KRB5CCNAME, provide password, or use -keytab)")

pkg/kerberos/getpac.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ import (
2121
"strings"
2222
"time"
2323

24-
"github.com/jcmturner/gokrb5/v8/config"
25-
"github.com/jcmturner/gokrb5/v8/crypto"
26-
"github.com/jcmturner/gokrb5/v8/iana"
27-
"github.com/jcmturner/gokrb5/v8/iana/flags"
28-
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
29-
"github.com/jcmturner/gokrb5/v8/iana/nametype"
30-
"github.com/jcmturner/gokrb5/v8/iana/patype"
31-
"github.com/jcmturner/gokrb5/v8/messages"
32-
"github.com/jcmturner/gokrb5/v8/types"
24+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/config"
25+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/crypto"
26+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/iana"
27+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/iana/flags"
28+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/iana/msgtype"
29+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/iana/nametype"
30+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/iana/patype"
31+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/messages"
32+
"github.com/mandiant/gopacket/pkg/third_party/gokrb5/types"
3333
)
3434

3535
// PACRequest holds configuration for a PAC retrieval request.
@@ -48,9 +48,13 @@ type PACRequest struct {
4848
func GetPAC(req *PACRequest) (*PAC, error) {
4949
realm := strings.ToUpper(req.Domain)
5050

51-
// Build kerberos config
51+
// Build kerberos config. Defense-in-depth: networking in this file is
52+
// hand-rolled via sendKDCRequest → transport.Dial, so the opsec keys
53+
// are no-ops here today. Stamp them so future use of a gokrb5 client
54+
// inherits the proxy/DNS guarantees automatically.
5255
cfg := config.New()
5356
cfg.LibDefaults.DefaultRealm = realm
57+
ApplyKrb5OpsecDefaults(cfg)
5458
cfg.LibDefaults.DefaultTktEnctypes = []string{"aes256-cts-hmac-sha1-96", "aes128-cts-hmac-sha1-96", "rc4-hmac"}
5559
cfg.LibDefaults.DefaultTktEnctypeIDs = []int32{18, 17, 23}
5660
cfg.LibDefaults.DefaultTGSEnctypes = []string{"aes256-cts-hmac-sha1-96", "aes128-cts-hmac-sha1-96", "rc4-hmac"}

0 commit comments

Comments
 (0)