Server Message Block (SMB) v2

Files and Directories management with an SMB server. Supports SMB2 and SMB3 protocols.

Utilities · Server Message Block (SMB)

Details

IDServer Message Block (SMB) v2
ProviderMicrosoft
CategoryUtilities
From Version5.0.0
Docker Imagedemisto/smbprotocol:1.0.0.9067966
Supported ModulesAgentix Cloud Runtime Security Cloud Posture Security XSIAM EDR Cortex Cloud

README

Files and Directories management with an SMB server. Supports SMB2 and SMB3 protocols.

Configure Server Message Block (SMB) v2 in Cortex

Parameter Description Required
Server IP / Hostname (e.g. 1.2.3.4)   False
Port   False
Domain Controller The domain controller hostname. This is useful for environments with DFS servers as it is used to identify the DFS domain information automatically. False
Username   False
Client GUID The client machine name to identify the client to the server on a new connection. False
Force Encryption Force encryption on the connection, requires SMBv3 or newer on the remote server. Default is “false”. False
Secure Dialect Negotiation Validate the negotiation info when connecting to a share. More information can be found on https://docs.microsoft.com/en-us/archive/blogs/openspecification/smb3-secure-dialect-negotiation False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

smb-download


Downloads a file from the server.

Base Command

smb-download

Input

Argument Name Description Required
file_path The path to the file, starting from the share, for example: Share/Folder/File. This field is case-insensitive. Required
hostname Server IP address / hostname. If empty, the hostname from the instance configuration is used. Optional
username The username to use when creating a new SMB session. If empty, the username from the instance configuration is used. Optional
password The password to use for authentication. If empty, the password from the instance configuration is used. Optional

Context Output

Path Type Description
File.Size number File size.
File.SHA1 string SHA1 hash of the file.
File.SHA256 string SHA256 hash of the file.
File.Name string File name.
File.SSDeep string SSDeep hash of the file.
File.EntryID string File entry ID.
File.Info string Information about the file.
File.Type string File type.
File.MD5 string MD5 hash of the file.

Command Example

!smb-download file_path=Shared/Tests/Test.txt

Context Example

{
    "File": {
        "EntryID": "2837@51c113de-6213-4aea-8beb-d4b88551f7f8",
        "Extension": "txt",
        "Info": "text/plain; charset=utf-8",
        "MD5": "ce114e4501d2f4e2dcea3e17b546f339",
        "Name": "Test.txt",
        "SHA1": "a54d88e06612d820bc3be72877c74f257b561b19",
        "SHA256": "c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e",
        "SHA512": "a028d4f74b602ba45eb0a93c9a4677240dcf281a1a9322f183bd32f0bed82ec72de9c3957b2f4c9a1ccf7ed14f85d73498df38017e703d47ebb9f0b3bf116f69",
        "SSDeep": "3:hMCEpn:hup",
        "Size": 14,
        "Type": "ASCII text, with no line terminators"
    }
}

Human Readable Output

smb-upload


Uploads a file to the server.

Base Command

smb-upload

Input

Argument Name Description Required
file_path The path to the file, starting from the share, for example: Share/Folder/File. This field is case-insensitive. Required
hostname Server IP address / hostname. If empty, the hostname from the instance configuration is used. Optional
username The username to use when creating a new SMB session. If empty, the username from the instance configuration is used. Optional
password The password to use for authentication. If empty, the password from the instance configuration is used. Optional
entryID EntryID of the file to send to the share. Optional
content File content to send to the share. Ignored if EntryID argument is specified. Optional

Context Output

There is no context output for this command.

Command Example

!smb-upload file_path=Shared/Tests/Test.txt content="This is a test"

Human Readable Output

File Test.txt was uploaded successfully

smb-directory-list


Returns a list containing the names of the entries in the directory given by path.

Base Command

smb-directory-list

Input

Argument Name Description Required
path The path to the directory, starting from the share, for example: Share/Folder. This field is case-insensitive. Required
hostname Server IP address / hostname. If empty, the hostname from the instance configuration is used. Optional
username The username to use when creating a new SMB session. If empty, the username from the instance configuration is used. Optional
password The password to use for authentication. If empty, the password from the instance configuration is used. Optional

Context Output

Path Type Description
SMB.Path.SharedFolder String The full path of the shared folder.
SMB.Path.Files Unknown List of files under the shared folder.
SMB.Path.Directories Unknown List of directories under the shared folder.

Command Example

!smb-directory-list path=Shared

Context Example

{
    "SMB": {
        "Path": {
            "Directories": [
                "Tests"
            ],
            "Files": [
                "123.txt",
                "test.jpg"
            ],
            "SharedFolder": "127.0.0.1/Shared"
        }
    }
}

