--- Server Message Block (SMB, also known as CIFS) traffic.
--
-- SMB traffic is normally
-- sent to/from ports 139 or 445 of Windows systems, although it's also implemented by
-- other systems (the most notable one being Samba).
--
-- The intention of this library is to eventually handle all aspects of the SMB protocol,
-- A programmer using this library must 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 that uses
-- this. 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
--
--
-- 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.
--
-- 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.
--
-- 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 [TODO: Where?], which are set by other
-- scripts. However, they can also be passed as parameters to the function, which will
-- override any other username/password set.
--
-- If a username is set without a password, then a NULL session is started. If a login fails,
-- we attempt to log in as the 'GUEST' account with a blank password. If that fails, we try
-- setting up a NULL session. Starting a NULL session will always work, but we may not get
-- any further (tree_connect
might fail).
--
-- In terms of the login protocol, by default, we sent only NTLMv1 authentication, Lanman
-- isn't set. The reason for this is, NTLMv2 isn't supported by every system (and I don't know
-- how to do message signing on the v2 protocols), and doesn't have a significant security
-- advantage over NTLMv1 (the major change in NTLMv2 is incorporating a client challenge).
-- Lanman is horribly insecure, though, so I don't send it at all. These options can, however,
-- be overridden either through script parameters or registry settings [TODO].
--
-- Lanman v1 is a fairly weak protocol, although it's still fairly difficult to reverse. NTLMv1 is a slightly more secure
-- protocol (although not much) -- it's also fairly difficult to reverse, though. Windows clients, by default send LMv1 and
-- NTLMv1 together, but every modern Windows server will accept NTLM alone, so I opted to use that. LMv2 and NTLMv2 are
-- slightly more secure, and they let the client specify random data (to help fight malicious servers with pre-
-- generated tables). LMv2 and NTLMv2 are identical, except that NTLMv2 has a longer client challenge. LMv2 can be sent
-- alone, but NTLMv2 can't.
--
-- Another interesting aspect of the password hashing is that the original password isn't even necessary, the
-- password's hash can be used instead. This hash can be dumped from memory of a live system by tools such as
-- pwdump and fgdump, or read straight from the SAM file. This means that if a password file is recovered,
-- it doesn't even need to be cracked before it can be used here.
--
-- The response to SMB_COM_SESSION_SETUP_ANDX
is fairly simple, containing a boolean for
-- success, along with the operating system and the lan manager name.
--
-- After a successful SMB_COM_SESSION_SETUP_ANDX
has been made, a
-- SMB_COM_TREE_CONNECT_ANDX
packet can be sent. This is what connects to a share.
-- The server responds to this with a boolean answer, and little more information.
--
-- Each share will either return STATUS_BAD_NETWORK_NAME
if the share doesn't
-- exist, STATUS_ACCESS_DENIED
if it exists but we don't have access, or
-- STATUS_SUCCESS
if exists and we do have access. STATUS_ACCESS_DENIED
is also returned
-- if the server requires message signing and we don't return a valid signature.
--
-- Once we're connected to a share, we can start doing other operations like reading/writing files
-- or calling RPC functions. Calling RPC functions is the interesting part, and it's done through
-- the SMB_TRANS
packet. The actual RPC protocol is built on top of the SMB protocol.
--
-- 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
-- smbusername
, smbpassword
, smbhash
,
-- smbguest
, and smbtype
, described below. Here's an
-- example of using these script arguments:
--
-- nmap --script=smb-