Releases: StrongWind1/NFSWolf
Release list
v1.0.0 -- Protocol crates on crates.io, auth enumeration, IANA registries, NFSv4 escape
The v1.0.0 release ships the eight protocol crates to crates.io as standalone libraries, adds comprehensive auth flavor enumeration, complete IANA RPC registries, 6 new analyzer findings, NFSv4 escape via LOOKUPP, and OS fingerprinting via EXCHANGE_ID.
Install
# From crates.io
cargo install nfswolf
# Prebuilt binaries (pick your platform below)| File | Link | FUSE | When to use |
|---|---|---|---|
nfswolf-linux-x86_64 |
musl, static | no | Zero-dep binary, any Linux kernel |
nfswolf-linux-x86_64-full |
glibc, dynamic | yes | nfswolf mount (requires libfuse3) |
nfswolf-linux-arm64 / -full |
same split | same | ARM64 Linux |
nfswolf-macos-universal |
fat binary | macFUSE | macOS (Apple Silicon + Intel) |
nfswolf-windows-x86_64-msvc.exe |
MSVC | no | Windows x86_64 |
Highlights
Protocol crates published to crates.io
All 8 protocol crates are now standalone libraries on crates.io, usable independently of the nfswolf binary:
onc-xdr-derive -- onc-xdr -- onc-rpc-client -- onc-rpcbind -- nfs-mount -- nfs-v2 -- nfs-v3 -- nfs-v4
Auth flavor enumeration
- SECINFO GSS mechanism decoding (krb5/krb5i/krb5p from OID, not pseudo-flavors)
- Scanner v4 SECINFO + v3 MNT auth probing on every export
AUTH_TOOWEAKoracle (F-1.8): detects Kerberos enforcement at the NFS layerAUTH_SHORTfinding (F-3.9): replayable session credentials from wire captures
New analyzer checks
| Finding | What it detects |
|---|---|
| F-1.8 | Kerberos enforced via AUTH_TOOWEAK (MOUNT accepts AUTH_SYS, GETATTR rejects) |
| F-3.7 | AUTH_DH advertised (cryptographically broken, RFC 5531) |
| F-3.8 | RPC-with-TLS supported (RFC 9289 STARTTLS probe) |
| F-3.9 | AUTH_SHORT session credentials (replayable without UID/GID) |
| F-4.6 | Unrestricted chown via PATHCONF (ownership hijacking) |
| F-5.7 | Case-insensitive filesystem (Windows NFS / NTFS fingerprint) |
| F-5.8 | Export root attributes leaked via AUTH_NONE GETATTR |
Complete IANA registries
- 1251 RPC program numbers (was 13) -- every assigned program in a portmapper DUMP decoded by name
- 19 auth flavor numbers (AUTH_NONE through AUTH_TLS, legacy flavors, krb5 pseudo-flavors)
- 19 auth status codes (AUTH_OK through RPCSEC_GSS_UNKNOWN_MESSAGE)
NFSv4 enhancements
- Escape via LOOKUPP -- pseudo-filesystem traversal to the real root without MOUNT
- OS fingerprinting via EXCHANGE_ID vendor/version strings
- SECINFO_NO_NAME fallback + WRONGSEC oracle for auth negotiation
- pNFS topology enumeration (GETDEVICEINFO/GETDEVICELIST)
- All 37 v4.0 operations + v4.1/v4.2 extensions wired
- Handle acquisition matrix: MOUNT v1/v3 cross-version with pad/trim variants
Crate restructuring
- Eight-crate rename from
nfswolf-*to vendor-neutral names (onc-xdr,onc-rpc-client,nfs-v3, etc.) - Portmapper/rpcbind extracted into
onc-rpcbind; MOUNT extracted intonfs-mount - NFSv2 on PooledTransport (pooling, circuit breaker, stealth, SOCKS5)
Other
- Scanner security notes for 15+ sideband RPC programs (NLM, NSM, NIS, RQUOTA, etc.)
- 543 tests across 8 workspace crates and the binary
- Trusted publishing CI for future crates.io releases
Verify
sha256sum -c SHA256SUMS --ignore-missing
cosign verify-blob \
--certificate-identity-regexp "^https://github\\.com/StrongWind1/NFSWolf/" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--signature SHA256SUMS.sig \
SHA256SUMSFull Changelog: v0.8.0...v1.0.0
v0.8.0
What's New in v0.8.0
Cross-Version Parity
- NFSv2 identity change --
uid,gid,hostname, andimpersonatenow work in the v2 shell by reconnecting with new credentials. Previously v2 identity was fixed at connect time. - NFSv2 fattr --
statnow shows correctrdev,fsid, and disk usage instead of zeros. - NFSv2 escape guards --
export_is_fs_rootcheck prevents false positives; BTRFS subvolume sweep now runs on v2 (previously v3-only). - NFSv2 default export -- v2 shell defaults to
/when no export specified, matching v3. - NFSv4 local commands --
handle,lcd,lls,lpwd,lmkdir,historynow work in the v4 shell.
Shell Aliases
All work across v2, v3, and v4 with tab completion:
| Alias | Command |
|---|---|
download / upload |
get / put |
ll |
ls -a (full columns) |
dir |
ls |
type |
cat |
del |
rm |
rename |
mv |
copy |
cp |
id |
whoami |
su |
impersonate |
Bug Fixes
- Analyzer proxy bypass -- per-export clients now inherit
--proxy,--hostname, and--aux-gids. Previously silently bypassed the SOCKS5 proxy and hardcoded the hostname. catvsgetcredential gap --getnow performs the same credential escalation ascat. Previouslycat /etc/shadowcould succeed whileget /etc/shadowfailed with NFS3ERR_ACCES.- NFSv4
catbinary corruption -- raw byte output instead of lossy UTF-8 conversion. - Pool
blocking_lockpanic --try_lockinstead ofblocking_lockin pool checkin, which panicked inside the tokio runtime. - Analyzer pagination --
check_nohideandcheck_symlink_preconditionsnow iterate all READDIRPLUS pages. - Analyzer shared pool -- one pool shared across exports instead of fresh pool per export.
Protocol Crate Improvements
Nfs2Error:is_permission_denied(),is_stale(),is_not_found()predicatesDisplayforNfsStat(v2) andNfs4Status(v4) with RFC error namesNfs2Client::into_transport(), tracing on v2 call failures- Removed dead
RpcbindTimeand duplicateOpaque::from_vec()
Code Quality
- Consolidated 4 recursive walkers into generic
walk_recursive()with filter closures - Deduplicated rwx formatting into shared
format_rwx() - 480 tests, all passing across 3 feature matrices
Full Changelog
https://github.com/StrongWind1/NFSWolf/blob/main/CHANGELOG.md#080---2026-07-28
v0.7.0 -- Six-crate workspace, NFSv2 shell, 469 tests
Complete workspace refactor and protocol expansion. Every code path live-tested against 6 NFS servers across ext4, XFS, BTRFS, NFSv2, NFSv3, and NFSv4.
Architecture
- Six-crate workspace: nfswolf-xdr, nfswolf-xdr-derive, nfswolf-rpc, nfswolf-nfs2, nfswolf-nfs3, nfswolf-nfs4. The
RpcTransporttrait is the single seam between wire protocol and connection policy. - NFSv3 domain API:
FileHandle,FileAttrs,Nfs3Errorwith oracle classification (is_handle_oracle_hit/is_handle_oracle_miss) and transient-error discrimination. - Evidence-driven credential ladder: file owner first, then caller+owner-group, then root, then READDIRPLUS-harvested identities ranked by frequency, then service accounts. Mode-bit pruning skips rungs that provably can't succeed.
Protocol coverage
- NFSv2: all 18 procedures, MOUNT v1 (NULL/MNT/UMNT/EXPORT), shell with 44 commands including
--handleMOUNT bypass and-cscripted mode. - NFSv3: all 22 procedures, MOUNT v3 (all 6), FUSE mount with auto-UID ladder, connection pool, circuit breaker, stealth pacing.
- NFSv4: 9 COMPOUND operations (PUTROOTFH, PUTFH, PUTPUBFH, LOOKUP, GETATTR, GETFH, SECINFO, READDIR, READ), 22 named status codes, cookieverf pagination fix.
- RPC: AUTH_SYS with 16-GID cap, portmapper v2 (DUMP/GETPORT), rpcbind v3/v4 (GETTIME/GETSTAT/GETADDR), auth_stat values 8-14.
Escape and brute-handle
- escape: automatic filesystem detection (ext4 inode 2, XFS inode 128/64/32, BTRFS subvol 5/256+). Probe order: ext4 first, XFS second, BTRFS last. Automatic NFSv2 fallback for v2-only servers. Reads
/etc/shadowvia shadow GID on success. - brute-handle: full cross-product
(inode_start..=inode_end) x (gen_start..=gen_end)sweep. Reports ALL discovered handles, not just the root. BTRFS subvol sweep as fallback. Automatic NFSv2 fallback. STALE/BADHANDLE oracle for format validation. - scan --auto-escape: works with NFSv2-only servers. Prints correct
--nfs-version 2rerun hints.
Security analysis
- F-1.7 mixed auth flavor downgrade detection (AUTH_SYS + Kerberos on same export).
- 21 findings detected by the analyzer, 14 exercised implicitly by protocol operations.
- WebNFS public handle probing with SNEGO-MCL flavor enumeration.
- Scanner wires EXPORT enumeration after UDP portmapper discovery.
Quality
- 469 tests (227 protocol crate unit tests, 106 integration tests, 22 proptest fuzz tests, 114 binary unit tests).
- Lint policy: pedantic clippy deny, 14 forbid-level compiler lints,
wildcard_importsdeny,use_selfwarn. - Zero TODO/FIXME markers. Zero unannotated
unwrap()/expect()in production code. - RFC compliance review: 57 RFCs audited against the codebase.
Bug fixes since v0.6.0
- XDR
Vec<u32>::unpackallocation amplification from forged wire lengths. - NFSv2
DirOpRes::Packwrong union encoding (wrote 100 extra bytes on error). - NFSv2 missing
NFSERR_WFLUSH=99. - NFSv2 shell
-cflag silently ignored. - NFSv4 READDIR
cookieverf=0on continuation calls. - Scanner EXPORT enumeration after UDP portmapper discovery.
- BTRFS compound UUID fingerprinting for export escape.
convert --format consolerequired-o(now prints to stdout).- BTRFS identity check in escape (fileid vs handle bytes).
Upgrading
The binary is a drop-in replacement for v0.6.0. No configuration changes needed. New CLI flags:
brute-handle:--inode-start,--inode-end,--gen-start,--gen-end(replace--fixed-inodeand--fs-type).shell --nfs-version 2 --handle HEX: MOUNT bypass on NFSv2 servers.convert --format consolewithout-o: prints to stdout.
Binaries
| Binary | Platform | Notes |
|---|---|---|
nfswolf-linux-x86_64 |
Linux x86_64 (musl static) | No FUSE (mount unavailable) |
nfswolf-linux-x86_64-full |
Linux x86_64 (glibc) | Full feature set including FUSE mount |
nfswolf-linux-arm64 |
Linux aarch64 (musl static) | No FUSE |
nfswolf-linux-arm64-full |
Linux aarch64 (glibc) | Full including FUSE |
nfswolf-macos-universal |
macOS universal (x86_64 + arm64) | |
nfswolf-windows-x86_64-msvc.exe |
Windows x86_64 |
SHA256SUMS is signed with the release signing key.
v0.6.0
v0.5.0
Added
scan --auto-escape: after discovery, automatically attempt an export escape (subtree_check bypass) against every discovered export path and print a ready-to-runshell --handlecommand for each filesystem root reached. Runs only on a complete scan, with bounded concurrency and a per-host timeout; honours--proxyand--delay/--jitter. The escape logic is shared with theescapesubcommand via a singlefind_escapeprimitive.analyze --json [FILE]: optional file argument writes the JSON report to a file (matchingscan --json <FILE>); with no value it still emits to stdout.- NFSv4 shell honours
--aux-gids(the shadow-GID trick now works in--nfs-version 4mode, including across mid-sessionuid/gid/hostnamereconnects).
Changed
- Breaking --
scan: the "additional ports to probe" flag is renamed--nfs-portto--probe-port.--nfs-portnow means the single-value port override consistently across every subcommand, andscanfolds it into its probe set instead of ignoring it. - Breaking --
convert:--formatis long-only; the-fshort flag is removed (-fis the targets-file flag inscan/analyze). shell: removed the local--uid/--gidthat shadowed the global-u/-g; the session now uses the global identity flags consistently, soshell -u 0works like every other subcommand.- analyzer: dropped the unsound bind-mount (F-2.6) check and the tautological insecure-port (F-7.2) check (both produced false positives on well-configured servers); added a plaintext-transport check (F-3.1, Info); F-1.2 is now emitted when a forged non-root UID is honoured; F-4.1 (
no_root_squash) and F-7.5 (all_squash+anonuid=0) are disambiguated; the world-writable/symlink check includes root-owned directories; duplicate F-1.3 findings are deduplicated. - Circuit breaker: trips only on genuine transient transport outages (never on
NFS3ERR_ACCES/PERM, nor onFragmentedReply), records connection-establishment failures so a dead host opens the breaker, and escalates the cooldown once per outage rather than per failure. Every RPC also carries a per-call timeout so a stalled server cannot pin a pool connection. - NFSv2/NFSv4: NFSv2 raw RPC now uses a fresh AUTH_SYS stamp per call and feeds the circuit breaker; NFSv4 clients honour
StealthConfig; both bound directory paging and XDR allocations against hostile servers; privileged source ports are used for raw NFSv2 RPC and MOUNT v1. - FUSE:
readloops on short reads (no more zero-filled gaps);readdirpages a directory to completion with a per-inode cache;forgetbounds inode-map growth; device major/minor are encoded correctly inmknod. - CLI:
analyzeresolves hostnames and IPv6 targets;--nfs-portand--hostnameare threaded through the offensive subcommands; the connection pool re-stamps the requested credential (aux-gids/hostname) on checkout.
Fixed
- Addressed roughly one hundred correctness, robustness, and protocol findings from a two-cycle security review: short-read/short-write loops in the shell and NFSv2 read paths, unbounded directory listings and in-memory reads, escape-handle byte-layout and root-confirmation correctness (fsid_type=7 length, XFS-root candidates, identity check against the export's own inode), wildcard/netmask export-ACL detection, and numerous smaller fixes. See the commit history for the full list.
Security
shell get -rnow rejects server-controlled directory-entry names that contain a path separator or..before writing locally, preventing a malicious NFS server from escaping the chosen download directory (a zip-slip-class arbitrary local file write -- remote code execution when run undersudo).- Report renderers and the live
analyzeconsole neutralize untrusted server data: terminal control/escape sequences, Markdown/CSV/HTML injection, and Unicode bidirectional / zero-width "trojan source" characters (CVE-2021-42574 class). - Bounded every directory-listing and XDR allocation driven by an attacker-supplied length or count (memory-exhaustion DoS), and added per-call/per-host timeouts so an unresponsive server cannot hang the client.
- UDP RPC binds to the target's address family and accepts replies only from the address it sent to (drops spoofed responses).
Full Changelog: v0.4.0...v0.5.0
v0.4.0
nfswolf 0.4.0
Added
shell:tree [depth]— recursively map a directory (default depth 3), always traversing hidden dot-directories (.ssh,.aws,.bash_historyare exactly what you want on a security tool).shellprompt now showsuid=<n> gid=<n>and tracks mid-sessionuid/gid/impersonatechanges.brute-handlewritability hint — reports a non-destructive read-write vs read-only signal per hit from advisory ACCESS bits (probed as uid=0 and the object's owner). It never writes to the server; a handle is not itself ro/rw — the export's flag and the credential decide.access::WRITE_BITS/access::grants_write()helpers inproto::nfs3::types.
Changed
- Grouped
--help— the nine subcommands are organised into Recon / Connect / Advanced / Utilities sections (commands are still invoked flat, e.g.nfswolf scan ...). shell: escalation-awareget—getnow follows the auto-UID escalation ladder likecat, soget /etc/shadowsucceeds where it previously failed withNFS3ERR_ACCES;treeescalates credentials to descend into root-only hidden directories.brute-handle: optional seed —--seed-handleis now optional; a barehost:/exporttarget derives the seed by mounting the export (MNTPROC_MNT), matchingescape.--seed-handle HEXstays as an explicit override and a new-e/--exportflag mirrorsescape.brute-handle: parity withescape— candidate generation now fingerprints the seed (--fs-type auto) and tries the same known-root candidates asescape(ext4 inode 2 / compound-UUID, XFS 128/64/32, BTRFS subvolumes) before the generic inode sweep. A hit is accepted onNFS3_OKorNFS3ERR_ACCES/NFS3ERR_PERM, so it finds the same rootsescapedoes (a root_squash'd root is a valid handle, no longer discarded).- Docs — reconciled the finding count (39 findings, F-1.1 through F-7.6), RFC citation format (
§), write-up severities, and CLI/command references across FINDINGS / ARCHITECTURE / README / CLAUDE; CONTRIBUTING MSRV is now 1.95.
Removed
docs/scanning-module-plan.md(the completed scan-rewrite plan); stale NLM/NSM references inconn.rs.
Binaries below are checksummed (SHA256SUMS), cosign-signed (SHA256SUMS.sig), and carry SLSA build-provenance attestations. The mount (FUSE) subcommand is in the -full (glibc) builds only — it cannot be statically linked against musl.
Full changelog: v0.3.1...v0.4.0
v0.3.1
What's Changed
- feat: rewrite scan module with PROG_MISMATCH probing, SIGINT handling, and UDP portmapper support by @StrongWind1 in #4
- ci: bump github/codeql-action from 4.35.2 to 4.35.3 in the actions-minor-patch group across 1 directory by @dependabot[bot] in #3
- deps: bump tokio from 1.52.1 to 1.52.3 in the cargo-minor-patch group by @dependabot[bot] in #6
- ci: bump github/codeql-action from 4.35.3 to 4.35.4 in the actions-minor-patch group by @dependabot[bot] in #5
New Contributors
- @StrongWind1 made their first contribution in #4
Full Changelog: v0.3.0...v0.3.1
v0.3.0
[0.3.0] - 2026-04-29
This release adds three login-history readers to the interactive shell -- last, lastb, and lastlog -- so an operator who has reached an NFS-exported filesystem root (typically via escape-root) can decode /var/log/wtmp, /var/log/btmp, and /var/log/lastlog directly over NFS without staging them locally first. Parsing follows the canonical glibc struct utmpx (384 bytes) and struct lastlog (292 bytes) layouts and was cross-checked against util-linux 2.42 login-utils/last.c.
Added
- Shell:
last [N]decodes/var/log/wtmpand prints paired login sessions with full timestamps and durations. The state machine mirrors util-linux 2.42login-utils/last.c::process_wtmp_file()-- USER_PROCESS pairs with DEAD_PROCESS onut_line, sysvinit pseudo-records (~/reboot,~/shutdown,~/runlevel) are reclassified, and unmatched sessions are closed asCrash(next boot) orDown(clean shutdown / runlevel 0/6) per the same rules. Always-on full-time format and numeric IPs. - Shell:
lastb [N]decodes/var/log/btmpand prints failed-login attempts. Samestruct utmpxparser aslast. - Shell:
lastlogdecodes/var/log/lastlog(uid-indexed 292-byte slots), maps UIDs to usernames via/etc/passwdfrom the same export, and prints one row per user that has actually logged in. When the classic flat file is empty or absent the command also probes/var/lib/lastlog/lastlog2.db(util-linux 2.42 default) and prints agethint -- the SQLite database is left to offline tooling because pure-Rust SQLite would violate the project's no-C-deps rule. - New module
src/util/utmp.rs: pure-Rust binary parser forstruct utmpx,struct lastlog, and/etc/passwd. Bounds-checked, panic-free, with seven unit tests covering record sizes, BOOT_TIME / USER_PROCESS layouts, partial-trailing-record handling, UID-indexed lastlog slots, and IPv4 address rendering. Spec-cited to util-linux 2.42, glibc<bits/utmp.h>, and<bits/lastlog.h>. Safe on every architecture supported by the project: the on-disk record sizes are fixed by the Linux ABI regardless of nativetime_twidth. - New shell helper
read_all_escalated(): returns the full contents of a file handle after running the standard auto-UID escalation ladder. Required by the binary log readers because wtmp/btmp are typicallygid=43(utmp); the helper transparently switches credentials onNFS3ERR_ACCES.
Changed
- Shell
escape-rootnow also rebases the session's notion of/to the constructed filesystem root. Absolute path lookups (cat /etc/shadow,last,cd /) walk from the underlying filesystem root rather than the narrow export the session originally MOUNTed through. Without this fix the new log readers couldn't reach/var/log/wtmpafter an escape because the path was still resolved against the original sub-export. - Crate metadata: expanded
description, addedfilesystemtocategories, added[package.metadata.docs.rs]withall-features = trueand--cfg docsrsso docs.rs rebuilds are deterministic, and switched theincludelist to absolute (/-prefixed) paths to match the convention used by most well-curated Rust crates. - README: added crates.io and docs.rs badges, and pointed the security-disclosure paragraph at the GitHub private security advisory channel rather than a
SECURITY.mdfile.
Full Changelog: v0.2.0...v0.3.0
v0.2.0
[0.2.0] - 2026-04-28
The headline change is a substantial CLI overhaul: the attack umbrella verb is gone, primitives that duplicated shell / mount were removed, and three offensive primitives (escape, brute-handle, uid-spray) have been promoted to top-level subcommands. The export subcommand was renamed to convert. Every subcommand now runs the full check matrix unconditionally — the per-check toggles are gone — and --help is grouped into seven sections on every subcommand. The scanner is faster and more resilient against half-open firewalls, and the FUSE driver is now feature-complete.
Added
- New top-level subcommands:
nfswolf escape,nfswolf brute-handle,nfswolf uid-spray. Replacesnfswolf attack escape | brute-handle | uid-spray. - New top-level subcommand
nfswolf convertthat renders a JSON dump produced bynfswolf analyze --jsoninto HTML / Markdown / CSV / TXT / console. The pipeline is nowanalyze --json > results.jsonthenconvert -i results.json -f html -o report.html.convertis safe to re-run because it does not touch the server. - Unified positional
<TARGET>parser shared by every subcommand that touches a single export. Acceptshost,host:/export, or bracketed IPv6 ([2001:db8::1]:/srv).--exportand--handlestill work as flags; the parser rejects ambiguous combinations with a clear error. --nfs-portand--mount-portare now global flags (previously duplicated onmountandshell).- Successful subcommand runs print a
# rerun: nfswolf …line on stderr that can be pasted back into the shell to reproduce the run. Suppressed by--quietor--json. --helpfor every subcommand is now grouped into seven sections: Target / Identity / Permissions / Network / Stealth / Output / Behavior.- Shell:
get -randput -rrecursive directory transfer withindicatifper-directory spinners;get --verify <sha256>validates the downloaded file against an expected hash. - Shell:
hostname <name>command setsauth_unix.machinenamemid-session to bypass hostname-restricted export ACLs (F-1.4 / F-3.3 precondition probe). - Shell: SHA-256 of every downloaded file is printed for evidence chains.
- Shell:
--proxy socks5://host:porttunnels every NFS connection through a SOCKS5 pivot. Inline CONNECT, no external crate. - Global
--transport-udpflag for single-shot UDP RPC probes (portmapper amplification measurement, NSM probes). Wiring into the scanner's portmapper queries is tracked as the next step intasklist.md. - FUSE: every
Nfs3Clientprocedure is now wired through aFilesystemcallback (lookup, getattr, setattr, access, readlink, mknod, mkdir, symlink, create, unlink, rmdir, rename, link, readdir, read, write, fsync, statfs). Auto-UID escalation runs on every callback and caches the resolved credential per inode. - NFSv4 shell:
nfswolf shell --nfs-version 4drops into a minimal NFSv4 shell (ls / cd / pwd / cat / get) usingNfs4DirectClient— works against NFSv4-only servers where MOUNT and the portmapper are filtered. - Scanner:
nfs4_reachable: boolfield inHostResult, set by a direct NFSv4 COMPOUND PUTROOTFH probe to confirm v4 even when portmapper is filtered (F-3.3).
Changed
- Scanner: per-host TCP probes for ports 111 and 2049 now run concurrently via
tokio::join!. A half-open firewall on one port no longer serializes the other. - Scanner: every portmap / mount RPC call inside
scan_host(detect_nfs_versions,list_exports,mount,dump_clients,detect_nis) is wrapped intokio::time::timeout(probe_timeout, …). A stateful firewall that completes the TCP handshake on 111 but drops RPC payload can no longer stall a worker for the underlying client default. - Scanner: per-host workers are panic-isolated. A single misbehaving target can no longer sink a multi-thousand-host sweep.
nfswolf mount(1)now detaches into a daemon so the FUSE handler outlives the shell.analyze: every analysis now runs the full check matrix unconditionally. The only per-run knobs are--test-read PATH,--test-read-uids,--test-read-gids, and--v4-depth.--test-readdefaults to/etc/shadowwhen no paths are supplied.analyze: dropped per-check toggles (-A/--check-all,--skip-version-check,--no-exploit,--check-v4,--check-no-root-squash,--check-insecure-port,--check-nohide,--check-v2-downgrade,--check-portmap-amplification,--check-nis,--probe-squash).analyze: dropped--output FILE/--txt FILE. The global--jsonflag now makesanalyzeemit a JSON array on stdout — capture with shell redirection and feed tonfswolf convert.scan: dropped per-check toggles (--fast,--no-rpc-enum,--check-portmap-amplification,--check-v2-downgrade,--check-nis,--check-portmap-bypass). Every scan now runs the full check matrix unconditionally. The only knobs are concurrency, ports, and timeout.mount: dropped--auto-uid,--allow-root,--suid,--dev,--allow-other,--elevate-perms. The credential ladder, owner-bit elevation, suid/dev passthrough, and shared-mount visibility are always on — this is a security toolkit, the goal is unobstructed access.-eshort for--exportwas added.shell: dropped--auto-uid. The credential ladder is always on; the shell falls through to escalated credentials on everyNFS3ERR_ACCES.--exportconsistently has-eas its short form on every subcommand that accepts it.
Removed
- The
attackparent verb is gone. - Removed
attack read,attack write,attack upload,attack harvest, andattack symlink-swap.shell(get,put,get -r,put -r,cat,find) andmount(regular filesystem tools) cover the same primitives with the same credential ladder. - Removed
attack lock-dosentirely. Lock-storm DoS was the only NLM-dependent feature; with it gone, the NLM and NSM clients (src/proto/nlm/,src/proto/nsm/), the F-6.1 NLM lock-attack analyzer check, and the portmapper helpersdetect_nlm/detect_nsmare removed. F-6.2 / F-6.3 (grace-period DoS, SETCLIENTID state destruction) were never implemented and are documented as out of scope. - Removed
attack v4-grace(placeholder-only; no working implementation). - Removed
src/engine/fs_walker.rs(recursive walker used only byharvest) and theCredentialManagerstruct fromsrc/engine/credential.rs(used only by removed attack modules). Theescalation_listhelper survives — it is shared byshell,mount, and the three offensive subcommands. - Removed inline
--escapeflag from offensive subcommands. To cross the export boundary, runnfswolf escapefirst and feed the resulting handle intoshell --handle HEXormount --handle HEX. The escape module is now the single entry point for export breakout.
Fixed
- FUSE:
--elevate-permsshift offset (now correctly copies owner bits to other; previously copied group bits, leaving 0700 unchanged). Behavior is now always-on. - FUSE:
--nfs-portbeing silently ignored when--exportwas used (was only honored with--handle). - FUSE:
--proxynot being passed to the connection pool, so--handlemounts now tunnel through SOCKS5. - FUSE: server-side symlink resolution and the null-attr READDIRPLUS fix-up are always on (NetApp / nested-export workaround).
- Multiple small CLI bugs surfaced by live-server testing.
v0.1.0
First public release. Covers the full NFS attack path: recon → enumeration → analysis → exploitation → shell. For authorized security research only.
Protocol support
- NFSv2, NFSv3, and NFSv4.0 over TCP with full XDR encoding
- AUTH_SYS credential injection with per-call stamp rotation to avoid duplicate-request-cache hits
- MOUNT, portmapper (DUMP / GETPORT), NLM4 lock procedures, and NSM stat/monitor
- NFSv4 COMPOUND operations: PUTROOTFH, GETFH, LOOKUP, GETATTR, READDIR, READ, SECINFO
- UDP transport for single-shot RPC probes (portmapper amplification measurement)
- SOCKS5 proxy support for all TCP connections
- Connection pool with per-(host, export, uid, gid) bucketing, LIFO reuse, and health eviction
- Circuit breaker with sliding-window failure tracking and exponential-backoff cooldown; permission denials do not trip the breaker during UID spraying
Subcommands
- scan — concurrent host and export enumeration across configurable CIDR ranges; detects NFSv2/v3/v4, supported auth flavors, and open portmapper/NLM/NSM services
- analyze — automated security analysis against all 36 findings (F-1.1 through F-7.6); produces a risk-scored report
- shell — interactive NFS shell with 35 commands, tab completion, and readline history; supports
get/putwith recursive (-r) directory transfer and SHA-256 verification;hostnamespoofing to bypass hostname-restricted exports - mount — FUSE filesystem mount with spoofed AUTH_SYS credentials; exposes the remote export as a local directory
- export — renders a prior analysis result in any of six output formats
- attack — nine targeted attack modules:
uid-spray— brute-force UID/GID pairs using the ACCESS oracleescape— construct file-handle escape payloads for ext4, XFS, and BTRFSread— read arbitrary files by inode using forged handleswrite— write files as any UID withoutno_root_squashmitigationharvest— recursive secret pattern matching across an export treebrute-handle— inode-range handle brute-force with STALE/BADHANDLE oracle discriminationlock-dos— NLM4 lock-storm denial-of-servicesymlink-swap— TOCTOU symlink substitution attackv4-grace— NFSv4 grace-period state disruption
Security analysis
- 36 findings across seven categories: credential spoofing (F-1.x), export escape (F-2.x), network (F-3.x), privilege escalation (F-4.x), enumeration (F-5.x), locking (F-6.x), and policy misconfiguration (F-7.x)
- Every finding references the authoritative RFC section and includes severity, detection method, and a detailed write-up
- Auto-UID resolution: nine-step strategy that tries NFSv2 (no root_squash negotiation), NFSv3 ACCESS oracle, and UID 0/65534/1000 before falling back to spray
File handle engine
- OS and filesystem fingerprinting from handle structure (Linux ext4, XFS, BTRFS, Windows, FreeBSD)
- Escape handle construction targeting inode 2 (ext4 root), XFS inode 128, and BTRFS subvolume UUID layouts
- BTRFS compound-UUID escape with subvolume enumeration
- Windows handle signing detection (HMAC presence / absence)
- Shannon entropy analysis for handle classification
Output and reporting
- Six report formats: ANSI-colored console, HTML (self-contained), JSON, CSV, Markdown, plain text
- Risk scoring: weighted sum across finding severities
--outputflag onexportselects format; all formats accept the sameAnalysisResultinput
Releases
- Pre-built binaries for Linux x86_64 (musl static, glibc+FUSE), Linux arm64 (musl static, glibc+FUSE), Windows x86_64 (MSVC, GNU), Windows arm64 (MSVC), macOS arm64, macOS x86_64, and macOS universal
SHA256SUMSfile with cosign keyless signature (SHA256SUMS.sig) for every release- SLSA build provenance attestations for every binary via
actions/attest-build-provenance