Releases: StrongWind1/NFSWolf
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