smbclient

smbclient is the Samba command-line client for SMB/CIFS file shares: you list a host’s shares, connect to one, move around with ls and cd, and pull files down with get, the way an old FTP client works. Reach for it the moment Nmap reports port 445 open and you want to turn “SMB is running” into “here is what this host actually lets me read.”

Mental model: smbclient [options] //host/share. No share plus -L lists; a share name drops you into an interactive prompt.

New to SMB? Core concepts
  • Share path: //TARGET_IP/sharename selects one share; just //TARGET_IP/ with -L lists them
  • Null session: -N connects with no credentials, testing anonymous / guest access
  • User auth: -U USERNAME, -U 'DOMAIN\USERNAME', or inline -U 'DOMAIN\USER%PASS'
  • Admin / hidden shares: names ending in $ (C$, ADMIN$, IPC$); visible is not the same as readable
  • SMB dialects: SMB1 (legacy, usually off), SMB2, SMB3; the client negotiates, -m forces a ceiling
  • Interactive commands: an FTP-style prompt with ls, cd, get, put, mget, recurse, prompt
  • Listing vs access: -L reads share metadata, connecting reads the share, and the two are separate ACLs
When to reach for smbclient (and when not)

Reach for it to browse one host’s shares by hand after a scan finds 445, pull the specific config or backup files a scanner skims past, confirm whether a share allows anonymous or guest access, verify that a share you locked down really rejects you, or grab a small readable share as a tar for offline review.

Reach for something else when you need to check share access across many hosts at once (NetExec), enumerate users, groups, and password policy over RPC (rpcclient, enum4linux-ng), read every share’s permissions in one shot without navigating (smbmap), or mount a share as a real filesystem for heavy work (mount -t cifs).

Install, update, verify#

sudo apt install -y smbclient                    # Debian / Ubuntu / Kali
sudo dnf install -y samba-client                 # Fedora / RHEL
brew install samba                               # macOS (provides smbclient)
sudo apt install --only-upgrade -y smbclient     # update

smbclient --version        # confirm the Samba version
command -v smbclient       # confirm it is on PATH
smbclient -L //TARGET_IP/ -N   # self-test: list a host you may test, no creds

On Kali, smbclient is part of the base install. Updates mostly buy protocol compatibility: newer clients negotiate SMB2 / SMB3 cleanly with modern Windows, while older ones sometimes need an explicit dialect flag.

Flags you’ll actually use#

Skim these first; the cheat sheet below is these flags combined.

FlagDoesFlagDoes
-LList shares and exit-cRun commands non-interactively ("ls; get f")
-NNull session (no password)-pConnect on a non-standard port
-UUser: USER, DOMAIN\USER, or DOMAIN\USER%PASS-ITarget a specific IP (skip name resolution)
-WSet the workgroup / domain-mForce max dialect (SMB2, SMB3)
-ARead credentials from an auth file-Tc / -TxCreate / extract a tar of the share
-kUse Kerberos authentication-dDebug level 0-10
--pw-nt-hashTreat the -U password as an NT hash (PtH)-tPer-operation timeout in seconds

Cheat sheet#

Every block starts simple and adds one flag at a time, so you can stop at the line that does the job.

# Build up a share listing: stop at the line you need
smbclient -L //TARGET_IP/ -N                      # 1. anonymous (null session)
smbclient -L //TARGET_IP/ -U USERNAME             # 2. + prompt for a password
smbclient -L //TARGET_IP/ -U 'DOMAIN\USERNAME'    # 3. + a domain account
smbclient -L //TARGET_IP/ -U 'DOMAIN\USER%PASS'   # 4. + inline password (labs only)

# Connect into one share
smbclient //TARGET_IP/data -N                     # anonymous into a share
smbclient //TARGET_IP/data -U USERNAME            # authenticated into a share
smbclient //TARGET_IP/data -U USERNAME -p 4455    # non-standard port

# One-shot commands (no interactive prompt)
smbclient //TARGET_IP/data -N -c "ls"             # list and exit
smbclient //TARGET_IP/data -N -c "recurse ON; ls" # full tree in one shot
smbclient //TARGET_IP/data -N -c "cd config; ls"  # step into a subdir first

