Skip to content

Releases: StrongWind1/NFSWolf

v1.0.0 -- Protocol crates on crates.io, auth enumeration, IANA registries, NFSv4 escape

Choose a tag to compare

@github-actions github-actions released this 08 Aug 14:53
v1.0.0
22383ed

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_TOOWEAK oracle (F-1.8): detects Kerberos enforcement at the NFS layer
  • AUTH_SHORT finding (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 into nfs-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 \
  SHA256SUMS

Full Changelog: v0.8.0...v1.0.0

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 28 Jul 20:52
v0.8.0
4580e9a

What's New in v0.8.0

Cross-Version Parity

  • NFSv2 identity change -- uid, gid, hostname, and impersonate now work in the v2 shell by reconnecting with new credentials. Previously v2 identity was fixed at connect time.
  • NFSv2 fattr -- stat now shows correct rdev, fsid, and disk usage instead of zeros.
  • NFSv2 escape guards -- export_is_fs_root check 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, history now 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.
  • cat vs get credential gap -- get now performs the same credential escalation as cat. Previously cat /etc/shadow could succeed while get /etc/shadow failed with NFS3ERR_ACCES.
  • NFSv4 cat binary corruption -- raw byte output instead of lossy UTF-8 conversion.
  • Pool blocking_lock panic -- try_lock instead of blocking_lock in pool checkin, which panicked inside the tokio runtime.
  • Analyzer pagination -- check_nohide and check_symlink_preconditions now 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() predicates
  • Display for NfsStat (v2) and Nfs4Status (v4) with RFC error names
  • Nfs2Client::into_transport(), tracing on v2 call failures
  • Removed dead RpcbindTime and duplicate Opaque::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

Choose a tag to compare

@github-actions github-actions released this 27 Jul 16:24
v0.7.0
e88f917

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 RpcTransport trait is the single seam between wire protocol and connection policy.
  • NFSv3 domain API: FileHandle, FileAttrs, Nfs3Error with 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 --handle MOUNT bypass and -c scripted 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/shadow via 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 2 rerun 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_imports deny, use_self warn.
  • 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>::unpack allocation amplification from forged wire lengths.
  • NFSv2 DirOpRes::Pack wrong union encoding (wrote 100 extra bytes on error).
  • NFSv2 missing NFSERR_WFLUSH=99.
  • NFSv2 shell -c flag silently ignored.
  • NFSv4 READDIR cookieverf=0 on continuation calls.
  • Scanner EXPORT enumeration after UDP portmapper discovery.
  • BTRFS compound UUID fingerprinting for export escape.
  • convert --format console required -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-inode and --fs-type).
  • shell --nfs-version 2 --handle HEX: MOUNT bypass on NFSv2 servers.
  • convert --format console without -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

Choose a tag to compare

@github-actions github-actions released this 02 Jul 18:37
v0.6.0
a450c3d

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 29 Jun 06:26
v0.5.0
d0bc3de

Added

  • scan --auto-escape: after discovery, automatically attempt an export escape (subtree_check bypass) against every discovered export path and print a ready-to-run shell --handle command for each filesystem root reached. Runs only on a complete scan, with bounded concurrency and a per-host timeout; honours --proxy and --delay/--jitter. The escape logic is shared with the escape subcommand via a single find_escape primitive.
  • analyze --json [FILE]: optional file argument writes the JSON report to a file (matching scan --json <FILE>); with no value it still emits to stdout.
  • NFSv4 shell honours --aux-gids (the shadow-GID trick now works in --nfs-version 4 mode, including across mid-session uid/gid/hostname reconnects).

Changed

  • Breaking -- scan: the "additional ports to probe" flag is renamed --nfs-port to --probe-port. --nfs-port now means the single-value port override consistently across every subcommand, and scan folds it into its probe set instead of ignoring it.
  • Breaking -- convert: --format is long-only; the -f short flag is removed (-f is the targets-file flag in scan/analyze).
  • shell: removed the local --uid/--gid that shadowed the global -u/-g; the session now uses the global identity flags consistently, so shell -u 0 works 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 on FragmentedReply), 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: read loops on short reads (no more zero-filled gaps); readdir pages a directory to completion with a per-inode cache; forget bounds inode-map growth; device major/minor are encoded correctly in mknod.
  • CLI: analyze resolves hostnames and IPv6 targets; --nfs-port and --hostname are 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 -r now 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 under sudo).
  • Report renderers and the live analyze console 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

Choose a tag to compare

@github-actions github-actions released this 29 Jun 06:05
v0.4.0
6da81f6

nfswolf 0.4.0

