--- Server Message Block (SMB, also known as CIFS) traffic. -- -- SMB traffic is normally sent to/from ports 139 or 445 of Windows systems, some of them -- properly and many of them not. Samba implements it, as do many printers and other embedded -- devices. Although the protocol has been documented decently well by Samba and others, -- many 3rd party implementations are broken or make assumptions. -- -- Naturally, I do the same; however, that being said, this has been tested against every -- broken implementation we could find, and will accept (or fail gracefully) against any -- bad implementations we could find. -- -- 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 find myself needing. If you -- require something more, let me know and I'll put it on my todo list. -- -- 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, 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 will be unexpected). -- -- 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 sent at all. 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 for performing single scans (the major change in NTLMv2 is incorporating -- a client challenge). Lanman is somewhat insecure, though, so I don't send it at all. These options -- can, however, be overridden either through script parameters or registry settings. -- -- Lanman v1 is a fairly weak protocol, although it's still fairly difficult to break. 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 (maybe some day, I'll do an Nmap script to dump it). -- This means that if a password file is recovered, it doesn't even need to be cracked before it can be used here. -- -- 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, -- example of using these script arguments: -- -- nmap --script=smb-