Human Readable Output

List Of Entries for 127.0.0.1/Shared

Directories Files SharedFolder
Tests 123.txt,
test.jpg
127.0.0.1/Shared

smb-file-remove


Removes a file from the server.

Base Command

smb-file-remove

Input

Argument Name Description Required
file_path The path to the file, starting from the share, for example: Share/Folder/File. This field is case-insensitive. Required
hostname Server IP address / hostname. If empty, the hostname from the instance configuration is used. Optional
username The username to use when creating a new SMB session. If empty, the username from the instance configuration is used. Optional
password The password to use for authentication. If empty, the password from the instance configuration is used. Optional

Context Output

There is no context output for this command.

Command Example

!smb-file-remove file_path=Shared/Tests/Test.txt

Human Readable Output

File Test.txt was deleted successfully

smb-directory-create


Creates a new directory under the given path.

Base Command

smb-directory-create

Input

Argument Name Description Required
path The path to the directory, starting from the share, for example: Share/NewFolder. This field is case-insensitive. Required
hostname Server IP address / hostname. If empty, the hostname from the instance configuration is used. Optional
username The username to use when creating a new SMB session. If empty, the username from the instance configuration is used. Optional
password The password to use for authentication. If empty, the password from the instance configuration is used. Optional

Context Output

There is no context output for this command.

Command Example

!smb-directory-create path=Shared/Tests

Human Readable Output

Directory: 127.0.0.1/Shared/Tests was created successfully

smb-directory-remove


Removes a directory from the given path.

Base Command

smb-directory-remove

Input

Argument Name Description Required
path The path to the directory, starting from the share, for example: Share/NewFolder. This field is case-insensitive. Required
hostname Server IP address / hostname. If empty, the hostname from the instance configuration is used. Optional
username The username to use when creating a new SMB session. If empty, the username from the instance configuration is used. Optional
password The password to use for authentication. If empty, the password from the instance configuration is used. Optional

Context Output

There is no context output for this command.

Command Example

!smb-directory-remove path=Shared/Tests

Human Readable Output

Directory: 127.0.0.1/Shared/Tests was removed successfully

Configuration parameters

  • hostname — Server IP / Hostname (e.g. 1.2.3.4)
  • port — Port
  • dc — Domain Controller
  • credentials — Username
  • client_guid — Client GUID
  • encrypt — Force Encryption
  • require_secure_negotiate — Secure Dialect Negotiation

Commands (6)

  • smb-directory-create

    Creates a new directory under the given path.

  • smb-directory-list

    Returns a list containing the names of the entries in the directory given by path.

  • smb-directory-remove

    Removes a directory from the given path.

  • smb-download

    Downloads a file from the server.

  • smb-file-remove

    Removes a file from the server.

  • smb-upload

    Uploads a file to the server.

import uuid

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

""" IMPORTS """

import smbclient
from smbclient import (
    mkdir,
    open_file,
    register_session,
    remove,
    rmdir,
    scandir,
)


def get_file_name(path):
    delimiter = "/" if "/" in path else "\\"
    return path.split(delimiter)[-1]


def handle_path(path):
    """
    Stripping the '\\' and '/' characters from a given path.
    Examples:
        \\Shared\\123.txt\\ ---> Shared\\123.txt
        /Shared/123.txt/ ---> Shared/123.txt
        \\Shared\\123.txt/\\ ---> Shared\\123.txt
    """
    return path.strip("\\/")


def create_share_path(hostname, path):
    r"""
    Create a path to the shared folder according to the smbprotocol convention: '\\server\share'.
    For reference see https://github.com/jborean93/smbprotocol/blob/master/examples/high-level/directory-management.py
    """
    return rf"\\{hostname}\{path}"


class SMBClient:
    def __init__(self, hostname, user, password, encrypt, port):
        self.hostname = hostname
        self._user = user
        self._password = password
        self._encrypt = encrypt
        self._port = port

    def create_session(
        self, hostname: str = None, user: str = None, password: str = None, encrypt: bool = False, port: int = None
    ):
        register_session(
            server=hostname or self.hostname,
            username=user or self._user,
            password=password or self._password,
            port=port or self._port,
            encrypt=encrypt or self._encrypt,
            auth_protocol="ntlm",
        )


def test_module(client: SMBClient):
    client.create_session()
    return "ok"


