rpcclient
rpcclient is Samba’s hands-on client for the Windows MS-RPC interfaces over SMB: point it at a host and ask direct questions, which users exist, what groups they hold, the password policy, the shares, and the domain SID. Reach for it when an automated scanner reported something and you want to confirm exactly what one account (or a null session) can actually read.
Mental model: rpcclient [auth] -c "command" TARGET_IP. Pick a session, run one RPC call, read the answer.
How rpcclient works: core concepts
- Transport: MS-RPC rides SMB named pipes, so it needs TCP
445(or139) reachable on the target. - Session type: authenticated (
-U USERNAME), null/anonymous (-U "" -N), or pass-the-hash (--pw-nt-hash); what you can read depends entirely on this. - Interactive vs one-shot: bare
rpcclientdrops you at anrpcclient $>prompt;-c "cmd"runs a command (or several with;) and exits, which is what you script. - RID: a Relative ID appended to the domain SID; every account is
<domain-SID>-<RID>, and...-500is always the built-in Administrator. - SID: the full
S-1-5-21-...identifier;lookupnamesandlookupsidsconvert between names and SIDs. - Named pipes: calls hit different interfaces, SAMR (users/groups), LSARPC (SIDs/policy/privileges), SRVSVC (shares), and each has its own permission gate.
- Permission-bound output: the same command can return full data, partial data, or
NT_STATUS_ACCESS_DENIED, purely as a function of the account you used.
When to reach for rpcclient (and when not)
Reach for it to confirm by hand exactly what a credential or null session can enumerate, pull a clean user list for later steps, read the password policy before any spraying, map SIDs and RID-cycle, or verify a single finding that enum4linux-ng or NetExec already reported.
Reach for something else to browse or download share contents (smbclient), to sweep many hosts or protocols at once (NetExec), to get a full automated SMB report in one pass (enum4linux-ng), or to pipe RPC results straight into code (Impacket samrdump / lookupsid).
Install, update, verify#
sudo apt install -y smbclient # Debian / Ubuntu / Kali (rpcclient ships with it)
sudo dnf install -y samba-client # Fedora / RHEL
brew install samba # macOS (Homebrew)
sudo apt install --only-upgrade -y smbclient # update
rpcclient --version # Samba version
command -v rpcclient # confirm it is on PATH
rpcclient --help | less # skim the connection options and pipe commands
rpcclient is part of the Samba client tools, so you install smbclient and get it alongside. There is no network self-test: rpcclient --help runs offline and proves the binary works, while a real connection returns either an rpcclient $> prompt or an NT_STATUS_* error.
Flags you’ll actually use#
Skim these first; the cheat sheet below is these flags combined.
| Flag | Does | Flag | Does |
|---|---|---|---|
-U USER | Set the session user (USER%PASS inline) | -c "cmd" | Run RPC command(s) then exit |
-U "" | Empty username (null session) | -A file | Read user/pass/domain from a file |
-N | No password prompt (null/anon) | --pw-nt-hash | Treat the password as an NT hash |
-W DOMAIN | Set the workgroup / domain | -k | Authenticate with Kerberos |
-p PORT | Non-standard SMB port | -d 3 | Raise debug level for diagnosis |
-I IP | Target IP (when host is a NetBIOS name) | --option='...' | Set any smb.conf option (legacy protocol) |
Cheat sheet#
Every connection block builds up one flag at a time, so you can stop at the line that logs you in. The query blocks default to a null session; swap -U "" -N for -U USERNAME when anonymous access is refused.
# Verify the tool
command -v rpcclient # is it on PATH
rpcclient --version # Samba version
# Build up a connection: stop at the line that logs you in
rpcclient -U "" -N TARGET_IP # 1. null session (empty user, no password)
rpcclient -U USERNAME TARGET_IP # 2. + prompt for a password
rpcclient -U USERNAME -W DOMAIN TARGET_IP # 3. + set the domain / workgroup
rpcclient -A creds.txt TARGET_IP # 4. or read creds from a locked file
rpcclient -U USERNAME --pw-nt-hash TARGET_IP # 5. or pass an NT hash instead of a password
# Server and domain facts (read-only)
rpcclient -U "" -N -c "srvinfo" TARGET_IP # OS version, server type, platform
rpcclient -U "" -N -c "querydominfo" TARGET_IP # domain/workgroup, role, user count
rpcclient -U "" -N -c "getdompwinfo" TARGET_IP # password policy: min length, complexity
rpcclient -U "" -N -c "lsaquery" TARGET_IP # the domain name and its SID
rpcclient -U "" -N -c "enumdomains" TARGET_IP # domains this server knows
# Users
rpcclient -U "" -N -c "enumdomusers" TARGET_IP # every user + RID
rpcclient -U "" -N -c "querydispinfo" TARGET_IP # users with full name + description
rpcclient -U "" -N -c "queryuser 0x457" TARGET_IP # one account by RID (flags, logon)
rpcclient -U "" -N -c "queryusergroups 0x457" TARGET_IP # the RIDs of a user's groups
# Groups
rpcclient -U "" -N -c "enumdomgroups" TARGET_IP # domain groups + RIDs
rpcclient -U "" -N -c "querygroup 0x200" TARGET_IP # one group's attributes
rpcclient -U "" -N -c "querygroupmem 0x200" TARGET_IP # member RIDs of a group
rpcclient -U "" -N -c "enumalsgroups builtin" TARGET_IP # built-in local groups (Administrators, ...)
# Identity mapping and SIDs
rpcclient -U "" -N -c "lookupnames USERNAME" TARGET_IP # name -> SID (+ RID)
rpcclient -U "" -N -c "lookupsids S-1-5-21-...-500" TARGET_IP # SID -> name
rpcclient -U "" -N -c "lsaenumsid" TARGET_IP # SIDs the LSA has cached
# RID cycle when enumdomusers is blocked but lookupsids is not
for i in $(seq 500 1100); do \
rpcclient -U "" -N -c "lookupsids S-1-5-21-1001-1001-1001-$i" TARGET_IP \
| grep -v UNKNOWN; done
# Privileges and rights
rpcclient -U USERNAME -c "enumprivs" TARGET_IP # privilege names the server defines
rpcclient -U USERNAME -c "lsaenumacctrights S-1-5-21-...-500" TARGET_IP # rights held by one SID
# Shares over RPC (a different surface than smbclient -L)
rpcclient -U "" -N -c "netshareenumall" TARGET_IP # every share, including hidden
rpcclient -U "" -N -c "netsharegetinfo SHARE" TARGET_IP # one share's path and info
# Chain, save, and parse
rpcclient -U "" -N -c "querydominfo; enumdomusers; enumdomgroups" TARGET_IP
rpcclient -U "" -N -c "enumdomusers" TARGET_IP 2>&1 | tee loot/users.txt
grep -oP 'user:\[\K[^\]]+' loot/users.txt # one clean username per line
# Change a password (WRITE op; only where you are explicitly authorized)
rpcclient -U USERNAME -c "setuserinfo2 TARGET_USER 23 NEWPASS" TARGET_IP
Command breakdowns#
Each block explains one situation, the exact command, and what to expect back.
Open a null session#
rpcclient -U "" -N TARGET_IP
Empty username, no password. Success is an rpcclient $> prompt (a finding in itself); a hardened box answers NT_STATUS_ACCESS_DENIED or NT_STATUS_LOGON_FAILURE. This is always the cheapest first attempt.
Authenticate with a username and password#
rpcclient -U USERNAME -W DOMAIN TARGET_IP
Prompts for the password so it stays out of shell history. Add -W DOMAIN on domain-joined targets. To avoid the prompt in scripts, put the creds in a file and use -A creds.txt.
Read the server and domain basics#
rpcclient -U "" -N -c "srvinfo; querydominfo" TARGET_IP
srvinfo returns the OS build and server type; querydominfo returns the workgroup or domain, the server role, and the total user count. This is your orientation before any per-object query.
Check the password policy before spraying#
rpcclient -U "" -N -c "getdompwinfo" TARGET_IP
Returns the minimum password length and the complexity flags. Read this first: it tells you the lockout risk and whether a spray candidate even meets the policy, so you do not lock accounts blindly.
List every domain user and RID#
rpcclient -U "" -N -c "enumdomusers" TARGET_IP
Prints lines like user:[bob] rid:[0x3e9]. This is the workhorse call. Save the names for spraying or AS-REP checks elsewhere, and keep the RIDs for targeted lookups.
Pull user details and descriptions#
rpcclient -U "" -N -c "querydispinfo" TARGET_IP
rpcclient -U "" -N -c "queryuser 0x457" TARGET_IP
querydispinfo lists every account with its full name and description in one call (passwords sometimes hide in a description). queryuser <RID> drills into one account: flags, last logon, and bad-password count when permitted.
Enumerate groups and their members#
rpcclient -U "" -N -c "enumdomgroups" TARGET_IP
rpcclient -U "" -N -c "querygroupmem 0x200" TARGET_IP
enumdomgroups gives group names and RIDs; feed a group RID to querygroupmem to get the member RIDs, then resolve each with lookupsids. This is how you find who sits in Domain Admins.
Find which groups a user is in#
rpcclient -U "" -N -c "queryusergroups 0x457" TARGET_IP
Takes a user RID and returns the RIDs of the groups that account belongs to. Pair it with enumdomgroups to turn those RIDs into readable group names.
List the built-in local groups#
rpcclient -U "" -N -c "enumalsgroups builtin" TARGET_IP
Enumerates the machine’s built-in aliases (Administrators, Remote Desktop Users, Backup Operators). Use enumalsgroups domain for domain-local aliases. Membership here often matters more than domain-group membership.
Map a name to a SID and back#
rpcclient -U "" -N -c "lookupnames USERNAME" TARGET_IP
rpcclient -U "" -N -c "lookupsids S-1-5-21-...-500" TARGET_IP
lookupnames resolves a name to its full SID (and exposes the domain SID prefix); lookupsids does the reverse. Together they are the plumbing behind RID cycling and group resolution.
Recover the domain SID#
rpcclient -U "" -N -c "lsaquery" TARGET_IP
Returns the domain name and its S-1-5-21-... SID. You need this prefix to build SIDs for lookupsids, so run it before any RID-cycling loop.
RID-cycle when enumdomusers is blocked#
for i in $(seq 500 1100); do \
rpcclient -U "" -N -c "lookupsids S-1-5-21-1001-1001-1001-$i" TARGET_IP \
| grep -v UNKNOWN; done
When enumdomusers is denied but lookupsids is not, walk the RID range against the real domain SID from lsaquery. Known RIDs resolve to names; unknown ones say *unknown*, which grep -v UNKNOWN filters out.
Enumerate shares over RPC#
rpcclient -U "" -N -c "netshareenumall" TARGET_IP
Lists every share the SRVSVC pipe reports, including hidden $ shares, which is a different code path than smbclient -L. Follow an interesting name with netsharegetinfo SHARE, then switch to smbclient to actually read it.
Authenticate with an NT hash (pass-the-hash)#
rpcclient -U USERNAME --pw-nt-hash -c "enumdomusers" TARGET_IP
When you hold an NT hash instead of a cleartext password, --pw-nt-hash tells rpcclient the value you supply at the prompt is the hash. Only against systems you are explicitly authorized to test.
Run several queries in one connection#
rpcclient -U "" -N -c "querydominfo; enumdomusers; enumdomgroups" TARGET_IP 2>&1 \
| tee "loot/rpc-$(date +%Y%m%d-%H%M).txt"
Semicolons chain commands over a single login, so you authenticate once and get everything in order. Piping through tee timestamps the output and keeps a copy instead of re-running noisy enumeration later.
Reset a user’s password (authorized only)#
rpcclient -U USERNAME -c "setuserinfo2 TARGET_USER 23 NEWPASS" TARGET_IP
A write operation: level 23 sets a new password for TARGET_USER when your account holds the reset right. It changes real state, so run it only where a scope explicitly permits it, and note the change.
Reading the output#
| Output | Meaning | Do next |
|---|---|---|
rpcclient $> prompt | Session accepted | You are in; run commands, and note if it was a null session |
user:[bob] rid:[0x3e9] | A user and its RID | Save the name; feed the RID to queryuser |
NT_STATUS_ACCESS_DENIED | Service answered, account lacks rights | Change the account, not the host |
NT_STATUS_LOGON_FAILURE | Wrong username or password | Re-check creds; try a null session |
NT_STATUS_CONNECTION_REFUSED / _RESET | SMB not open or filtered | Re-scan 139/445 |
NT_STATUS_ACCOUNT_LOCKED_OUT | Too many bad logons | Stop; you tripped lockout, back off |
| Empty user or group list | Stripped box, guest session, or hidden by policy | Not proof of “nothing there”; try credentials |
RIDs print in hex (rid:[0x457]), and queryuser accepts hex or decimal, so keep the notation consistent. Every SID you build for lookupsids needs the domain prefix from lsaquery, not just the trailing RID.
Troubleshooting#
| Problem | Cause | Fix |
|---|---|---|
command not found | Samba client not installed / stale PATH | Install smbclient; open a fresh shell |
NT_STATUS_CONNECTION_REFUSED | SMB not open or filtered | Confirm 445/139 with a port scan first |
NT_STATUS_LOGON_FAILURE | Wrong username or password | Re-check creds; try -U "" -N |
NT_STATUS_ACCESS_DENIED | Account lacks rights for that call | Use valid creds; expect partial output |
| Hangs with no prompt | Wrong port or host unreachable | Add -p, verify the IP, try -d 3 |
| Null session rejected | Anonymous access disabled | Supply real credentials instead |
protocol negotiation failed | Modern client refuses legacy SMB/NTLM | Add --option='client min protocol=NT1' |
| Output differs from a writeup | Samba version or flag changes | Check rpcclient --version and --help |
Gotchas#
- RPC commands go at the
rpcclient $>prompt or after-c, never at the system shell. Typingenumdomusersin bash just givescommand not found. - Permissions are per-call, not per-session. A null session that answers
srvinfocan still denyenumdomusers, so one refusal does not mean the whole session is useless. -U USERNAME%PASSWORDleaks the password into shell history and the process list. Prefer the interactive prompt or-A creds.txt(thenchmod 600it).- Modern Samba disables SMB1 and legacy auth by default, so an old “easy null session” can fail with a negotiation error that is your client’s doing, not the target’s; force the old protocol only when you must.
lookupsidsneeds the full domain SID fromlsaquery, not a bare RID; a RID-cycle loop built on the wrong prefix silently resolves nothing.- A failed null session says nothing about credentialed access. They are separate paths, so do not skip
-U USERNAMEjust because-U "" -Nwas denied.
Pairs with#
nmap confirms 139/445 are open before you ever launch rpcclient. enum4linux-ng runs the same SAMR and LSARPC calls automatically for a fast overview, then rpcclient verifies any single finding with one precise call. NetExec sweeps many hosts and protocols and does password checks at scale, where rpcclient is deliberately one host at a time. Once you find a share, hand it to smbclient to browse and download; when you want RPC output piped into code, reach for Impacket’s samrdump and lookupsid.