1--- 2-- Implements the Server Message Block (SMB) protocol version 2 and 3. 3-- 4-- The implementation extends smb.lua to support SMB dialects 2.02, 2.10, 3.0, 5-- 3.02 and 3.11. This is a work in progress and not all commands are 6-- implemented yet. Features/functionality will be added as the scripts 7-- get updated. I tried to be consistent with the current implementation of 8-- smb.lua but some fields may have changed name or don't exist anymore. 9-- 10-- @author Paulino Calderon <paulino@calderonpale.com> 11-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html 12--- 13 14local datetime = require "datetime" 15local string = require "string" 16local stdnse = require "stdnse" 17local table = require "table" 18local tableaux = require "tableaux" 19local match = require "match" 20 21_ENV = stdnse.module("smb2", stdnse.seeall) 22 23local TIMEOUT = 10000 24local command_names = {} 25local command_codes = 26{ 27 SMB2_COM_NEGOTIATE = 0x0000, 28 SMB2_COM_SESSION_SETUP = 0x0001, 29 SMB2_COM_LOGOFF = 0x0002, 30 SMB2_COM_TREE_CONNECT = 0x0003, 31 SMB2_COM_TREE_DISCONNECT = 0x0004, 32 SMB2_COM_CREATE = 0x0005, 33 SMB2_COM_CLOSE = 0x0006, 34 SMB2_COM_FLUSH = 0x0007, 35 SMB2_COM_READ = 0x0008, 36 SMB2_COM_WRITE = 0x0009, 37 SMB2_COM_LOCK = 0x000A, 38 SMB2_COM_IOCTL = 0x000B, 39 SMB2_COM_CANCEL = 0x000C, 40 SMB2_COM_ECHO = 0x000D, 41 SMB2_COM_QUERY_DIRECTORY = 0x000E, 42 SMB2_COM_CHANGE_NOTIFY = 0x000F, 43 SMB2_COM_QUERY_INFO = 0x0010, 44 SMB2_COM_SET_INFO = 0x0011, 45 SMB2_COM_OPLOCK_BREAK = 0x0012 46} 47local smb2_values_codes = {} 48local smb2_values = { 49 -- Security Mode 50 SMB2_NEGOTIATE_SIGNING_ENABLED = 0x0001, 51 SMB2_NEGOTIATE_SIGNING_REQUIRED = 0x0002, 52 -- Capabilities 53 SMB2_GLOBAL_CAP_DFS = 0x00000001, 54 SMB2_GLOBAL_CAP_LEASING = 0x00000002, 55 SMB2_GLOBAL_CAP_LARGE_MTU = 0x00000004, 56 SMB2_GLOBAL_CAP_MULTI_CHANNEL = 0x00000008, 57 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 0x00000010, 58 SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 0x00000020, 59 SMB2_GLOBAL_CAP_ENCRYPTION = 0x00000040, 60 -- Context Types 61 SMB2_ENCRYPTION_CAPABILITIES = 0x0002, 62 SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001 63} 64 65for i, v in pairs(command_codes) do 66 command_names[v] = i 67end 68for i, v in pairs(smb2_values) do 69 smb2_values_codes[v] = i 70end 71 72--- 73-- Creates a SMB2 SYNC header packet. 74-- 75-- SMB2 Packet Header - SYNC: 76-- * https://msdn.microsoft.com/en-us/library/cc246529.aspx 77-- 78-- @param smb The SMB object associated with the connection. 79-- @param command The SMB2 command to execute. 80-- @param overrides Overrides table. 81-- @return header The encoded SMB2 SYNC header. 82--- 83function smb2_encode_header_sync(smb, command, overrides) 84 overrides = overrides or {} 85 86 local sig = "\xFESMB" -- SMB2 packet 87 local structureSize = 64 -- SYNC header structure size 88 local flags = 0 -- TODO: Set flags that will work for all dialects 89 90 -- Increase the message id 91 if smb['MessageId'] then 92 smb['MessageId'] = smb['MessageId'] + 1 93 end 94 95 -- Header structure 96 local header = string.pack("<c4 I2 I2 I4 I2 I2 I4 I4 I8 I4 I4 I8 c16", 97 sig, -- 4 bytes: ProtocolId 98 structureSize, -- 2 bytes: StructureSize. Must be 64. 99 (overrides['CreditCharge'] or 0), -- 2 bytes: CreditCharge. 100 (overrides['Status'] or 0), -- 4 bytes: (ChannelSequence/Reserved)/Status. 101 command, -- 2 bytes: Command. 102 (overrides['CreditR'] or 0), -- 2 bytes: CreditRequest/CreditResponse. 103 (overrides['Flags'] or flags), -- 4 bytes: Flags. TODO 104 (overrides['NextCommand'] or 0), -- 4 bytes: NextCommand. 105 (overrides['MessageId'] or smb['MessageId'] or 0), -- 8 bytes: MessageId. 106 (overrides['Reserved'] or 0), -- 4 bytes: Reserved. 107 (overrides['TreeId'] or smb['TreeId'] or 0), -- 4 bytes: TreeId. 108 (overrides['SessionId'] or smb['SessionId'] or 0), -- 8 bytes: SessionId. 109 (overrides['Signature'] or '1234567890123456') -- 16 bytes: Signature. 110 ) 111 112 return header 113end 114 115--- 116-- Sends a SMB2 packet 117-- @param smb The SMB object associated with the connection 118-- @param header The header encoded with <code>smb_encode_sync_header</code>. 119-- @param data The data. 120-- @param overrides Overrides table. 121-- @return Boolean Status. 122-- @return An error message if status is false. 123--- 124function smb2_send(smb, header, data, overrides) 125 overrides = overrides or {} 126 local body = header .. data 127 local attempts = 5 128 local status, err 129 130 local out = string.pack(">s4", body) 131 repeat 132 attempts = attempts - 1 133 stdnse.debug3("SMB: Sending SMB packet (len: %d, attempts remaining: %d)", #out, attempts) 134 status, err = smb['socket']:send(out) 135 until(status or (attempts == 0)) 136 137 if(attempts == 0) then 138 stdnse.debug1("SMB: Sending packet failed after 5 tries! Giving up.") 139 end 140 141 return status, err 142end 143 144--- 145-- Reads the next SMB2 packet from the socket, and parses it into the header and data. 146-- Netbios handling based taken from smb.lua. 147-- 148-- @param smb The SMB object associated with the connection 149-- @param read_data [optional] Return data section. Set to false if you only need the header. Default: true 150-- @return (status, header, data) If status is true, the header, 151-- and data are all the raw arrays of bytes. 152-- If status is false, header contains an error message and data is undefined. 153--- 154function smb2_read(smb, read_data) 155 stdnse.debug3("SMB2: Receiving SMB2 packet") 156 157 -- Receive the response -- we make sure to receive at least 4 bytes, the length of the NetBIOS length 158 smb['socket']:set_timeout(TIMEOUT) 159 160 -- attempt to read the Netbios header 161 local status, netbios_data = smb['socket']:receive_buf(match.numbytes(4), true); 162 163 -- Make sure the connection is still alive 164 if not status then 165 return false, "SMB2: Failed to receive bytes: " .. netbios_data 166 end 167 168 -- The length of the packet is 4 bytes of big endian (for our purposes). 169 -- The NetBIOS header is 24 bits, big endian 170 local netbios_length, pos = string.unpack(">I4", netbios_data) 171 -- Make the length 24 bits 172 netbios_length = netbios_length & 0x00FFFFFF 173 174 -- The total length is the netbios_length, plus 4 (for the length itself) 175 local length = netbios_length + 4 176 177 local status, smb_data = smb['socket']:receive_buf(match.numbytes(netbios_length), true) 178 179 -- Make sure the connection is still alive 180 if not status then 181 return false, "SMB2: Failed to receive bytes after 5 attempts: " .. smb_data 182 end 183 184 local result = netbios_data .. smb_data 185 if(#result ~= length) then 186 stdnse.debug1("SMB2: ERROR: Received wrong number of bytes, there will likely be issues (received %d, expected %d)", #result, length) 187 return false, string.format("SMB2: ERROR: Didn't receive the expected number of bytes; received %d, expected %d. This will almost certainly cause some errors.", #result, length) 188 end 189 190 -- The header is 64 bytes. 191 if (pos + 64 > #result) then 192 stdnse.debug2("SMB2: SMB2 packet too small. Size needed to be at least '%d' but we got '%d' bytes", pos+64, #result) 193 return false, "SMB2: ERROR: Header packet too small." 194 end 195 local header, pos = string.unpack("<c64", result, pos) 196 197 -- Read the data section or skip it if read_data is false. 198 local data 199 if(read_data == nil or read_data == true) then 200 data = result:sub(pos) 201 end 202 203 stdnse.debug3("SMB2: smb2_read() received %d bytes", #result) 204 return true, header, data 205end 206 207--- 208-- Sends SMB2_COM_NEGOTIATE command for a SMB2/SMB3 connection. 209-- This function works for dialects 2.02, 2.10, 3.0, 3.02 and 3.11. 210-- 211-- Packet structure: https://msdn.microsoft.com/en-us/library/cc246543.aspx 212-- 213-- @param smb The associated SMB connection object. 214-- @param overrides Overrides table. 215-- @return (status, dialect) If status is true, the negotiated dialect is returned as the second value. 216-- Otherwise if status is false, the error message is returned. 217function negotiate_v2(smb, overrides) 218 local StructureSize = 36 -- Must be set to 36. 219 local DialectCount 220 if overrides['Dialects'] then 221 DialectCount = #overrides['Dialects'] 222 else 223 DialectCount = 1 224 end 225 -- The client MUST set SecurityMode bit to 0x01 if the SMB2_NEGOTIATE_SIGNING_REQUIRED bit is not set, 226 -- and MUST NOT set this bit if the SMB2_NEGOTIATE_SIGNING_REQUIRED bit is set. 227 -- The server MUST ignore this bit. 228 local SecurityMode = overrides["SecurityMode"] or smb2_values['SMB2_NEGOTIATE_SIGNING_ENABLED'] 229 local Capabilities = overrides["Capabilities"] or 0 -- SMB 3.x dialect requires capabilities to be constructed 230 local GUID = overrides["GUID"] or "1234567890123456" 231 local ClientStartTime = overrides["ClientStartTime"] or 0 -- ClientStartTime only used in dialects > 3.11 232 local total_data = 0 -- Data counter 233 local padding_data = "" -- Padding string to align contexts 234 local context_data -- Holds Context data 235 local is_0311 = false -- Flag for SMB 3.11 236 local status, err 237 238 if not( overrides['Dialects'] ) then -- Set 2.02 as default dialect if user didn't select one 239 overrides['Dialects'] = {0x0202} 240 end 241 242 local header = smb2_encode_header_sync(smb, command_codes['SMB2_COM_NEGOTIATE'], overrides) 243 244 -- We construct the first block that works for dialects 2.02 up to 3.11. 245 local data = string.pack("<I2 I2 I2 I2 I4 c16", 246 StructureSize, -- 2 bytes: StructureSize 247 DialectCount, -- 2 bytes: DialectCount 248 SecurityMode, -- 2 bytes: SecurityMode 249 0, -- 2 bytes: Reserved - Must be 0 250 Capabilities, -- 4 bytes: Capabilities - 0 for dialects > 3.x 251 GUID -- 16 bytes: ClientGuid 252 ) 253 254 -- The next block gets interpreted in different ways depending on the dialect 255 if tableaux.contains(overrides['Dialects'], 0x0311) then 256 is_0311 = true 257 end 258 259 -- If we are dealing with 3.11 we need to set the following fields: 260 -- NegotiateContextOffset, NegotiateContextCount, and Reserved2 261 if is_0311 then 262 total_data = #header + #data + (DialectCount*2) 263 padding_data = string.rep("\0", (8 - total_data % 8) % 8) 264 total_data = total_data + #padding_data 265 data = data .. string.pack("<I4 I2 I2", 266 total_data+8, -- NegotiateContextOffset (4 bytes) 267 0x2, -- NegotiateContextCount (2 bytes) 268 0x0 -- Reserved2 (2 bytes) 269 ) 270 else -- If it's not 3.11, the bytes are the ClientStartTime (8 bytes) 271 data = data .. string.pack("<I8", ClientStartTime) -- If it is not 3.11, we set it to 0 272 end -- if is_0311 273 274 -- Now we build the Dialect list, 16 bit integers 275 if(overrides['Dialects'] == nil) then -- If no custom dialect is defined, used the default 2.10 276 data = data .. string.pack("<I2", 0x0210) 277 else -- Dialects are set in overrides table 278 for _, v in ipairs(overrides['Dialects']) do 279 data = data .. string.pack("<I2", v) 280 end 281 end 282 283 -- If 3.11, we now need to add some padding between the dialects and the NegotiateContextList 284 -- I was only able to get this to work using both NegotiateContexts: 285 -- * SMB2_PREAUTH_INTEGRITY_CAPABILITIES 286 -- * SMB2_ENCRYPTION_CAPABILITIES 287 if is_0311 then 288 data = data .. padding_data 289 local negotiate_context_list, context_data 290 291 -- We set SMB2_ENCRYPTION_CAPABILITIES first 292 context_data = string.pack("<I2 I2 I2", 293 0x2, -- CipherCount (2 bytes): 2 ciphers available 294 0x0002, -- Ciphers (2 bytes each): AES-128-GCM 295 0x0001 -- Ciphers (2 bytes each): AES-128-CCM 296 ) 297 data = data .. string.pack("<I2 I2 I4", 298 smb2_values['SMB2_ENCRYPTION_CAPABILITIES'],-- ContextType (2 bytes) 299 #context_data, -- DataLength (2 bytes) 300 0x0 -- Reserved (4 bytes) 301 ) .. context_data -- Data (SMB2_ENCRYPTION_CAPABILITIES) 302 303 -- We now add SMB2_PREAUTH_INTEGRITY_CAPABILITIES 304 -- We add the padding between contexts so they are 8 byte aligned 305 total_data = #header + #data 306 padding_data = string.rep("\0", (8 - total_data % 8) % 8) 307 data = data .. padding_data 308 context_data = context_data .. string.pack("<I2 I2 I2 I16 I16", 309 0x1, -- HashAlgorithmCount (2 bytes) 310 0x20, -- SaltLength (2 bytes) 311 0x0001, -- HashAlgorithms (2 bytes each): SHA-512 312 0x0, -- Salt 313 0x1 -- Salt 314 ) 315 data = data .. string.pack("<I2 I2 I4", 316 smb2_values['SMB2_PREAUTH_INTEGRITY_CAPABILITIES'], -- ContextType (2 bytes) 317 #context_data, -- DataLength (2 bytes) 318 0x0 -- Reserved (4 bytes) 319 ) .. context_data 320 321 end 322 323 status, err = smb2_send(smb, header, data) 324 if not status then 325 return false, err 326 end 327 status, header, data = smb2_read(smb) 328 329 local protocol_version, structure_size, credit_charge, status = string.unpack("<c4 I2 I2 I4", header) 330 -- Get the protocol version 331 if(protocol_version ~= ("\xFESMB") or structure_size ~= 64) then 332 return false, "SMB: Server returned an invalid SMBv2 packet" 333 end 334 stdnse.debug2("SMB2_COM_NEGOTIATE returned status '%s'", status) 335 336 if status ~= 0 then 337 stdnse.debug2("SMB2_COM_NEGOTIATE command failed: Dialect not supported.") 338 return false, "SMB2: Dialect is not supported. Exiting." 339 end 340 341 local parameters_format = "<I2 I2 I2 I2 c16 I4 I4 I4 I4 I8 I8" 342 if #data < string.packsize(parameters_format) then 343 -- smb.lua can tolerate missing time/timezone, but it's less likely any 344 -- SMB2 implementations will not have them. If this becomes a problem, we 345 -- can shorten this unpack format like in smb.negotiate_v1 346 return false, "SMB2: ERROR: Server returned less data than it was supposed to (one or more fields are missing)" 347 end 348 349 local data_structure_size, security_mode, negotiate_context_count 350 data_structure_size, smb['security_mode'], smb['dialect'], 351 negotiate_context_count, smb['server_guid'], smb['capabilities'], 352 smb['max_trans'], smb['max_read'], smb['max_write'], smb['time'], 353 smb['start_time'] = string.unpack(parameters_format, data) 354 355 if(data_structure_size ~= 65) then 356 return false, string.format("Server returned an unknown structure size in SMB2 NEGOTIATE response") 357 end 358 359 -- Convert the time and timezone to human readable values (taken from smb.lua) 360 smb['time'] = (smb['time'] // 10000000) - 11644473600 361 smb['date'] = datetime.format_timestamp(smb['time']) 362 363 -- Samba does not report the boot time 364 if smb['start_time'] ~= 0 then 365 smb['start_time'] = (smb['start_time'] // 10000000) - 11644473600 366 smb['start_date'] = datetime.format_timestamp(smb['start_time']) 367 else 368 smb['start_date'] = "N/A" 369 end 370 371 local security_buffer_offset, security_buffer_length, neg_context_offset 372 security_buffer_offset, security_buffer_length, neg_context_offset = string.unpack("<I2 I2 I4", data) 373 if status == 0 then 374 return true, overrides['Dialects'] 375 else 376 return false, string.format("Status error code:%s",status) 377 end 378end 379 380return _ENV; 381