# Download
smbclient //TARGET_IP/data -U USERNAME -c "get notes.txt loot/notes.txt"
smbclient //TARGET_IP/backup -U USERNAME -c "recurse ON; prompt OFF; mget *"  # bulk (small shares)
smbclient //TARGET_IP/data -U USERNAME -Tc loot/data.tar   # whole share as one tar

# Upload (writable shares, authorized only)
smbclient //TARGET_IP/uploads -U USERNAME -c "put report.txt report.txt"

# Auth variants
smbclient //TARGET_IP/data -U 'DOMAIN\USERNAME' --pw-nt-hash -c "ls"  # pass-the-hash
smbclient //TARGET_IP/data -A creds.txt -c "ls"   # credentials from a file
smbclient //TARGET_IP/data -k -c "ls"             # Kerberos ticket (kinit first)

# Stubborn hosts
smbclient -L //TARGET_IP/ -N -m SMB2              # force a max dialect
smbclient -L //TARGET_IP/ -N -I TARGET_IP         # skip NetBIOS name resolution
smbclient -L //TARGET_IP/ -N -d 3                 # verbose negotiation trace

# Save + echo
smbclient -L //TARGET_IP/ -N | tee notes/shares.txt

# Interactive prompt (inside "smb: \>")
# ls / cd DIR / get FILE / mget * / put FILE / recurse ON / prompt OFF / lcd DIR

Command breakdowns#

Each block below explains one situation, the exact command, and what to expect back.

List shares anonymously (null session)#

smbclient -L //TARGET_IP/ -N

Prints a Sharename / Type / Comment table if the host allows anonymous listing, or a clean NT_STATUS_ACCESS_DENIED if it does not. Either result confirms SMB is reachable; note any non-default share names for the next step.

List shares as an authenticated user#

smbclient -L //TARGET_IP/ -U USERNAME

Prompts for the password, then shows the shares that account can see, usually more than the anonymous view. Use -U 'DOMAIN\USERNAME' on an AD-joined target and quote it so the shell keeps the backslash.

Connect into a share interactively#

smbclient //TARGET_IP/data -U USERNAME

Drops you at an smb: \> prompt inside the share. From here ls, cd, get, and mget behave like an FTP session. Omit -L and name the share to get this prompt.

Run one command and save the output#

smbclient //TARGET_IP/data -N -c "ls" | tee notes/data-listing.txt

-c runs one or more semicolon-separated commands without the interactive prompt, so the listing pipes straight into your notes and stays reproducible.

Download a single file#

smbclient //TARGET_IP/data -U USERNAME -c "get config.bak loot/config.bak"

The second argument is the local path; get config.bak alone would drop the file in your current directory. Expect a getting file ... line and the copy in loot/.

Recursively list a whole share#

smbclient //TARGET_IP/data -N -c "recurse ON; ls"

recurse ON makes ls walk every subdirectory, so you map the whole share in one call instead of cd-ing around by hand. It also changes how mget behaves, so turn it off again for a targeted pull.

Bulk-download a small share#

smbclient //TARGET_IP/backup -U USERNAME -c "recurse ON; prompt OFF; mget *"

prompt OFF stops smbclient asking about every file; recurse ON makes mget * descend into subdirectories. Only when scope justifies it, and only on small shares, or you flood your disk.

Grab an entire share as a tar archive#

smbclient //TARGET_IP/data -N -Tc loot/data.tar

-Tc writes the whole share into a local tar file in one pass, no interactive session needed. -Tx extracts a tar back onto a writable share. Handy for offline review of everything at once.

Upload a file to a writable share#

smbclient //TARGET_IP/uploads -U USERNAME -c "put report.txt report.txt"

put copies a local file up; a putting file ... line confirms write access, which is itself a notable finding. Clean up anything you drop.

Pass-the-hash with an NT hash#

smbclient //TARGET_IP/data -U 'DOMAIN\USERNAME' --pw-nt-hash -c "ls"

When prompted for a password, paste the NT hash instead. Useful when you recovered a hash but never the cleartext, and only inside an authorized scope.

Authenticate to a domain account#

smbclient -L //TARGET_IP/ -W DOMAIN -U USERNAME