def smb_upload(client: SMBClient, args: dict):
    hostname = args.get("hostname")
    path = handle_path(args.get("file_path"))
    path = create_share_path(hostname or client.hostname, path)
    username = args.get("username")
    password = args.get("password")
    entryID = args.get("entryID")
    content = args.get("content")

    if not entryID and not content:
        raise DemistoException("You must provide a content to upload using one of the following arguments: content, entryID.")

    client.create_session(hostname, username, password)

    # For the content argument - the input is text.
    writing_mode = "w"
    if entryID:
        file = demisto.getFilePath(entryID)
        filePath = file["path"]
        writing_mode = "wb"

        with open(filePath, mode="rb") as f:
            content = f.read()

    with open_file(rf"{path}", mode=writing_mode) as file_obj:
        file_obj.write(content)
    return f"File {get_file_name(path)} was uploaded successfully"


def smb_download(client: SMBClient, args: dict):
    hostname = args.get("hostname")
    path = handle_path(args.get("file_path"))
    path = create_share_path(hostname or client.hostname, path)
    username = args.get("username")
    password = args.get("password")

    client.create_session(hostname, username, password)

    with open_file(rf"{path}", mode="rb") as fd:
        file_contents = fd.read()
        file_name = get_file_name(path)
        return fileResult(file_name, file_contents)


def smb_remove_file(client: SMBClient, args: dict):
    hostname = args.get("hostname")
    path = handle_path(args.get("file_path"))
    path = create_share_path(hostname or client.hostname, path)
    username = args.get("username")
    password = args.get("password")

    client.create_session(hostname, username, password)
    remove(path)
    file_name = get_file_name(path)
    return f"File {file_name} was deleted successfully"


def list_dir(client: SMBClient, args: dict):
    hostname = args.get("hostname")
    username = args.get("username")
    password = args.get("password")
    path = handle_path(args.get("path"))
    path = create_share_path(hostname or client.hostname, path)

    client.create_session(hostname, username, password)
    entries = list(scandir(path))

    files = []
    dirs = []

    for entry in entries:
        if entry.is_file():
            files.append(entry.name)
        if entry.is_dir():
            dirs.append(entry.name)

    context = {
        "SharedFolder": path,
        "Files": files,
        "Directories": dirs,
    }
    return CommandResults(
        outputs_prefix="SMB.Path",
        outputs_key_field="SharedFolder",
        outputs=context,
        readable_output=tableToMarkdown(f"List Of Entries for {path}", context),
    )


def smb_mkdir(client: SMBClient, args: dict):
    hostname = args.get("hostname")
    username = args.get("username")
    password = args.get("password")
    path = handle_path(args.get("path"))
    path = create_share_path(hostname or client.hostname, path)

    client.create_session(hostname, username, password)

    mkdir(path)

    return f"Directory: {path} was created successfully"


def smb_rmdir(client: SMBClient, args: dict):
    hostname = args.get("hostname")
    username = args.get("username")
    password = args.get("password")
    path = handle_path(args.get("path"))
    path = create_share_path(hostname or client.hostname, path)

    client.create_session(hostname, username, password)
    rmdir(path)

    return f"Directory: {path} was removed successfully"


def main():
    params = demisto.params()
    hostname = params["hostname"]
    port = int(params.get("port", "445"))
    user = params["credentials"]["identifier"]
    password = params["credentials"]["password"]
    encrypt = params.get("encrypt", False)
    dc = params.get("dc", None)
    verify = params.get("require_secure_negotiate", True)
    client_guid = params.get("client_guid", None)

    # Temporary workaround to an issue in the smbprotocol package.
    # Git issue: https://github.com/jborean93/smbprotocol/issues/109
    config = smbclient.ClientConfig(username=user, password=password, require_secure_negotiate=verify)
    config.domain_controller = dc

    if client_guid:
        try:
            client_guid = uuid.UUID(client_guid)
            config.client_guid = client_guid
        except ValueError:
            demisto.info(f"Failed to convert {client_guid} to a valid UUID string. Using a random generated UUID instead")

    client = SMBClient(hostname=hostname, user=user, password=password, encrypt=encrypt, port=port)

    demisto.info(f"Command being called is {demisto.command()}")

    try:
        if demisto.command() == "test-module":
            return_results(test_module(client))
        elif demisto.command() == "smb-download":
            return_results(smb_download(client, demisto.args()))
        elif demisto.command() == "smb-upload":
            return_results(smb_upload(client, demisto.args()))
        elif demisto.command() == "smb-directory-list":
            return_results(list_dir(client, demisto.args()))
        elif demisto.command() == "smb-file-remove":
            return_results(smb_remove_file(client, demisto.args()))
        elif demisto.command() == "smb-directory-create":
            return_results(smb_mkdir(client, demisto.args()))
        elif demisto.command() == "smb-directory-remove":
            return_results(smb_rmdir(client, demisto.args()))
    except Exception as e:
        return_error(f"Failed to execute {demisto.command()} command. Error: {e!s}")
    finally:
        smbclient.reset_connection_cache()


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()