Added

  • shell: tree [depth] — recursively map a directory (default depth 3), always traversing hidden dot-directories (.ssh, .aws, .bash_history are exactly what you want on a security tool).
  • shell prompt now shows uid=<n> gid=<n> and tracks mid-session uid / gid / impersonate changes.
  • brute-handle writability 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 in proto::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-aware getget now follows the auto-UID escalation ladder like cat, so get /etc/shadow succeeds where it previously failed with NFS3ERR_ACCES; tree escalates credentials to descend into root-only hidden directories.
  • brute-handle: optional seed--seed-handle is now optional; a bare host:/export target derives the seed by mounting the export (MNTPROC_MNT), matching escape. --seed-handle HEX stays as an explicit override and a new -e/--export flag mirrors escape.
  • brute-handle: parity with escape — candidate generation now fingerprints the seed (--fs-type auto) and tries the same known-root candidates as escape (ext4 inode 2 / compound-UUID, XFS 128/64/32, BTRFS subvolumes) before the generic inode sweep. A hit is accepted on NFS3_OK or NFS3ERR_ACCES/NFS3ERR_PERM, so it finds the same roots escape does (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 in conn.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

Choose a tag to compare

@github-actions github-actions released this 16 Jun 16:12
v0.3.1
4eff72c

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

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 29 Apr 04:12
v0.3.0
448588f

[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/wtmp and prints paired login sessions with full timestamps and durations. The state machine mirrors util-linux 2.42 login-utils/last.c::process_wtmp_file() -- USER_PROCESS pairs with DEAD_PROCESS on ut_line, sysvinit pseudo-records (~/reboot, ~/shutdown, ~/runlevel) are reclassified, and unmatched sessions are closed as Crash (next boot) or Down (clean shutdown / runlevel 0/6) per the same rules. Always-on full-time format and numeric IPs.
  • Shell: lastb [N] decodes /var/log/btmp and prints failed-login attempts. Same struct utmpx parser as last.
  • Shell: lastlog decodes /var/log/lastlog (uid-indexed 292-byte slots), maps UIDs to usernames via /etc/passwd from 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 a get hint -- 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 for struct 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 native time_t width.
  • 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 typically gid=43 (utmp); the helper transparently switches credentials on NFS3ERR_ACCES.

Changed

  • Shell escape-root now 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/wtmp after an escape because the path was still resolved against the original sub-export.
  • Crate metadata: expanded description, added filesystem to categories, added [package.metadata.docs.rs] with all-features = true and --cfg docsrs so docs.rs rebuilds are deterministic, and switched the include list 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.md file.

Full Changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 29 Apr 03:08
v0.2.0
e67ac89

[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. Replaces nfswolf attack escape | brute-handle | uid-spray.
  • New top-level subcommand nfswolf convert that renders a JSON dump produced by nfswolf analyze --json into HTML / Markdown / CSV / TXT / console. The pipeline is now analyze --json > results.json then convert -i results.json -f html -o report.html. convert is safe to re-run because it does not touch the server.
  • Unified positional <TARGET> parser shared by every subcommand that touches a single export. Accepts host, host:/export, or bracketed IPv6 ([2001:db8::1]:/srv). --export and --handle still work as flags; the parser rejects ambiguous combinations with a clear error.
  • --nfs-port and --mount-port are now global flags (previously duplicated on mount and shell).
  • Successful subcommand runs print a # rerun: nfswolf … line on stderr that can be pasted back into the shell to reproduce the run. Suppressed by --quiet or --json.
  • --help for every subcommand is now grouped into seven sections: Target / Identity / Permissions / Network / Stealth / Output / Behavior.
  • Shell: get -r and put -r recursive directory transfer with indicatif per-directory spinners; get --verify <sha256> validates the downloaded file against an expected hash.
  • Shell: hostname <name> command sets auth_unix.machinename mid-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:port tunnels every NFS connection through a SOCKS5 pivot. Inline CONNECT, no external crate.
  • Global --transport-udp flag for single-shot UDP RPC probes (portmapper amplification measurement, NSM probes). Wiring into the scanner's portmapper queries is tracked as the next step in tasklist.md.
  • FUSE: every Nfs3Client procedure is now wired through a Filesystem callback (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 4 drops into a minimal NFSv4 shell (ls / cd / pwd / cat / get) using Nfs4DirectClient — works against NFSv4-only servers where MOUNT and the portmapper are filtered.
  • Scanner: nfs4_reachable: bool field in HostResult, 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 in tokio::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-read defaults to /etc/shadow when 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 --json flag now makes analyze emit a JSON array on stdout — capture with shell redirection and feed to nfswolf 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. -e short for --export was added.
  • shell: dropped --auto-uid. The credential ladder is always on; the shell falls through to escalated credentials on every NFS3ERR_ACCES.
  • --export consistently has -e as its short form on every subcommand that accepts it.

Removed

  • The attack parent verb is gone.
  • Removed attack read, attack write, attack upload, attack harvest, and attack symlink-swap. shell (get, put, get -r, put -r, cat, find) and mount (regular filesystem tools) cover the same primitives with the same credential ladder.
  • Removed attack lock-dos entirely. 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 helpers detect_nlm / detect_nsm are 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 by harvest) and the CredentialManager struct from src/engine/credential.rs (used only by removed attack modules). The escalation_list helper survives — it is shared by shell, mount, and the three offensive subcommands.
  • Removed inline --escape flag from offensive subcommands. To cross the export boundary, run nfswolf escape first and feed the resulting handle into shell --handle HEX or mount --handle HEX. The escape module is now the single entry point for export breakout.

Fixed

  • FUSE: --elevate-perms shift offset (now correctly copies owner bits to other; previously copied group bits, leaving 0700 unchanged). Behavior is now always-on.
  • FUSE: --nfs-port being silently ignored when --export was used (was only honored with --handle).
  • FUSE: --proxy not being passed to the connection pool, so --handle mounts 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

Choose a tag to compare

@github-actions github-actions released this 17 Apr 20:22
72c69f9

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/put with recursive (-r) directory transfer and SHA-256 verification; hostname spoofing 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 oracle
    • escape — construct file-handle escape payloads for ext4, XFS, and BTRFS
    • read — read arbitrary files by inode using forged handles
    • write — write files as any UID without no_root_squash mitigation
    • harvest — recursive secret pattern matching across an export tree
    • brute-handle — inode-range handle brute-force with STALE/BADHANDLE oracle discrimination
    • lock-dos — NLM4 lock-storm denial-of-service
    • symlink-swap — TOCTOU symlink substitution attack
    • v4-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
  • --output flag on export selects format; all formats accept the same AnalysisResult input

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
  • SHA256SUMS file with cosign keyless signature (SHA256SUMS.sig) for every release
  • SLSA build provenance attestations for every binary via actions/attest-build-provenance