Two compounding bugs in wmiexec / atexec / smbexec / dcomexec made
the output-retrieval loop return early on any command that didn't
finish within the first 100ms poll, leaking the temp file in ADMIN$
/ C$. Issue #22 reports the symptom for wmiexec (systeminfo, ping);
the same broken pattern existed in all four tools.
1. Wrong call site. The polling loop treated a sharing-violation
on smbClient.Cat as the signal "command still running." Cat
opens with FILE_SHARE_READ-compatible access — it succeeds
against the writer on the first poll and returns the file as
it currently exists (typically empty). The conflict actually
lives on Rm: deleting the file requires DELETE access, which
conflicts with the writer's share mode. Moved the sharing-
violation check from Cat to Rm. Matches Impacket's wmiexec.py.
2. Dead string match. The check was
strings.Contains(err.Error(), "STATUS_SHARING_VIOLATION"). The
underlying smb2 library's NtStatus.Error() returns only the
human-readable description ("A file cannot be opened because
the share access flags are incompatible.") — the literal
constant name never appears in err.Error(), so the check could
never fire. Same issue for STATUS_OBJECT_NAME_NOT_FOUND in the
not-found branch (further muddled by smb2/conn.go translating
that NTSTATUS to os.ErrNotExist before wrapping).
Added typed helpers in pkg/smb (IsSharingViolation, IsNotFound)
that unwrap through *os.PathError and match on
*smb2.ResponseError.Code plus the os.ErrNotExist sentinel.
NTSTATUS values are hardcoded since the smb2/internal/erref
package can't be imported from outside the smb2 tree.
The dcomexec "broken / connection reset / use of closed" branch
stays string-matched — those errors come from net, not smb2.
Thanks to @aimogging in #22 for the diagnosis and proof-of-concept
in #29; this change applies the same Cat-vs-Rm insight across all
four exec tools and replaces the err.Error() substring matching
with typed-error helpers so future smb2 library changes don't
silently break the check again.
Verified against GOAD winterfell: wmiexec whoami / systeminfo /
ping -n 4 1.1.1.1 all return full output, exit 0, no ADMIN$
residue, both directly from the operator box and over SOCKS5H
proxy.
Fixes#6. The module was declared as `module gopacket` in go.mod,
which is not a canonical import path. External projects could not
`go get github.com/mandiant/gopacket` to use any of the 24
protocol packages as a library; the only workaround was to clone
the repo and add a `replace` directive to their own go.mod.
This commit:
- Sets `module github.com/mandiant/gopacket` in go.mod.
- Rewrites 434 import statements across 157 files from the bare
`gopacket/...` prefix to `github.com/mandiant/gopacket/...`.
Pure mechanical change, no behavior difference. Makes the README's
library story (pkg/ directory, 24 reusable packages) actually
usable from external code.