Skip to content

F-5.15: rquotad Exposes UID Activity via Quota Queries

Classification

  • Severity: Medium (Information Disclosure / Credential Discovery)
  • CVSS Vector: Network / Low Complexity / No Auth Required
  • Affected Versions: Any NFS server co-hosting rquotad (program 100011)
  • Service: rquotad (program 100011, version 1, procedure GETQUOTA)
  • Prerequisite: rquotad reachable via portmapper (port resolved via GETPORT on port 111)

Summary

rquotad (program 100011) is a Sun-originated RPC service that returns per-UID disk usage without authentication. A GETQUOTA call for a specific UID reveals whether that UID has disk activity on the queried export -- non-zero curblocks or curfiles confirms the UID exists and has consumed storage. This turns rquotad into a UID existence oracle. Additionally, the bsize field in every quota response leaks the filesystem block size, which fingerprints the filesystem type (ext4=4096, XFS=512, ZFS=1024) and narrows the escape strategy before any NFS operation is attempted. Active UIDs discovered through rquotad feed the credential ladder for targeted AUTH_SYS spoofing.

Technical detail

GETQUOTA wire format

rquotad uses a de facto standard wire format from Sun's rquota.x (no RFC exists):

GETQUOTA v1 (procedure 1):
  Input:  export_path (XDR string) + uid (u32)
  Output: status (Q_OK=1 / Q_NOQUOTA=2 / Q_EPERM=3) + rquota struct

The rquota struct (returned on Q_OK):

Field Size Meaning
bsize u32 Filesystem block size in bytes
active bool Whether quota enforcement is active
bhardlimit u32 Hard block limit
bsoftlimit u32 Soft block limit
curblocks u32 Current blocks used by this UID
fhardlimit u32 Hard file (inode) limit
fsoftlimit u32 Soft file (inode) limit
curfiles u32 Current files owned by this UID
btimeleft u32 Seconds until soft block limit enforced
ftimeleft u32 Seconds until soft file limit enforced

UID existence oracle

The critical observation: Q_OK with non-zero curblocks or curfiles means the UID has consumed disk resources on this export. Q_NOQUOTA means either the UID does not exist, has no quota record, or has no disk activity. The distinction is useful even without quotas enabled -- many Linux systems return Q_OK with zero limits (no enforcement) but accurate usage counts.

GETQUOTA(uid=0)     -> Q_OK, curblocks=15234, curfiles=892   # root is active
GETQUOTA(uid=1000)  -> Q_OK, curblocks=4521,  curfiles=127   # user 1000 exists and is active
GETQUOTA(uid=1001)  -> Q_NOQUOTA                              # no activity for uid 1001
GETQUOTA(uid=65534) -> Q_OK, curblocks=0,     curfiles=3     # nobody has 3 files

Filesystem fingerprinting via bsize

The bsize field is set by the kernel's sb_dqopt() path and reflects the filesystem's native block size:

bsize Value Filesystem Notes
4096 ext4 Default block size for ext4
512 XFS XFS reports sector size as bsize
1024 ZFS ZFS default record size
4096 btrfs Matches page size
1024 ext2/ext3 Small-filesystem default

This fingerprint is available before any NFS operation. Combined with file handle analysis (F-2.1), it confirms the filesystem type and narrows escape candidate selection.

No authentication required

rquotad performs no authentication check on GETQUOTA requests. The service accepts queries from any source IP that can reach its port. The port is dynamically assigned and discoverable via portmapper GETPORT (program 100011, version 1, protocol TCP).

Exploitation

Automated (nfswolf)

# The analyzer probes rquotad during analysis:
nfswolf analyze target:/export

# Output when active UIDs are found:
# [MEDIUM] F-5.15: rquotad exposes UID activity via quota queries
#   Evidence: block_size=4096; active_uids: uid=0 blocks=15234 files=892,
#     uid=1000 blocks=4521 files=127

Manual UID sweep

#!/usr/bin/env bash
set -euo pipefail

TARGET="${1:?Usage: $0 <target>}"
EXPORT="${2:-/}"

# Resolve rquotad port
PORT=$(rpcinfo -p "$TARGET" | awk '/100011.*tcp/ {print $4; exit}')
if [[ -z "$PORT" ]]; then
    echo "rquotad not registered"
    exit 1
fi

# Sweep common UIDs
for uid in 0 $(seq 500 520) $(seq 1000 1020) 65534; do
    result=$(rquota -p "$EXPORT" -u "$uid" "$TARGET" 2>/dev/null) || continue
    echo "uid=$uid: $result"
done

Credential ladder integration

Active UIDs discovered via rquotad are injected into the credential ladder as high-confidence targets. Their disk activity confirms they are real accounts with file ownership on the export, making them better candidates than blind UID brute-force.

Impact

  • UID existence confirmation: Identifies which UIDs have disk activity on the export without authentication
  • Filesystem fingerprinting: The bsize field reveals the filesystem type before any NFS operation
  • Credential ladder acceleration: Active UIDs are high-confidence targets for AUTH_SYS spoofing (F-1.1), bypassing brute-force enumeration
  • Quota limit disclosure: Hard and soft limits reveal the server's resource allocation policy
  • Activity profiling: curblocks and curfiles reveal the relative disk footprint of each user

Limitations

  • rquotad is not universally deployed -- many modern systems do not run it
  • Some distributions restrict rquotad to localhost or require tcp_wrappers authorization
  • Q_NOQUOTA does not definitively prove the UID does not exist -- it may exist with no disk activity
  • The service must be resolvable via portmapper (port 111); if portmapper is firewalled, rquotad is unreachable

Detection (nfswolf)

The analyzer resolves rquotad via portmapper GETPORT (program 100011, version 1, TCP), then issues GETQUOTA for UIDs 0, 1000, and 65534. If any query returns Q_OK with non-zero curblocks or curfiles, or if any response includes a non-zero bsize, the finding fires at Medium severity. The evidence lists the block size and all active UIDs with their usage counts.

Remediation

  1. Disable rquotad if remote quota queries are not needed:

    systemctl stop rpc-rquotad
    systemctl disable rpc-rquotad
    

  2. Firewall rquotad -- restrict access to the rquotad port from untrusted networks:

    # Fix rquotad to a known port for firewall rules
    echo "RPCRQUOTADOPTS='-p 875'" >> /etc/sysconfig/rpc-rquotad
    iptables -A INPUT -p tcp --dport 875 -s !192.168.1.0/24 -j DROP
    

  3. Use tcp_wrappers if the rquotad build supports it:

    # /etc/hosts.deny
    rquotad: ALL
    # /etc/hosts.allow
    rquotad: 192.168.1.0/255.255.255.0
    

  4. Migrate to NFSv4 -- NFSv4 does not use rquotad; quota information is accessed via the GETATTR operation with the quota_avail_hard/quota_avail_soft/quota_used attributes, which are subject to the export's sec= enforcement

Finding Relationship
F-1.1: UID/GID Spoofing Active UIDs from rquotad are spoofed via AUTH_SYS
F-5.4: RPC Service Enumeration Portmapper DUMP reveals rquotad registration
F-5.14: POSIX ACL Entries Both findings feed the credential ladder with targeted UIDs/GIDs