Skip to content

nfs protocol crash on NFSv4-only servers #1073

@zephvr

Description

@zephvr

Describe the bug
When analysing a NFS server that only supports NFSv4 netexec crashes

To Reproduce
Steps to reproduce the behavior i.e.:
Command: nxc nfs 127.0.0.1
Resulted in:

[12:03:33] ERROR    Exception while calling proto_flow() on target 127.0.0.1: RPC_PROG_MISMATCH: remote can't support version: 1 2                                                                                                                                      connection.py:187
                    ╭─────────────────────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ───────────────────────────────────────────────────────────────────────────────────────────────────────╮                  
                    │ /root/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/connection.py:177 in __init__                                                                                                                                            │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │   174 │   │   self.logger.info(f"Socket info: host={self.host}, hostname={self.hostname},                                                                                                                                                       │                  
                    │       kerberos={self.kerberos}, ipv6={self.is_ipv6}, link-local                                                                                                                                                                                 │                  
                    │       ipv6={self.is_link_local_ipv6}")                                                                                                                                                                                                          │                  
                    │   175 │   │                                                                                                                                                                                                                                     │                  
                    │   176 │   │   try:                                                                                                                                                                                                                              │                  
                    │ ❱ 177 │   │   │   self.proto_flow()                                                                                                                                                                                                             │                  
                    │   178 │   │   except FileNotFoundError as e:                                                                                                                                                                                                    │                  
                    │   179 │   │   │   self.logger.error(f"File not found error on target {target}: {e}")                                                                                                                                                            │                  
                    │   180 │   │   except Exception as e:                                                                                                                                                                                                            │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │ /root/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/connection.py:244 in proto_flow                                                                                                                                          │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │   241 │   │   │   self.logger.info(f"Failed to create connection object for target                                                                                                                                                              │                  
                    │       {self.host}, exiting...")                                                                                                                                                                                                                 │                  
                    │   242 │   │   else:                                                                                                                                                                                                                             │                  
                    │   243 │   │   │   self.logger.debug("Created connection object")                                                                                                                                                                                │                  
                    │ ❱ 244 │   │   │   self.enum_host_info()                                                                                                                                                                                                         │                  
                    │   245 │   │   │                                                                                                                                                                                                                                 │                  
                    │   246 │   │   │   # Construct the output file template using os.path.join for OS compatibility                                                                                                                                                  │                  
                    │   247 │   │   │   base_log_dir = os.path.join(NXC_PATH, "logs")                                                                                                                                                                                 │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │ /root/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/protocols/nfs.py:140 in enum_host_info                                                                                                                                   │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │   137 │   │   self.nfs3 = NFSv3(self.host, nfs_port, self.args.nfs_timeout, self.auth)                                                                                                                                                          │                  
                    │   138 │   │   self.nfs3.connect()                                                                                                                                                                                                               │                  
                    │   139 │   │   # Check if root escape is possible                                                                                                                                                                                                │                  
                    │ ❱ 140 │   │   self.root_escape = self.try_root_escape()                                                                                                                                                                                         │                  
                    │   141 │   │   self.nfs3.disconnect()                                                                                                                                                                                                            │                  
                    │   142 │                                                                                                                                                                                                                                         │                  
                    │   143 │   def print_host_info(self):                                                                                                                                                                                                            │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │ /root/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/protocols/nfs.py:597 in try_root_escape                                                                                                                                  │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │   594 │   │   if not self.nfs3:                                                                                                                                                                                                                 │                  
                    │   595 │   │   │   raise Exception("NFS connection is not established")                                                                                                                                                                          │                  
                    │   596 │   │                                                                                                                                                                                                                                     │                  
                    │ ❱ 597 │   │   output_export = str(self.mount.export())                                                                                                                                                                                          │                  
                    │   598 │   │   reg = re.compile(r"ex_dir=b'([^']*)'")  # Get share names                                                                                                                                                                         │                  
                    │   599 │   │   shares = list(reg.findall(output_export))                                                                                                                                                                                         │                  
                    │   600                                                                                                                                                                                                                                           │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │ /root/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/pyNfsClient/mount.py:58 in export                                                                                                                                            │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │   55 │                                                                                                                                                                                                                                          │                  
                    │   56 │   def export(self):                                                                                                                                                                                                                      │                  
                    │   57 │   │   log.debug("Get mount export on %s" % self.host)                                                                                                                                                                                    │                  
                    │ ❱ 58 │   │   export = super(Mount, self).request(self.program, self.program_version, 5)                                                                                                                                                         │                  
                    │   59 │   │                                                                                                                                                                                                                                      │                  
                    │   60 │   │   unpacker = nfs_pro_v3Unpacker(export)                                                                                                                                                                                              │                  
                    │   61 │   │   return unpacker.unpack_exports()                                                                                                                                                                                                   │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │ /root/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/pyNfsClient/rpc.py:141 in request                                                                                                                                            │                  
                    │                                                                                                                                                                                                                                                 │                  
                    │   138 │   │   │   │   raise Exception("RPC_PROG_UNAVAIL: remote hasn't exported program")                                                                                                                                                       │                  
                    │   139 │   │   │   elif accept_stat == PROG_MISMATCH:                                                                                                                                                                                            │                  
                    │   140 │   │   │   │   low, high = struct.unpack('!LL', data[24:32])                                                                                                                                                                             │                  
                    │ ❱ 141 │   │   │   │   raise Exception(f"RPC_PROG_MISMATCH: remote can't support version: {low}                                                                                                                                                  │                  
                    │       {high}")                                                                                                                                                                                                                                  │                  
                    │   142 │   │   │   elif accept_stat == PROC_UNAVAIL:                                                                                                                                                                                             │                  
                    │   143 │   │   │   │   raise Exception("RPC_PROC_UNAVAIL: remote doesn't support procedure")                                                                                                                                                     │                  
                    │   144 │   │   │   elif accept_stat == GARBAGE_ARGS:                                                                                                                                                                                             │                  
                    ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                  
                    Exception: RPC_PROG_MISMATCH: remote can't support version: 1 2

Expected behavior
nxc should not crash and should instead output:

NFS         127.0.0.1       39057  127.0.0.1        [*] Supported NFS versions: (4) (root escape:False)

NetExec info

  • OS: Debian 13
  • Version of nxc: 1.5.0 - Yippie-Ki-Yay - 08b43bf - 42
  • Installed from: pip

Additional context
Commenting out try_root_escape in nfs.py allows the execution to finish without crashing. The issue may be related to this function.

To test this simply install nfs-server and write vers3=n in /etc/nfs.conf

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions