Library smb

Implements functionality related to Server Message Block (SMB, an extension of CIFS) traffic, which is a Windows protocol.

SMB traffic is normally sent to/from ports 139 or 445 of Windows systems. Other systems implement SMB as well, including Samba and a lot of embedded devices. Some of them implement it properly and many of them not. Although the protocol has been documented decently well by Samba and others, many 3rd party implementations are broken or make assumptions. Even Samba's and Windows' implementations aren't completely compatible. As a result, creating an implementation that accepts everything is a bit of a minefield. Microsoft's extensive documentation is available at the following URLs:

Where possible, this implementation, since it's intended for scanning, will attempt to accept any invalid implementations it can, and fail gracefully if it can't. This has been tested against a great number of weird implementations, and it now works against all of them.

The intention of this library is to eventually handle all aspects of the SMB protocol. That being said, I'm only implementing the pieces that I (Ron Bowes) need. If you require something more, let me know and I'll put it on my todo list.

A programmer using this library should already have some knowledge of the SMB protocol, although a lot isn't necessary. You can pick up a lot by looking at the code. The basic login/logoff is this:

[connect]
C->S SMB_COM_NEGOTIATE
S->C SMB_COM_NEGOTIATE
C->S SMB_COM_SESSION_SETUP_ANDX
S->C SMB_COM_SESSION_SETUP_ANDX
C->S SMB_COM_TREE_CONNECT_ANDX
S->C SMB_COM_TREE_CONNECT_ANDX
...
C->S SMB_COM_TREE_DISCONNECT
S->C SMB_COM_TREE_DISCONNECT
C->S SMB_COM_LOGOFF_ANDX
S->C SMB_COM_LOGOFF_ANDX
[disconnect]

In terms of functions here, the protocol is:

status, smbstate = smb.start(host)
status, err      = smb.negotiate_protocol(smbstate, {})
status, err      = smb.start_session(smbstate, {})
status, err      = smb.tree_connect(smbstate, path, {})
...
status, err      = smb.tree_disconnect(smbstate)
status, err      = smb.logoff(smbstate)
status, err      = smb.stop(smbstate)

The stop function will automatically call tree_disconnect and logoff, cleaning up the session, if it hasn't been done already.

To initially begin the connection, there are two options:

1) Attempt to start a raw session over 445, if it's open.

2) Attempt to start a NetBIOS session over 139. Although the protocol's the same, it requires a session request packet. That packet requires the computer's name, which is requested using a NBSTAT probe over UDP port 137.

Once it's connected, a SMB_COM_NEGOTIATE packet is sent, requesting the protocol "NT LM 0.12", which is the most commonly supported one. Among other things, the server's response contains the host's security level, the system time, and the computer/domain name. Some systems will refuse to use that protocol and return "-1" or "1" instead of 0. If that's detected, we kill the connection (because the protocol following won't work).

If that's successful, SMB_COM_SESSION_SETUP_ANDX is sent. It is essentially the logon packet, where the username, domain, and password are sent to the server for verification. The username and password are generally picked up from the program parameters, which are set when running a script, or from the registry where it can be set by other scripts (for example, smb-brute.nse). However, they can also be passed as parameters to the function, which will override any other username/password set.

If a username and password are set, they are used for the first login attempt. If a login fails, or they weren't set, a connection as the 'GUEST' account with a blank password is attempted. If that fails, then a NULL session is established, which should always work. The username/password will give the highest access level, GUEST will give lower access, and NULL will give the lowest (often, NULL will give no access).

The actual login protocol used by SMB_COM_SESSION_SETUP_ANDX is explained in detail in smbauth.lua.

Thanks go to Christopher R. Hertel and his book Implementing CIFS, which taught me everything I know about Microsoft's protocols. Additionally, I used Samba's list of error codes for my constants. Although I don't believe they would be covered by GPL, since they're public now anyways, but I'm not a lawyer and, if somebody feels differently, let me know and we can sort this out.

Scripts that use this module can use the script arguments listed below example of using these script arguments:

nmap --script=smb-<script>.nse --script-args=smbuser=ron,smbpass=iagotest2k3,smbbasic=1,smbsign=force <host>

Author:

  • Ron Bowes <ron@skullsecurity.net>

Copyright © Same as Nmap--See https://nmap.org/book/man-legal.html

Source: https://svn.nmap.org/nmap/nselib/smb.lua

Script Arguments

smbbasic

Forces the authentication to use basic security, as opposed to "extended security". Against most modern systems, extended security should work, but there may be cases where you want to force basic. There's a chance that you'll get better results for enumerating users if you turn on basic authentication.

smbsign

Controls whether or not server signatures are checked in SMB packets. By default, on Windows, server signatures aren't enabled or required. By default, this library will always sign packets if it knows how, and will check signatures if the server says to. Possible values are:

  • force: Always check server signatures, even if server says it doesn't support them (will probably fail, but is technically more secure).
  • negotiate: [default] Use signatures if server supports them.
  • ignore: Never check server signatures. Not recommended.
  • disable: Don't send signatures, at all, and don't check the server's. not recommended. More information on signatures can be found in smbauth.lua.
randomseed

Set to a value to change the filenames/service names that are randomly generated.

smbport

Override the default port choice. If smbport is open, it's used. It's assumed to be the same protocol as port 445, not port 139. Since it probably isn't possible to change Windows' ports normally, this is mostly useful if you're bouncing through a relay or something.

Functions

add_account (host, username, domain, password, password_hash, hash_type, is_admin)

Wrapper around smbauth.add_account.

close_file (smb, overrides)

This sends a SMB request to close a file (or a pipe).

create_file (smb, path, overrides)

This sends a SMB request to open or create a file.

delete_file (smb, path, overrides)

This sends a SMB request to delete a file (or a pipe).

disable_extended (smb)

Turn off extended security negotiations for this connection.

file_delete (host, share, remotefile)

Delete a file from the remote machine

file_read (host, share, remotefile, use_anonymous, overrides)

Write given data to the remote machine on the given share. This is similar to file_upload, except the data is given as a string, not a file.

file_upload (host, localfile, share, remotefile, overrides, encoded)

Upload a file from the local machine to the remote machine, on the given share.

file_write (host, data, share, remotefile, use_anonymous)

Write given data to the remote machine on the given share. This is similar to file_upload, except the data is given as a string, not a file.

files_exist (host, share, files, overrides)

Check how many files, in a given list, exist on the given share.

find_files (smbstate, fname, options)

List files based on a pattern within a given share and directory

get_account (host)

Wrapper around smbauth.get_account.

get_fqpn (host, sharename)

Returns the fully qualified path name (FQPN) for shares. This is required for modern versions of Windows. Returns \\<ip>\<sharename> when successful. Otherwise, returns the same share name.

get_os (host)

Retrieve information about the host's operating system. This should always be possible to call, as long as there isn't already a SMB session established.

get_overrides (username, domain, password, password_hash, hash_type, overrides)

Create an 'overrides' table

get_overrides_anonymous (overrides)

Get an 'overrides' table for the anonymous user

get_port (host)

Determines whether or not SMB checks are possible on this host, and, if they are, which port is best to use. This is how it decides:

get_socket_info (host)

Basically a wrapper around socket:get_info, except that it also makes a SMB connection before calling the get_info function. Returns the mac address as well, for convenience.

get_status_name (status)

Convert a status number from the SMB header into a status name, returning an error message (not nil) if it wasn't found.

get_uniqueish_name (host, extension, seed)

Generate a string that's somewhat unique, but is based on factors that won't change on a host.

get_windows_version (os)

Converts numbered Windows version strings ("Windows 5.0", "Windows 5.1") to names ("Windows 2000", "Windows XP").

is_admin (host, username, domain, password, password_hash, hash_type)

Determines, as accurately as possible, whether or not an account is an administrator. If there is an error, 'false' is simply returned.

list_dialects (host, overrides)

Returns list of supported dialects for SMBv1, SMBv2 and SMBv3.

logoff (smb, overrides)

Logs off the current user. Strictly speaking this isn't necessary, but it's the polite thing to do.

negotiate_protocol (smb, overrides)

Wrapper function to negotiate the protocol to use in the SMB connection. By default it attempts to negotiate with using following dialects:

  • NT LM 12.0 (SMBv1)
negotiate_v1 (smb, overrides)

Negotiates SMBv1 connections

read_file (smb, offset, count, overrides)

This sends a SMB request to read from a file (or a pipe).

send_transaction_named_pipe (smb, function_parameters, function_data, pipe, no_setup, overrides)

This is the core of making MSRPC calls. It sends out a MSRPC packet with the given parameters and data.

share_anonymous_can_read (host, share)

Check whether or not a share is accessible by the anonymous user. Assumes that share_host_returns_proper_error has been called and returns true.

share_anonymous_can_write (host, share)

Determine whether or not the anonymous user has write access on the share. This is done by creating then deleting a file.

share_find_writable (host)

Find a share that the current user can write to. Return it, along with its path. If no share could be found, an error is returned. If the path cannot be determined, the returned path is nil.

share_get_details (host, share)

Get all the details we can about the share. These details are stored in a table and returned.

share_get_list (host)

Retrieve a list of fileshares, along with any details that could be pulled. This is the core of smb-enum-shares.nse, but can also be used by any script that needs to find an open share.

share_host_returns_proper_error (host, use_anonymous)

Determine whether or not a host will accept any share name (I've seen this on certain systems; it's bad, because it means we cannot tell whether or not a share exists).

share_user_can_read (host, share)

Check whether or not a share is accessible by the current user. Assumes that share_host_returns_proper_error has been called and returns true.

share_user_can_write (host, share)

Determine whether or not the current user has read or read/write access on the share. This is done by creating then deleting a file.

smb_encode_header (smb, command, overrides)

Creates a string containing a SMB packet header. The header looks like this:

smb_read (smb, read_data)

Reads the next packet from the socket, and parses it into the header, parameters, and data.

smb_send (smb, header, parameters, data, overrides)

Prepends the NetBIOS header to the packet, which is essentially the length, encoded in 4 bytes of big endian, and sends it out.

start (host)

Begins a SMB session, automatically determining the best way to connect.

start_ex (host, bool_negotiate_protocol, bool_start_session, str_tree_connect, str_create_file, bool_disable_extended, overrides)

Initiates a SMB connection over whichever port it can, then optionally sends the common initialization packets.

start_netbios (host, port, name)

Begins a SMB session over NetBIOS.

start_raw (host, port)

Begins a raw SMB session, likely over port 445. Since nothing extra is required, this function simply makes a connection and returns the socket.

start_session (smb, overrides, log_errors)

Sends out SMB_COM_SESSION_SETUP_ANDX, which attempts to log a user in.

stop (smb)

Kills the SMB connection and closes the socket.

tree_connect (smb, path, overrides)

Sends out SMB_COM_SESSION_TREE_CONNECT_ANDX, which attempts to connect to a share.

tree_disconnect (smb, overrides)

Disconnects a tree session. Should be called before logging off and disconnecting.

write_file (smb, write_data, offset, overrides)

This sends a SMB request to write to a file (or a pipe).

Functions

add_account (host, username, domain, password, password_hash, hash_type, is_admin)

Wrapper around smbauth.add_account.

Parameters

host
 
username
 
domain
 
password
 
password_hash
 
hash_type
 
is_admin
 
close_file (smb, overrides)

This sends a SMB request to close a file (or a pipe).

Parameters

smb
The SMB object associated with the connection
overrides
The overrides table

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is undefined.
create_file (smb, path, overrides)

This sends a SMB request to open or create a file.

Most of the parameters I pass here are used directly from a packetlog, especially the various permissions fields and flags. I might make this more adjustable in the future, but this has been working for me.

Parameters

smb
The SMB object associated with the connection
path
The path of the file or pipe to open
overrides
[optional] Overrides for various fields

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a table containing a lot of different elements, the most important one being 'fid', the handle to the opened file.
delete_file (smb, path, overrides)

This sends a SMB request to delete a file (or a pipe).

Parameters

smb
The SMB object associated with the connection
path
The path of the file to delete
overrides
The overrides table

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is undefined.
disable_extended (smb)

Turn off extended security negotiations for this connection.

There are a few reasons you might want to do that, the main ones being that extended security is going to be marginally slower and it's not going to give the same level of information in some cases (namely, it doesn't present the server's name).

Parameters

smb
The SMB state table.
file_delete (host, share, remotefile)

Delete a file from the remote machine

Parameters

host
The host object
share
The share to upload it to (eg, C$).
remotefile
The remote file on the machine. It is relative to the share's root. It can be a string, or an array.

Return value:

(status, err) If status is false, err is an error message. Otherwise, err is undefined.
file_read (host, share, remotefile, use_anonymous, overrides)

Write given data to the remote machine on the given share. This is similar to file_upload, except the data is given as a string, not a file.

Parameters

host
The host object
share
The share to read it from (eg, C$).
remotefile
The remote file on the machine. It is relative to the share's root.
use_anonymous
[optional] If set to 'true', test is done by the anonymous user rather than the current user.
overrides
[optional] Override various fields in the SMB packets.

Return value:

(status, err) If status is false, err is an error message. Otherwise, err is undefined.
file_upload (host, localfile, share, remotefile, overrides, encoded)

Upload a file from the local machine to the remote machine, on the given share.

Parameters

host
The host object
localfile
The file on the local machine, relative to the nmap path
share
The share to upload it to (eg, C$).
remotefile
The remote file on the machine. It is relative to the share's root.
overrides
A table of override values that's passed to the smb functions.
encoded
Set to 'true' if the file is encoded (xor'ed with 0xFF), It will be decoded before upload. Default: false

Return value:

(status, err) If status is false, err is an error message. Otherwise, err is undefined.
file_write (host, data, share, remotefile, use_anonymous)

Write given data to the remote machine on the given share. This is similar to file_upload, except the data is given as a string, not a file.

Parameters

host
The host object
data
The string containing the data to be written
share
The share to upload it to (eg, C$).
remotefile
The remote file on the machine. It is relative to the share's root.
use_anonymous
[optional] If set to 'true', test is done by the anonymous user rather than the current user.

Return value:

(status, err) If status is false, err is an error message. Otherwise, err is undefined.
files_exist (host, share, files, overrides)

Check how many files, in a given list, exist on the given share.

Parameters

host
The host object
share
The share to read it from (eg, C$).
files
A list of files to look for; it is relative to the share's root.
overrides
[optional] Override various fields in the SMB packets.

Return values:

  1. status: A true/false value indicating success
  2. count: The number of files that existed, or an error message if status is 'false'
  3. files: A list of the files that existed.
find_files (smbstate, fname, options)

List files based on a pattern within a given share and directory

Parameters

smbstate
the SMB object associated with the connection
fname
filename to search for, relative to share path
options
table containing none or more of the following maxfiles how many files to request in a single Trans2 op srch_attrs table containing one or more of the following boolean attributes: ro - find read only files hidden - find hidden files system - find system files volid - include volume ids in result dir - find directories archive - find archived files

Return value:

iterator function retrieving the next result
get_account (host)

Wrapper around smbauth.get_account.

Parameters

host
 
get_fqpn (host, sharename)

Returns the fully qualified path name (FQPN) for shares. This is required for modern versions of Windows. Returns \\<ip>\<sharename> when successful. Otherwise, returns the same share name.

Parameters

host
 
sharename
 
get_os (host)

Retrieve information about the host's operating system. This should always be possible to call, as long as there isn't already a SMB session established.

The returned table has the following keys (shown here with sample values).

  • os: "Windows 7 Professional 7601 Service Pack 1"
  • lanmanager: "Windows 7 Professional 6.1"
  • domain: "WORKGROUP"
  • server: "COMPUTERNAME"
  • time: 1347121470.0462
  • date: "2012-09-08 09:24:30"
  • timezone: -7
  • timezone_str: UTC-7
  • port: 445
The table may also contain these additional keys:
  • fqdn: "Sql2008.lab.test.local"
  • domain_dns: "lab.test.local"
  • forest_dns: "test.local"
  • workgroup

Parameters

host
The host object

Return value:

(status, data) If status is true, data is a table of values; otherwise, data is an error message.
get_overrides (username, domain, password, password_hash, hash_type, overrides)

Create an 'overrides' table

Parameters

username
 
domain
 
password
 
password_hash
 
hash_type
 
overrides
 
get_overrides_anonymous (overrides)

Get an 'overrides' table for the anonymous user

Parameters

overrides
[optional] A base table of overrides. The appropriate fields will be added.
get_port (host)

Determines whether or not SMB checks are possible on this host, and, if they are, which port is best to use. This is how it decides:

  • If port tcp/445 is open, use it for a raw connection
  • Otherwise, if ports tcp/139 and udp/137 are open, do a NetBIOS connection. Since UDP scanning isn't default, we're also ok with udp/137 in an unknown state.

Parameters

host
The host object.

Return value:

The port number to use, or nil if we don't have an SMB port
get_socket_info (host)

Basically a wrapper around socket:get_info, except that it also makes a SMB connection before calling the get_info function. Returns the mac address as well, for convenience.

Parameters

host
The host object

Return values:

  1. status: true for successful, false otherwise.
  2. If status is true, the local ip address; otherwise, an error message.
  3. The local port (not really meaningful, since it'll change next time).
  4. The remote ip address.
  5. The report port.
  6. The mac address, if possible; nil otherwise.
get_status_name (status)

Convert a status number from the SMB header into a status name, returning an error message (not nil) if it wasn't found.

Parameters

status
The numerical status.

Return value:

A string representing the error. Never nil.
get_uniqueish_name (host, extension, seed)

Generate a string that's somewhat unique, but is based on factors that won't change on a host.

At the moment, this is a very simple hash based on the IP address. This hash is *very* likely to have collisions, and that's by design -- while it should be somewhat unique, I don't want it to be trivial to uniquely determine who it originated from.

TODO: At some point, I should re-do this function properly, with a method of hashing that's somewhat proven.

Parameters

host
The host object
extension
[optional] The extension to add on the end of the file. Default: none.
seed
[optional] Some randomness on which to base the name. If you want to do multiple files, each with its own uniqueish name, this can be used.

Return value:

(status, data) If status is true, data is a table of values; otherwise, data is an error message. Can be any kind of string.
get_windows_version (os)

Converts numbered Windows version strings ("Windows 5.0", "Windows 5.1") to names ("Windows 2000", "Windows XP").

Parameters

os
The numbered OS version.

Return value:

The actual name of the OS (or the same as the os parameter if no match was found).
is_admin (host, username, domain, password, password_hash, hash_type)

Determines, as accurately as possible, whether or not an account is an administrator. If there is an error, 'false' is simply returned.

Parameters

host
 
username
 
domain
 
password
 
password_hash
 
hash_type
 
list_dialects (host, overrides)

Returns list of supported dialects for SMBv1, SMBv2 and SMBv3.

Parameters

host
The SMB host to connect to.
overrides
[optional] Overrides for various fields.

Return values:

  1. Boolean status
  2. Table of supported dialects or error message
logoff (smb, overrides)

Logs off the current user. Strictly speaking this isn't necessary, but it's the polite thing to do.

Parameters

smb
The SMB object associated with the connection
overrides
THe overrides table

Return value:

(status, result) If status is false, result is an error message. If status is true, the logoff was successful.
negotiate_protocol (smb, overrides)

Wrapper function to negotiate the protocol to use in the SMB connection. By default it attempts to negotiate with using following dialects:

  • NT LM 12.0 (SMBv1)

Parameters

smb
The SMB object
overrides
Overrides table

Return value:

Boolean status
negotiate_v1 (smb, overrides)

Negotiates SMBv1 connections

Sends the following:

  • List of known protocols

This function adds to smb:

  • 'security_mode' Whether or not to use cleartext passwords, message signatures, etc.
  • 'max_mpx' Maximum number of multiplexed connections
  • 'max_vc' Maximum number of virtual circuits
  • 'max_buffer' Maximum buffer size
  • 'max_raw_buffer' Maximum buffer size for raw connections (considered obsolete)
  • 'session_key' A value that's basically just echoed back
  • 'capabilities' The server's capabilities
  • 'time' The server's time (in UNIX-style seconds since 1970)
  • 'date' The server's date in a user-readable format
  • 'timezone' The server's timezone, in hours from UTC
  • 'timezone_str' The server's timezone, as a string
  • 'server_challenge' A random string used for challenge/response
  • 'domain' The server's primary domain or workgroup
  • 'server' The server's name

Parameters

smb
The SMB object associated with the connection.
overrides
Overrides table.

Return values:

  1. Boolean status
  2. The negotiated dialect in human readable form or an error message.
read_file (smb, offset, count, overrides)

This sends a SMB request to read from a file (or a pipe).

Parameters

smb
The SMB object associated with the connection
offset
The offset to read from (ignored if it's a pipe)
count
The maximum number of bytes to read
overrides
The overrides table

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a table containing a lot of different elements.
send_transaction_named_pipe (smb, function_parameters, function_data, pipe, no_setup, overrides)

This is the core of making MSRPC calls. It sends out a MSRPC packet with the given parameters and data.

Don't confuse these parameters and data with SMB's concepts of parameters and data -- they are completely different. In fact, these parameters and data are both sent in the SMB packet's 'data' section.

It is probably best to think of this as another protocol layer. This function will wrap SMB stuff around a MSRPC call, make the call, then unwrap the SMB stuff from it before returning.

Parameters

smb
The SMB object associated with the connection
function_parameters
The parameter data to pass to the function. This is untested, since none of the transactions I've done have required parameters.
function_data
The data to send with the packet. This is basically the next protocol layer
pipe
[optional] The pipe to transact on. Default: "\PIPE\".
no_setup
[optional] If set, the 'setup' is set to 0 and some parameters are left off. This occurs while using the LANMAN Remote API. Default: false.
overrides
The overrides table

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a table containing 'parameters' and 'data', representing the parameters and data returned by the server.
share_anonymous_can_read (host, share)

Check whether or not a share is accessible by the anonymous user. Assumes that share_host_returns_proper_error has been called and returns true.

Parameters

host
The host object
share
The share to test

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a boolean value: true if anonymous access is permitted, false otherwise.
share_anonymous_can_write (host, share)

Determine whether or not the anonymous user has write access on the share. This is done by creating then deleting a file.

Parameters

host
The host object
share
The share to test

Return value:

(status, result) If status is false, result is an error message. The error message 'NT_STATUS_OBJECT_NAME_NOT_FOUND' should be handled gracefully; it indicates that the share isn't a fileshare. Otherwise, result is a boolean value: true if the file was successfully written, false if it was not.
share_find_writable (host)

Find a share that the current user can write to. Return it, along with its path. If no share could be found, an error is returned. If the path cannot be determined, the returned path is nil.

Parameters

host
The host object.

Return value:

(status, name, path, names) If status is false, result is an error message. Otherwise, name is the name of the share, path is its path, if it could be determined, and names is a list of all writable shares.
share_get_details (host, share)

Get all the details we can about the share. These details are stored in a table and returned.

Parameters

host
The host object.
share
An array of shares to check.

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a boolean value: true if the file was successfully written, false if it was not.
share_get_list (host)

Retrieve a list of fileshares, along with any details that could be pulled. This is the core of smb-enum-shares.nse, but can also be used by any script that needs to find an open share.

In the best care, the shares are determined by calling msrpc.enum_shares, and information is gathered by calling msrpc.get_share_info. These require a certain level of access, though, so as a fallback, a pre-programmed list of shares is used, and these are verified by attempting a connection.

Parameters

host
The host object.

Return value:

(status, result, extra) If status is false, result is an error message. Otherwise, result is an array of shares with as much detail as we could get. If extra isn't nil, it is set to extra information that should be displayed (such as a warning).
share_host_returns_proper_error (host, use_anonymous)

Determine whether or not a host will accept any share name (I've seen this on certain systems; it's bad, because it means we cannot tell whether or not a share exists).

Parameters

host
The host object
use_anonymous
[optional] If set to 'true', test is done by the anonymous user rather than the current user.

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a boolean value: true if the file was successfully written, false if it was not.
share_user_can_read (host, share)

Check whether or not a share is accessible by the current user. Assumes that share_host_returns_proper_error has been called and returns true.

Parameters

host
The host object
share
The share to test

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a boolean value: true if anonymous access is permitted, false otherwise.
share_user_can_write (host, share)

Determine whether or not the current user has read or read/write access on the share. This is done by creating then deleting a file.

Parameters

host
The host object
share
The share to test

Return value:

(status, result) If status is false, result is an error message. The error message 'NT_STATUS_OBJECT_NAME_NOT_FOUND' should be handled gracefully; it indicates that the share isn't a fileshare. Otherwise, result is a boolean value: true if the file was successfully written, false if it was not.
smb_encode_header (smb, command, overrides)

Creates a string containing a SMB packet header. The header looks like this:

--------------------------------------------------------------------------------------------------
| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0 |
--------------------------------------------------------------------------------------------------
|         0xFF           |          'S'          |        'M'            |         'B'           |
--------------------------------------------------------------------------------------------------
|        Command         |                             Status...                                 |
--------------------------------------------------------------------------------------------------
|    ...Status           |        Flags          |                    Flags2                     |
--------------------------------------------------------------------------------------------------
|                    PID_high                    |                  Signature.....               |
--------------------------------------------------------------------------------------------------
|                                        ....Signature....                                       |
--------------------------------------------------------------------------------------------------
|              ....Signature                     |                    Unused                     |
--------------------------------------------------------------------------------------------------
|                      TID                       |                     PID                       |
--------------------------------------------------------------------------------------------------
|                      UID                       |                     MID                       |
-------------------------------------------------------------------------------------------------

All fields are, incidentally, encoded in little endian byte order.

For the purposes here, the program doesn't care about most of the fields so they're given default values. The "command" field is the only one we ever have to set manually, in my experience. The TID and UID need to be set, but those are stored in the smb state and don't require user intervention.

Parameters

smb
The smb state table.
command
The command to use.
overrides
The overrides table. Keep in mind that overriding things like flags is generally a very bad idea, unless you know what you're doing.

Return value:

A binary string containing the packed packet header.
smb_read (smb, read_data)

Reads the next packet from the socket, and parses it into the header, parameters, and data.

Parameters

smb
The SMB object associated with the connection
read_data
[optional] This function will read the data section if and only if this value is true. This is a workaround for a bug in the tree connect packet, where the length is set incorrectly. Default: true.

Return value:

(status, header, parameters, data) If status is true, the header, parameters, and data are all the raw arrays (with the lengths already removed). If status is false, header contains an error message and parameters/ data are undefined.
smb_send (smb, header, parameters, data, overrides)

Prepends the NetBIOS header to the packet, which is essentially the length, encoded in 4 bytes of big endian, and sends it out.

The length field is actually 17 or 24 bits wide, depending on whether or not we're using raw, but that shouldn't matter.

Parameters

smb
The SMB object associated with the connection
header
The header, encoded with smb_get_header.
parameters
The parameters.
data
The data.
overrides
Overrides table.

Return value:

(result, err) If result is false, err is the error message. Otherwise, err is undefined
start (host)

Begins a SMB session, automatically determining the best way to connect.

Parameters

host
The host object

Return value:

(status, smb) if the status is true, result is the newly crated smb object; otherwise, socket is the error message.
start_ex (host, bool_negotiate_protocol, bool_start_session, str_tree_connect, str_create_file, bool_disable_extended, overrides)

Initiates a SMB connection over whichever port it can, then optionally sends the common initialization packets.

Note that each packet depends on the previous one, so if you want to go all the way up to create_file, you have to set all parameters.

If anything fails, we back out of the connection and return an error, so the calling function doesn't have to call smb.stop().

Parameters

host
The host object.
bool_negotiate_protocol
[optional] If 'true', send the protocol negotiation. Default: false.
bool_start_session
[optional] If 'true', start the session. Default: false.
str_tree_connect
[optional] The tree to connect to, if given (eg. "IPC$" or "C$"). If not given, packet isn't sent.
str_create_file
[optional] The path and name of the file (or pipe) that's created, if given. If not given, packet isn't sent.
bool_disable_extended
[optional] If set to true, disables extended security negotiations.
overrides
[optional] A table of overrides (for, for example, username, password, etc.) to pass to all functions.
start_netbios (host, port, name)

Begins a SMB session over NetBIOS.

This requires a NetBIOS Session Start message to be sent first, which in turn requires the NetBIOS name. The name can be provided as a parameter, or it can be automatically determined.

Automatically determining the name is interesting, to say the least. Here are the names it tries, and the order it tries them in:

  • The name the user provided, if present
  • The name pulled from NetBIOS (udp/137), if possible
  • The generic name "*SMBSERVER"
  • Each subset of the domain name (for example, scanme.insecure.org would attempt "scanme", "scanme.insecure", and "scanme.insecure.org")

This whole sequence is a little hackish, but it's the standard way of doing it.

Parameters

host
The host object to check.
port
The port to use (most likely 139).
name
[optional] The NetBIOS name of the host. Will attempt to automatically determine if it isn't given.

Return value:

(status, socket) if status is true, result is the port Otherwise, socket is the error message.
start_raw (host, port)

Begins a raw SMB session, likely over port 445. Since nothing extra is required, this function simply makes a connection and returns the socket.

Parameters

host
The host object to check.
port
The port to use (most likely 445).

Return value:

(status, socket) if status is true, result is the newly created socket. Otherwise, socket is the error message.
start_session (smb, overrides, log_errors)

Sends out SMB_COM_SESSION_SETUP_ANDX, which attempts to log a user in.

Sends the following:

  • Negotiated parameters (multiplexed connections, virtual circuit, capabilities)
  • Passwords (plaintext, unicode, lanman, ntlm, lmv2, ntlmv2, etc)
  • Account name
  • OS (I just send "Nmap")
  • Native LAN Manager (no clue what that is, but it seems to be ignored)

Receives the following:

  • User ID
  • Server OS

Parameters

smb
The SMB object associated with the connection
overrides
[optional] A table of overrides for username, domain, password, password_hash, and hash_type. If any of these are given, it's used first. If they aren't, then Nmap parameters, Nmap registry entries, guest, and NULL sessions are used.
log_errors
[optional] If set, will display login. Default: true.

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is nil and the following elements are added to the smb table: * 'uid' The UserID for the session * 'is_guest' If set, the username wasn't found so the user was automatically logged in as the guest account * 'os' The operating system * 'lanmanager' The server's LAN Manager
stop (smb)

Kills the SMB connection and closes the socket.

In addition to killing the connection, this function will log off the user and disconnect the connected tree, if possible.

Parameters

smb
The SMB object associated with the connection

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is undefined.
tree_connect (smb, path, overrides)

Sends out SMB_COM_SESSION_TREE_CONNECT_ANDX, which attempts to connect to a share.

Sends the following:

  • Password (for share-level security, which we don't support)
  • Share name
  • Share type (or "?????" if it's unknown, that's what we do)

Receives the following:

  • Tree ID

Parameters

smb
The SMB object associated with the connection
path
The path to connect (eg, "\\servername\C$")
overrides
[optional] Overrides for various fields

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a table with the following elements: * 'tid' The TreeID for the session
tree_disconnect (smb, overrides)

Disconnects a tree session. Should be called before logging off and disconnecting.

Parameters

smb
The SMB object associated with the connection
overrides
THe overrides table

Return value:

(status, result) If status is false, result is an error message. If status is true, the disconnect was successful.
write_file (smb, write_data, offset, overrides)

This sends a SMB request to write to a file (or a pipe).

Parameters

smb
The SMB object associated with the connection
write_data
The data to write
offset
The offset to write it to (ignored for pipes)
overrides
The overrides table

Return value:

(status, result) If status is false, result is an error message. Otherwise, result is a table containing a lot of different elements, the most important one being 'fid', the handle to the opened file.