> For the complete documentation index, see [llms.txt](https://www.impacket.wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.impacket.wiki/tutorials/your-first-smb-session.md).

# Establishing Your First SMB Session

## What you'll learn

By exploring this tutorial, you will learn some of the following such as:

* Connecting to a remote Windows machine over SMB using Impacket
* Authenticating to a remote Windows system
* Listing available shares and browse directories on a target system
* Upload a file from your local machine to a remote share
* Download a file from a remote share to your local machine
* Combine everything into a reusable file-transfer tool

Every step here hinges on uses Impacket's `SMBConnection` class. You will write each piece on its own first, understand what it does, and then assemble the final tool at the end that allows you to learn how to use the SMB implementation to a basic degree.

## Prerequisites

Before you start, make sure you have the following ready.

**A target Windows machine** with file sharing enabled. This can be a VM on your local network, a stock Windows 10/11 install or a Windows Server with a writeable share. Throughout this tutorial we will use the placeholder values below. Substitute the values below with your own wherever neccesary:

| Placeholder  | Meaning                           | Example         |
| ------------ | --------------------------------- | --------------- |
| `TARGET_IP`  | IP address of the Windows host    | `192.168.56.10` |
| `SHARE_NAME` | Name of a writeable share         | `SharedFiles`   |
| `USERNAME`   | A valid local or domain account   | `labuser`       |
| `PASSWORD`   | The password for that account     | `Password123!`  |
| `DOMAIN`     | Domain or `.` for a local account | `.`             |

Start by creating **A test file** to transfer. Create a small one now so it is ready when you need it:

```bash
echo "Hello from the attacker machine!" > testfile.txt
```

## Step 1 Import Impacket and understand the SMBConnection object

Create a new file called `smb_basics.py`. This is your scratch file for the rest of the tutorial.

Start with the single import you need:

```python
from impacket.smbconnection import SMBConnection
```

`SMBConnection` is Impacket's high-level wrapper around the SMB protocol. It handles dialect negotiation (SMBv1, SMBv2, SMBv3), NTLM authentication, and session management for you. Almost everything you will do in this tutorial is a method call on an `SMBConnection` instance. If you do not understand any of these yet, feel free to go to explore the relevant specifications if you would like the "theory" or explore the explanations and reference sections

> **What is happening underneath?** When you create an `SMBConnection`, Impacket opens a TCP socket to port 445 on the target, sends an SMB Negotiate request, and agrees on a protocol version. This is the first step in establishing our SMB session

## Step 2 Connect and authenticate

Add the following to `smb_basics.py`:

```python
from impacket.smbconnection import SMBConnection

#Connection and authentication detials. NOTE use your own material if different
target_ip  = "192.168.56.10"
username   = "labuser"
password   = "Password123!"
domain     = "."                 # use "." for local accounts

# 1. Establish the TCP + SMB negotiation
conn = SMBConnection(target_ip, target_ip)  # (remoteName, remoteHost)
print(f"[*] Connected to {target_ip}")

# 2. Authenticate
conn.login(username, password, domain)
print(f"[+] Authenticated as {domain}\\{username}")
```

Run it:

```bash
python3 smb_basics.py
```

You should see:

```
[*] Connected to 192.168.56.10
[+] Authenticated as .\labuser
```

If you get a connection timeout, verify the target IP is reachable and port 445 is open. If you get `STATUS_LOGON_FAILURE`, ensure the username, password, and domain are all correct/the expected values as opposed to the place holders

### What just happened

1. `SMBConnection(target_ip, target_ip)` opened a socket and completed the SMB Negotiate exchange. The first argument (`remoteName`) is the NetBIOS name used in the SMB header, passing the IP works fine for modern SMB2/3 connections. The second argument (`remoteHost`) is the actual address to connect to.
2. `conn.login()` sent an NTLM authentication sequence (Type 1 → Type 2 → Type 3) and the server granted you a session. You now hold an authenticated SMB session that will stay open for the life of the `conn` object.

> Note that this also means that at the end of our use of the `conn` object we must close/terminate our connection appropriately

## Step 3 List available shares

Now that you have a session, go ahead and find out what share folders the target system has. To do that, add this block below your authentication code:

```python
# 3. List shares
shares = conn.listShares()

print("\n[*] Available shares:")
for share in shares:
    share_name = share['shi1_netname'][:-1]  # strip null terminator
    share_type = share['shi1_type']
    print(f"    {share_name:<20} (type: {share_type})")
```

Run the script again. You will see output similar to:

```
[*] Available shares:
    ADMIN$               (type: 2147483648)
    C$                   (type: 2147483648)
    IPC$                 (type: 2147483651)
    SharedFiles          (type: 0)
```

The share with type `0` is a disk share, which is the one you can read from and write to. The shares ending in `$` are administrative or hidden shares.

> **Try it yourself.** Identify the writeable share name from your output. You will use it in the next steps. If you don't have a custom share, you can use `C$` if your account has administrator privileges.

## Step 4 Browse a remote directory

Pick the writeable share you identified and list its root directory. Add this block:

```python
# 4. List files in the share root
share_name = "SharedFiles"  # replace with your share

files = conn.listPath(share_name, "*")

print(f"\n[*] Contents of \\\\{target_ip}\\{share_name}\\")
for f in files:
    filename = f.get_longname()
    is_dir = f.is_directory()
    file_size = f.get_filesize()
    kind = "<DIR>" if is_dir else f"{file_size:>8} bytes"
    print(f"    {filename:<30} {kind}")
```

Now run it. You should see the directory listing of the share:

```
[*] Contents of \\192.168.56.10\SharedFiles\
    .                              <DIR>
    ..                             <DIR>
    quarterly_report.docx          14832 bytes
    notes.txt                       1024 bytes
```

### Understanding `listPath`

`conn.listPath(shareName, path)` takes two arguments: the share name and a path pattern. The `*` wildcard returns everything in the root of that share. You can also pass subdirectory paths like `subdir\\*` to list nested folders (note the backslash, SMB uses Windows path separators).

## Step 5 Upload a file to the remote share

Now push the `testfile.txt` you created earlier up to the share. Add this block:

```python
# 5. Upload a local file to the remote share
local_file   = "testfile.txt"
remote_path  = "testfile.txt"   # path relative to the share root

with open(local_file, "rb") as fh:
    conn.putFile(share_name, remote_path, fh.read)

print(f"[+] Uploaded {local_file} -> \\\\{target_ip}\\{share_name}\\{remote_path}")
```

Run the script. Then verify the upload by listing the share contents again, you should see `testfile.txt` in the output from Step 4.

### How `putFile` works

```python
conn.putFile(shareName, pathName, callback)
```

The third argument is a **callable** that `putFile` will call repeatedly to read chunks of data. By passing `fh.read` (the file object's `read` method, without parentheses), you give Impacket a function it can call. It will call `fh.read(65536)` internally, getting 64 KB chunks until the file is exhausted.

## Step 6 Download a file from the remote share

Now do the reverse and pull a file from the remote share down to your local machine. Add this block:

```python
# 6. Download a remote file to the local machine
remote_file = "testfile.txt"    # the file you just uploaded
local_dest  = "downloaded_testfile.txt"

with open(local_dest, "wb") as fh:
    conn.getFile(share_name, remote_file, fh.write)

print(f"[+] Downloaded \\\\{target_ip}\\{share_name}\\{remote_file} -> {local_dest}")
```

Run it, then confirm the contents:

```bash
cat downloaded_testfile.txt
```

You should see `Hello from the attacker machine!`.

### How `getFile` works

```python
conn.getFile(shareName, pathName, callback)
```

This is the mirror image of `putFile`. The third argument is a callable that Impacket calls with each chunk of data it receives. By passing `fh.write`, every chunk is written straight to disk.

## Step 7 Clean up the session

Always close your connection when you are done. Add this at the very bottom:

```python
# 7. Disconnect
conn.logoff()
conn.close()
print("[*] Session closed.")
```

This sends an SMB Logoff and tears down the TCP socket cleanly. In scripts that run and exit, the OS will close the socket anyway, but explicit cleanup is a good habit, especially when you start writing longer-running tools.

## Step 8 Build the file transfer tool

You have now done every individual operation in isolation. It is time to combine them into a single, usable command-line tool.

Start by creating a new file called `smb_transfer.py`:

```python
#!/usr/bin/env python3
"""
smb_transfer.py - Transfer files to/from a remote SMB share using Impacket.

Usage:
    Upload:    python3 smb_transfer.py upload   <local_file> <remote_path> [options]
    Download:  python3 smb_transfer.py download <remote_path> <local_file> [options]
"""

import argparse
import sys
import os

from impacket.smbconnection import SMBConnection


def connect(target, username, password, domain):
    """Establish an authenticated SMB session."""
    try:
        conn = SMBConnection(target, target)
    except Exception as e:
        sys.exit(f"[!] Connection failed: {e}")

    try:
        conn.login(username, password, domain)
    except Exception as e:
        sys.exit(f"[!] Authentication failed: {e}")

    print(f"[+] Authenticated to {target} as {domain}\\{username}")
    return conn


def upload_file(conn, share, local_path, remote_path):
    """Upload a local file to the remote share."""
    if not os.path.isfile(local_path):
        sys.exit(f"[!] Local file not found: {local_path}")

    file_size = os.path.getsize(local_path)

    with open(local_path, "rb") as fh:
        conn.putFile(share, remote_path, fh.read)

    print(f"[+] Uploaded {local_path} ({file_size} bytes) -> \\\\{share}\\{remote_path}")


def download_file(conn, share, remote_path, local_path):
    """Download a file from the remote share to the local machine."""
    with open(local_path, "wb") as fh:
        conn.getFile(share, remote_path, fh.write)

    downloaded_size = os.path.getsize(local_path)
    print(f"[+] Downloaded \\\\{share}\\{remote_path} -> {local_path} ({downloaded_size} bytes)")


def parse_args():
    parser = argparse.ArgumentParser(
        description="Transfer files to/from a remote SMB share.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  Upload a file:
    python3 smb_transfer.py upload payload.exe tools/payload.exe \\
        -t 192.168.56.10 -u labuser -p 'Password123!' -s SharedFiles

  Download a file:
    python3 smb_transfer.py download logs/access.log ./access.log \\
        -t 192.168.56.10 -u labuser -p 'Password123!' -s SharedFiles
        """,
    )

    parser.add_argument(
        "action",
        choices=["upload", "download"],
        help="Direction of transfer.",
    )
    parser.add_argument(
        "source",
        help="Source path (local file for upload, remote path for download).",
    )
    parser.add_argument(
        "destination",
        help="Destination path (remote path for upload, local file for download).",
    )
    parser.add_argument("-t", "--target", required=True, help="Target IP or hostname.")
    parser.add_argument("-u", "--username", required=True, help="SMB username.")
    parser.add_argument("-p", "--password", required=True, help="SMB password.")
    parser.add_argument(
        "-d", "--domain", default=".", help="Domain (default: '.' for local accounts)."
    )
    parser.add_argument("-s", "--share", required=True, help="Target share name.")

    return parser.parse_args()


def main():
    args = parse_args()

    conn = connect(args.target, args.username, args.password, args.domain)

    try:
        if args.action == "upload":
            upload_file(conn, args.share, args.source, args.destination)
        else:
            download_file(conn, args.share, args.source, args.destination)
    except Exception as e:
        sys.exit(f"[!] Transfer failed: {e}")
    finally:
        conn.logoff()
        conn.close()
        print("[*] Session closed.")


if __name__ == "__main__":
    main()
```

### Test your tool

**Upload:**

```bash
python3 smb_transfer.py upload testfile.txt testfile.txt -t 192.168.56.10 -u labuser -p 'Password123!' -s SharedFiles
```

**Download:**

```bash
python3 smb_transfer.py download testfile.txt ./pulled_testfile.txt -t 192.168.56.10 -u labuser -p 'Password123!' -s SharedFiles
```

Following this tutorial, both commands should have thus concluded and been sucessfully ran.

## Review what you learned

This tutorial walked you through the full lifecycle of an SMB interaction using Impacket:

1. **`SMBConnection(remoteName, remoteHost)`** — opens a socket and negotiates an SMB dialect.
2. **`conn.login(user, password, domain)`** — authenticates with NTLM and establishes a session.
3. **`conn.listShares()`** — enumerates available shares and their types.
4. **`conn.listPath(share, pattern)`** — lists files and directories within a share.
5. **`conn.putFile(share, path, readCallback)`** — uploads data using a read callback.
6. **`conn.getFile(share, path, writeCallback)`** — downloads data using a write callback.
7. **`conn.logoff()` / `conn.close()`** — tears down the session cleanly.

## Where to go next

Now that you can move files over SMB, here are some directions to explore:

* **NTLM hash authentication.** Try replacing `conn.login(user, password, domain)` with `conn.login(user, '', domain, lmhash='', nthash='aad3b...')` to authenticate using a pass-the-hash technique.
* **Error handling.** What happens if the share doesn't exist? If the remote path has subdirectories that don't exist yet? Add defensive checks to your tool.
* **Recursive transfers.** Extend the tool to upload or download entire directories by walking `listPath` results recursively.
* **Kerberos authentication.** Swap NTLM for Kerberos by exploring `SMBConnection`'s `kerberosLogin()` method.

## References

* **Source Files**: `impacket/smb.py`, `impacket/smb3.py`, `impacket/smbconnection.py`
* **\[MS-SMB]**: SMB 1.0 Protocol Specification
* **\[MS-SMB2]**: SMB 2.0/3.0 Protocol Specification
* **\[MS-CIFS]**: Common Internet File System Protocol


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://www.impacket.wiki/tutorials/your-first-smb-session.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