-W sets the workgroup / domain separately when -U 'DOMAIN\USERNAME' is awkward to quote. A NT_STATUS_LOGON_FAILURE here means the creds are wrong, not that the host is down.

Force an SMB dialect on a stubborn host#

smbclient -L //TARGET_IP/ -N -m SMB2

-m caps the protocol at a dialect. Reach for it when a modern host refuses SMB1 or an old host only speaks it, and negotiation otherwise fails outright.

Connect on a non-standard port#

smbclient -L //TARGET_IP/ -N -p 4455

-p points smbclient at a redirected or tunneled SMB port instead of 445. Common through a pivot or a port-forward.

Read credentials from a file#

printf 'username=USER\npassword=PASS\ndomain=DOMAIN\n' > creds.txt
smbclient //TARGET_IP/data -A creds.txt -c "ls"

-A reads the three fields from a file so the password never lands in your shell history or the process list. Prefer this over inline %PASSWORD anywhere that matters.

Debug a connection that hangs or refuses#

smbclient -L //TARGET_IP/ -N -d 3

-d 3 raises the debug level so you see the negotiation and where it stalls: a silent hang points at a firewall, a fast refusal at nothing listening on 445.

Reading the output#

You seeMeaningDo next
Sharename / Type / Comment tableListing allowedNote non-default shares (data, backup), skip IPC$
smb: \> promptConnected to a sharels, cd, get; an empty ls means access but no files here
NT_STATUS_ACCESS_DENIEDAnonymous listing blockedRetry with -U USERNAME
NT_STATUS_LOGON_FAILUREWrong username or passwordRe-check creds; quote 'DOMAIN\USER'
NT_STATUS_CONNECTION_REFUSEDNothing on 445 / 139Confirm SMB is open; re-scan the port
NT_STATUS_BAD_NETWORK_NAMEShare name is wrongRe-list and copy the exact name
protocol negotiation failedDialect mismatchForce -m SMB2 or -m SMB3

Admin shares (C$, ADMIN$) that you can actually read usually mean administrative access, which is worth recording carefully. IPC$ is the inter-process channel, not a file share.

Troubleshooting#

ProblemCauseFix
command not foundNot installed / stale PATHReinstall smbclient; open a fresh shell
NT_STATUS_CONNECTION_REFUSEDNothing on 445 / 139Re-check the IP and that SMB is open
NT_STATUS_ACCESS_DENIED (listing)Anonymous listing blockedRetry with -U USERNAME
NT_STATUS_LOGON_FAILUREWrong username or passwordRe-check creds; quote 'DOMAIN\USER'
protocol negotiation failedSMB dialect mismatchForce -m SMB2 or -m SMB3
NT_STATUS_BAD_NETWORK_NAMEShare name wrongRe-list shares; copy the exact name
Hangs with no outputFirewall dropping packetsConfirm reachability; add -d 3 for detail
Backslash disappears in -UShell ate the escapeSingle-quote it: -U 'DOMAIN\USERNAME'

Gotchas#

  • Always single-quote -U 'DOMAIN\USERNAME', or the shell strips the backslash and you authenticate as the wrong principal against the wrong domain.
  • mget * does nothing useful without prompt OFF, because it otherwise stops to confirm every single file one at a time.
  • recurse ON changes both ls and mget, so an innocent mget * will walk the entire share once you have turned recursion on.
  • An inline %PASSWORD lands in shell history and the process list, fine for a throwaway lab but leaky anywhere real; use -A or the interactive prompt instead.
  • A share in the -L list is not one you can necessarily enter, since listing metadata and read access are separate ACLs; connect to confirm.
  • get file.txt drops into your current directory, not where you ran from mentally; pass a second path (get file.txt loot/file.txt) to place it deliberately.

Pairs with#

Nmap finds and fingerprints the SMB ports (139 / 445) before you connect. enum4linux-ng and rpcclient enumerate users, groups, and password policy over RPC when share browsing alone runs dry. NetExec checks share access and sprays one credential across many hosts fast, then hands you the boxes worth opening by hand in smbclient. For a one-shot read of every share’s permissions reach for smbmap, and to work with many files using normal Linux tools mount the share with mount -t cifs instead.

Find us elsewhere

Merch, stickers, and moreSupport the work at the Solvere Labs shop