1--- 2-- Implements functionality related to Server Message Block (SMB, an extension 3-- of CIFS) traffic, which is a Windows protocol. 4-- 5-- SMB traffic is normally sent to/from ports 139 or 445 of Windows systems. Other systems 6-- implement SMB as well, including Samba and a lot of embedded devices. Some of them implement 7-- it properly and many of them not. Although the protocol has been documented decently 8-- well by Samba and others, many 3rd party implementations are broken or make assumptions. 9-- Even Samba's and Windows' implementations aren't completely compatible. As a result, 10-- creating an implementation that accepts everything is a bit of a minefield. Microsoft's 11-- extensive documentation is available at the following URLs: 12-- * SMB: http://msdn.microsoft.com/en-us/library/cc246231(v=prot.13).aspx 13-- * CIFS: http://msdn.microsoft.com/en-us/library/ee442092(v=prot.13).aspx 14-- 15-- Where possible, this implementation, since it's intended for scanning, will attempt to 16-- accept any invalid implementations it can, and fail gracefully if it can't. This has 17-- been tested against a great number of weird implementations, and it now works against 18-- all of them. 19-- 20-- The intention of this library is to eventually handle all aspects of the SMB protocol. 21-- That being said, I'm only implementing the pieces that I (Ron Bowes) need. If you 22-- require something more, let me know and I'll put it on my todo list. 23-- 24-- A programmer using this library should already have some knowledge of the SMB protocol, 25-- although a lot isn't necessary. You can pick up a lot by looking at the code. The basic 26-- login/logoff is this: 27-- 28-- <code> 29-- [connect] 30-- C->S SMB_COM_NEGOTIATE 31-- S->C SMB_COM_NEGOTIATE 32-- C->S SMB_COM_SESSION_SETUP_ANDX 33-- S->C SMB_COM_SESSION_SETUP_ANDX 34-- C->S SMB_COM_TREE_CONNECT_ANDX 35-- S->C SMB_COM_TREE_CONNECT_ANDX 36-- ... 37-- C->S SMB_COM_TREE_DISCONNECT 38-- S->C SMB_COM_TREE_DISCONNECT 39-- C->S SMB_COM_LOGOFF_ANDX 40-- S->C SMB_COM_LOGOFF_ANDX 41-- [disconnect] 42-- </code> 43-- 44-- In terms of functions here, the protocol is: 45-- 46-- <code> 47-- status, smbstate = smb.start(host) 48-- status, err = smb.negotiate_protocol(smbstate, {}) 49-- status, err = smb.start_session(smbstate, {}) 50-- status, err = smb.tree_connect(smbstate, path, {}) 51-- ... 52-- status, err = smb.tree_disconnect(smbstate) 53-- status, err = smb.logoff(smbstate) 54-- status, err = smb.stop(smbstate) 55-- </code> 56-- 57-- The <code>stop</code> function will automatically call tree_disconnect and logoff, 58-- cleaning up the session, if it hasn't been done already. 59-- 60-- To initially begin the connection, there are two options: 61-- 62-- 1) Attempt to start a raw session over 445, if it's open. 63-- 64-- 2) Attempt to start a NetBIOS session over 139. Although the 65-- protocol's the same, it requires a <code>session request</code> packet. 66-- That packet requires the computer's name, which is requested 67-- using a NBSTAT probe over UDP port 137. 68-- 69-- Once it's connected, a <code>SMB_COM_NEGOTIATE</code> packet is sent, requesting the protocol 70-- "NT LM 0.12", which is the most commonly supported one. Among other things, the server's 71-- response contains the host's security level, the system time, and the computer/domain name. 72-- Some systems will refuse to use that protocol and return "-1" or "1" instead of 0. If that's 73-- detected, we kill the connection (because the protocol following won't work). 74-- 75-- If that's successful, <code>SMB_COM_SESSION_SETUP_ANDX</code> is sent. It is essentially the logon 76-- packet, where the username, domain, and password are sent to the server for verification. 77-- The username and password are generally picked up from the program parameters, which are 78-- set when running a script, or from the registry where it can be set by other scripts (for 79-- example, <code>smb-brute.nse</code>). However, they can also be passed as parameters to the 80-- function, which will override any other username/password set. 81-- 82-- If a username and password are set, they are used for the first login attempt. If a login fails, 83-- or they weren't set, a connection as the 'GUEST' account with a blank password is attempted. If 84-- that fails, then a NULL session is established, which should always work. The username/password 85-- will give the highest access level, GUEST will give lower access, and NULL will give the lowest 86-- (often, NULL will give no access). 87-- 88-- The actual login protocol used by <code>SMB_COM_SESSION_SETUP_ANDX</code> is explained in detail 89-- in <code>smbauth.lua</code>. 90-- 91-- Thanks go to Christopher R. Hertel and his book Implementing CIFS, which 92-- taught me everything I know about Microsoft's protocols. Additionally, I used Samba's 93-- list of error codes for my constants. Although I don't believe they would be covered 94-- by GPL, since they're public now anyways, but I'm not a lawyer and, if somebody feels 95-- differently, let me know and we can sort this out. 96-- 97-- Scripts that use this module can use the script arguments listed below 98-- example of using these script arguments: 99-- <code> 100-- nmap --script=smb-<script>.nse --script-args=smbuser=ron,smbpass=iagotest2k3,smbbasic=1,smbsign=force <host> 101-- </code> 102-- 103-- @args smbbasic Forces the authentication to use basic security, as opposed to "extended security". 104-- Against most modern systems, extended security should work, but there may be cases 105-- where you want to force basic. There's a chance that you'll get better results for 106-- enumerating users if you turn on basic authentication. 107-- @args smbsign Controls whether or not server signatures are checked in SMB packets. By default, on Windows, 108-- server signatures aren't enabled or required. By default, this library will always sign 109-- packets if it knows how, and will check signatures if the server says to. Possible values are: 110-- * <code>force</code>: Always check server signatures, even if server says it doesn't support them (will 111-- probably fail, but is technically more secure). 112-- * <code>negotiate</code>: [default] Use signatures if server supports them. 113-- * <code>ignore</code>: Never check server signatures. Not recommended. 114-- * <code>disable</code>: Don't send signatures, at all, and don't check the server's. not recommended. 115-- More information on signatures can be found in <code>smbauth.lua</code>. 116-- @args smbport Override the default port choice. If <code>smbport</code> is open, it's used. It's assumed 117-- to be the same protocol as port 445, not port 139. Since it probably isn't possible to change 118-- Windows' ports normally, this is mostly useful if you're bouncing through a relay or something. 119-- @args randomseed Set to a value to change the filenames/service names that are randomly generated. 120-- 121-- @author Ron Bowes <ron@skullsecurity.net> 122-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html 123----------------------------------------------------------------------- 124local asn1 = require "asn1" 125local datetime = require "datetime" 126local io = require "io" 127local math = require "math" 128local match = require "match" 129local netbios = require "netbios" 130local nmap = require "nmap" 131local smbauth = require "smbauth" 132local stdnse = require "stdnse" 133local string = require "string" 134local table = require "table" 135local tableaux = require "tableaux" 136local unicode = require "unicode" 137local smb2 = require "smb2" 138_ENV = stdnse.module("smb", stdnse.seeall) 139 140-- These arrays are filled in with constants at the bottom of this file 141command_codes = {} 142command_names = {} 143status_codes = {} 144status_names = {} 145filetype_codes = {} 146filetype_names = {} 147 148local TIMEOUT = 10000 149 150---Wrapper around <code>smbauth.add_account</code>. 151function add_account(host, username, domain, password, password_hash, hash_type, is_admin) 152 smbauth.add_account(host, username, domain, password, password_hash, hash_type, is_admin) 153end 154 155---Wrapper around <code>smbauth.get_account</code>. 156function get_account(host) 157 return smbauth.get_account(host) 158end 159---Create an 'overrides' table 160function get_overrides(username, domain, password, password_hash, hash_type, overrides) 161 if(not(overrides)) then 162 return {username=username, domain=domain, password=password, password_hash=password_hash, hash_type=hash_type} 163 else 164 overrides['username'] = username 165 overrides['domain'] = domain 166 overrides['password'] = password 167 overrides['password_hash'] = password_hash 168 overrides['hash_type'] = hash_type 169 end 170end 171 172---Get an 'overrides' table for the anonymous user 173-- 174--@param overrides [optional] A base table of overrides. The appropriate fields will be added. 175function get_overrides_anonymous(overrides) 176 if(not(overrides)) then 177 return {username='', domain='', password='', password_hash=nil, hash_type='none'} 178 else 179 overrides['username'] = '' 180 overrides['domain'] = '' 181 overrides['password'] = '' 182 overrides['password_hash'] = '' 183 overrides['hash_type'] = 'none' 184 end 185end 186 187---Convert a status number from the SMB header into a status name, returning an error message (not nil) if 188-- it wasn't found. 189-- 190--@param status The numerical status. 191--@return A string representing the error. Never nil. 192function get_status_name(status) 193 194 if(status_names[status] == nil) then 195 -- If the name wasn't found in the array, do a linear search on it 196 for i, v in pairs(status_names) do 197 if(v == status) then 198 return i 199 end 200 end 201 202 return string.format("NT_STATUS_UNKNOWN (0x%08x)", status) 203 else 204 return status_names[status] 205 end 206end 207 208 209--- Determines whether or not SMB checks are possible on this host, and, if they are, 210-- which port is best to use. This is how it decides: 211-- 212-- * If port tcp/445 is open, use it for a raw connection 213-- * 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. 214-- 215--@param host The host object. 216--@return The port number to use, or nil if we don't have an SMB port 217function get_port(host) 218 local port_u137 = nmap.get_port_state(host, {number=137, protocol="udp"}) 219 local port_t139 = nmap.get_port_state(host, {number=139, protocol="tcp"}) 220 local port_t445 = nmap.get_port_state(host, {number=445, protocol="tcp"}) 221 local custom_port = nil 222 223 if(nmap.registry.args.smbport ~= nil) then 224 custom_port = nmap.get_port_state(host, {number=tonumber(nmap.registry.args.smbport), protocol="tcp"}) 225 end 226 227 -- Try a user-defined port first 228 if(custom_port ~= nil and custom_port.state == "open") then 229 return custom_port.number 230 end 231 232 if(port_t445 ~= nil and port_t445.state == "open") then 233 -- tcp/445 is open, we're good 234 return 445 235 end 236 237 if(port_t139 ~= nil and port_t139.state == "open") then 238 -- tcp/139 is open, check uf udp/137 is open or unknown 239 if(port_u137 == nil or port_u137.state == "open" or port_u137.state == "open|filtered") then 240 return 139 241 end 242 end 243 244 return nil 245end 246 247---Turn off extended security negotiations for this connection. 248-- 249-- There are a few reasons you might want to do that, the main ones being that 250-- extended security is going to be marginally slower and it's not going to 251-- give the same level of information in some cases (namely, it doesn't present 252-- the server's name). 253--@param smb The SMB state table. 254function disable_extended(smb) 255 smb['extended_security'] = false 256end 257 258--- Begins a SMB session, automatically determining the best way to connect. 259-- 260-- @param host The host object 261-- @return (status, smb) if the status is true, result is the newly crated smb object; 262-- otherwise, socket is the error message. 263function start(host) 264 local port = get_port(host) 265 local status, result 266 local state = {} 267 268 state['uid'] = 0 269 state['tid'] = 0 270 state['mid'] = 1 271 state['pid'] = math.random(32766) + 1 272 state['host'] = host 273 state['ip'] = host.ip 274 state['sequence'] = -1 275 276 -- Check whether or not the user requested basic authentication 277 if(stdnse.get_script_args( "smbbasic" )) then 278 state['extended_security'] = false 279 else 280 state['extended_security'] = true 281 end 282 283 -- Store the name of the server 284 local nbcache_mutex = nmap.mutex("Netbios lookup mutex") 285 nbcache_mutex "lock" 286 if ( not(host.registry['netbios_name']) ) then 287 status, result = netbios.get_server_name(host.ip) 288 if(status == true) then 289 host.registry['netbios_name'] = result 290 state['name'] = result 291 end 292 else 293 stdnse.debug2("SMB: Resolved netbios name from cache") 294 state['name'] = host.registry['netbios_name'] 295 end 296 nbcache_mutex "done" 297 298 stdnse.debug2("SMB: Starting SMB session for %s (%s)", host.name, host.ip) 299 300 if(port == nil) then 301 return false, "SMB: Couldn't find a valid port to check" 302 end 303 304 -- Initialize the accounts for logging on 305 smbauth.init_account(host) 306 307 if(port ~= 139) then 308 status, state['socket'] = start_raw(host, port) 309 state['port'] = port 310 311 if(status == false) then 312 return false, state['socket'] 313 end 314 return true, state 315 316 else 317 status, state['socket'] = start_netbios(host, port) 318 state['port'] = port 319 if(status == false) then 320 return false, state['socket'] 321 end 322 return true, state 323 324 end 325 326 return false, "SMB: Couldn't find a valid port to check" 327end 328 329---Initiates a SMB connection over whichever port it can, then optionally sends 330-- the common initialization packets. 331-- 332-- Note that each packet depends on the previous one, so if you want to go all 333-- the way up to create_file, you have to set all parameters. 334-- 335-- If anything fails, we back out of the connection and return an error, so the 336-- calling function doesn't have to call smb.stop(). 337-- 338--@param host The host object. 339--@param bool_negotiate_protocol [optional] If 'true', send the protocol 340-- negotiation. Default: false. 341--@param bool_start_session [optional] If 'true', start the session. Default: 342-- false. 343--@param str_tree_connect [optional] The tree to connect to, if given (eg. 344-- "IPC$" or "C$"). If not given, packet isn't sent. 345--@param str_create_file [optional] The path and name of the file (or pipe) 346-- that's created, if given. If not given, packet isn't 347-- sent. 348--@param overrides [optional] A table of overrides (for, for example, username, 349-- password, etc.) to pass to all functions. 350--@param bool_disable_extended [optional] If set to true, disables extended 351-- security negotiations. 352function start_ex(host, bool_negotiate_protocol, bool_start_session, str_tree_connect, str_create_file, bool_disable_extended, overrides) 353 local smbstate 354 local status, err 355 356 -- Make sure we have overrides 357 overrides = overrides or {} 358 359 -- Begin the SMB session 360 status, smbstate = start(host) 361 if(status == false) then 362 return false, smbstate 363 end 364 365 -- Disable extended security if it was requested 366 if(bool_disable_extended == true) then 367 disable_extended(smbstate) 368 end 369 370 if(bool_negotiate_protocol == true) then 371 -- Negotiate the protocol 372 status, err = negotiate_protocol(smbstate, overrides) 373 if(status == false) then 374 stop(smbstate) 375 return false, err 376 end 377 378 if(bool_start_session == true) then 379 -- Start up a session 380 status, err = start_session(smbstate, overrides) 381 if(status == false) then 382 stop(smbstate) 383 return false, err 384 end 385 386 if(str_tree_connect ~= nil) then 387 -- Connect to share 388 status, err = tree_connect(smbstate, str_tree_connect, overrides) 389 if(status == false) then 390 stop(smbstate) 391 return false, err 392 end 393 394 if(str_create_file ~= nil) then 395 -- Try to connect to requested pipe 396 status, err = create_file(smbstate, str_create_file, overrides) 397 if(status == false) then 398 stop(smbstate) 399 return false, err 400 end 401 end 402 end 403 end 404 end 405 406 -- Return everything 407 return true, smbstate 408end 409 410--- Kills the SMB connection and closes the socket. 411-- 412-- In addition to killing the connection, this function will log off the user and disconnect 413-- the connected tree, if possible. 414-- 415--@param smb The SMB object associated with the connection 416--@return (status, result) If status is false, result is an error message. Otherwise, result 417-- is undefined. 418function stop(smb) 419 420 if(smb['tid'] ~= 0) then 421 tree_disconnect(smb) 422 end 423 424 if(smb['uid'] ~= 0) then 425 logoff(smb) 426 end 427 428 stdnse.debug2("SMB: Closing socket") 429 if(smb['socket'] ~= nil) then 430 local status, err = smb['socket']:close() 431 432 if(status == false) then 433 return false, "SMB: Failed to close socket: " .. err 434 end 435 end 436 437 return true 438end 439 440--- Begins a raw SMB session, likely over port 445. Since nothing extra is required, this 441-- function simply makes a connection and returns the socket. 442-- 443--@param host The host object to check. 444--@param port The port to use (most likely 445). 445--@return (status, socket) if status is true, result is the newly created socket. 446-- Otherwise, socket is the error message. 447function start_raw(host, port) 448 local status, err 449 local socket = nmap.new_socket() 450 451 socket:set_timeout(TIMEOUT) 452 status, err = socket:connect(host, port, "tcp") 453 454 if(status == false) then 455 return false, "SMB: Failed to connect to host: " .. err 456 end 457 458 return true, socket 459end 460 461--- This function will take a string like "a.b.c.d" and return "a", "a.b", "a.b.c", and "a.b.c.d". 462-- 463-- This is used for discovering NetBIOS names. If a NetBIOS name is unknown, the substrings of the 464-- DNS name can be used in this way. 465-- 466--@param name The name to take apart 467--@return An array of the sub names 468local function get_subnames(name) 469 local i = -1 470 local list = {} 471 472 repeat 473 local subname = name 474 475 i = string.find(name, "[.]", i + 1) 476 if(i ~= nil) then 477 subname = string.sub(name, 1, i - 1) 478 end 479 480 list[#list + 1] = string.upper(subname) 481 482 until i == nil 483 484 return list 485end 486 487--- Begins a SMB session over NetBIOS. 488-- 489-- This requires a NetBIOS Session Start message to be sent first, which in 490-- turn requires the NetBIOS name. The name can be provided as a parameter, or 491-- it can be automatically determined. 492-- 493-- Automatically determining the name is interesting, to say the least. Here 494-- are the names it tries, and the order it tries them in: 495-- * The name the user provided, if present 496-- * The name pulled from NetBIOS (udp/137), if possible 497-- * The generic name "*SMBSERVER" 498-- * Each subset of the domain name (for example, scanme.insecure.org would 499-- attempt "scanme", "scanme.insecure", and "scanme.insecure.org") 500-- 501-- This whole sequence is a little hackish, but it's the standard way of doing 502-- it. 503-- 504--@param host The host object to check. 505--@param port The port to use (most likely 139). 506--@param name [optional] The NetBIOS name of the host. Will attempt to 507-- automatically determine if it isn't given. 508--@return (status, socket) if status is true, result is the port 509-- Otherwise, socket is the error message. 510function start_netbios(host, port, name) 511 local i 512 local status, err 513 local pos, result, flags, length 514 local socket = nmap.new_socket() 515 516 -- First, populate the name array with all possible names, in order of significance 517 local names = {} 518 519 -- Use the name parameter 520 if(name ~= nil) then 521 names[#names + 1] = name 522 end 523 524 -- Get the name of the server from NetBIOS 525 status, name = netbios.get_server_name(host.ip) 526 if(status == true) then 527 names[#names + 1] = name 528 end 529 530 -- "*SMBSERVER" is a special name that any server should respond to 531 names[#names + 1] = "*SMBSERVER" 532 533 -- If all else fails, use each substring of the DNS name (this is a HUGE hack, but is actually 534 -- a recommended way of doing this!) 535 if(host.name ~= nil and host.name ~= "") then 536 local new_names = get_subnames(host.name) 537 for i = 1, #new_names, 1 do 538 names[#names + 1] = new_names[i] 539 end 540 end 541 542 -- This loop will try all the NetBIOS names we've collected, hoping one of them will work. Yes, 543 -- this is a hackish way, but it's actually the recommended way. 544 i = 1 545 repeat 546 547 -- Use the current name 548 name = names[i] 549 550 -- Some debug information 551 stdnse.debug1("SMB: Trying to start NetBIOS session with name = '%s'", name) 552 -- Request a NetBIOS session 553 local session_request = string.pack(">BBI2zz", 554 0x81, -- session request 555 0x00, -- flags 556 0x44, -- length 557 netbios.name_encode(name), -- server name 558 netbios.name_encode("NMAP") -- client name 559 ); 560 561 stdnse.debug3("SMB: Connecting to %s", host.ip) 562 socket:set_timeout(TIMEOUT) 563 status, err = socket:connect(host, port, "tcp") 564 if(status == false) then 565 socket:close() 566 return false, "SMB: Failed to connect: " .. err 567 end 568 569 -- Send the session request 570 stdnse.debug3("SMB: Sending NetBIOS session request with name %s", name) 571 status, err = socket:send(session_request) 572 if(status == false) then 573 socket:close() 574 return false, "SMB: Failed to send: " .. err 575 end 576 socket:set_timeout(TIMEOUT) 577 578 -- Receive the session response 579 stdnse.debug3("SMB: Receiving NetBIOS session response") 580 status, result = socket:receive_buf(match.numbytes(4), true); 581 if(status == false) then 582 socket:close() 583 return false, "SMB: Failed to close socket: " .. result 584 end 585 result, flags, length, pos = string.unpack(">BBI2", result) 586 587 -- Check for a positive session response (0x82) 588 if result == 0x82 then 589 stdnse.debug3("SMB: Successfully established NetBIOS session with server name %s", name) 590 return true, socket 591 end 592 593 -- If the session failed, close the socket and try the next name 594 stdnse.debug1("SMB: Session request failed, trying next name") 595 socket:close() 596 597 -- Try the next name 598 i = i + 1 599 600 until i > #names 601 602 -- We reached the end of our names list 603 stdnse.debug1("SMB: None of the NetBIOS names worked!") 604 return false, "SMB: Couldn't find a NetBIOS name that works for the server. Sorry!" 605end 606 607--- Creates a string containing a SMB packet header. The header looks like this: 608-- 609--<code> 610-- -------------------------------------------------------------------------------------------------- 611-- | 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 | 612-- -------------------------------------------------------------------------------------------------- 613-- | 0xFF | 'S' | 'M' | 'B' | 614-- -------------------------------------------------------------------------------------------------- 615-- | Command | Status... | 616-- -------------------------------------------------------------------------------------------------- 617-- | ...Status | Flags | Flags2 | 618-- -------------------------------------------------------------------------------------------------- 619-- | PID_high | Signature..... | 620-- -------------------------------------------------------------------------------------------------- 621-- | ....Signature.... | 622-- -------------------------------------------------------------------------------------------------- 623-- | ....Signature | Unused | 624-- -------------------------------------------------------------------------------------------------- 625-- | TID | PID | 626-- -------------------------------------------------------------------------------------------------- 627-- | UID | MID | 628-- ------------------------------------------------------------------------------------------------- 629--</code> 630-- 631-- All fields are, incidentally, encoded in little endian byte order. 632-- 633-- For the purposes here, the program doesn't care about most of the fields so they're given default 634-- values. The "command" field is the only one we ever have to set manually, in my experience. The TID 635-- and UID need to be set, but those are stored in the smb state and don't require user intervention. 636-- 637--@param smb The smb state table. 638--@param command The command to use. 639--@param 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. 640--@return A binary string containing the packed packet header. 641function smb_encode_header(smb, command, overrides) 642 -- Make sure we have an overrides array 643 overrides = overrides or {} 644 645 -- Used for the header 646 local sig = "\xFFSMB" 647 648 -- Pretty much every flags is deprecated. We set these two because they're required to be on. 649 local flags = (0x10 | 0x08) -- SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES 650 -- These flags are less deprecated. We negotiate 32-bit status codes and long names. We also don't include Unicode, which tells 651 -- the server that we deal in ASCII. 652 local flags2 = (0x4000 | 0x2000 | 0x0040 | 0x0001) -- SMB_FLAGS2_32BIT_STATUS | SMB_FLAGS2_EXECUTE_ONLY_READS | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAMES 653 654 -- Unless the user's disabled the security signature, add it 655 if(nmap.registry.args.smbsign ~= "disable") then 656 flags2 = (flags2 | 0x0004) -- SMB_FLAGS2_SECURITY_SIGNATURE 657 end 658 659 660 if(smb['extended_security'] == true) then 661 flags2 = (flags2 | 0x0800) -- SMB_EXTENDED_SECURITY 662 end 663 664 -- TreeID should never ever be 'nil', but it seems to happen once in awhile so print an error 665 if(smb['tid'] == nil) then 666 return false, string.format("SMB: ERROR: TreeID value was set to nil on host %s", smb['ip']) 667 end 668 669 local header = string.pack("<BBBBB I4 B I2 I2 I8 I2 I2 I2 I2 I2", 670 sig:byte(1), -- Header 671 sig:byte(2), -- Header 672 sig:byte(3), -- Header 673 sig:byte(4), -- Header 674 command, -- Command 675 (overrides['status'] or 0), -- status 676 (overrides['flags'] or flags), -- flags 677 (overrides['flags2'] or flags2), -- flags2 678 (overrides['pid_high'] or 0), -- extra (pid_high) 679 (overrides['signature'] or 0), -- extra (signature) 680 (overrides['extra'] or 0), -- extra (unused) 681 (overrides['tid'] or smb['tid']), -- tid 682 (overrides['pid'] or smb['pid']), -- pid 683 (overrides['uid'] or smb['uid']), -- uid 684 (overrides['mid'] or smb['mid']) -- mid 685 ) 686 687 return header 688end 689 690--- Converts a string containing the parameters section into the encoded 691-- parameters string. 692-- 693-- The encoding is simple: 694-- * (1 byte) The number of 2-byte values in the parameters section 695-- * (variable) The parameter section 696-- This is automatically done by <code>smb_send</code>. 697-- 698-- @param parameters The parameters section. 699-- @param overrides The overrides table. The only thing possible to override here is the length. 700-- @return The encoded parameters. 701local function smb_encode_parameters(parameters, overrides) 702 -- Make sure we have an overrides array 703 overrides = overrides or {} 704 705 return string.pack("<B", overrides['parameters_length'] or (#parameters / 2)) .. parameters 706end 707 708--- Converts a string containing the data section into the encoded data string. 709-- 710-- The encoding is simple: 711-- * (2 bytes) The number of bytes in the data section 712-- * (variable) The data section 713-- This is automatically done by <code>smb_send</code>. 714-- 715-- @param data The data section. 716-- @param overrides The overrides table. The only thing possible to override here is the length. 717-- @return The encoded data. 718local function smb_encode_data(data, overrides) 719 -- Make sure we have an overrides array 720 overrides = overrides or {} 721 722 return string.pack("<I2", overrides['data_length'] or #data) .. data 723end 724 725---Sign the message, if possible. This is done by replacing the signature with the sequence 726-- number, creating a hash, then putting that hash in the signature location. 727--@param smb The smb state object. 728--@param body The body of the packet that's being signed. 729--@return The body of the packet, with the signature in place. 730local function message_sign(smb, body) 731 smb['sequence'] = smb['sequence'] + 1 732 733 if(smb['mac_key'] == nil) then 734 stdnse.debug3("SMB: Not signing message (missing mac_key)") 735 return body 736 elseif(nmap.registry.args.smbsign == "disable") then 737 stdnse.debug3("SMB: Not signing message (disabled by user)") 738 739 return body 740 end 741 742 -- Convert the sequence number to a string 743 local sequence = string.pack("<I8", smb['sequence']) 744 -- Create a new string, with the sequence number in place 745 local new_packet = string.sub(body, 1, 14) .. sequence .. string.sub(body, 23) 746 -- Calculate the signature 747 local signature = smbauth.calculate_signature(smb['mac_key'], new_packet) 748 749 return string.sub(body, 1, 14) .. signature .. string.sub(body, 23) 750end 751 752---Check the signature of the message. 753-- 754-- This is the opposite of <code>message_sign</code>, and works the same way 755-- (replaces the signature with the sequence number, calculates hash, checks) 756--@param smb The smb state object. 757--@param body The body of the packet that's being checked. 758--@return A true/false value -- true if the packet was signed properly, false if it wasn't. 759local function message_check_signature(smb, body) 760 smb['sequence'] = smb['sequence'] + 1 761 762 if(smb['mac_key'] == nil) then 763 stdnse.debug3("SMB: Not signing message (missing mac_key)") 764 return true 765 elseif(nmap.registry.args.smbsign ~= "force" and (smb['security_mode'] & 0x0A) ~= 0) then 766 stdnse.debug3("SMB: Not signing message (server doesn't support it -- default)") 767 return true 768 elseif(nmap.registry.args.smbsign == "disable" or nmap.registry.args.smbsign == "ignore") then 769 stdnse.debug3("SMB: Not signing message (disabled by user)") 770 return true 771 end 772 773 -- Pull out the signature that they used 774 local signature = string.sub(body, 15, 22) 775 776 -- Turn the sequence into a string 777 local sequence = string.pack("<I8", smb['sequence']) 778 -- Create a new string, with the sequence number in place 779 local new_packet = string.sub(body, 1, 14) .. sequence .. string.sub(body, 23) 780 781 -- Calculate the proper signature 782 local real_signature = smbauth.calculate_signature(smb['mac_key'], new_packet) 783 784 -- Validate the signature 785 return signature == real_signature 786end 787 788--- Prepends the NetBIOS header to the packet, which is essentially the length, encoded 789-- in 4 bytes of big endian, and sends it out. 790-- 791-- The length field is actually 17 or 24 bits wide, depending on whether or 792-- not we're using raw, but that shouldn't matter. 793-- 794--@param smb The SMB object associated with the connection 795--@param header The header, encoded with <code>smb_get_header</code>. 796--@param parameters The parameters. 797--@param data The data. 798--@param overrides Overrides table. 799--@return (result, err) If result is false, err is the error message. Otherwise, err is 800-- undefined 801function smb_send(smb, header, parameters, data, overrides) 802 overrides = overrides or {} 803 804 local encoded_parameters = smb_encode_parameters(parameters, overrides) 805 local encoded_data = smb_encode_data(data, overrides) 806 local body = header .. encoded_parameters .. encoded_data 807 local status, err 808 809 -- Calculate the message signature 810 body = message_sign(smb, body) 811 812 local out = string.pack(">s4", body) 813 814 815 stdnse.debug3("SMB: Sending SMB packet (len: %d)", #out) 816 status, err = smb['socket']:send(out) 817 818 if not status then 819 stdnse.debug1("SMB: Sending packet failed.") 820 end 821 822 return status, err 823end 824 825--- Reads the next packet from the socket, and parses it into the header, parameters, 826-- and data. 827-- 828--@param smb The SMB object associated with the connection 829--@param read_data [optional] This function will read the data section if and only if 830-- this value is true. This is a workaround for a bug in the tree connect packet, 831-- where the length is set incorrectly. Default: true. 832--@return (status, header, parameters, data) If status is true, the header, 833-- parameters, and data are all the raw arrays (with the lengths already 834-- removed). If status is false, header contains an error message and parameters/ 835-- data are undefined. 836function smb_read(smb, read_data) 837 local pos, netbios_data, netbios_length, length, header, parameter_length, parameters, data_length, data 838 839 stdnse.debug3("SMB: Receiving SMB packet") 840 841 -- Receive the response -- we make sure to receive at least 4 bytes, the length of the NetBIOS length 842 smb['socket']:set_timeout(TIMEOUT) 843 844 -- attempt to read the Netbios header 845 local status, netbios_data = smb['socket']:receive_buf(match.numbytes(4), true); 846 847 -- Make sure the connection is still alive 848 if not status then 849 return false, "SMB: Failed to receive bytes: " .. netbios_data 850 end 851 852 -- The length of the packet is 4 bytes of big endian (for our purposes). 853 -- The NetBIOS header is 24 bits, big endian 854 netbios_length, pos = string.unpack(">I4", netbios_data) 855 -- Make the length 24 bits 856 netbios_length = (netbios_length & 0x00FFFFFF) 857 858 -- The total length is the netbios_length, plus 4 (for the length itself) 859 length = netbios_length + 4 860 861 local status, smb_data = smb['socket']:receive_buf(match.numbytes(netbios_length), true) 862 863 -- Make sure the connection is still alive 864 if not status then 865 return false, "SMB: Failed to receive bytes: " .. smb_data 866 end 867 868 local result = netbios_data .. smb_data 869 if(#result ~= length) then 870 stdnse.debug1("SMB: ERROR: Received wrong number of bytes, there will likely be issues (received %d, expected %d)", #result, length) 871 return false, string.format("SMB: ERROR: Didn't receive the expected number of bytes; received %d, expected %d. This will almost certainly cause some errors.", #result, length) 872 end 873 874 -- Check the message signature (ignoring the first four bytes, which are the netbios header) 875 local good_signature = message_check_signature(smb, string.sub(result, 5)) 876 if(good_signature == false) then 877 return false, "SMB: ERROR: Server returned invalid signature" 878 end 879 880 local header_format = "<c32 B" 881 if (#result - pos + 1) < string.packsize(header_format) then 882 return false, "SMB: ERROR: Server returned less data than needed for header" 883 end 884 header, parameter_length, pos = string.unpack("<c32 B", result, pos) 885 886 -- Double the length parameter, since parameters are two-byte values. 887 if (length - pos + 1) < (parameter_length * 2) then 888 return false, "SMB: ERROR: parameter_length greater than response length" 889 end 890 parameters, pos = string.unpack(("<c%d"):format(parameter_length*2), result, pos) 891 892 -- The data length is a 2-byte value. 893 data_length, pos = string.unpack("<I2", result, pos) 894 895 -- Read that many bytes of data. 896 if(read_data == nil or read_data == true) then 897 if (length - pos + 1) < data_length then 898 return false, "SMB: ERROR: data_length greater than response length" 899 end 900 data = string.unpack("c" .. data_length, result, pos) 901 else 902 data = nil 903 end 904 905 stdnse.debug3("SMB: Received %d bytes", #result) 906 return true, header, parameters, data 907end 908 909--- 910-- Negotiates SMBv1 connections 911-- 912-- Sends the following: 913-- * List of known protocols 914-- 915-- This function adds to <code>smb</code>: 916-- * 'security_mode' Whether or not to use cleartext passwords, message signatures, etc. 917-- * 'max_mpx' Maximum number of multiplexed connections 918-- * 'max_vc' Maximum number of virtual circuits 919-- * 'max_buffer' Maximum buffer size 920-- * 'max_raw_buffer' Maximum buffer size for raw connections (considered obsolete) 921-- * 'session_key' A value that's basically just echoed back 922-- * 'capabilities' The server's capabilities 923-- * 'time' The server's time (in UNIX-style seconds since 1970) 924-- * 'date' The server's date in a user-readable format 925-- * 'timezone' The server's timezone, in hours from UTC 926-- * 'timezone_str' The server's timezone, as a string 927-- * 'server_challenge' A random string used for challenge/response 928-- * 'domain' The server's primary domain or workgroup 929-- * 'server' The server's name 930-- 931-- @param smb The SMB object associated with the connection. 932-- @param overrides Overrides table. 933-- @return Boolean status 934-- @return The negotiated dialect in human readable form or an error message. 935--- 936function negotiate_v1(smb, overrides) 937 local header = smb_encode_header(smb, command_codes['SMB_COM_NEGOTIATE'], overrides) 938 -- Make sure we have overrides 939 overrides = overrides or {} 940 941 -- Parameters are blank 942 local parameters = "" 943 local data = string.pack("<BzBz", 2, (overrides['dialect'] or "NT LM 0.12"), 2, "") 944 945 -- Send the negotiate request 946 stdnse.debug2("SMB: Sending SMB_COM_NEGOTIATE") 947 local result, err = smb_send(smb, header, parameters, data, overrides) 948 if(result == false) then 949 return false, err 950 end 951 -- Read the result 952 local status, header, parameters, data = smb_read(smb) 953 if(status ~= true) then 954 return false, header 955 end 956 957 -- Check if we fell off the packet 958 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 959 if #header < string.packsize(header_format) then 960 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 961 end 962 963 -- Parse out the header 964 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 965 966 -- Get the protocol version 967 if(protocol_version == ("\xFESMB")) then 968 return false, "SMB: Server returned a SMBv2 packet, don't know how to handle" 969 end 970 971 -- Since this is the first response seen, check any necessary flags here 972 if((flags2 & 0x0800) ~= 0x0800) then 973 smb['extended_security'] = false 974 end 975 976 -- Parse the parameter section 977 local dialect_format = "<I2" 978 local parameters_format = "<BI2 I2 I4 I4 I4 I4" 979 if #parameters < (string.packsize(dialect_format) + string.packsize(parameters_format)) then 980 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [9]" 981 end 982 smb['dialect'], pos = string.unpack(dialect_format, parameters) 983 984 -- Check if the server didn't like our requested protocol 985 if(smb['dialect'] ~= 0) then 986 stdnse.debug2("Server negotiated an unknown protocol (#%d) -- aborting", smb['dialect']) 987 return false, string.format("Server negotiated an unknown protocol (#%d) -- aborting", smb['dialect']) 988 end 989 990 smb.security_mode, smb.max_mpx, smb.max_vc, smb.max_buffer, smb.max_raw_buffer, smb.session_key, smb.capabilities, pos = string.unpack(parameters_format, parameters, pos) 991 -- Some broken implementations of SMB don't send these variables 992 smb.time = 0 993 smb.timezone = 0 994 smb.key_length = 0 995 smb.byte_count = 0 996 if (#parameters - pos + 1) >= 8 then 997 smb.time, pos = string.unpack("<I8", parameters, pos) 998 if (#parameters - pos + 1) >= 2 then 999 smb.timezone, pos = string.unpack("<i2", parameters, pos) 1000 if (#parameters - pos + 1) >= 1 then 1001 smb.key_length, pos = string.unpack("B", parameters, pos) 1002 if (#parameters - pos + 1) >= 2 then 1003 smb.byte_count, pos = string.unpack("<I2", parameters, pos) 1004 end 1005 end 1006 end 1007 end 1008 1009 -- Convert the time and timezone to more useful values 1010 smb['time'] = (smb['time'] // 10000000) - 11644473600 1011 smb['date'] = datetime.format_timestamp(smb['time']) 1012 smb['timezone'] = -(smb['timezone'] / 60) 1013 if(smb['timezone'] == 0) then 1014 smb['timezone_str'] = "UTC+0" 1015 elseif(smb['timezone'] < 0) then 1016 smb['timezone_str'] = "UTC-" .. math.abs(smb['timezone']) 1017 else 1018 smb['timezone_str'] = "UTC+" .. smb['timezone'] 1019 end 1020 1021 -- Data section 1022 if(smb['extended_security'] == true) then 1023 if #data < 16 then 1024 return false, "SMB: ERROR: not enough data for extended security" 1025 end 1026 smb.server_guid, pos = string.unpack("<c16", data) 1027 1028 -- do we have a security blob? 1029 if ( #data - pos + 1 > 0 ) then 1030 smb.security_blob = data:sub(pos) 1031 pos = #data + 1 1032 end 1033 else 1034 if #data < smb.key_length then 1035 return false, "SMB: ERROR: not enough data for server_challenge" 1036 end 1037 smb.server_challenge, pos = string.unpack(string.format("<c%d", smb['key_length']), data) 1038 1039 -- Get the (null-terminated) domain as a Unicode string 1040 smb['domain'] = "" 1041 smb['server'] = "" 1042 1043 local remainder = unicode.utf16to8(string.sub(data, pos)) 1044 pos, pos = string.find(remainder, "\0", 1, true) 1045 if pos == nil then 1046 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [14]" 1047 end 1048 smb['domain'] = string.sub(remainder, 1, pos) 1049 1050 -- Get the server name as a Unicode string 1051 -- Note: This can be nil, Samba leaves this off 1052 local pos2 = pos + 1 1053 pos, pos = string.find(remainder, "\0", pos2, true) 1054 if pos ~= nil then 1055 smb['server'] = string.sub(remainder, pos2, pos) 1056 end 1057 end 1058 1059 stdnse.debug2("SMB_COM_NEGOTIATE got status:%s", status) 1060 if status == 0 then 1061 return true, overrides['dialect'] or "NT LM 0.12" 1062 end 1063end 1064 1065--- 1066-- Wrapper function to negotiate the protocol to use in the SMB connection. 1067-- By default it attempts to negotiate with using following dialects: 1068-- * NT LM 12.0 (SMBv1) 1069-- @param smb The SMB object 1070-- @param overrides Overrides table 1071-- @return Boolean status 1072--- 1073function negotiate_protocol(smb, overrides) 1074 local status, dialect 1075 status, dialect = negotiate_v1(smb, overrides) 1076 if status then 1077 return true 1078 else 1079 stdnse.debug1("Couldn't negotiate a SMBv1 connection:%s", dialect) 1080 return false, string.format("Could not negotiate a connection:%s", dialect) 1081 end 1082end 1083 1084--- 1085-- Returns list of supported dialects for SMBv1, SMBv2 and SMBv3. 1086-- @param host The SMB host to connect to. 1087-- @param overrides [optional] Overrides for various fields. 1088-- @return Boolean status 1089-- @return Table of supported dialects or error message 1090--- 1091function list_dialects(host, overrides) 1092 local smb2_dialects = {0x0202, 0x0210, 0x0300, 0x0302, 0x0311} 1093 local supported_dialects = {} 1094 local status, smb1_dialect 1095 local smbstate 1096 1097 overrides = tableaux.tcopy(overrides or {}) 1098 1099 -- Check for SMBv1 first 1100 stdnse.debug2("Checking if SMBv1 is supported") 1101 status, smbstate = start(host) 1102 if(status == false) then 1103 return false, smbstate 1104 end 1105 1106 status, smb1_dialect = negotiate_v1(smbstate, overrides) 1107 if status then --Add SMBv1 as a dialect 1108 table.insert(supported_dialects, smb1_dialect) 1109 end 1110 stop(smbstate) 1111 status = false -- Finish SMBv1 and close connection 1112 1113 -- Check SMB2 and SMB3 dialects 1114 for i, dialect in pairs(smb2_dialects) do 1115 local dialect_human = stdnse.tohex(dialect, {separator = ".", group = 2}) 1116 -- we need a clean connection for each negotiate request 1117 status, smbstate = start(host) 1118 if(status == false) then 1119 return false, smbstate 1120 end 1121 stdnse.debug2("Checking if dialect '%s' is supported", dialect_human) 1122 overrides['Dialects'] = {dialect} 1123 status, dialect = smb2.negotiate_v2(smbstate, overrides) 1124 if status then 1125 stdnse.debug2("SMB2: Dialect '%s' is supported", dialect_human) 1126 table.insert(supported_dialects, dialect_human) 1127 end 1128 --clean smb connection 1129 stop(smbstate) 1130 status = false 1131 end 1132 1133 return true, supported_dialects 1134end 1135 1136--- This is an internal function and should not be called externally. Use 1137-- the start_session() function instead. 1138local function start_session_basic(smb, log_errors, overrides) 1139 local i, err 1140 local status, result 1141 local header, parameters, data, domain 1142 local andx_command, andx_reserved, andx_offset, action 1143 local os, lanmanager 1144 local username, domain, password, password_hash, hash_type 1145 local busy_count = 0 1146 1147 header = smb_encode_header(smb, command_codes['SMB_COM_SESSION_SETUP_ANDX'], overrides) 1148 1149 -- Get the first account, unless they overrode it 1150 if(overrides ~= nil and overrides['username'] ~= nil) then 1151 result = true 1152 username = overrides['username'] 1153 domain = overrides['domain'] 1154 password = overrides['password'] 1155 password_hash = overrides['password_hash'] 1156 hash_type = overrides['hash_type'] 1157 else 1158 result, username, domain, password, password_hash, hash_type = smbauth.get_account(smb['host']) 1159 end 1160 1161 while result ~= false do 1162 local lanman, ntlm 1163 1164 lanman, ntlm, smb['mac_key'] = smbauth.get_password_response(smb['ip'], username, domain, password, password_hash, hash_type, smb['server_challenge'], false) 1165 1166 -- Parameters 1167 parameters = string.pack("<BBI2 I2I2 I2 I4 I2I2 I4I4", 1168 0xFF, -- ANDX -- no further commands 1169 0x00, -- ANDX -- Reserved (0) 1170 0x0000, -- ANDX -- next offset 1171 0xFFFF, -- Max buffer size 1172 0x0001, -- Max multiplexes 1173 0x0001, -- Virtual circuit num 1174 smb['session_key'], -- The session key 1175 #lanman, -- ANSI/Lanman password length 1176 #ntlm, -- Unicode/NTLM password length 1177 0x00000000, -- Reserved 1178 0x00000050 -- Capabilities 1179 ) 1180 1181 -- Data is a list of strings, terminated by a blank one. 1182 data = lanman -- ANSI/Lanman password 1183 .. ntlm -- Unicode/NTLM password 1184 .. string.pack("<zzzz", 1185 username, -- Account 1186 domain, -- Domain 1187 "Nmap", -- OS 1188 "Native Lanman" -- Native LAN Manager 1189 ) 1190 1191 -- Send the session setup request 1192 stdnse.debug2("SMB: Sending SMB_COM_SESSION_SETUP_ANDX") 1193 result, err = smb_send(smb, header, parameters, data, overrides) 1194 if(result == false) then 1195 return false, err 1196 end 1197 1198 -- Read the result 1199 status, header, parameters, data = smb_read(smb) 1200 if(status ~= true) then 1201 return false, header 1202 end 1203 1204 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1205 if #header < string.packsize(header_format) then 1206 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [17]" 1207 end 1208 -- Check if we were allowed in 1209 local protocol_version, command, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos 1210 protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1211 1212 -- Check if we're successful 1213 if(status == 0) then 1214 1215 -- Parse the parameters 1216 local parameters_format = "<BB I2 I2" 1217 if #parameters < string.packsize(parameters_format) then 1218 return false, "SMB: ERROR: Server returned less data than needed" 1219 end 1220 andx_command, andx_reserved, andx_offset, action, pos = string.unpack(parameters_format, parameters) 1221 1222 -- Parse the data 1223 status, os, lanmanager, domain, pos = pcall(string.unpack, "<zzz", data) 1224 if not status then 1225 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [19]" 1226 end 1227 1228 -- Fill in the smb object and smb string 1229 smb['uid'] = uid 1230 smb['is_guest'] = (action & 1) 1231 smb['os'] = os 1232 smb['lanmanager'] = lanmanager 1233 1234 -- Check if they're using an un-supported system 1235 if(os == "" or lanmanager == "" or domain == "") then 1236 stdnse.debug1("SMB: WARNING: the server is using a non-standard SMB implementation; your mileage may vary (%s)", smb['ip']) 1237 elseif(os == "Unix" or string.sub(lanmanager, 1, 5) == "Samba") then 1238 stdnse.debug1("SMB: WARNING: the server appears to be Unix; your mileage may vary.") 1239 end 1240 1241 -- Check if they were logged in as a guest 1242 if(log_errors == nil or log_errors == true) then 1243 if(smb['is_guest'] == 1) then 1244 stdnse.debug1("SMB: Login as %s\\%s failed, but was given guest access (username may be wrong, or system may only allow guest)", domain, stdnse.string_or_blank(username)) 1245 else 1246 stdnse.debug2("SMB: Login as %s\\%s succeeded", domain, stdnse.string_or_blank(username)) 1247 end 1248 end 1249 1250 -- Set the initial sequence number 1251 smb['sequence'] = 1 1252 1253 return true 1254 1255 else 1256 -- Check if we got the error NT_STATUS_REQUEST_NOT_ACCEPTED 1257 if(status == 0xc00000d0) then 1258 busy_count = busy_count + 1 1259 1260 if(busy_count > 9) then 1261 return false, "SMB: ERROR: Server has too many active connections; giving up." 1262 end 1263 1264 local backoff = math.random() * 10 1265 stdnse.debug1("SMB: Server has too many active connections; pausing for %s seconds.", math.floor(backoff * 100) / 100) 1266 stdnse.sleep(backoff) 1267 else 1268 -- This username failed, print a warning and keep going 1269 if(log_errors == nil or log_errors == true) then 1270 stdnse.debug1("SMB: Login as %s\\%s failed (%s)", domain, stdnse.string_or_blank(username), get_status_name(status)) 1271 end 1272 1273 -- Go to the next account 1274 if(overrides == nil or overrides['username'] == nil) then 1275 smbauth.next_account(smb['host']) 1276 result, username, domain, password, password_hash, hash_type = smbauth.get_account(smb['host']) 1277 else 1278 result = false 1279 end 1280 end 1281 end 1282 end 1283 1284 if(log_errors ~= false) then 1285 stdnse.debug1("SMB: ERROR: %s", username) 1286 end 1287 1288 if (status ~= nil) then 1289 return false, get_status_name(status) 1290 else 1291 return false, username 1292 end 1293end 1294 1295--- This is an internal function and should not be called externally. Use 1296-- the start_session() function instead. 1297local function start_session_extended(smb, log_errors, overrides) 1298 local i 1299 local status, status_name, result, err 1300 local header, parameters, data 1301 local andx_command, andx_reserved, andx_offset, action, security_blob_length 1302 local os, lanmanager 1303 local username, domain, password, password_hash, hash_type 1304 local busy_count = 0 1305 1306 -- Set a default status_name, in case everything fails 1307 status_name = "An unknown error has occurred" 1308 1309 -- Get the first account, unless they overrode it 1310 if(overrides ~= nil and overrides['username'] ~= nil) then 1311 result = true 1312 username = overrides['username'] 1313 domain = overrides['domain'] 1314 password = overrides['password'] 1315 password_hash = overrides['password_hash'] 1316 hash_type = overrides['hash_type'] 1317 else 1318 result, username, domain, password, password_hash, hash_type = smbauth.get_account(smb['host']) 1319 if(not(result)) then 1320 return result, username 1321 end 1322 end 1323 1324 -- check what kind of security blob we were given in the negotiate protocol request 1325 local sp_nego = false 1326 if ( smb['security_blob'] and #smb['security_blob'] > 11 ) then 1327 local oid, pos = string.unpack(">c6", smb['security_blob'], 5) 1328 sp_nego = ( oid == "\x2b\x06\x01\x05\x05\x02" or oid == "\x06\x06\x2b\x06\x01\x05" ) -- check for SPNEGO OID 1.3.6.1.5.5.2 1329 end 1330 1331 local ntlm_challenge_accepted = false 1332 while result ~= false do 1333 -- These are loop variables 1334 local security_blob = nil 1335 local security_blob_length = 0 1336 1337 -- This loop takes care of the multiple packets that "extended security" requires 1338 repeat 1339 -- Get the new security blob, passing the old security blob as a parameter. If there was no previous security blob, then nil is passed, which creates a new one 1340 if ( not(security_blob) ) then 1341 status, security_blob, smb['mac_key'] = smbauth.get_security_blob(security_blob, smb['ip'], username, domain, password, password_hash, hash_type, (sp_nego and 0x00088215)) 1342 1343 if ( sp_nego ) then 1344 local enc = asn1.ASN1Encoder:new() 1345 local mechtype = enc:encode( { type = 'A0', value = enc:encode( { type = '30', value = enc:encode( { type = '06', value = stdnse.fromhex("2b06010401823702020a") } ) } ) } ) 1346 local oid = enc:encode( { type = '06', value = stdnse.fromhex("2b0601050502") } ) 1347 1348 security_blob = enc:encode(security_blob) 1349 security_blob = enc:encode( { type = 'A2', value = security_blob } ) 1350 security_blob = mechtype .. security_blob 1351 security_blob = enc:encode( { type = '30', value = security_blob } ) 1352 security_blob = enc:encode( { type = 'A0', value = security_blob } ) 1353 security_blob = oid .. security_blob 1354 security_blob = enc:encode( { type = '60', value = security_blob } ) 1355 end 1356 else 1357 if ( sp_nego ) then 1358 if (smb['domain'] or smb['server']) and (not domain or #domain == 0) then 1359 domain = smb['domain'] or smb['server'] 1360 end 1361 hash_type = "ntlm" 1362 end 1363 1364 status, security_blob, smb['mac_key'] = smbauth.get_security_blob(security_blob, smb['ip'], username, domain, password, password_hash, hash_type, (sp_nego and 0x00088215)) 1365 1366 if ( sp_nego ) then 1367 local enc = asn1.ASN1Encoder:new() 1368 security_blob = enc:encode(security_blob) 1369 security_blob = enc:encode( { type = 'A2', value = security_blob } ) 1370 security_blob = enc:encode( { type = '30', value = security_blob } ) 1371 security_blob = enc:encode( { type = 'A1', value = security_blob } ) 1372 end 1373 1374 end 1375 1376 -- There was an error processing the security blob 1377 if(status == false) then 1378 return false, string.format("SMB: ERROR: Security blob: %s", security_blob) 1379 end 1380 1381 header = smb_encode_header(smb, command_codes['SMB_COM_SESSION_SETUP_ANDX'], overrides) 1382 1383 -- Data is a list of strings, terminated by a blank one. 1384 data = security_blob -- Security blob 1385 .. string.pack("<zzz", 1386 "Nmap", -- OS 1387 "Native Lanman", -- Native LAN Manager 1388 "" -- Primary domain 1389 ) 1390 1391 -- Parameters 1392 parameters = string.pack("<BB I2 I2 I2 I2 I4 I2 I4 I4", 1393 0xFF, -- ANDX -- no further commands 1394 0x00, -- ANDX -- Reserved (0) 1395 #data + 24 + #header + 3, -- ANDX -- next offset 1396 0xFFFF, -- Max buffer size 1397 0x0001, -- Max multiplexes 1398 0x0001, -- Virtual circuit num 1399 smb['session_key'], -- The session key 1400 #security_blob, -- Security blob length 1401 0x00000000, -- Reserved 1402 0x80000050 -- Capabilities 1403 ) 1404 1405 -- Send the session setup request 1406 stdnse.debug2("SMB: Sending SMB_COM_SESSION_SETUP_ANDX") 1407 result, err = smb_send(smb, header, parameters, data, overrides) 1408 if(result == false) then 1409 return false, err 1410 end 1411 1412 -- Read the result 1413 status, header, parameters, data = smb_read(smb) 1414 if(status ~= true) then 1415 return false, header 1416 end 1417 1418 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1419 if #header < string.packsize(header_format) then 1420 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 1421 end 1422 1423 -- Check if we were allowed in 1424 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1425 smb['uid'] = uid 1426 1427 -- Get a human readable name 1428 status_name = get_status_name(status) 1429 1430 -- Only parse the parameters if it's ok or if we're going to keep going 1431 if(status_name == "NT_STATUS_SUCCESS" or status_name == "NT_STATUS_MORE_PROCESSING_REQUIRED") then 1432 -- Parse the parameters 1433 local parameters_format = "<BBI2 I2 I2" 1434 if #parameters < string.packsize(parameters_format) then 1435 return false, "SMB: ERROR: Server returned less data than needed" 1436 end 1437 andx_command, andx_reserved, andx_offset, action, security_blob_length, pos = string.unpack(parameters_format, parameters) 1438 smb['is_guest'] = (action & 1) 1439 1440 -- Parse the data 1441 if #data < security_blob_length then 1442 return false, "SMB: ERROR: Server returned less data than needed" 1443 end 1444 security_blob, pos = string.unpack(("<c%d"):format(security_blob_length), data) 1445 status, os, lanmanager, pos = pcall(string.unpack, "zz", data, pos) 1446 1447 if not ntlm_challenge_accepted then 1448 if ( status_name == "NT_STATUS_MORE_PROCESSING_REQUIRED" and sp_nego ) then 1449 local start = security_blob:find("NTLMSSP") 1450 security_blob = security_blob:sub(start) 1451 end 1452 1453 if not status or security_blob == nil then 1454 return false, "SMB: ERROR: NTLM challenge not accepted or lanmanager missing" 1455 end 1456 smb['os'] = os 1457 smb['lanmanager'] = lanmanager 1458 1459 local host_info = smbauth.get_host_info_from_security_blob(security_blob) 1460 if ( host_info ) then 1461 smb['fqdn'] = host_info['fqdn'] 1462 smb['domain_dns'] = host_info['dns_domain_name'] 1463 smb['forest_dns'] = host_info['dns_forest_name'] 1464 smb['server'] = host_info['netbios_computer_name'] 1465 smb['domain'] = host_info['netbios_domain_name'] 1466 end 1467 ntlm_challenge_accepted = true 1468 end 1469 1470 1471 -- If it's ok, do a cleanup and return true 1472 if(status_name == "NT_STATUS_SUCCESS") then 1473 -- Check if they're using an un-supported system 1474 if not status then 1475 stdnse.debug1("SMB: WARNING: the server is using a non-standard SMB implementation; your mileage may vary (%s)", smb['ip']) 1476 elseif(os == "Unix" or string.sub(lanmanager, 1, 5) == "Samba") then 1477 stdnse.debug1("SMB: WARNING: the server appears to be Unix; your mileage may vary.") 1478 end 1479 1480 -- Check if they were logged in as a guest 1481 if(log_errors == nil or log_errors == true) then 1482 if(smb['is_guest'] == 1) then 1483 stdnse.debug1("SMB: Extended login to %s as %s\\%s failed, but was given guest access (username may be wrong, or system may only allow guest)", smb['ip'], domain, stdnse.string_or_blank(username)) 1484 else 1485 stdnse.debug2("SMB: Extended login to %s as %s\\%s succeeded", smb['ip'], domain, stdnse.string_or_blank(username)) 1486 end 1487 end 1488 1489 -- Set the initial sequence number 1490 smb['sequence'] = 1 1491 1492 return true 1493 end -- Status is ok 1494 end -- Should we parse the parameters/data? 1495 until status_name ~= "NT_STATUS_MORE_PROCESSING_REQUIRED" 1496 1497 -- Check if we got the error NT_STATUS_REQUEST_NOT_ACCEPTED 1498 if(status == 0xc00000d0) then 1499 busy_count = busy_count + 1 1500 1501 if(busy_count > 9) then 1502 return false, "SMB: ERROR: Server has too many active connections; giving up." 1503 end 1504 1505 local backoff = math.random() * 10 1506 stdnse.debug1("SMB: Server has too many active connections; pausing for %s seconds.", math.floor(backoff * 100) / 100) 1507 stdnse.sleep(backoff) 1508 else 1509 -- Display a message to the user, and try the next account 1510 if(log_errors == nil or log_errors == true) then 1511 stdnse.debug1("SMB: Extended login to %s as %s\\%s failed (%s)", smb['ip'], domain, stdnse.string_or_blank(username), status_name) 1512 end 1513 1514 -- Go to the next account 1515 if(overrides == nil or overrides['username'] == nil) then 1516 smbauth.next_account(smb['host']) 1517 result, username, domain, password, password_hash, hash_type = smbauth.get_account(smb['host']) 1518 if(not(result)) then 1519 return false, username 1520 end 1521 else 1522 result = false 1523 end 1524 end 1525 1526 -- Reset the user id 1527 smb['uid'] = 0 1528 1529 end -- Loop over the accounts 1530 1531 if(log_errors == nil or log_errors == true) then 1532 stdnse.debug1("SMB: ERROR: All logins failed, sorry it didn't work out!") 1533 end 1534 1535 return false, status_name 1536end 1537 1538--- Sends out SMB_COM_SESSION_SETUP_ANDX, which attempts to log a user in. 1539-- 1540-- Sends the following: 1541-- * Negotiated parameters (multiplexed connections, virtual circuit, capabilities) 1542-- * Passwords (plaintext, unicode, lanman, ntlm, lmv2, ntlmv2, etc) 1543-- * Account name 1544-- * OS (I just send "Nmap") 1545-- * Native LAN Manager (no clue what that is, but it seems to be ignored) 1546-- 1547-- Receives the following: 1548-- * User ID 1549-- * Server OS 1550-- 1551--@param smb The SMB object associated with the connection 1552--@param overrides [optional] A table of overrides for username, domain, password, password_hash, and hash_type. 1553-- If any of these are given, it's used first. If they aren't, then Nmap parameters, Nmap registry entries, 1554-- guest, and NULL sessions are used. 1555--@param log_errors [optional] If set, will display login. Default: true. 1556--@return (status, result) If status is false, result is an error message. Otherwise, result is nil and the following 1557-- elements are added to the smb table: 1558-- * 'uid' The UserID for the session 1559-- * 'is_guest' If set, the username wasn't found so the user was automatically logged in as the guest account 1560-- * 'os' The operating system 1561-- * 'lanmanager' The server's LAN Manager 1562function start_session(smb, overrides, log_errors) 1563 -- Use a mutex to avoid some issues (see http://seclists.org/nmap-dev/2011/q1/464) 1564 local smb_auth_mutex = nmap.mutex( "SMB Authentication Mutex" ) 1565 smb_auth_mutex( "lock" ) 1566 1567 local status, result 1568 if(smb['extended_security'] == true) then 1569 status, result = start_session_extended(smb, log_errors, overrides) 1570 else 1571 status, result = start_session_basic(smb, log_errors, overrides) 1572 end 1573 1574 smb_auth_mutex( "done" ) 1575 return status, result 1576end 1577 1578--- Sends out <code>SMB_COM_SESSION_TREE_CONNECT_ANDX</code>, which attempts to 1579-- connect to a share. 1580-- 1581-- Sends the following: 1582-- * Password (for share-level security, which we don't support) 1583-- * Share name 1584-- * Share type (or "?????" if it's unknown, that's what we do) 1585-- 1586-- Receives the following: 1587-- * Tree ID 1588-- 1589--@param smb The SMB object associated with the connection 1590--@param path The path to connect (eg, <code>"\\servername\C$"</code>) 1591--@param overrides [optional] Overrides for various fields 1592--@return (status, result) If status is false, result is an error message. Otherwise, result is a 1593-- table with the following elements: 1594-- * 'tid' The TreeID for the session 1595function tree_connect(smb, path, overrides) 1596 local header, parameters, data, err, result 1597 local andx_command, andx_reserved, andx_offset, action 1598 local status 1599 1600 -- Make sure we have overrides 1601 overrides = overrides or {} 1602 1603 header = smb_encode_header(smb, command_codes['SMB_COM_TREE_CONNECT_ANDX'], overrides) 1604 parameters = string.pack("<BBI2 I2 I2", 1605 0xFF, -- ANDX no further commands 1606 0x00, -- ANDX reserved 1607 0x0000, -- ANDX offset 1608 (overrides['tree_connect_flags'] or 0x0000), -- flags 1609 0x0000 -- password length (for share-level security) 1610 ) 1611 data = string.pack("zz", 1612 -- Share-level password 1613 path, -- Path 1614 (overrides['tree_type'] or "?????") -- Type of tree ("?????" = any) 1615 ) 1616 1617 -- Send the tree connect request 1618 stdnse.debug2("SMB: Sending SMB_COM_TREE_CONNECT_ANDX") 1619 result, err = smb_send(smb, header, parameters, data, overrides) 1620 if(result == false) then 1621 return false, err 1622 end 1623 1624 -- Read the result 1625 status, header, parameters, data = smb_read(smb) 1626 if(status ~= true) then 1627 return false, header 1628 end 1629 1630 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1631 if #header < string.packsize(header_format) then 1632 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 1633 end 1634 -- Check if we were allowed in 1635 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1636 1637 if(status ~= 0) then 1638 return false, get_status_name(status) 1639 end 1640 1641 if(tid == 0 or tonumber(tid) == 0) then 1642 return false, "SMB: ERROR: Server didn't establish a proper tree connection (likely an embedded system)" 1643 end 1644 1645 smb['tid'] = tid 1646 1647 return true 1648 1649end 1650 1651--- Disconnects a tree session. Should be called before logging off and disconnecting. 1652--@param smb The SMB object associated with the connection 1653--@param overrides THe overrides table 1654--@return (status, result) If status is false, result is an error message. If status is true, 1655-- the disconnect was successful. 1656function tree_disconnect(smb, overrides) 1657 overrides = overrides or {} 1658 local header 1659 1660 header = smb_encode_header(smb, command_codes['SMB_COM_TREE_DISCONNECT'], overrides) 1661 1662 -- Send the tree disconnect request 1663 stdnse.debug2("SMB: Sending SMB_COM_TREE_DISCONNECT") 1664 local result, err = smb_send(smb, header, "", "", overrides) 1665 if(result == false) then 1666 return false, err 1667 end 1668 1669 -- Read the result 1670 local status, header, parameters, data = smb_read(smb) 1671 if(status ~= true) then 1672 return false, header 1673 end 1674 1675 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1676 if #header < string.packsize(header_format) then 1677 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 1678 end 1679 1680 -- Check if there was an error 1681 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1682 1683 if(status ~= 0) then 1684 return false, get_status_name(status) 1685 end 1686 1687 smb['tid'] = 0 1688 1689 return true 1690 1691end 1692 1693---Logs off the current user. Strictly speaking this isn't necessary, but it's the polite thing to do. 1694-- 1695--@param smb The SMB object associated with the connection 1696--@param overrides THe overrides table 1697--@return (status, result) If status is false, result is an error message. If status is true, 1698-- the logoff was successful. 1699function logoff(smb, overrides) 1700 overrides = overrides or {} 1701 local header, parameters, data 1702 local status 1703 1704 header = smb_encode_header(smb, command_codes['SMB_COM_LOGOFF_ANDX'], overrides) 1705 1706 -- Parameters are a blank ANDX block 1707 parameters = string.pack("<BB I2", 1708 0xFF, -- ANDX no further commands 1709 0x00, -- ANDX reserved 1710 0x0000 -- ANDX offset 1711 ) 1712 1713 -- Send the tree disconnect request 1714 stdnse.debug2("SMB: Sending SMB_COM_LOGOFF_ANDX") 1715 local result, err = smb_send(smb, header, parameters, "", overrides) 1716 if(result == false) then 1717 return false, err 1718 end 1719 1720 -- Read the result 1721 status, header, parameters, data = smb_read(smb) 1722 if(status ~= true) then 1723 return false, header 1724 end 1725 1726 -- Reset session variables (note: this has to come after the smb_read(), otherwise the message signatures cause a problem 1727 smb['uid'] = 0 1728 smb['sequence'] = -1 1729 smb['mac_key'] = nil 1730 1731 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1732 if #header < string.packsize(header_format) then 1733 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [22]" 1734 end 1735 1736 -- Check if there was an error 1737 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1738 1739 if(status == 0xc0000022) then 1740 stdnse.debug1("SMB: ERROR: Access was denied in 'logoff', indicating a problem with your message signatures") 1741 return false, "SMB: ERROR: Access was denied in 'logoff', indicating a problem with your message signatures" 1742 end 1743 if(status ~= 0) then 1744 return false, get_status_name(status) 1745 end 1746 1747 return true 1748 1749end 1750 1751--- This sends a SMB request to open or create a file. 1752-- 1753-- Most of the parameters I pass here are used directly from a packetlog, 1754-- especially the various permissions fields and flags. I might make this 1755-- more adjustable in the future, but this has been working for me. 1756-- 1757--@param smb The SMB object associated with the connection 1758--@param path The path of the file or pipe to open 1759--@param overrides [optional] Overrides for various fields 1760--@return (status, result) If status is false, result is an error message. Otherwise, result is a table 1761-- containing a lot of different elements, the most important one being 'fid', the handle to the opened file. 1762function create_file(smb, path, overrides) 1763 local header, parameters, data 1764 local andx_command, andx_reserved, andx_offset 1765 local oplock_level, fid, create_action, created, last_access, last_write, last_change, attributes, allocation_size, end_of_file, filetype, ipc_state, is_directory 1766 local error_count = 0 1767 1768 local status, pos 1769 repeat 1770 local mutex = nmap.mutex(smb['host']) 1771 mutex "lock" 1772 1773 -- Make sure we have overrides 1774 overrides = overrides or {} 1775 1776 header = smb_encode_header(smb, command_codes['SMB_COM_NT_CREATE_ANDX'], overrides) 1777 parameters = string.pack("<BBI2 B I2 I4 I4 I4 I8 I4 I4 I4 I4 I4 B", 1778 0xFF, -- ANDX no further commands 1779 0x00, -- ANDX reserved 1780 0x0000, -- ANDX offset 1781 0x00, -- Reserved 1782 #path, -- Path length 1783 (overrides['file_create_flags'] or 0x00000016), -- Create flags 1784 (overrides['file_create_root_fid'] or 0x00000000), -- Root FID 1785 (overrides['file_create_access_mask'] or 0x02000000), -- Access mask 1786 (overrides['file_create_allocation_size'] or 0x0000000000000000), -- Allocation size 1787 (overrides['file_create_attributes'] or 0x00000000), -- File attributes 1788 (overrides['file_create_share_attributes'] or 0x00000007), -- Share attributes 1789 (overrides['file_create_disposition'] or 0x00000000), -- Disposition 1790 (overrides['file_create_options'] or 0x00000000), -- Create options 1791 (overrides['file_create_impersonation'] or 0x00000002), -- Impersonation 1792 (overrides['file_create_security_flags'] or 0x01) -- Security flags 1793 ) 1794 1795 data = string.pack("z", path) 1796 1797 -- Send the create file 1798 stdnse.debug2("SMB: Sending SMB_COM_NT_CREATE_ANDX") 1799 local result, err = smb_send(smb, header, parameters, data, overrides) 1800 if(result == false) then 1801 mutex "done" 1802 return false, err 1803 end 1804 1805 -- Read the result 1806 status, header, parameters, data = smb_read(smb, false) 1807 mutex "done" 1808 if(status ~= true) then 1809 return false, header 1810 end 1811 1812 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1813 if #header < string.packsize(header_format) then 1814 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [23]" 1815 end 1816 1817 -- Check if we were allowed in 1818 local protocol_version, command, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid 1819 protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1820 1821 if(status == 0xc00000ac) then 1822 error_count = error_count + 1 1823 if(error_count > 10) then 1824 return false, "SMB: ERROR: Server returned NT_STATUS_PIPE_NOT_AVAILABLE too many times; giving up." 1825 end 1826 stdnse.debug1("WARNING: Server refused connection with NT_STATUS_PIPE_NOT_AVAILABLE; trying again") 1827 stdnse.sleep(.2) 1828 end 1829 until (status ~= 0xc00000ac) 1830 1831 if(status ~= 0) then 1832 return false, get_status_name(status) 1833 end 1834 1835 -- Parse the parameters 1836 local parameters_format = "<BBI2 BI2 I4 I8 I8 I8 I8 I4 I8 I8 I2 I2 B" 1837 if #parameters < string.packsize(parameters_format) then 1838 return false, "SMB: ERROR: Server returned less data than needed" 1839 end 1840 andx_command, andx_reserved, andx_offset, oplock_level, fid, create_action, created, last_access, last_write, last_change, attributes, allocation_size, end_of_file, filetype, ipc_state, is_directory, pos = string.unpack(parameters_format, parameters) 1841 1842 -- Fill in the smb table 1843 smb['oplock_level'] = oplock_level 1844 smb['fid'] = fid 1845 smb['create_action'] = create_action 1846 smb['created'] = created 1847 smb['last_access'] = last_access 1848 smb['last_write'] = last_write 1849 smb['last_change'] = last_change 1850 smb['attributes'] = attributes 1851 smb['allocation_size'] = allocation_size 1852 smb['end_of_file'] = end_of_file 1853 smb['filetype'] = filetype 1854 smb['ipc_state'] = ipc_state 1855 smb['is_directory'] = is_directory 1856 1857 return true 1858end 1859 1860--- This sends a SMB request to read from a file (or a pipe). 1861-- 1862--@param smb The SMB object associated with the connection 1863--@param offset The offset to read from (ignored if it's a pipe) 1864--@param count The maximum number of bytes to read 1865--@param overrides The overrides table 1866--@return (status, result) If status is false, result is an error message. Otherwise, result is a table 1867-- containing a lot of different elements. 1868function read_file(smb, offset, count, overrides) 1869 overrides = overrides or {} 1870 local header, parameters, data 1871 local andx_command, andx_reserved, andx_offset 1872 local remaining, data_compaction_mode, reserved_1, data_length_low, data_offset, data_length_high, reserved_2, reserved_3 1873 local response = {} 1874 local status 1875 1876 header = smb_encode_header(smb, command_codes['SMB_COM_READ_ANDX'], overrides) 1877 parameters = string.pack("<BBI2 I2 I4 I2 I2 I4 I2 I4", 1878 0xFF, -- ANDX no further commands 1879 0x00, -- ANDX reserved 1880 0x0000, -- ANDX offset 1881 smb['fid'], -- FID 1882 offset, -- Offset 1883 count, -- Max count low 1884 count, -- Min count 1885 0xFFFFFFFF, -- Reserved 1886 0, -- Remaining 1887 0x00000000 -- High offset 1888 ) 1889 1890 data = "" 1891 1892 -- Send the create file 1893 stdnse.debug2("SMB: Sending SMB_COM_READ_ANDX") 1894 local result, err = smb_send(smb, header, parameters, data, overrides) 1895 if(result == false) then 1896 return false, err 1897 end 1898 1899 -- Read the result 1900 status, header, parameters, data = smb_read(smb) 1901 if(status ~= true) then 1902 return false, header 1903 end 1904 1905 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 1906 if #header < string.packsize(header_format) then 1907 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [25]" 1908 end 1909 1910 -- Check if we were allowed in 1911 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 1912 1913 if(status ~= 0 and 1914 (status ~= status_codes.NT_STATUS_BUFFER_OVERFLOW and (smb['filetype'] == filetype_codes.FILE_TYPE_BYTE_MODE_PIPE or 1915 smb['filetype'] == filetype_codes.FILE_TYPE_MESSAGE_MODE_PIPE) ) ) then 1916 return false, get_status_name(status) 1917 end 1918 1919 -- Parse the parameters 1920 local parameters_format = "<BBI2 I2 I2 I2 I2 I2 I4 I2 I4" 1921 if #parameters < string.packsize(parameters_format) then 1922 return false, "SMB: ERROR: Server returned less data than needed" 1923 end 1924 andx_command, andx_reserved, andx_offset, remaining, data_compaction_mode, reserved_1, data_length_low, data_offset, data_length_high, reserved_2, reserved_3, pos = string.unpack(parameters_format, parameters) 1925 1926 response['remaining'] = remaining 1927 response['data_length'] = (data_length_low | (data_length_high << 16)) 1928 response['status'] = status 1929 1930 1931 -- data_start is the offset of the beginning of the data section -- we use this to calculate where the read data lives 1932 if(response['data_length'] == 0) then 1933 response['data'] = 0 1934 else 1935 local data_start = #header + 1 + #parameters + 2 1936 if(data_offset < data_start) then 1937 return false, "SMB: Start of data isn't in data section" 1938 end 1939 1940 -- Figure out the offset into the data section 1941 data_offset = data_offset - data_start 1942 1943 -- Make sure we don't run off the edge of the packet 1944 if(data_offset + response['data_length'] > #data) then 1945 return false, "SMB: Data returned runs off the end of the packet" 1946 end 1947 1948 -- Pull the data string out of the data 1949 response['data'] = string.sub(data, data_offset + 1, data_offset + response['data_length']) 1950 end 1951 1952 return true, response 1953end 1954 1955--- This sends a SMB request to write to a file (or a pipe). 1956-- 1957--@param smb The SMB object associated with the connection 1958--@param write_data The data to write 1959--@param offset The offset to write it to (ignored for pipes) 1960--@param overrides The overrides table 1961--@return (status, result) If status is false, result is an error message. Otherwise, result is a table 1962-- containing a lot of different elements, the most important one being 'fid', the handle to the opened file. 1963function write_file(smb, write_data, offset, overrides) 1964 overrides = overrides or {} 1965 local header, parameters, data 1966 local andx_command, andx_reserved, andx_offset 1967 local response = {} 1968 local status 1969 1970 header = smb_encode_header(smb, command_codes['SMB_COM_WRITE_ANDX'], overrides) 1971 parameters = string.pack("<BBI2 I2 I4 I4 I2 I2 I2 I2 I2 I4", 1972 0xFF, -- ANDX no further commands 1973 0x00, -- ANDX reserved 1974 0x0000, -- ANDX offset 1975 smb['fid'], -- FID 1976 offset, -- Offset 1977 0xFFFFFFFF, -- Reserved 1978 0x0008, -- Write mode (Message start, don't write raw, don't return remaining, don't write through 1979 #write_data,-- Remaining 1980 0x0000, -- Data length high 1981 #write_data,-- Data length low -- TODO: set this properly (to the 2-byte value) 1982 0x003F, -- Data offset 1983 0x00000000 -- Data offset high 1984 ) 1985 1986 data = write_data 1987 1988 -- Send the create file 1989 stdnse.debug2("SMB: Sending SMB_COM_WRITE_ANDX") 1990 local result, err = smb_send(smb, header, parameters, data, overrides) 1991 if(result == false) then 1992 return false, err 1993 end 1994 1995 1996 -- Read the result 1997 status, header, parameters, data = smb_read(smb) 1998 if(status ~= true) then 1999 return false, header 2000 end 2001 2002 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 2003 if #header < string.packsize(header_format) then 2004 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 2005 end 2006 2007 -- Check if we were allowed in 2008 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 2009 2010 if(status ~= 0) then 2011 return false, get_status_name(status) 2012 end 2013 2014 -- Parse the parameters 2015 local parameters_format = "<BBI2 I2 I2 I2 I2" 2016 if #parameters < string.packsize(parameters_format) then 2017 return false, "SMB: ERROR: Server returned less data than needed" 2018 end 2019 local count_reserved, count_high, remaining, count_low 2020 andx_command, andx_reserved, andx_offset, count_low, remaining, count_high, count_reserved, pos = string.unpack(parameters_format, parameters) 2021 2022 response['count_low'] = count_low 2023 response['remaining'] = remaining 2024 response['count_high'] = count_high 2025 response['reserved'] = count_reserved 2026 2027 return true, response 2028end 2029 2030--- This sends a SMB request to close a file (or a pipe). 2031-- 2032--@param smb The SMB object associated with the connection 2033--@param overrides The overrides table 2034--@return (status, result) If status is false, result is an error message. Otherwise, result is undefined. 2035function close_file(smb, overrides) 2036 overrides = overrides or {} 2037 local header, parameters, data 2038 local pos 2039 local status 2040 local andx_command, andx_reserved, andx_offset 2041 local response = {} 2042 2043 header = smb_encode_header(smb, command_codes['SMB_COM_CLOSE'], overrides) 2044 parameters = string.pack("<I2 I4", 2045 smb['fid'], -- FID 2046 0xFFFFFFFF -- Last write (unspecified) 2047 ) 2048 2049 data = "" 2050 2051 -- Send the close file 2052 stdnse.debug2("SMB: Sending SMB_CLOSE") 2053 local result, err = smb_send(smb, header, parameters, data, overrides) 2054 if(result == false) then 2055 return false, err 2056 end 2057 2058 -- Read the result 2059 status, header, parameters, data = smb_read(smb) 2060 if(status ~= true) then 2061 return false, header 2062 end 2063 2064 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 2065 if #header < string.packsize(header_format) then 2066 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [27]" 2067 end 2068 2069 -- Check if the close was successful 2070 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 2071 2072 if(status ~= 0) then 2073 return false, get_status_name(status) 2074 end 2075 2076 -- Close response has no parameters or data 2077 return true, response 2078end 2079 2080--- This sends a SMB request to delete a file (or a pipe). 2081-- 2082--@param smb The SMB object associated with the connection 2083--@param path The path of the file to delete 2084--@param overrides The overrides table 2085--@return (status, result) If status is false, result is an error message. Otherwise, result is undefined. 2086function delete_file(smb, path, overrides) 2087 overrides = overrides or {} 2088 local header, parameters, data 2089 local andx_command, andx_reserved, andx_offset 2090 local status 2091 2092 header = smb_encode_header(smb, command_codes['SMB_COM_DELETE'], overrides) 2093 parameters = string.pack("<I2", 2094 0x0027 -- Search attributes (0x27 = include read only, hidden, system, and archive) 2095 ) 2096 2097 data = string.pack("<Bz", 2098 0x04, -- Ascii formatted filename 2099 path) 2100 2101 -- Send the close file 2102 stdnse.debug2("SMB: Sending SMB_CLOSE") 2103 local result, err = smb_send(smb, header, parameters, data, overrides) 2104 if(result == false) then 2105 return false, err 2106 end 2107 2108 -- Read the result 2109 status, header, parameters, data = smb_read(smb) 2110 if(status ~= true) then 2111 return false, header 2112 end 2113 2114 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 2115 if #header < string.packsize(header_format) then 2116 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 2117 end 2118 2119 -- Check if the close was successful 2120 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 2121 2122 if(status ~= 0) then 2123 return false, get_status_name(status) 2124 end 2125 2126 -- Close response has no parameters or data 2127 return true 2128end 2129 2130--- 2131-- Implements SMB_COM_TRANSACTION2 to support the find_files function 2132-- This function has not been extensively tested 2133-- 2134--@param smb SMB object associated with the connection 2135--@param sub_command code of a SMB_COM_TRANSACTION2 sub command 2136--@param trans2_param Parameter data to pass to the function 2137--@param trans2_data Data to send with the packet 2138--@param overrides The overrides table 2139--@return status Boolean outcome of the request 2140--@return error error message if the status is false 2141local function send_transaction2(smb, sub_command, trans2_param, trans2_data, overrides) 2142 overrides = overrides or {} 2143 trans2_param = trans2_param or "" 2144 trans2_data = trans2_data or "" 2145 2146 local header = smb_encode_header(smb, command_codes['SMB_COM_TRANSACTION2'], overrides) 2147 local pad1 = "\0\0\0" -- Name, Pad1 2148 local pad2 = ("\0"):rep((4 - #trans2_param % 4) % 4) 2149 2150 local trans2_param_len = #trans2_param 2151 -- 68 = 32 SMB header 2152 -- + 31 SMB parameters 2153 -- + 2 SMB data ByteCount field 2154 -- + 3 #pad1 2155 local trans2_param_pos = 68 2156 local trans2_data_len = #trans2_data 2157 local trans2_data_pos = trans2_param_pos + trans2_param_len + #pad2 2158 if trans2_data_len == 0 then 2159 pad2 = "" 2160 trans2_data_pos = 0 2161 end 2162 2163 -- SMB parameters are 31 bytes long, incl. initial WordCount field 2164 -- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/f7d148cd-e3d5-49ae-8b37-9633822bfeac 2165 local parameters = string.pack("<I2 I2 I2 I2 BB I2 I4 I2 I2 I2 I2 I2 BB I2 ", 2166 trans2_param_len, -- Total parameter count 2167 trans2_data_len, -- Total data count 2168 0x000a, -- Max parameter count 2169 0xff80, -- Max data count 2170 0x00, -- Max setup count 2171 0x00, -- Reserved 2172 0x0000, -- Flags (2-way transaction, don't disconnect TIDs) 2173 5000, -- Timeout (ms) 2174 0x0000, -- Reserved 2175 trans2_param_len, -- Parameter count 2176 trans2_param_pos, -- Parameter offset 2177 trans2_data_len, -- Data count 2178 trans2_data_pos, -- Data offset 2179 0x01, -- Setup count 2180 0x00, -- Reserved 2181 sub_command -- Sub command 2182 ) 2183 2184 local data = pad1 .. trans2_param .. pad2 .. trans2_data 2185 2186 -- Send the transaction request 2187 stdnse.debug2("SMB: Sending SMB_COM_TRANSACTION2") 2188 return smb_send(smb, header, parameters, data, overrides) 2189end 2190 2191local function receive_transaction2(smb) 2192 2193 -- Read the result 2194 local status, header, parameters, data = smb_read(smb) 2195 if(status ~= true) then 2196 return false, header 2197 end 2198 2199 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 2200 if #header < string.packsize(header_format) then 2201 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 2202 end 2203 2204 -- Check if it worked 2205 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 2206 2207 if(status ~= 0) then 2208 if(status_names[status] == nil) then 2209 return false, string.format("Unknown SMB error: 0x%08x\n", status) 2210 else 2211 return false, status_names[status] 2212 end 2213 end 2214 2215 -- Parse the parameters 2216 local parameters_format = "<I2 I2 I2 I2 I2 I2 I2 I2 I2 BB" 2217 if #parameters < string.packsize(parameters_format) then 2218 return false, "SMB: ERROR: Server returned less data than needed" 2219 end 2220 local total_word_count, total_data_count, reserved1, parameter_count, parameter_offset, parameter_displacement, data_count, data_offset, data_displacement, setup_count, reserved2, pos = string.unpack(parameters_format, parameters) 2221 2222 -- Convert the parameter/data offsets into something more useful (the offset into the data section) 2223 -- - 0x20 for the header, - 0x01 for the length. 2224 parameter_offset = parameter_offset - 0x20 - 0x01 - #parameters - 0x02; 2225 -- - 0x20 for the header, - 0x01 for parameter length, the parameter length, and - 0x02 for the data length. 2226 data_offset = data_offset - 0x20 - 0x01 - #parameters - 0x02; 2227 2228 -- I'm not sure I entirely understand why the '+1' is here, but I think it has to do with the string starting at '1' and not '0'. 2229 local function_parameters = string.sub(data, parameter_offset + 1, parameter_offset + parameter_count) 2230 local function_data = string.sub(data, data_offset + 1, data_offset + data_count) 2231 2232 local response = {} 2233 response['parameters'] = function_parameters 2234 response['data'] = function_data 2235 2236 return true, response 2237end 2238 2239 2240 2241---This is the core of making MSRPC calls. It sends out a MSRPC packet with the 2242-- given parameters and data. 2243-- 2244-- Don't confuse these parameters and data with SMB's concepts of parameters 2245-- and data -- they are completely different. In fact, these parameters and 2246-- data are both sent in the SMB packet's 'data' section. 2247-- 2248-- It is probably best to think of this as another protocol layer. This 2249-- function will wrap SMB stuff around a MSRPC call, make the call, then unwrap 2250-- the SMB stuff from it before returning. 2251-- 2252--@param smb The SMB object associated with the connection 2253--@param function_parameters The parameter data to pass to the function. This 2254-- is untested, since none of the transactions I've 2255-- done have required parameters. 2256--@param function_data The data to send with the packet. This is basically the 2257-- next protocol layer 2258--@param pipe [optional] The pipe to transact on. Default: "\PIPE\". 2259--@param no_setup [optional] If set, the 'setup' is set to 0 and some 2260-- parameters are left off. This occurs while using the LANMAN 2261-- Remote API. Default: false. 2262--@param overrides The overrides table 2263--@return (status, result) If status is false, result is an error message. 2264-- Otherwise, result is a table containing 'parameters' and 'data', 2265-- representing the parameters and data returned by the server. 2266function send_transaction_named_pipe(smb, function_parameters, function_data, pipe, no_setup, overrides) 2267 overrides = overrides or {} 2268 local header, parameters, data 2269 local parameter_offset = 0 2270 local parameter_size = 0 2271 local data_offset = 0 2272 local data_size = 0 2273 local total_word_count, total_data_count, reserved1, parameter_count, parameter_displacement, data_count, data_displacement, setup_count, reserved2 2274 local response = {} 2275 local status 2276 2277 if(pipe == nil) then 2278 pipe = "\\PIPE\\" 2279 end 2280 2281 -- Header is 0x20 bytes long (not counting NetBIOS header). 2282 header = smb_encode_header(smb, command_codes['SMB_COM_TRANSACTION'], overrides) -- 0x25 = SMB_COM_TRANSACTION 2283 2284 -- 0x20 for SMB header, 0x01 for parameters header, 0x20 for parameters length, 0x02 for data header, 0x07 for "\PIPE\" 2285 if(function_parameters) then 2286 parameter_offset = 0x20 + 0x01 + 0x20 + 0x02 + (#pipe + 1) 2287 parameter_size = #function_parameters 2288 end 2289 2290 if(function_data) then 2291 data_offset = 0x20 + 0x01 + 0x20 + 0x02 + (#pipe + 1) + parameter_size 2292 data_size = #function_data 2293 end 2294 2295 local setup 2296 if(no_setup) then 2297 setup = string.pack("<BB", 2298 0x00, -- Number of 'setup' words (none) 2299 0x00 -- Reserved. 2300 ) 2301 else 2302 setup = string.pack("<BBI2 I2 ", 2303 0x02, -- Number of 'setup' words 2304 0x00, -- Reserved. 2305 0x0026, -- Function to call. 2306 smb['fid'] -- Handle to open file 2307 ) 2308 end 2309 2310 -- Parameters are 0x20 bytes long. 2311 parameters = string.pack("<I2 I2 I2 I2 BBI2 I4 I2 I2 I2 I2 I2", 2312 parameter_size, -- Total parameter count. 2313 data_size, -- Total data count. 2314 0x0008, -- Max parameter count. 2315 0x3984, -- Max data count. 2316 0x00, -- Max setup count. 2317 0x00, -- Reserved. 2318 0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs). 2319 0x00001388, -- Timeout (0x00000000 = return immediately). 2320 0x0000, -- Reserved. 2321 parameter_size, -- Parameter bytes. 2322 parameter_offset, -- Parameter offset. 2323 data_size, -- Data bytes. 2324 data_offset -- Data offset. 2325 ) .. setup 2326 2327 data = string.pack("<zI4", pipe, 0) -- Padding 2328 .. (function_parameters or '') 2329 .. (function_data or '') 2330 2331 -- Send the transaction request 2332 stdnse.debug2("SMB: Sending SMB_COM_TRANSACTION") 2333 local result, err = smb_send(smb, header, parameters, data, overrides) 2334 if(result == false) then 2335 return false, err 2336 end 2337 2338 -- Read the result 2339 status, header, parameters, data = smb_read(smb) 2340 if(status ~= true) then 2341 return false, header 2342 end 2343 2344 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 2345 if #header < string.packsize(header_format) then 2346 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 2347 end 2348 2349 -- Check if it worked 2350 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 2351 2352 if(status ~= 0) then 2353 if(status_names[status] == nil) then 2354 return false, string.format("Unknown SMB error: 0x%08x\n", status) 2355 else 2356 return false, status_names[status] 2357 end 2358 end 2359 2360 -- Parse the parameters 2361 local parameters_format = "<I2 I2 I2 I2 I2 I2 I2 I2 I2 BB" 2362 if #parameters < string.packsize(parameters_format) then 2363 return false, "SMB: ERROR: Server returned less data than needed" 2364 end 2365 total_word_count, total_data_count, reserved1, parameter_count, parameter_offset, parameter_displacement, data_count, data_offset, data_displacement, setup_count, reserved2, pos = string.unpack(parameters_format, parameters) 2366 2367 -- Convert the parameter/data offsets into something more useful (the offset into the data section) 2368 -- - 0x20 for the header, - 0x01 for the length. 2369 parameter_offset = parameter_offset - 0x20 - 0x01 - #parameters - 0x02; 2370 -- - 0x20 for the header, - 0x01 for parameter length, the parameter length, and - 0x02 for the data length. 2371 data_offset = data_offset - 0x20 - 0x01 - #parameters - 0x02; 2372 2373 -- I'm not sure I entirely understand why the '+1' is here, but I think it has to do with the string starting at '1' and not '0'. 2374 function_parameters = string.sub(data, parameter_offset + 1, parameter_offset + parameter_count) 2375 function_data = string.sub(data, data_offset + 1, data_offset + data_count) 2376 2377 response['parameters'] = function_parameters 2378 response['data'] = function_data 2379 2380 return true, response 2381end 2382 2383function send_transaction_waitnamedpipe(smb, priority, pipe, overrides) 2384 overrides = overrides or {} 2385 local header, parameters, data 2386 local parameter_offset, data_offset 2387 local total_word_count, total_data_count, reserved1, parameter_count, parameter_offset, parameter_displacement, data_count, data_offset, data_displacement, setup_count, reserved2 2388 local response = {} 2389 local padding = "" 2390 local status 2391 2392 -- Header is 0x20 bytes long (not counting NetBIOS header). 2393 header = smb_encode_header(smb, command_codes['SMB_COM_TRANSACTION'], overrides) -- 0x25 = SMB_COM_TRANSACTION 2394 2395 -- Parameters are 0x20 bytes long. 2396 parameters = string.pack("<I2 I2 I2 I2 BBI2 I4 I2 I2 I2 I2 I2 BBI2 I2 ", 2397 0, -- Total parameter count. 2398 0, -- Total data count. 2399 0x000, -- Max parameter count. 2400 0x400, -- Max data count. 2401 0x00, -- Max setup count. 2402 0x00, -- Reserved. 2403 0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs). 2404 30, -- Timeout (0x00000000 = return immediately). 2405 0x0000, -- Reserved. 2406 0, -- Parameter bytes. 2407 0, -- Parameter offset. 2408 0, -- Data bytes. 2409 0, -- Data offset. 2410 0x02, -- Number of 'setup' words (only ever seen '2'). 2411 0x00, -- Reserved. 2412 0x0053, -- Function to call. 2413 priority -- Handle to open file 2414 ) 2415 2416 data = string.pack("z", pipe) .. string.rep('\0', (4 - ((#pipe+1) % 4)) % 4) 2417 2418 -- Send the transaction request 2419 stdnse.debug2("SMB: Sending SMB_COM_TRANSACTION (WaitNamedPipe)") 2420 local result, err = smb_send(smb, header, parameters, data, overrides) 2421 if(result == false) then 2422 return false, err 2423 end 2424 2425 -- Read the result 2426 status, header, parameters, data = smb_read(smb) 2427 if(status ~= true) then 2428 return false, header 2429 end 2430 2431 local header_format = "<c4 B I4 B I2 I2 i8 I2 I2 I2 I2 I2" 2432 if #header < string.packsize(header_format) then 2433 return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [8]" 2434 end 2435 2436 -- Parse out the header 2437 local protocol_version, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid, pos = string.unpack(header_format, header) 2438 2439 if(status ~= 0) then 2440 if(status_names[status] == nil) then 2441 return false, string.format("Unknown SMB error: 0x%08x\n", status) 2442 else 2443 return false, status_names[status] 2444 end 2445 end 2446 2447 -- Parse the parameters 2448 local parameters_format = "<I2 I2 I2 I2 I2 I2 I2 I2 I2 BB" 2449 if #parameters < string.packsize(parameters_format) then 2450 return false, "SMB: ERROR: Server returned less data than needed" 2451 end 2452 total_word_count, total_data_count, reserved1, parameter_count, parameter_offset, parameter_displacement, data_count, data_offset, data_displacement, setup_count, reserved2, pos = string.unpack(parameters_format, parameters) 2453 2454 return true, response 2455end 2456 2457---Upload a file from the local machine to the remote machine, on the given share. 2458-- 2459--@param host The host object 2460--@param localfile The file on the local machine, relative to the nmap path 2461--@param share The share to upload it to (eg, C$). 2462--@param remotefile The remote file on the machine. It is relative to the share's root. 2463--@param overrides A table of override values that's passed to the smb functions. 2464--@param encoded Set to 'true' if the file is encoded (xor'ed with 0xFF), It will be decoded before upload. Default: false 2465--@return (status, err) If status is false, err is an error message. Otherwise, err is undefined. 2466function file_upload(host, localfile, share, remotefile, overrides, encoded) 2467 local status, err, smbstate 2468 local chunk = 1024 2469 2470 -- Attempt to open a handle to the file without adding a path to it 2471 local handle = io.open(localfile, "r") 2472 2473 -- If the open failed, try to search for the file 2474 if(not(handle)) then 2475 stdnse.debug1("Couldn't open %s directly, searching Nmap's paths...", localfile) 2476 local filename = nmap.fetchfile(localfile) 2477 2478 -- Check if it was found 2479 if(filename == nil) then 2480 return false, string.format("Couldn't find the file to upload (%s)", localfile) 2481 end 2482 handle = io.open(filename, "r") 2483 end 2484 2485 -- Create the SMB session 2486 status, smbstate = start_ex(host, true, true, share, remotefile, nil, overrides) 2487 if(status == false) then 2488 return false, smbstate 2489 end 2490 2491 2492 local i = 0 2493 local data = handle:read(chunk) 2494 local new_data = {} 2495 while(data ~= nil and #data > 0) do 2496 2497 if(encoded) then 2498 for j = 1, #data, 1 do 2499 new_data[j] = string.char(0xFF ~ string.byte(data, j)) 2500 end 2501 data = table.concat(new_data, "", 1, #data) 2502 end 2503 2504 status, err = write_file(smbstate, data, i) 2505 if(status == false) then 2506 stop(smbstate) 2507 return false, err 2508 end 2509 2510 data = handle:read(chunk) 2511 i = i + chunk 2512 end 2513 2514 handle:close() 2515 status, err = close_file(smbstate) 2516 if(status == false) then 2517 stop(smbstate) 2518 return false, err 2519 end 2520 2521 -- Stop the session 2522 stop(smbstate) 2523 2524 return true 2525end 2526 2527---Write given data to the remote machine on the given share. This is similar to <code>file_upload</code>, except the 2528-- data is given as a string, not a file. 2529-- 2530--@param host The host object 2531--@param data The string containing the data to be written 2532--@param share The share to upload it to (eg, C$). 2533--@param remotefile The remote file on the machine. It is relative to the share's root. 2534--@param use_anonymous [optional] If set to 'true', test is done by the anonymous user rather than the current user. 2535--@return (status, err) If status is false, err is an error message. Otherwise, err is undefined. 2536function file_write(host, data, share, remotefile, use_anonymous) 2537 local status, err, smbstate 2538 local chunk = 1024 2539 local overrides = nil 2540 2541 -- If anonymous is being used, create some overrides 2542 if(use_anonymous) then 2543 overrides = get_overrides_anonymous() 2544 end 2545 2546 -- Create the SMB session 2547 status, smbstate = start_ex(host, true, true, share, remotefile, nil, overrides) 2548 2549 if(status == false) then 2550 return false, smbstate 2551 end 2552 2553 local i = 1 2554 while(i <= #data) do 2555 local chunkdata = string.sub(data, i, i + chunk - 1) 2556 status, err = write_file(smbstate, chunkdata, i - 1) 2557 if(status == false) then 2558 stop(smbstate) 2559 return false, err 2560 end 2561 2562 i = i + chunk 2563 end 2564 2565 status, err = close_file(smbstate) 2566 if(status == false) then 2567 stop(smbstate) 2568 return false, err 2569 end 2570 2571 -- Stop the session 2572 stop(smbstate) 2573 2574 return true 2575end 2576 2577---Write given data to the remote machine on the given share. This is similar to <code>file_upload</code>, except the 2578-- data is given as a string, not a file. 2579-- 2580--@param host The host object 2581--@param share The share to read it from (eg, C$). 2582--@param remotefile The remote file on the machine. It is relative to the share's root. 2583--@param use_anonymous [optional] If set to 'true', test is done by the anonymous user rather than the current user. 2584--@param overrides [optional] Override various fields in the SMB packets. 2585--@return (status, err) If status is false, err is an error message. Otherwise, err is undefined. 2586function file_read(host, share, remotefile, use_anonymous, overrides) 2587 local status, err, smbstate 2588 local result 2589 local chunk = 1024 2590 local read = "" 2591 2592 -- Make sure we got overrides 2593 overrides = overrides or {} 2594 2595 -- If anonymous is being used, create some overrides 2596 if(use_anonymous) then 2597 overrides = get_overrides_anonymous(overrides) 2598 end 2599 2600 -- Create the SMB session 2601 status, smbstate = start_ex(host, true, true, share, remotefile, nil, overrides) 2602 2603 if(status == false) then 2604 return false, smbstate 2605 end 2606 2607 local i = 1 2608 while true do 2609 status, result = read_file(smbstate, i - 1, chunk) 2610 if(status == false) then 2611 stop(smbstate) 2612 return false, result 2613 end 2614 2615 if(result['data_length'] == 0) then 2616 break 2617 end 2618 2619 read = read .. result['data'] 2620 i = i + chunk 2621 end 2622 2623 status, err = close_file(smbstate) 2624 if(status == false) then 2625 stop(smbstate) 2626 return false, err 2627 end 2628 2629 -- Stop the session 2630 stop(smbstate) 2631 return true, read 2632end 2633 2634---Check how many files, in a given list, exist on the given share. 2635-- 2636--@param host The host object 2637--@param share The share to read it from (eg, C$). 2638--@param files A list of files to look for; it is relative to the share's root. 2639--@param overrides [optional] Override various fields in the SMB packets. 2640--@return status: A true/false value indicating success 2641--@return count: The number of files that existed, or an error message if status is 'false' 2642--@return files: A list of the files that existed. 2643function files_exist(host, share, files, overrides) 2644 local status, smbstate, result, err 2645 2646 -- Make sure we got overrides 2647 overrides = overrides or {} 2648 2649 -- We don't wan to be creating the files 2650 overrides['file_create_disposition'] = 1 2651 2652 -- Create the SMB session 2653 status, smbstate = start_ex(host, true, true, share, nil, nil, overrides) 2654 2655 if(status == false) then 2656 return false, smbstate 2657 end 2658 2659 local exist = 0 2660 local list = {} 2661 2662 for _, file in ipairs(files) do 2663 -- Try and open the file 2664 status, result = create_file(smbstate, file, overrides) 2665 2666 -- If there was an error other than 'file already exists', return an error 2667 if(not(status) and result ~= 'NT_STATUS_OBJECT_NAME_NOT_FOUND') then 2668 return false, result 2669 end 2670 2671 -- If the file existed, count it and close it 2672 if(status) then 2673 exist = exist + 1 2674 table.insert(list, file) 2675 status, err = close_file(smbstate) 2676 if(status == false) then 2677 stop(smbstate) 2678 return false, err 2679 end 2680 end 2681 end 2682 2683 -- Stop the session 2684 stop(smbstate) 2685 return true, exist, list 2686end 2687 2688---Delete a file from the remote machine 2689-- 2690--@param host The host object 2691--@param share The share to upload it to (eg, C$). 2692--@param remotefile The remote file on the machine. It is relative to the share's root. It can be a string, or an array. 2693--@return (status, err) If status is false, err is an error message. Otherwise, err is undefined. 2694function file_delete(host, share, remotefile) 2695 local status, smbstate, err 2696 2697 -- Create the SMB session 2698 status, smbstate = start_ex(host, true, true, share) 2699 if(status == false) then 2700 return false, smbstate 2701 end 2702 2703 -- Make sure the remotefile is always a table, to save on duplicate code 2704 if(type(remotefile) ~= "table") then 2705 remotefile = {remotefile} 2706 end 2707 2708 2709 for _, file in ipairs(remotefile) do 2710 status, err = delete_file(smbstate, file) 2711 if(status == false) then 2712 stdnse.debug1("SMB: Couldn't delete %s\\%s: %s", share, file, err) 2713 if(err ~= 'NT_STATUS_OBJECT_NAME_NOT_FOUND') then 2714 stop(smbstate) 2715 return false, err 2716 end 2717 end 2718 end 2719 2720 -- Stop the session 2721 stop(smbstate) 2722 2723 return true 2724end 2725 2726-- Sends TRANS2_FIND_FIRST2 / TRANS2_FIND_NEXT2 request, takes care of 2727-- short/fragmented responses, and returns a list of file entries 2728-- 2729-- @param smbstate the SMB object associated with the connection 2730-- @param srch_id of search to resume (for TRANS2_FIND_NEXT2) or nil 2731-- @param trans2_params string representing Trans2_Parameters 2732-- @return status of the request 2733-- @return srch_id of search to resume later, or nil if the search completed 2734-- or the error message if status is false 2735-- @return list of file entries 2736local function send_and_receive_find_request(smbstate, srch_id, trans2_params) 2737 local TRANS2_FIND_FIRST2 = 1 2738 local TRANS2_FIND_NEXT2 = 2 2739 local sub_command = srch_id and TRANS2_FIND_NEXT2 or TRANS2_FIND_FIRST2 2740 local status = send_transaction2(smbstate, sub_command, trans2_params, "") 2741 if not status then 2742 return false, "Failed to send data to server: send_transaction2" 2743 end 2744 2745 local resp 2746 status, resp = receive_transaction2(smbstate) 2747 if not status or #resp.parameters < 2 then 2748 return false, "Failed to receive data from server: receive_transaction2" 2749 end 2750 2751 local param_pos = 1 2752 if sub_command == TRANS2_FIND_FIRST2 then 2753 srch_id, param_pos = string.unpack("<I2", resp.parameters, param_pos) 2754 end 2755 2756 -- parse Trans2_Parameters 2757 -- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/4e65d94e-09af-4511-a77a-b73adf1c52d6 2758 local param_fmt = "<I2 I2 xx I2" 2759 if #resp.parameters < param_pos - 1 + param_fmt:packsize() then 2760 return false, "Truncated response from server: receive_transaction2" 2761 end 2762 local srch_cnt, srch_end, last_name_pos = param_fmt:unpack(resp.parameters, param_pos) 2763 2764 -- format of SMB_FIND_FILE_BOTH_DIRECTORY_INFO, without trailing FileName 2765 -- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/2aa849f4-1bc0-42bf-9c8f-d09f11fccc4c 2766 local entry_fmt = "<I4 xxxx I8 I8 I8 I8 I8 I8 I4 I4 xxxx B x c24" 2767 local entry_len = entry_fmt:packsize() 2768 2769 -- check if we need more packets to reassemble this transaction 2770 while #resp.data < last_name_pos + entry_len do 2771 local status, tmp = receive_transaction2(smbstate) 2772 if not status then 2773 return false, "Truncated response from receive_transaction2" 2774 end 2775 resp.data = resp.data .. tmp.data 2776 end 2777 2778 -- parse response, based on SMB_FIND_FILE_BOTH_DIRECTORY_INFO 2779 local entries = {} 2780 local data_pos = 1 2781 while srch_cnt > 0 do 2782 if #resp.data - data_pos + 1 < entry_len then 2783 return false, "Truncated response from receive_transaction2" 2784 end 2785 local entry = {} 2786 local next_pos, fn_pos, fn_len, sfn_len 2787 next_pos, entry.created, entry.accessed, entry.write, entry.change, 2788 entry.eof, entry.alloc_size, entry.attrs, fn_len, sfn_len, 2789 entry.s_fname, fn_pos = entry_fmt:unpack(resp.data, data_pos) 2790 2791 local time = entry.created 2792 time = (time // 10000000) - 11644473600 2793 entry.created = datetime.format_timestamp(time) 2794 2795 if sfn_len > 0 then 2796 entry.s_fname = entry.s_fname:sub(1, sfn_len) 2797 else 2798 entry.s_fname = nil 2799 end 2800 2801 if #resp.data - fn_pos + 1 < fn_len then 2802 return false, "Truncated response from receive_transaction2" 2803 end 2804 entry.fname = string.unpack("z", resp.data, fn_pos) 2805 table.insert(entries, entry) 2806 data_pos = data_pos + next_pos 2807 srch_cnt = srch_cnt - 1 2808 end 2809 return true, (srch_end == 0 and srch_id or nil), entries 2810end 2811 2812--- 2813-- List files based on a pattern within a given share and directory 2814-- 2815-- @param smbstate the SMB object associated with the connection 2816-- @param fname filename to search for, relative to share path 2817-- @param options table containing none or more of the following 2818-- <code>maxfiles</code> how many files to request in a single Trans2 op 2819-- <code>srch_attrs</code> table containing one or more of the following boolean attributes: 2820-- <code>ro</code> - find read only files 2821-- <code>hidden</code> - find hidden files 2822-- <code>system</code> - find system files 2823-- <code>volid</code> - include volume ids in result 2824-- <code>dir</code> - find directories 2825-- <code>archive</code> - find archived files 2826-- @return iterator function retrieving the next result 2827function find_files (smbstate, fname, options) 2828 options = options or {} 2829 2830 -- convert options.srch_attrs to a bitmap 2831 local xlat_srch_attrs = {ro = "SMB_FILE_ATTRIBUTE_READONLY", 2832 hidden = "SMB_FILE_ATTRIBUTE_HIDDEN", 2833 system = "SMB_FILE_ATTRIBUTE_SYSTEM", 2834 volid = "SMB_FILE_ATTRIBUTE_VOLUME", 2835 dir = "SMB_FILE_ATTRIBUTE_DIRECTORY", 2836 archive = "SMB_FILE_ATTRIBUTE_ARCHIVE"} 2837 local srch_attrs_mask = 0 2838 local srch_attrs = options.srch_attrs or {ro=true, hidden=false, system=true, dir=true} 2839 for k, v in pairs(srch_attrs) do 2840 if v then 2841 srch_attrs_mask = srch_attrs_mask | file_attributes[xlat_srch_attrs[k]] 2842 end 2843 end 2844 2845 fname = fname or '\\*' 2846 if fname:sub(1,1) ~= '\\' then 2847 fname = '\\' .. fname 2848 end 2849 2850 local srch_flags = 0x0002 | 0x0004 -- SMB_FIND_CLOSE_AT_EOS, SMB_FIND_RETURN_RESUME_KEYS 2851 local srch_info_lvl = 0x0104 -- SMB_FIND_FILE_BOTH_DIRECTORY_INFO 2852 local max_srch_cnt = tonumber(options.maxfiles) 2853 if max_srch_cnt and max_srch_cnt > 0 then 2854 max_srch_cnt = math.floor(4 + math.min(1020, max_srch_cnt)) 2855 else 2856 max_srch_cnt = 1024 2857 end 2858 2859 -- state variables for next_entry() iterator 2860 local first_run = true 2861 local srch_id = nil 2862 local last_fname = nil 2863 local entries = {} 2864 local entry_idx = 1 2865 2866 local function next_entry() 2867 if entry_idx > #entries then -- get more file entries from the target 2868 local trans2_params 2869 if first_run then -- TRANS2_FIND_FIRST2 2870 first_run = false 2871 -- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/b2b2a730-9499-4f05-884e-d5bb7b9caf90 2872 trans2_params = string.pack("<I2 I2 I2 I2 I4 z", 2873 srch_attrs_mask, -- what types of files to return 2874 max_srch_cnt, -- maximum number of returned entries 2875 srch_flags, -- Flags 2876 srch_info_lvl, -- level of returned file details 2877 0, -- SearchStorageType 2878 fname) -- file name to search for 2879 -- FIXME filename ASCII vs UNICODE 2880 else -- TRANS2_FIND_NEXT2 2881 if not srch_id then -- the search is over 2882 return 2883 end 2884 -- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/80dc980e-fe03-455c-ada6-7c5dd6c551ba 2885 trans2_params = string.pack("<I2 I2 I2 I4 I2 z", 2886 srch_id, -- which search to resume 2887 max_srch_cnt, -- maximum number of returned entries 2888 srch_info_lvl, -- level of returned file details 2889 0, -- ResumeKey 2890 srch_flags, -- Flags 2891 last_fname) -- last file name previously returned 2892 -- FIXME wtf is ResumeKey? 2893 end 2894 local status 2895 status, srch_id, entries = send_and_receive_find_request(smbstate, srch_id, trans2_params) 2896 if not status then 2897 stdnse.debug1("Routine find_files failed with error: %s", srch_id) 2898 srch_id = nil 2899 entries = {} 2900 end 2901 entry_idx = 1 2902 if #entries == 0 then 2903 return 2904 end 2905 end 2906 local entry = entries[entry_idx] 2907 last_fname = entry.fname 2908 entry_idx = entry_idx + 1 2909 return entry 2910 end 2911 return next_entry 2912end 2913 2914---Determine whether or not the anonymous user has write access on the share. This is done by creating then 2915-- deleting a file. 2916-- 2917--@param host The host object 2918--@param share The share to test 2919--@return (status, result) If status is false, result is an error message. The error message 'NT_STATUS_OBJECT_NAME_NOT_FOUND' 2920-- should be handled gracefully; it indicates that the share isn't a fileshare. Otherwise, result is a boolean value: 2921-- true if the file was successfully written, false if it was not. 2922function share_anonymous_can_write(host, share) 2923 local filename, status, err 2924 2925 -- First, choose a filename. This should be random. 2926 filename = "nmap-test-file" 2927 2928 -- Next, attempt to write to that file 2929 status, err = file_write(host, string.rep("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10), share, filename, true) 2930 if(status == false) then 2931 if(err == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then 2932 return false, err 2933 end 2934 2935 if(err == "NT_STATUS_ACCESS_DENIED" or err == "NT_STATUS_INVALID_PARAMETER") then 2936 return true, false 2937 end 2938 2939 return false, "Error writing test file to disk as anonymous: " .. err 2940 end 2941 2942 -- Now the important part: delete it 2943 status, err = file_delete(host, share, filename) 2944 if(status == false) then 2945 return false, "Error deleting test file as anonymous: " .. err 2946 end 2947 2948 return true, true 2949end 2950 2951 2952---Determine whether or not the current user has read or read/write access on the share. This is done by creating then 2953-- deleting a file. 2954-- 2955--@param host The host object 2956--@param share The share to test 2957--@return (status, result) If status is false, result is an error message. The error message 'NT_STATUS_OBJECT_NAME_NOT_FOUND' 2958-- should be handled gracefully; it indicates that the share isn't a fileshare. Otherwise, result is a boolean value: 2959-- true if the file was successfully written, false if it was not. 2960function share_user_can_write(host, share) 2961 2962 local filename, status, err 2963 2964 -- First, choose a filename. This should be random. 2965 filename = "nmap-test-file" 2966 2967 -- Next, attempt to write to that file 2968 status, err = file_write(host, string.rep("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10), share, filename) 2969 if(status == false) then 2970 if(err == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then 2971 return false, err 2972 end 2973 2974 if(err == "NT_STATUS_ACCESS_DENIED" or err == "NT_STATUS_INVALID_PARAMETER") then 2975 return true, false 2976 end 2977 2978 return false, "Error writing test file to disk as user: " .. err 2979 end 2980 2981 -- Now the important part: delete it 2982 status, err = file_delete(host, share, filename) 2983 if(status == false) then 2984 return false, "Error deleting test file as user: " .. err 2985 end 2986 2987 return true, true 2988end 2989 2990---Check whether or not a share is accessible by the anonymous user. Assumes that <code>share_host_returns_proper_error</code> 2991-- has been called and returns <code>true</code>. 2992-- 2993--@param host The host object 2994--@param share The share to test 2995--@return (status, result) If status is false, result is an error message. Otherwise, result is a boolean value: 2996-- true if anonymous access is permitted, false otherwise. 2997function share_anonymous_can_read(host, share) 2998 local status, smbstate, err 2999 local overrides = get_overrides_anonymous() 3000 3001 -- Begin the SMB session 3002 status, smbstate = start(host) 3003 if(status == false) then 3004 return false, smbstate 3005 end 3006 3007 -- Negotiate the protocol 3008 status, err = negotiate_protocol(smbstate, overrides) 3009 if(status == false) then 3010 stop(smbstate) 3011 return false, err 3012 end 3013 3014 -- Start up a null session 3015 status, err = start_session(smbstate, overrides) 3016 3017 if(status == false) then 3018 stop(smbstate) 3019 return false, err 3020 end 3021 3022 -- Attempt a connection to the share 3023 status, err = tree_connect(smbstate, share, overrides) 3024 if(status == false) then 3025 3026 -- Stop the session 3027 stop(smbstate) 3028 3029 -- ACCESS_DENIED is the expected error: it tells us that the connection failed 3030 if(err == 0xc0000022 or err == 'NT_STATUS_ACCESS_DENIED') then 3031 return true, false 3032 else 3033 return false, err 3034 end 3035 end 3036 3037 3038 3039 stop(smbstate) 3040 return true, true 3041end 3042 3043---Check whether or not a share is accessible by the current user. Assumes that <code>share_host_returns_proper_error</code> 3044-- has been called and returns <code>true</code>. 3045-- 3046--@param host The host object 3047--@param share The share to test 3048--@return (status, result) If status is false, result is an error message. Otherwise, result is a boolean value: 3049-- true if anonymous access is permitted, false otherwise. 3050function share_user_can_read(host, share) 3051 local status, smbstate, err 3052 local overrides = {} 3053 3054 -- Begin the SMB session 3055 status, smbstate = start(host) 3056 if(status == false) then 3057 return false, smbstate 3058 end 3059 3060 -- Negotiate the protocol 3061 status, err = negotiate_protocol(smbstate, overrides) 3062 if(status == false) then 3063 stop(smbstate) 3064 return false, err 3065 end 3066 3067 -- Start up a null session 3068 status, err = start_session(smbstate, overrides) 3069 if(status == false) then 3070 stop(smbstate) 3071 return false, err 3072 end 3073 3074 -- Attempt a connection to the share 3075 status, err = tree_connect(smbstate, share, overrides) 3076 if(status == false) then 3077 3078 -- Stop the session 3079 stop(smbstate) 3080 3081 -- ACCESS_DENIED is the expected error: it tells us that the connection failed 3082 if(err == 0xc0000022 or err == 'NT_STATUS_ACCESS_DENIED') then 3083 return true, false 3084 else 3085 return false, err 3086 end 3087 end 3088 3089 stop(smbstate) 3090 return true, true 3091end 3092 3093---Determine whether or not a host will accept any share name (I've seen this on certain systems; it's 3094-- bad, because it means we cannot tell whether or not a share exists). 3095-- 3096--@param host The host object 3097--@param use_anonymous [optional] If set to 'true', test is done by the anonymous user rather than the current user. 3098--@return (status, result) If status is false, result is an error message. Otherwise, result is a boolean value: 3099-- true if the file was successfully written, false if it was not. 3100function share_host_returns_proper_error(host, use_anonymous) 3101 local status, smbstate, err 3102 local share = "nmap-share-test" 3103 local overrides 3104 3105 if ( use_anonymous ) then 3106 overrides = get_overrides_anonymous() 3107 end 3108 3109 -- Begin the SMB session 3110 status, smbstate = start(host) 3111 if(status == false) then 3112 return false, smbstate 3113 end 3114 3115 -- Negotiate the protocol 3116 status, err = negotiate_protocol(smbstate, overrides) 3117 if(status == false) then 3118 stop(smbstate) 3119 return false, err 3120 end 3121 3122 -- Start up a null session 3123 status, err = start_session(smbstate, overrides) 3124 if(status == false) then 3125 stop(smbstate) 3126 return false, err 3127 end 3128 3129 -- Connect to the share 3130 stdnse.debug1("SMB: Trying a random share to see if server responds properly: %s", share) 3131 status, err = tree_connect(smbstate, share, overrides) 3132 3133 if(status == false) then 3134 -- If the error is NT_STATUS_ACCESS_DENIED (0xc0000022), that's bad -- we don't want non-existent shares 3135 -- showing up as 'access denied'. Any other error is ok. 3136 if(err == 0xc0000022 or err == 'NT_STATUS_ACCESS_DENIED') then 3137 stdnse.debug1("SMB: Server doesn't return proper value for non-existent shares (returns ACCESS_DENIED)") 3138 stop(smbstate) 3139 return true, false 3140 end 3141 else 3142 -- If we were actually able to connect to this share, then there's probably a serious issue 3143 stdnse.debug1("SMB: Server doesn't return proper value for non-existent shares (accepts the connection)") 3144 stop(smbstate) 3145 return true, false 3146 end 3147 3148 stop(smbstate) 3149 return true, true 3150end 3151 3152---Get all the details we can about the share. These details are stored in a table and returned. 3153-- 3154--@param host The host object. 3155--@param share An array of shares to check. 3156--@return (status, result) If status is false, result is an error message. Otherwise, result is a boolean value: 3157-- true if the file was successfully written, false if it was not. 3158function share_get_details(host, share) 3159 local msrpc = require "msrpc" -- avoid require cycle 3160 local smbstate, status, result 3161 local i 3162 local details = {} 3163 3164 --Transform name to FQPN form 3165 status, share = get_fqpn(host, share) 3166 if not status then 3167 stdnse.debug1("SMB:Couldn't obtain FQPN share name. Trying with '%s'", share) 3168 end 3169 3170 -- Save the name 3171 details['name'] = share 3172 3173 -- Check if the current user can read the share 3174 stdnse.debug1("SMB: Checking if share %s can be read by the current user", share) 3175 status, result = share_user_can_read(host, share) 3176 if(status == false) then 3177 return false, result 3178 end 3179 details['user_can_read'] = result 3180 3181 -- Check if the anonymous reader can read the share 3182 stdnse.debug1("SMB: Checking if share %s can be read by the anonymous user", share) 3183 status, result = share_anonymous_can_read(host, share) 3184 if(status == true) then 3185 details['anonymous_can_read'] = result 3186 end 3187 3188 -- Check if the current user can write to the share 3189 stdnse.debug1("SMB: Checking if share %s can be written by the current user", share) 3190 status, result = share_user_can_write(host, share) 3191 if(status == false) then 3192 if(result == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then 3193 details['user_can_write'] = "NT_STATUS_OBJECT_NAME_NOT_FOUND" 3194 else 3195 return false, result 3196 end 3197 end 3198 details['user_can_write'] = result 3199 3200 -- Check if the anonymous user can write to the share 3201 stdnse.debug1("SMB: Checking if share %s can be written by the anonymous user", share) 3202 status, result = share_anonymous_can_write(host, share) 3203 if(status == false and result == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then 3204 details['anonymous_can_write'] = "NT_STATUS_OBJECT_NAME_NOT_FOUND" 3205 elseif( status == true ) then 3206 details['anonymous_can_write'] = result 3207 end 3208 3209 -- Try and get full details about the share 3210 status, result = msrpc.get_share_info(host, share) 3211 if(status == false) then 3212 -- We don't stop for this error (it's pretty common since administrative privileges are required here) 3213 stdnse.debug1("SMB: Failed to get share info for %s: %s", share, result) 3214 details['details'] = result 3215 else 3216 -- Process the result a bit 3217 result = result['info'] 3218 if(result['max_users'] == 0xFFFFFFFF) then 3219 result['max_users'] = "<unlimited>" 3220 end 3221 details['details'] = result 3222 end 3223 3224 return true, details 3225end 3226 3227---Retrieve a list of fileshares, along with any details that could be pulled. This is the core of smb-enum-shares.nse, but 3228-- can also be used by any script that needs to find an open share. 3229-- 3230-- In the best care, the shares are determined by calling <code>msrpc.enum_shares</code>, and information is gathered by calling 3231-- <code>msrpc.get_share_info</code>. These require a certain level of access, though, so as a fallback, a pre-programmed list of 3232-- shares is used, and these are verified by attempting a connection. 3233-- 3234--@param host The host object. 3235--@return (status, result, extra) If status is false, result is an error message. Otherwise, result is an array of shares with as much 3236-- detail as we could get. If extra isn't nil, it is set to extra information that should be displayed (such as a warning). 3237function share_get_list(host) 3238 local msrpc = require "msrpc" -- avoid require cycle 3239 local status, result 3240 local enum_status 3241 local extra = "" 3242 local shares = {} 3243 local share_details = {} 3244 3245 -- Try and do this the good way, make a MSRPC call to get the shares 3246 stdnse.debug1("SMB: Attempting to log into the system to enumerate shares") 3247 enum_status, shares = msrpc.enum_shares(host) 3248 3249 -- If that failed, try doing it with brute force. This almost certainly won't find everything, but it's the 3250 -- best we can do. 3251 if(enum_status == false) then 3252 stdnse.debug1("SMB: Enumerating shares failed, guessing at common ones (%s)", shares) 3253 extra = string.format("ERROR: Enumerating shares failed, guessing at common ones (%s)", shares) 3254 3255 -- Take some common share names I've seen (thanks to Brandon Enright for most of these, except the last few) 3256 shares = {"ADMIN", "BACKUP", "DATA", "DESKTOP", "DOCS", "FILES", "GROUPS", "HD", "HOME", "INFO", "IPC", "MEDIA", "MY DOCUMENTS", "NETLOGON", "PICTURES", "PORN", "PR0N", "PRINT", "PROGRAMS", "PRON", "PUBLIC", "SHARE", "SHARED", "SOFTWARE", "STMP", "TEMP", "TEST", "TMP", "USERS", "WEB DOCUMENTS","WEBSERVER", "WWW", "XSERVE" } 3257 3258 -- Try every alphabetic share 3259 for i = string.byte("A", 1), string.byte("Z", 1), 1 do 3260 shares[#shares + 1] = string.char(i) 3261 end 3262 3263 -- For each share, add one with the same name and a trailing '$' 3264 local sharesLength = #shares 3265 for shareItr = 1, sharesLength, 1 do 3266 shares[ sharesLength + shareItr ] = shares[ shareItr ] .. '$' 3267 end 3268 else 3269 stdnse.debug1("SMB: Found %d shares, will attempt to find more information", #shares) 3270 end 3271 3272 -- Sort the shares 3273 table.sort(shares) 3274 3275 -- Ensure that the server returns the proper error message 3276 -- first try anonymously, then using a user account (in case anonymous connections are not supported) 3277 for _, anon in ipairs({true, false}) do 3278 status, result = share_host_returns_proper_error(host, anon) 3279 3280 if(status == true and result == false) then 3281 return false, "Server doesn't return proper value for non-existent shares; can't enumerate shares" 3282 end 3283 end 3284 3285 if(status == false) then 3286 return false, result 3287 end 3288 3289 -- Get more information on each share 3290 for i = 1, #shares, 1 do 3291 local status, result 3292 stdnse.debug1("SMB: Getting information for share: %s", shares[i]) 3293 status, result = share_get_details(host, shares[i]) 3294 if(status == false and result == 'NT_STATUS_BAD_NETWORK_NAME') then 3295 stdnse.debug1("SMB: Share doesn't exist: %s", shares[i]) 3296 elseif(status == false) then 3297 stdnse.debug1("SMB: Error while getting share details: %s", result) 3298 return false, result 3299 else 3300 -- Save the share details 3301 table.insert(share_details, result) 3302 end 3303 end 3304 3305 return true, share_details, extra 3306end 3307 3308---Find a share that the current user can write to. Return it, along with its path. If no share could be found, 3309-- an error is returned. If the path cannot be determined, the returned path is nil. 3310-- 3311--@param host The host object. 3312--@return (status, name, path, names) If status is false, result is an error message. Otherwise, name is the name of the share, 3313-- path is its path, if it could be determined, and names is a list of all writable shares. 3314function share_find_writable(host) 3315 local i 3316 local status, shares 3317 local main_name, main_path 3318 local names = {} 3319 local writable = {} 3320 3321 status, shares = share_get_list(host) 3322 if(status == false) then 3323 return false, shares 3324 end 3325 3326 for i = 1, #shares, 1 do 3327 if(shares[i]['user_can_write'] == true) then 3328 if(main_name == nil) then 3329 main_name = shares[i]['name'] 3330 3331 if(shares[i]['details'] ~= nil) then 3332 main_path = shares[i]['details']['path'] 3333 end 3334 end 3335 3336 table.insert(names, shares[i]['name']) 3337 end 3338 end 3339 3340 if(main_name == nil) then 3341 return false, "Couldn't find a writable share!" 3342 else 3343 return true, main_name, main_path, names 3344 end 3345end 3346 3347--- Converts numbered Windows version strings (<code>"Windows 5.0"</code>, <code>"Windows 5.1"</code>) to names (<code>"Windows 2000"</code>, <code>"Windows XP"</code>). 3348--@param os The numbered OS version. 3349--@return The actual name of the OS (or the same as the <code>os</code> parameter if no match was found). 3350function get_windows_version(os) 3351 3352 if(os == "Windows 5.0") then 3353 return "Windows 2000" 3354 elseif(os == "Windows 5.1")then 3355 return "Windows XP" 3356 end 3357 3358 return os 3359 3360end 3361 3362---Retrieve information about the host's operating system. This should always be possible to call, as long as there isn't already 3363-- a SMB session established. 3364-- 3365-- The returned table has the following keys (shown here with sample values). 3366-- * <code>os</code>: <code>"Windows 7 Professional 7601 Service Pack 1"</code> 3367-- * <code>lanmanager</code>: <code>"Windows 7 Professional 6.1"</code> 3368-- * <code>domain</code>: <code>"WORKGROUP"</code> 3369-- * <code>server</code>: <code>"COMPUTERNAME"</code> 3370-- * <code>time</code>: <code>1347121470.0462</code> 3371-- * <code>date</code>: <code>"2012-09-08 09:24:30"</code> 3372-- * <code>timezone</code>: <code>-7</code> 3373-- * <code>timezone_str</code>: <code>UTC-7</code> 3374-- * <code>port</code>: <code>445</code> 3375-- The table may also contain these additional keys: 3376-- * <code>fqdn</code>: <code>"Sql2008.lab.test.local"</code> 3377-- * <code>domain_dns</code>: <code>"lab.test.local"</code> 3378-- * <code>forest_dns</code>: <code>"test.local"</code> 3379-- * <code>workgroup</code> 3380-- 3381--@param host The host object 3382--@return (status, data) If status is true, data is a table of values; otherwise, data is an error message. 3383function get_os(host) 3384 local state 3385 local status, smbstate 3386 3387 local response = {} 3388 3389 -- Start up SMB 3390 status, smbstate = start_ex(host, true, true, nil, nil, true) 3391 if(status == false) then 3392 return false, smbstate 3393 end 3394 3395 -- See if we actually got something 3396 if(smbstate['os'] == nil and smbstate['lanmanager'] == nil) then 3397 return false, "Server didn't return OS details" 3398 end 3399 3400 response['os'] = smbstate['os'] 3401 response['lanmanager'] = smbstate['lanmanager'] 3402 response['domain'] = smbstate['domain'] 3403 response['server'] = smbstate['server'] 3404 response['date'] = smbstate['date'] 3405 response['time'] = smbstate['time'] 3406 response['timezone_str'] = smbstate['timezone_str'] 3407 response['timezone'] = smbstate['timezone'] 3408 response['port'] = smbstate['port'] 3409 3410 -- Kill SMB 3411 stop(smbstate) 3412 3413 3414 -- Start another session with extended security. This will allow us to get 3415 -- additional information about the target. 3416 status, smbstate = start_ex(host, true, true, nil, nil, false) 3417 if(status == true) then 3418 -- See if we actually got something 3419 if (smbstate['fqdn'] or smbstate['domain_dns'] or smbstate['forest_dns']) then 3420 response['fqdn'] = smbstate['fqdn'] 3421 response['domain_dns'] = smbstate['domain_dns'] 3422 response['forest_dns'] = smbstate['forest_dns'] 3423 -- After a non-extended security negotiation, smbstate['domain'] will 3424 -- contain the NetBIOS domain name, or the workgroup name. However, 3425 -- after an extended-security session setup, smbstate['domain'] will 3426 -- contain the NetBIOS domain name. For hosts in a workgroup, Windows 3427 -- uses the NetBIOS hostname as the NetBIOS domain name. Comparing the 3428 -- two will reveal whether the target is in a domain or a workgroup. 3429 if ( smbstate['domain'] ~= nil and response['domain'] ~= smbstate['domain'] ) then 3430 response['workgroup'] = response['domain'] 3431 response['domain'] = nil 3432 end 3433 end 3434 3435 -- Kill SMB again 3436 stop(smbstate) 3437 end 3438 3439 return true, response 3440end 3441 3442---Basically a wrapper around <code>socket:get_info</code>, except that it also makes a SMB connection before calling the 3443-- <code>get_info</code> function. Returns the mac address as well, for convenience. 3444-- 3445--@param host The host object 3446--@return status: true for successful, false otherwise. 3447--@return If status is true, the local ip address; otherwise, an error message. 3448--@return The local port (not really meaningful, since it'll change next time). 3449--@return The remote ip address. 3450--@return The report port. 3451--@return The mac address, if possible; nil otherwise. 3452function get_socket_info(host) 3453 local status, lhost, lport, rhost, rport 3454 local smbstate, socket 3455 3456 -- Start SMB (we need a socket to get the proper local ip 3457 status, smbstate = start_ex(host) 3458 if(status == false) then 3459 return false, smbstate 3460 end 3461 3462 socket = smbstate['socket'] 3463 status, lhost, lport, rhost, rport = socket:get_info() 3464 if(status == false) then 3465 return false, lhost 3466 end 3467 3468 -- Stop SMB 3469 stop(smbstate) 3470 3471 -- Get the mac in hex format, if possible 3472 local lmac = nil 3473 if(host.mac_addr_src) then 3474 lmac = stdnse.tohex(host.mac_addr_src, {separator = ":"}) 3475 end 3476 3477 return true, lhost, lport, rhost, rport, lmac 3478end 3479 3480---Generate a string that's somewhat unique, but is based on factors that won't 3481-- change on a host. 3482-- 3483-- At the moment, this is a very simple hash based on the IP address. This hash 3484-- is *very* likely to have collisions, and that's by design -- while it should 3485-- be somewhat unique, I don't want it to be trivial to uniquely determine who 3486-- it originated from. 3487-- 3488-- TODO: At some point, I should re-do this function properly, with a method of 3489-- hashing that's somewhat proven. 3490-- 3491--@param host The host object 3492--@param extension [optional] The extension to add on the end of the file. 3493-- Default: none. 3494--@param seed [optional] Some randomness on which to base the name. If you want 3495-- to do multiple files, each with its own uniqueish name, this can 3496-- be used. 3497--@return (status, data) If status is true, data is a table of values; 3498-- otherwise, data is an error message. Can be any kind of string. 3499function get_uniqueish_name(host, extension, seed) 3500 3501 local status 3502 local lhost, lport, rhost, rport 3503 if(type(host) == "table") then 3504 status, lhost = get_socket_info(host) 3505 else 3506 lhost = host 3507 end 3508 3509 -- Create our ultra-weak hash by using a simple xor/shift algorithm 3510 -- I tested this, and in 255 tests, there were roughly 10 collisions. That's about what I'm looking for. 3511 local hash = 0 3512 local i 3513 local str = lhost .. (seed or "") .. (extension or "") .. (nmap.registry.args.randomseed or "") 3514 3515 for i = 1, #str, 1 do 3516 local chr = str:byte(i) 3517 hash = hash ~ chr 3518 hash = (hash << 3) | (hash >> 29) 3519 hash = hash ~ 3 3520 hash = hash & 0xFFFFFFFF 3521 end 3522 3523 local response 3524 if(extension) then 3525 response = string.format("%x.%s", hash, extension) 3526 else 3527 response = string.format("%x", hash) 3528 end 3529 3530 return true, response 3531end 3532 3533---Determines, as accurately as possible, whether or not an account is an administrator. If there is an error, 3534-- 'false' is simply returned. 3535function is_admin(host, username, domain, password, password_hash, hash_type) 3536 local msrpc = require "msrpc" -- avoid require cycle 3537 local overrides = get_overrides(username, domain, password, password_hash, hash_type) 3538 3539 stdnse.debug1("SMB: Checking if %s is an administrator", username) 3540 3541 local status, smbstate = start(host) 3542 if(status == false) then 3543 stdnse.debug1("SMB; is_admin: Failed to start SMB: %s [%s]", smbstate, username) 3544 stop(smbstate) 3545 return false 3546 end 3547 3548 local status, err = negotiate_protocol(smbstate, overrides) 3549 if(status == false) then 3550 stdnse.debug1("SMB; is_admin: Failed to negotiate protocol: %s [%s]", err, username) 3551 stop(smbstate) 3552 return false 3553 end 3554 3555 status, err = start_session(smbstate, overrides) 3556 if(status == false) then 3557 stdnse.debug1("SMB; is_admin: Failed to start session %s [%s]", err, username) 3558 stop(smbstate) 3559 return false 3560 end 3561 3562 local _, fqpn_share = get_fqpn(host, "IPC$") 3563 status, err = tree_connect(smbstate, fqpn_share, overrides) 3564 if(status == false) then 3565 stdnse.debug1("SMB; is_admin: Failed to connect tree: %s [%s]", err, username) 3566 stop(smbstate) 3567 return false 3568 end 3569 3570 status, err = create_file(smbstate, msrpc.SRVSVC_PATH, overrides) 3571 if(status == false) then 3572 stdnse.debug1("SMB; is_admin: Failed to create file: %s [%s]", err, username) 3573 stop(smbstate) 3574 return false 3575 end 3576 3577 status, err = msrpc.bind(smbstate, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil) 3578 if(status == false) then 3579 stdnse.debug1("SMB; is_admin: Failed to bind: %s [%s]", err, username) 3580 stop(smbstate) 3581 return false 3582 end 3583 3584 -- Call netservergetstatistics for 'server' 3585 status, err = msrpc.srvsvc_netservergetstatistics(smbstate, host.ip) 3586 if(status == false) then 3587 stdnse.debug1("SMB; is_admin: Couldn't get server stats (may be normal): %s [%s]", err, username) 3588 stop(smbstate) 3589 return false 3590 end 3591 3592 stop(smbstate) 3593 3594 return true 3595end 3596 3597--- 3598-- Returns the fully qualified path name (FQPN) for shares. 3599-- This is required for modern versions of Windows. 3600-- Returns \\<ip>\<sharename> when successful. Otherwise, returns the same share name. 3601--- 3602function get_fqpn(host, sharename) 3603 if host.ip and sharename then 3604 return true, string.format("\\\\%s\\%s", host.ip, sharename) 3605 end 3606 stdnse.debug1("SMB: get_fqpn: Couldn't determine server IP address") 3607 return false, sharename 3608end 3609 3610command_codes = 3611{ 3612 SMB_COM_CREATE_DIRECTORY = 0x00, 3613 SMB_COM_DELETE_DIRECTORY = 0x01, 3614 SMB_COM_OPEN = 0x02, 3615 SMB_COM_CREATE = 0x03, 3616 SMB_COM_CLOSE = 0x04, 3617 SMB_COM_FLUSH = 0x05, 3618 SMB_COM_DELETE = 0x06, 3619 SMB_COM_RENAME = 0x07, 3620 SMB_COM_QUERY_INFORMATION = 0x08, 3621 SMB_COM_SET_INFORMATION = 0x09, 3622 SMB_COM_READ = 0x0A, 3623 SMB_COM_WRITE = 0x0B, 3624 SMB_COM_LOCK_BYTE_RANGE = 0x0C, 3625 SMB_COM_UNLOCK_BYTE_RANGE = 0x0D, 3626 SMB_COM_CREATE_TEMPORARY = 0x0E, 3627 SMB_COM_CREATE_NEW = 0x0F, 3628 SMB_COM_CHECK_DIRECTORY = 0x10, 3629 SMB_COM_PROCESS_EXIT = 0x11, 3630 SMB_COM_SEEK = 0x12, 3631 SMB_COM_LOCK_AND_READ = 0x13, 3632 SMB_COM_WRITE_AND_UNLOCK = 0x14, 3633 SMB_COM_READ_RAW = 0x1A, 3634 SMB_COM_READ_MPX = 0x1B, 3635 SMB_COM_READ_MPX_SECONDARY = 0x1C, 3636 SMB_COM_WRITE_RAW = 0x1D, 3637 SMB_COM_WRITE_MPX = 0x1E, 3638 SMB_COM_WRITE_MPX_SECONDARY = 0x1F, 3639 SMB_COM_WRITE_COMPLETE = 0x20, 3640 SMB_COM_QUERY_SERVER = 0x21, 3641 SMB_COM_SET_INFORMATION2 = 0x22, 3642 SMB_COM_QUERY_INFORMATION2 = 0x23, 3643 SMB_COM_LOCKING_ANDX = 0x24, 3644 SMB_COM_TRANSACTION = 0x25, 3645 SMB_COM_TRANSACTION_SECONDARY = 0x26, 3646 SMB_COM_IOCTL = 0x27, 3647 SMB_COM_IOCTL_SECONDARY = 0x28, 3648 SMB_COM_COPY = 0x29, 3649 SMB_COM_MOVE = 0x2A, 3650 SMB_COM_ECHO = 0x2B, 3651 SMB_COM_WRITE_AND_CLOSE = 0x2C, 3652 SMB_COM_OPEN_ANDX = 0x2D, 3653 SMB_COM_READ_ANDX = 0x2E, 3654 SMB_COM_WRITE_ANDX = 0x2F, 3655 SMB_COM_NEW_FILE_SIZE = 0x30, 3656 SMB_COM_CLOSE_AND_TREE_DISC = 0x31, 3657 SMB_COM_TRANSACTION2 = 0x32, 3658 SMB_COM_TRANSACTION2_SECONDARY = 0x33, 3659 SMB_COM_FIND_CLOSE2 = 0x34, 3660 SMB_COM_FIND_NOTIFY_CLOSE = 0x35, 3661 SMB_COM_TREE_CONNECT = 0x70, 3662 SMB_COM_TREE_DISCONNECT = 0x71, 3663 SMB_COM_NEGOTIATE = 0x72, 3664 SMB_COM_SESSION_SETUP_ANDX = 0x73, 3665 SMB_COM_LOGOFF_ANDX = 0x74, 3666 SMB_COM_TREE_CONNECT_ANDX = 0x75, 3667 SMB_COM_QUERY_INFORMATION_DISK = 0x80, 3668 SMB_COM_SEARCH = 0x81, 3669 SMB_COM_FIND = 0x82, 3670 SMB_COM_FIND_UNIQUE = 0x83, 3671 SMB_COM_FIND_CLOSE = 0x84, 3672 SMB_COM_NT_TRANSACT = 0xA0, 3673 SMB_COM_NT_TRANSACT_SECONDARY = 0xA1, 3674 SMB_COM_NT_CREATE_ANDX = 0xA2, 3675 SMB_COM_NT_CANCEL = 0xA4, 3676 SMB_COM_NT_RENAME = 0xA5, 3677 SMB_COM_OPEN_PRINT_FILE = 0xC0, 3678 SMB_COM_WRITE_PRINT_FILE = 0xC1, 3679 SMB_COM_CLOSE_PRINT_FILE = 0xC2, 3680 SMB_COM_GET_PRINT_QUEUE = 0xC3, 3681 SMB_COM_READ_BULK = 0xD8, 3682 SMB_COM_WRITE_BULK = 0xD9, 3683 SMB_COM_WRITE_BULK_DATA = 0xDA, 3684 SMB_NO_FURTHER_COMMANDS = 0xFF 3685} 3686 3687for i, v in pairs(command_codes) do 3688 command_names[v] = i 3689end 3690 3691 3692-- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/2198f480-e047-4df0-ba64-f28eadef00b9 3693file_attributes = 3694{ 3695 SMB_FILE_ATTRIBUTE_NORMAL = 0x0000, 3696 SMB_FILE_ATTRIBUTE_READONLY = 0x0001, 3697 SMB_FILE_ATTRIBUTE_HIDDEN = 0x0002, 3698 SMB_FILE_ATTRIBUTE_SYSTEM = 0x0004, 3699 SMB_FILE_ATTRIBUTE_VOLUME = 0x0008, 3700 SMB_FILE_ATTRIBUTE_DIRECTORY = 0x0010, 3701 SMB_FILE_ATTRIBUTE_ARCHIVE = 0x0020, 3702 SMB_SEARCH_ATTRIBUTE_READONLY = 0x0100, 3703 SMB_SEARCH_ATTRIBUTE_HIDDEN = 0x0200, 3704 SMB_SEARCH_ATTRIBUTE_SYSTEM = 0x0400, 3705 SMB_SEARCH_ATTRIBUTE_DIRECTORY = 0x1000, 3706 SMB_SEARCH_ATTRIBUTE_ARCHIVE = 0x2000 3707} 3708 3709 3710-- see http://msdn.microsoft.com/en-us/library/cc231196(v=prot.10).aspx 3711status_codes = 3712{ 3713 NT_STATUS_SUCCESS = 0x00000000, 3714 NT_STATUS_WERR_BADFILE = 0x00000002, 3715 NT_STATUS_WERR_ACCESS_DENIED = 0x00000005, 3716 NT_STATUS_WERR_INVALID_PARAMETER = 0x00000057, 3717 NT_STATUS_WERR_INVALID_NAME = 0x0000007b, 3718 NT_STATUS_WERR_UNKNOWN_LEVEL = 0x0000007c, 3719 NT_STATUS_WERR_MORE_DATA = 0x000000ea, 3720 NT_STATUS_NO_MORE_ITEMS = 0x00000103, 3721 NT_STATUS_MORE_ENTRIES = 0x00000105, 3722 NT_STATUS_SOME_NOT_MAPPED = 0x00000107, 3723 NT_STATUS_SERVICE_REQUEST_TIMEOUT = 0x0000041D, 3724 NT_STATUS_SERVICE_NO_THREAD = 0x0000041E, 3725 NT_STATUS_SERVICE_DATABASE_LOCKED = 0x0000041F, 3726 NT_STATUS_SERVICE_ALREADY_RUNNING = 0x00000420, 3727 NT_STATUS_INVALID_SERVICE_ACCOUNT = 0x00000421, 3728 NT_STATUS_SERVICE_DISABLED = 0x00000422, 3729 NT_STATUS_CIRCULAR_DEPENDENCY = 0x00000423, 3730 NT_STATUS_SERVICE_DOES_NOT_EXIST = 0x00000424, 3731 NT_STATUS_SERVICE_CANNOT_ACCEPT_CTRL = 0x00000425, 3732 NT_STATUS_SERVICE_NOT_ACTIVE = 0x00000426, 3733 NT_STATUS_FAILED_SERVICE_CONTROLLER_CONNECT = 0x00000427, 3734 NT_STATUS_EXCEPTION_IN_SERVICE = 0x00000428, 3735 NT_STATUS_DATABASE_DOES_NOT_EXIST = 0x00000429, 3736 NT_STATUS_SERVICE_SPECIFIC_ERROR = 0x0000042a, 3737 NT_STATUS_PROCESS_ABORTED = 0x0000042b, 3738 NT_STATUS_SERVICE_DEPENDENCY_FAIL = 0x0000042c, 3739 NT_STATUS_SERVICE_LOGON_FAILED = 0x0000042d, 3740 NT_STATUS_SERVICE_START_HANG = 0x0000042e, 3741 NT_STATUS_INVALID_SERVICE_LOCK = 0x0000042f, 3742 NT_STATUS_SERVICE_MARKED_FOR_DELETE = 0x00000430, 3743 NT_STATUS_SERVICE_EXISTS = 0x00000431, 3744 NT_STATUS_ALREADY_RUNNING_LKG = 0x00000432, 3745 NT_STATUS_SERVICE_DEPENDENCY_DELETED = 0x00000433, 3746 NT_STATUS_BOOT_ALREADY_ACCEPTED = 0x00000434, 3747 NT_STATUS_SERVICE_NEVER_STARTED = 0x00000435, 3748 NT_STATUS_DUPLICATE_SERVICE_NAME = 0x00000436, 3749 NT_STATUS_DIFFERENT_SERVICE_ACCOUNT = 0x00000437, 3750 NT_STATUS_CANNOT_DETECT_DRIVER_FAILURE = 0x00000438, 3751 DOS_STATUS_UNKNOWN_ERROR = 0x00010001, 3752 DOS_STATUS_NONSPECIFIC_ERROR = 0x00010002, 3753 DOS_STATUS_DIRECTORY_NOT_FOUND = 0x00030001, 3754 DOS_STATUS_ACCESS_DENIED = 0x00050001, 3755 DOS_STATUS_INVALID_FID = 0x00060001, 3756 DOS_STATUS_INVALID_NETWORK_NAME = 0x00060002, 3757 NT_STATUS_BUFFER_OVERFLOW = 0x80000005, 3758 NT_STATUS_UNSUCCESSFUL = 0xc0000001, 3759 NT_STATUS_NOT_IMPLEMENTED = 0xc0000002, 3760 NT_STATUS_INVALID_INFO_CLASS = 0xc0000003, 3761 NT_STATUS_INFO_LENGTH_MISMATCH = 0xc0000004, 3762 NT_STATUS_ACCESS_VIOLATION = 0xc0000005, 3763 NT_STATUS_IN_PAGE_ERROR = 0xc0000006, 3764 NT_STATUS_PAGEFILE_QUOTA = 0xc0000007, 3765 NT_STATUS_INVALID_HANDLE = 0xc0000008, 3766 NT_STATUS_BAD_INITIAL_STACK = 0xc0000009, 3767 NT_STATUS_BAD_INITIAL_PC = 0xc000000a, 3768 NT_STATUS_INVALID_CID = 0xc000000b, 3769 NT_STATUS_TIMER_NOT_CANCELED = 0xc000000c, 3770 NT_STATUS_INVALID_PARAMETER = 0xc000000d, 3771 NT_STATUS_NO_SUCH_DEVICE = 0xc000000e, 3772 NT_STATUS_NO_SUCH_FILE = 0xc000000f, 3773 NT_STATUS_INVALID_DEVICE_REQUEST = 0xc0000010, 3774 NT_STATUS_END_OF_FILE = 0xc0000011, 3775 NT_STATUS_WRONG_VOLUME = 0xc0000012, 3776 NT_STATUS_NO_MEDIA_IN_DEVICE = 0xc0000013, 3777 NT_STATUS_UNRECOGNIZED_MEDIA = 0xc0000014, 3778 NT_STATUS_NONEXISTENT_SECTOR = 0xc0000015, 3779 NT_STATUS_MORE_PROCESSING_REQUIRED = 0xc0000016, 3780 NT_STATUS_NO_MEMORY = 0xc0000017, 3781 NT_STATUS_CONFLICTING_ADDRESSES = 0xc0000018, 3782 NT_STATUS_NOT_MAPPED_VIEW = 0xc0000019, 3783 NT_STATUS_UNABLE_TO_FREE_VM = 0xc000001a, 3784 NT_STATUS_UNABLE_TO_DELETE_SECTION = 0xc000001b, 3785 NT_STATUS_INVALID_SYSTEM_SERVICE = 0xc000001c, 3786 NT_STATUS_ILLEGAL_INSTRUCTION = 0xc000001d, 3787 NT_STATUS_INVALID_LOCK_SEQUENCE = 0xc000001e, 3788 NT_STATUS_INVALID_VIEW_SIZE = 0xc000001f, 3789 NT_STATUS_INVALID_FILE_FOR_SECTION = 0xc0000020, 3790 NT_STATUS_ALREADY_COMMITTED = 0xc0000021, 3791 NT_STATUS_ACCESS_DENIED = 0xc0000022, 3792 NT_STATUS_BUFFER_TOO_SMALL = 0xc0000023, 3793 NT_STATUS_OBJECT_TYPE_MISMATCH = 0xc0000024, 3794 NT_STATUS_NONCONTINUABLE_EXCEPTION = 0xc0000025, 3795 NT_STATUS_INVALID_DISPOSITION = 0xc0000026, 3796 NT_STATUS_UNWIND = 0xc0000027, 3797 NT_STATUS_BAD_STACK = 0xc0000028, 3798 NT_STATUS_INVALID_UNWIND_TARGET = 0xc0000029, 3799 NT_STATUS_NOT_LOCKED = 0xc000002a, 3800 NT_STATUS_PARITY_ERROR = 0xc000002b, 3801 NT_STATUS_UNABLE_TO_DECOMMIT_VM = 0xc000002c, 3802 NT_STATUS_NOT_COMMITTED = 0xc000002d, 3803 NT_STATUS_INVALID_PORT_ATTRIBUTES = 0xc000002e, 3804 NT_STATUS_PORT_MESSAGE_TOO_LONG = 0xc000002f, 3805 NT_STATUS_INVALID_PARAMETER_MIX = 0xc0000030, 3806 NT_STATUS_INVALID_QUOTA_LOWER = 0xc0000031, 3807 NT_STATUS_DISK_CORRUPT_ERROR = 0xc0000032, 3808 NT_STATUS_OBJECT_NAME_INVALID = 0xc0000033, 3809 NT_STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034, 3810 NT_STATUS_OBJECT_NAME_COLLISION = 0xc0000035, 3811 NT_STATUS_HANDLE_NOT_WAITABLE = 0xc0000036, 3812 NT_STATUS_PORT_DISCONNECTED = 0xc0000037, 3813 NT_STATUS_DEVICE_ALREADY_ATTACHED = 0xc0000038, 3814 NT_STATUS_OBJECT_PATH_INVALID = 0xc0000039, 3815 NT_STATUS_OBJECT_PATH_NOT_FOUND = 0xc000003a, 3816 NT_STATUS_OBJECT_PATH_SYNTAX_BAD = 0xc000003b, 3817 NT_STATUS_DATA_OVERRUN = 0xc000003c, 3818 NT_STATUS_DATA_LATE_ERROR = 0xc000003d, 3819 NT_STATUS_DATA_ERROR = 0xc000003e, 3820 NT_STATUS_CRC_ERROR = 0xc000003f, 3821 NT_STATUS_SECTION_TOO_BIG = 0xc0000040, 3822 NT_STATUS_PORT_CONNECTION_REFUSED = 0xc0000041, 3823 NT_STATUS_INVALID_PORT_HANDLE = 0xc0000042, 3824 NT_STATUS_SHARING_VIOLATION = 0xc0000043, 3825 NT_STATUS_QUOTA_EXCEEDED = 0xc0000044, 3826 NT_STATUS_INVALID_PAGE_PROTECTION = 0xc0000045, 3827 NT_STATUS_MUTANT_NOT_OWNED = 0xc0000046, 3828 NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED = 0xc0000047, 3829 NT_STATUS_PORT_ALREADY_SET = 0xc0000048, 3830 NT_STATUS_SECTION_NOT_IMAGE = 0xc0000049, 3831 NT_STATUS_SUSPEND_COUNT_EXCEEDED = 0xc000004a, 3832 NT_STATUS_THREAD_IS_TERMINATING = 0xc000004b, 3833 NT_STATUS_BAD_WORKING_SET_LIMIT = 0xc000004c, 3834 NT_STATUS_INCOMPATIBLE_FILE_MAP = 0xc000004d, 3835 NT_STATUS_SECTION_PROTECTION = 0xc000004e, 3836 NT_STATUS_EAS_NOT_SUPPORTED = 0xc000004f, 3837 NT_STATUS_EA_TOO_LARGE = 0xc0000050, 3838 NT_STATUS_NONEXISTENT_EA_ENTRY = 0xc0000051, 3839 NT_STATUS_NO_EAS_ON_FILE = 0xc0000052, 3840 NT_STATUS_EA_CORRUPT_ERROR = 0xc0000053, 3841 NT_STATUS_FILE_LOCK_CONFLICT = 0xc0000054, 3842 NT_STATUS_LOCK_NOT_GRANTED = 0xc0000055, 3843 NT_STATUS_DELETE_PENDING = 0xc0000056, 3844 NT_STATUS_CTL_FILE_NOT_SUPPORTED = 0xc0000057, 3845 NT_STATUS_UNKNOWN_REVISION = 0xc0000058, 3846 NT_STATUS_REVISION_MISMATCH = 0xc0000059, 3847 NT_STATUS_INVALID_OWNER = 0xc000005a, 3848 NT_STATUS_INVALID_PRIMARY_GROUP = 0xc000005b, 3849 NT_STATUS_NO_IMPERSONATION_TOKEN = 0xc000005c, 3850 NT_STATUS_CANT_DISABLE_MANDATORY = 0xc000005d, 3851 NT_STATUS_NO_LOGON_SERVERS = 0xc000005e, 3852 NT_STATUS_NO_SUCH_LOGON_SESSION = 0xc000005f, 3853 NT_STATUS_NO_SUCH_PRIVILEGE = 0xc0000060, 3854 NT_STATUS_PRIVILEGE_NOT_HELD = 0xc0000061, 3855 NT_STATUS_INVALID_ACCOUNT_NAME = 0xc0000062, 3856 NT_STATUS_USER_EXISTS = 0xc0000063, 3857 NT_STATUS_NO_SUCH_USER = 0xc0000064, 3858 NT_STATUS_GROUP_EXISTS = 0xc0000065, 3859 NT_STATUS_NO_SUCH_GROUP = 0xc0000066, 3860 NT_STATUS_MEMBER_IN_GROUP = 0xc0000067, 3861 NT_STATUS_MEMBER_NOT_IN_GROUP = 0xc0000068, 3862 NT_STATUS_LAST_ADMIN = 0xc0000069, 3863 NT_STATUS_WRONG_PASSWORD = 0xc000006a, 3864 NT_STATUS_ILL_FORMED_PASSWORD = 0xc000006b, 3865 NT_STATUS_PASSWORD_RESTRICTION = 0xc000006c, 3866 NT_STATUS_LOGON_FAILURE = 0xc000006d, 3867 NT_STATUS_ACCOUNT_RESTRICTION = 0xc000006e, 3868 NT_STATUS_INVALID_LOGON_HOURS = 0xc000006f, 3869 NT_STATUS_INVALID_WORKSTATION = 0xc0000070, 3870 NT_STATUS_PASSWORD_EXPIRED = 0xc0000071, 3871 NT_STATUS_ACCOUNT_DISABLED = 0xc0000072, 3872 NT_STATUS_NONE_MAPPED = 0xc0000073, 3873 NT_STATUS_TOO_MANY_LUIDS_REQUESTED = 0xc0000074, 3874 NT_STATUS_LUIDS_EXHAUSTED = 0xc0000075, 3875 NT_STATUS_INVALID_SUB_AUTHORITY = 0xc0000076, 3876 NT_STATUS_INVALID_ACL = 0xc0000077, 3877 NT_STATUS_INVALID_SID = 0xc0000078, 3878 NT_STATUS_INVALID_SECURITY_DESCR = 0xc0000079, 3879 NT_STATUS_PROCEDURE_NOT_FOUND = 0xc000007a, 3880 NT_STATUS_INVALID_IMAGE_FORMAT = 0xc000007b, 3881 NT_STATUS_NO_TOKEN = 0xc000007c, 3882 NT_STATUS_BAD_INHERITANCE_ACL = 0xc000007d, 3883 NT_STATUS_RANGE_NOT_LOCKED = 0xc000007e, 3884 NT_STATUS_DISK_FULL = 0xc000007f, 3885 NT_STATUS_SERVER_DISABLED = 0xc0000080, 3886 NT_STATUS_SERVER_NOT_DISABLED = 0xc0000081, 3887 NT_STATUS_TOO_MANY_GUIDS_REQUESTED = 0xc0000082, 3888 NT_STATUS_GUIDS_EXHAUSTED = 0xc0000083, 3889 NT_STATUS_INVALID_ID_AUTHORITY = 0xc0000084, 3890 NT_STATUS_AGENTS_EXHAUSTED = 0xc0000085, 3891 NT_STATUS_INVALID_VOLUME_LABEL = 0xc0000086, 3892 NT_STATUS_SECTION_NOT_EXTENDED = 0xc0000087, 3893 NT_STATUS_NOT_MAPPED_DATA = 0xc0000088, 3894 NT_STATUS_RESOURCE_DATA_NOT_FOUND = 0xc0000089, 3895 NT_STATUS_RESOURCE_TYPE_NOT_FOUND = 0xc000008a, 3896 NT_STATUS_RESOURCE_NAME_NOT_FOUND = 0xc000008b, 3897 NT_STATUS_ARRAY_BOUNDS_EXCEEDED = 0xc000008c, 3898 NT_STATUS_FLOAT_DENORMAL_OPERAND = 0xc000008d, 3899 NT_STATUS_FLOAT_DIVIDE_BY_ZERO = 0xc000008e, 3900 NT_STATUS_FLOAT_INEXACT_RESULT = 0xc000008f, 3901 NT_STATUS_FLOAT_INVALID_OPERATION = 0xc0000090, 3902 NT_STATUS_FLOAT_OVERFLOW = 0xc0000091, 3903 NT_STATUS_FLOAT_STACK_CHECK = 0xc0000092, 3904 NT_STATUS_FLOAT_UNDERFLOW = 0xc0000093, 3905 NT_STATUS_INTEGER_DIVIDE_BY_ZERO = 0xc0000094, 3906 NT_STATUS_INTEGER_OVERFLOW = 0xc0000095, 3907 NT_STATUS_PRIVILEGED_INSTRUCTION = 0xc0000096, 3908 NT_STATUS_TOO_MANY_PAGING_FILES = 0xc0000097, 3909 NT_STATUS_FILE_INVALID = 0xc0000098, 3910 NT_STATUS_ALLOTTED_SPACE_EXCEEDED = 0xc0000099, 3911 NT_STATUS_INSUFFICIENT_RESOURCES = 0xc000009a, 3912 NT_STATUS_DFS_EXIT_PATH_FOUND = 0xc000009b, 3913 NT_STATUS_DEVICE_DATA_ERROR = 0xc000009c, 3914 NT_STATUS_DEVICE_NOT_CONNECTED = 0xc000009d, 3915 NT_STATUS_DEVICE_POWER_FAILURE = 0xc000009e, 3916 NT_STATUS_FREE_VM_NOT_AT_BASE = 0xc000009f, 3917 NT_STATUS_MEMORY_NOT_ALLOCATED = 0xc00000a0, 3918 NT_STATUS_WORKING_SET_QUOTA = 0xc00000a1, 3919 NT_STATUS_MEDIA_WRITE_PROTECTED = 0xc00000a2, 3920 NT_STATUS_DEVICE_NOT_READY = 0xc00000a3, 3921 NT_STATUS_INVALID_GROUP_ATTRIBUTES = 0xc00000a4, 3922 NT_STATUS_BAD_IMPERSONATION_LEVEL = 0xc00000a5, 3923 NT_STATUS_CANT_OPEN_ANONYMOUS = 0xc00000a6, 3924 NT_STATUS_BAD_VALIDATION_CLASS = 0xc00000a7, 3925 NT_STATUS_BAD_TOKEN_TYPE = 0xc00000a8, 3926 NT_STATUS_BAD_MASTER_BOOT_RECORD = 0xc00000a9, 3927 NT_STATUS_INSTRUCTION_MISALIGNMENT = 0xc00000aa, 3928 NT_STATUS_INSTANCE_NOT_AVAILABLE = 0xc00000ab, 3929 NT_STATUS_PIPE_NOT_AVAILABLE = 0xc00000ac, 3930 NT_STATUS_INVALID_PIPE_STATE = 0xc00000ad, 3931 NT_STATUS_PIPE_BUSY = 0xc00000ae, 3932 NT_STATUS_ILLEGAL_FUNCTION = 0xc00000af, 3933 NT_STATUS_PIPE_DISCONNECTED = 0xc00000b0, 3934 NT_STATUS_PIPE_CLOSING = 0xc00000b1, 3935 NT_STATUS_PIPE_CONNECTED = 0xc00000b2, 3936 NT_STATUS_PIPE_LISTENING = 0xc00000b3, 3937 NT_STATUS_INVALID_READ_MODE = 0xc00000b4, 3938 NT_STATUS_IO_TIMEOUT = 0xc00000b5, 3939 NT_STATUS_FILE_FORCED_CLOSED = 0xc00000b6, 3940 NT_STATUS_PROFILING_NOT_STARTED = 0xc00000b7, 3941 NT_STATUS_PROFILING_NOT_STOPPED = 0xc00000b8, 3942 NT_STATUS_COULD_NOT_INTERPRET = 0xc00000b9, 3943 NT_STATUS_FILE_IS_A_DIRECTORY = 0xc00000ba, 3944 NT_STATUS_NOT_SUPPORTED = 0xc00000bb, 3945 NT_STATUS_REMOTE_NOT_LISTENING = 0xc00000bc, 3946 NT_STATUS_DUPLICATE_NAME = 0xc00000bd, 3947 NT_STATUS_BAD_NETWORK_PATH = 0xc00000be, 3948 NT_STATUS_NETWORK_BUSY = 0xc00000bf, 3949 NT_STATUS_DEVICE_DOES_NOT_EXIST = 0xc00000c0, 3950 NT_STATUS_TOO_MANY_COMMANDS = 0xc00000c1, 3951 NT_STATUS_ADAPTER_HARDWARE_ERROR = 0xc00000c2, 3952 NT_STATUS_INVALID_NETWORK_RESPONSE = 0xc00000c3, 3953 NT_STATUS_UNEXPECTED_NETWORK_ERROR = 0xc00000c4, 3954 NT_STATUS_BAD_REMOTE_ADAPTER = 0xc00000c5, 3955 NT_STATUS_PRINT_QUEUE_FULL = 0xc00000c6, 3956 NT_STATUS_NO_SPOOL_SPACE = 0xc00000c7, 3957 NT_STATUS_PRINT_CANCELLED = 0xc00000c8, 3958 NT_STATUS_NETWORK_NAME_DELETED = 0xc00000c9, 3959 NT_STATUS_NETWORK_ACCESS_DENIED = 0xc00000ca, 3960 NT_STATUS_BAD_DEVICE_TYPE = 0xc00000cb, 3961 NT_STATUS_BAD_NETWORK_NAME = 0xc00000cc, 3962 NT_STATUS_TOO_MANY_NAMES = 0xc00000cd, 3963 NT_STATUS_TOO_MANY_SESSIONS = 0xc00000ce, 3964 NT_STATUS_SHARING_PAUSED = 0xc00000cf, 3965 NT_STATUS_REQUEST_NOT_ACCEPTED = 0xc00000d0, 3966 NT_STATUS_REDIRECTOR_PAUSED = 0xc00000d1, 3967 NT_STATUS_NET_WRITE_FAULT = 0xc00000d2, 3968 NT_STATUS_PROFILING_AT_LIMIT = 0xc00000d3, 3969 NT_STATUS_NOT_SAME_DEVICE = 0xc00000d4, 3970 NT_STATUS_FILE_RENAMED = 0xc00000d5, 3971 NT_STATUS_VIRTUAL_CIRCUIT_CLOSED = 0xc00000d6, 3972 NT_STATUS_NO_SECURITY_ON_OBJECT = 0xc00000d7, 3973 NT_STATUS_CANT_WAIT = 0xc00000d8, 3974 NT_STATUS_PIPE_EMPTY = 0xc00000d9, 3975 NT_STATUS_CANT_ACCESS_DOMAIN_INFO = 0xc00000da, 3976 NT_STATUS_CANT_TERMINATE_SELF = 0xc00000db, 3977 NT_STATUS_INVALID_SERVER_STATE = 0xc00000dc, 3978 NT_STATUS_INVALID_DOMAIN_STATE = 0xc00000dd, 3979 NT_STATUS_INVALID_DOMAIN_ROLE = 0xc00000de, 3980 NT_STATUS_NO_SUCH_DOMAIN = 0xc00000df, 3981 NT_STATUS_DOMAIN_EXISTS = 0xc00000e0, 3982 NT_STATUS_DOMAIN_LIMIT_EXCEEDED = 0xc00000e1, 3983 NT_STATUS_OPLOCK_NOT_GRANTED = 0xc00000e2, 3984 NT_STATUS_INVALID_OPLOCK_PROTOCOL = 0xc00000e3, 3985 NT_STATUS_INTERNAL_DB_CORRUPTION = 0xc00000e4, 3986 NT_STATUS_INTERNAL_ERROR = 0xc00000e5, 3987 NT_STATUS_GENERIC_NOT_MAPPED = 0xc00000e6, 3988 NT_STATUS_BAD_DESCRIPTOR_FORMAT = 0xc00000e7, 3989 NT_STATUS_INVALID_USER_BUFFER = 0xc00000e8, 3990 NT_STATUS_UNEXPECTED_IO_ERROR = 0xc00000e9, 3991 NT_STATUS_UNEXPECTED_MM_CREATE_ERR = 0xc00000ea, 3992 NT_STATUS_UNEXPECTED_MM_MAP_ERROR = 0xc00000eb, 3993 NT_STATUS_UNEXPECTED_MM_EXTEND_ERR = 0xc00000ec, 3994 NT_STATUS_NOT_LOGON_PROCESS = 0xc00000ed, 3995 NT_STATUS_LOGON_SESSION_EXISTS = 0xc00000ee, 3996 NT_STATUS_INVALID_PARAMETER_1 = 0xc00000ef, 3997 NT_STATUS_INVALID_PARAMETER_2 = 0xc00000f0, 3998 NT_STATUS_INVALID_PARAMETER_3 = 0xc00000f1, 3999 NT_STATUS_INVALID_PARAMETER_4 = 0xc00000f2, 4000 NT_STATUS_INVALID_PARAMETER_5 = 0xc00000f3, 4001 NT_STATUS_INVALID_PARAMETER_6 = 0xc00000f4, 4002 NT_STATUS_INVALID_PARAMETER_7 = 0xc00000f5, 4003 NT_STATUS_INVALID_PARAMETER_8 = 0xc00000f6, 4004 NT_STATUS_INVALID_PARAMETER_9 = 0xc00000f7, 4005 NT_STATUS_INVALID_PARAMETER_10 = 0xc00000f8, 4006 NT_STATUS_INVALID_PARAMETER_11 = 0xc00000f9, 4007 NT_STATUS_INVALID_PARAMETER_12 = 0xc00000fa, 4008 NT_STATUS_REDIRECTOR_NOT_STARTED = 0xc00000fb, 4009 NT_STATUS_REDIRECTOR_STARTED = 0xc00000fc, 4010 NT_STATUS_STACK_OVERFLOW = 0xc00000fd, 4011 NT_STATUS_NO_SUCH_PACKAGE = 0xc00000fe, 4012 NT_STATUS_BAD_FUNCTION_TABLE = 0xc00000ff, 4013 NT_STATUS_DIRECTORY_NOT_EMPTY = 0xc0000101, 4014 NT_STATUS_FILE_CORRUPT_ERROR = 0xc0000102, 4015 NT_STATUS_NOT_A_DIRECTORY = 0xc0000103, 4016 NT_STATUS_BAD_LOGON_SESSION_STATE = 0xc0000104, 4017 NT_STATUS_LOGON_SESSION_COLLISION = 0xc0000105, 4018 NT_STATUS_NAME_TOO_LONG = 0xc0000106, 4019 NT_STATUS_FILES_OPEN = 0xc0000107, 4020 NT_STATUS_CONNECTION_IN_USE = 0xc0000108, 4021 NT_STATUS_MESSAGE_NOT_FOUND = 0xc0000109, 4022 NT_STATUS_PROCESS_IS_TERMINATING = 0xc000010a, 4023 NT_STATUS_INVALID_LOGON_TYPE = 0xc000010b, 4024 NT_STATUS_NO_GUID_TRANSLATION = 0xc000010c, 4025 NT_STATUS_CANNOT_IMPERSONATE = 0xc000010d, 4026 NT_STATUS_IMAGE_ALREADY_LOADED = 0xc000010e, 4027 NT_STATUS_ABIOS_NOT_PRESENT = 0xc000010f, 4028 NT_STATUS_ABIOS_LID_NOT_EXIST = 0xc0000110, 4029 NT_STATUS_ABIOS_LID_ALREADY_OWNED = 0xc0000111, 4030 NT_STATUS_ABIOS_NOT_LID_OWNER = 0xc0000112, 4031 NT_STATUS_ABIOS_INVALID_COMMAND = 0xc0000113, 4032 NT_STATUS_ABIOS_INVALID_LID = 0xc0000114, 4033 NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE = 0xc0000115, 4034 NT_STATUS_ABIOS_INVALID_SELECTOR = 0xc0000116, 4035 NT_STATUS_NO_LDT = 0xc0000117, 4036 NT_STATUS_INVALID_LDT_SIZE = 0xc0000118, 4037 NT_STATUS_INVALID_LDT_OFFSET = 0xc0000119, 4038 NT_STATUS_INVALID_LDT_DESCRIPTOR = 0xc000011a, 4039 NT_STATUS_INVALID_IMAGE_NE_FORMAT = 0xc000011b, 4040 NT_STATUS_RXACT_INVALID_STATE = 0xc000011c, 4041 NT_STATUS_RXACT_COMMIT_FAILURE = 0xc000011d, 4042 NT_STATUS_MAPPED_FILE_SIZE_ZERO = 0xc000011e, 4043 NT_STATUS_TOO_MANY_OPENED_FILES = 0xc000011f, 4044 NT_STATUS_CANCELLED = 0xc0000120, 4045 NT_STATUS_CANNOT_DELETE = 0xc0000121, 4046 NT_STATUS_INVALID_COMPUTER_NAME = 0xc0000122, 4047 NT_STATUS_FILE_DELETED = 0xc0000123, 4048 NT_STATUS_SPECIAL_ACCOUNT = 0xc0000124, 4049 NT_STATUS_SPECIAL_GROUP = 0xc0000125, 4050 NT_STATUS_SPECIAL_USER = 0xc0000126, 4051 NT_STATUS_MEMBERS_PRIMARY_GROUP = 0xc0000127, 4052 NT_STATUS_FILE_CLOSED = 0xc0000128, 4053 NT_STATUS_TOO_MANY_THREADS = 0xc0000129, 4054 NT_STATUS_THREAD_NOT_IN_PROCESS = 0xc000012a, 4055 NT_STATUS_TOKEN_ALREADY_IN_USE = 0xc000012b, 4056 NT_STATUS_PAGEFILE_QUOTA_EXCEEDED = 0xc000012c, 4057 NT_STATUS_COMMITMENT_LIMIT = 0xc000012d, 4058 NT_STATUS_INVALID_IMAGE_LE_FORMAT = 0xc000012e, 4059 NT_STATUS_INVALID_IMAGE_NOT_MZ = 0xc000012f, 4060 NT_STATUS_INVALID_IMAGE_PROTECT = 0xc0000130, 4061 NT_STATUS_INVALID_IMAGE_WIN_16 = 0xc0000131, 4062 NT_STATUS_LOGON_SERVER_CONFLICT = 0xc0000132, 4063 NT_STATUS_TIME_DIFFERENCE_AT_DC = 0xc0000133, 4064 NT_STATUS_SYNCHRONIZATION_REQUIRED = 0xc0000134, 4065 NT_STATUS_DLL_NOT_FOUND = 0xc0000135, 4066 NT_STATUS_OPEN_FAILED = 0xc0000136, 4067 NT_STATUS_IO_PRIVILEGE_FAILED = 0xc0000137, 4068 NT_STATUS_ORDINAL_NOT_FOUND = 0xc0000138, 4069 NT_STATUS_ENTRYPOINT_NOT_FOUND = 0xc0000139, 4070 NT_STATUS_CONTROL_C_EXIT = 0xc000013a, 4071 NT_STATUS_LOCAL_DISCONNECT = 0xc000013b, 4072 NT_STATUS_REMOTE_DISCONNECT = 0xc000013c, 4073 NT_STATUS_REMOTE_RESOURCES = 0xc000013d, 4074 NT_STATUS_LINK_FAILED = 0xc000013e, 4075 NT_STATUS_LINK_TIMEOUT = 0xc000013f, 4076 NT_STATUS_INVALID_CONNECTION = 0xc0000140, 4077 NT_STATUS_INVALID_ADDRESS = 0xc0000141, 4078 NT_STATUS_DLL_INIT_FAILED = 0xc0000142, 4079 NT_STATUS_MISSING_SYSTEMFILE = 0xc0000143, 4080 NT_STATUS_UNHANDLED_EXCEPTION = 0xc0000144, 4081 NT_STATUS_APP_INIT_FAILURE = 0xc0000145, 4082 NT_STATUS_PAGEFILE_CREATE_FAILED = 0xc0000146, 4083 NT_STATUS_NO_PAGEFILE = 0xc0000147, 4084 NT_STATUS_INVALID_LEVEL = 0xc0000148, 4085 NT_STATUS_WRONG_PASSWORD_CORE = 0xc0000149, 4086 NT_STATUS_ILLEGAL_FLOAT_CONTEXT = 0xc000014a, 4087 NT_STATUS_PIPE_BROKEN = 0xc000014b, 4088 NT_STATUS_REGISTRY_CORRUPT = 0xc000014c, 4089 NT_STATUS_REGISTRY_IO_FAILED = 0xc000014d, 4090 NT_STATUS_NO_EVENT_PAIR = 0xc000014e, 4091 NT_STATUS_UNRECOGNIZED_VOLUME = 0xc000014f, 4092 NT_STATUS_SERIAL_NO_DEVICE_INITED = 0xc0000150, 4093 NT_STATUS_NO_SUCH_ALIAS = 0xc0000151, 4094 NT_STATUS_MEMBER_NOT_IN_ALIAS = 0xc0000152, 4095 NT_STATUS_MEMBER_IN_ALIAS = 0xc0000153, 4096 NT_STATUS_ALIAS_EXISTS = 0xc0000154, 4097 NT_STATUS_LOGON_NOT_GRANTED = 0xc0000155, 4098 NT_STATUS_TOO_MANY_SECRETS = 0xc0000156, 4099 NT_STATUS_SECRET_TOO_LONG = 0xc0000157, 4100 NT_STATUS_INTERNAL_DB_ERROR = 0xc0000158, 4101 NT_STATUS_FULLSCREEN_MODE = 0xc0000159, 4102 NT_STATUS_TOO_MANY_CONTEXT_IDS = 0xc000015a, 4103 NT_STATUS_LOGON_TYPE_NOT_GRANTED = 0xc000015b, 4104 NT_STATUS_NOT_REGISTRY_FILE = 0xc000015c, 4105 NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED = 0xc000015d, 4106 NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR = 0xc000015e, 4107 NT_STATUS_FT_MISSING_MEMBER = 0xc000015f, 4108 NT_STATUS_ILL_FORMED_SERVICE_ENTRY = 0xc0000160, 4109 NT_STATUS_ILLEGAL_CHARACTER = 0xc0000161, 4110 NT_STATUS_UNMAPPABLE_CHARACTER = 0xc0000162, 4111 NT_STATUS_UNDEFINED_CHARACTER = 0xc0000163, 4112 NT_STATUS_FLOPPY_VOLUME = 0xc0000164, 4113 NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND = 0xc0000165, 4114 NT_STATUS_FLOPPY_WRONG_CYLINDER = 0xc0000166, 4115 NT_STATUS_FLOPPY_UNKNOWN_ERROR = 0xc0000167, 4116 NT_STATUS_FLOPPY_BAD_REGISTERS = 0xc0000168, 4117 NT_STATUS_DISK_RECALIBRATE_FAILED = 0xc0000169, 4118 NT_STATUS_DISK_OPERATION_FAILED = 0xc000016a, 4119 NT_STATUS_DISK_RESET_FAILED = 0xc000016b, 4120 NT_STATUS_SHARED_IRQ_BUSY = 0xc000016c, 4121 NT_STATUS_FT_ORPHANING = 0xc000016d, 4122 NT_STATUS_PARTITION_FAILURE = 0xc0000172, 4123 NT_STATUS_INVALID_BLOCK_LENGTH = 0xc0000173, 4124 NT_STATUS_DEVICE_NOT_PARTITIONED = 0xc0000174, 4125 NT_STATUS_UNABLE_TO_LOCK_MEDIA = 0xc0000175, 4126 NT_STATUS_UNABLE_TO_UNLOAD_MEDIA = 0xc0000176, 4127 NT_STATUS_EOM_OVERFLOW = 0xc0000177, 4128 NT_STATUS_NO_MEDIA = 0xc0000178, 4129 NT_STATUS_NO_SUCH_MEMBER = 0xc000017a, 4130 NT_STATUS_INVALID_MEMBER = 0xc000017b, 4131 NT_STATUS_KEY_DELETED = 0xc000017c, 4132 NT_STATUS_NO_LOG_SPACE = 0xc000017d, 4133 NT_STATUS_TOO_MANY_SIDS = 0xc000017e, 4134 NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED = 0xc000017f, 4135 NT_STATUS_KEY_HAS_CHILDREN = 0xc0000180, 4136 NT_STATUS_CHILD_MUST_BE_VOLATILE = 0xc0000181, 4137 NT_STATUS_DEVICE_CONFIGURATION_ERROR = 0xc0000182, 4138 NT_STATUS_DRIVER_INTERNAL_ERROR = 0xc0000183, 4139 NT_STATUS_INVALID_DEVICE_STATE = 0xc0000184, 4140 NT_STATUS_IO_DEVICE_ERROR = 0xc0000185, 4141 NT_STATUS_DEVICE_PROTOCOL_ERROR = 0xc0000186, 4142 NT_STATUS_BACKUP_CONTROLLER = 0xc0000187, 4143 NT_STATUS_LOG_FILE_FULL = 0xc0000188, 4144 NT_STATUS_TOO_LATE = 0xc0000189, 4145 NT_STATUS_NO_TRUST_LSA_SECRET = 0xc000018a, 4146 NT_STATUS_NO_TRUST_SAM_ACCOUNT = 0xc000018b, 4147 NT_STATUS_TRUSTED_DOMAIN_FAILURE = 0xc000018c, 4148 NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE = 0xc000018d, 4149 NT_STATUS_EVENTLOG_FILE_CORRUPT = 0xc000018e, 4150 NT_STATUS_EVENTLOG_CANT_START = 0xc000018f, 4151 NT_STATUS_TRUST_FAILURE = 0xc0000190, 4152 NT_STATUS_MUTANT_LIMIT_EXCEEDED = 0xc0000191, 4153 NT_STATUS_NETLOGON_NOT_STARTED = 0xc0000192, 4154 NT_STATUS_ACCOUNT_EXPIRED = 0xc0000193, 4155 NT_STATUS_POSSIBLE_DEADLOCK = 0xc0000194, 4156 NT_STATUS_NETWORK_CREDENTIAL_CONFLICT = 0xc0000195, 4157 NT_STATUS_REMOTE_SESSION_LIMIT = 0xc0000196, 4158 NT_STATUS_EVENTLOG_FILE_CHANGED = 0xc0000197, 4159 NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 0xc0000198, 4160 NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 0xc0000199, 4161 NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT = 0xc000019a, 4162 NT_STATUS_DOMAIN_TRUST_INCONSISTENT = 0xc000019b, 4163 NT_STATUS_FS_DRIVER_REQUIRED = 0xc000019c, 4164 NT_STATUS_NO_USER_SESSION_KEY = 0xc0000202, 4165 NT_STATUS_USER_SESSION_DELETED = 0xc0000203, 4166 NT_STATUS_RESOURCE_LANG_NOT_FOUND = 0xc0000204, 4167 NT_STATUS_INSUFF_SERVER_RESOURCES = 0xc0000205, 4168 NT_STATUS_INVALID_BUFFER_SIZE = 0xc0000206, 4169 NT_STATUS_INVALID_ADDRESS_COMPONENT = 0xc0000207, 4170 NT_STATUS_INVALID_ADDRESS_WILDCARD = 0xc0000208, 4171 NT_STATUS_TOO_MANY_ADDRESSES = 0xc0000209, 4172 NT_STATUS_ADDRESS_ALREADY_EXISTS = 0xc000020a, 4173 NT_STATUS_ADDRESS_CLOSED = 0xc000020b, 4174 NT_STATUS_CONNECTION_DISCONNECTED = 0xc000020c, 4175 NT_STATUS_CONNECTION_RESET = 0xc000020d, 4176 NT_STATUS_TOO_MANY_NODES = 0xc000020e, 4177 NT_STATUS_TRANSACTION_ABORTED = 0xc000020f, 4178 NT_STATUS_TRANSACTION_TIMED_OUT = 0xc0000210, 4179 NT_STATUS_TRANSACTION_NO_RELEASE = 0xc0000211, 4180 NT_STATUS_TRANSACTION_NO_MATCH = 0xc0000212, 4181 NT_STATUS_TRANSACTION_RESPONDED = 0xc0000213, 4182 NT_STATUS_TRANSACTION_INVALID_ID = 0xc0000214, 4183 NT_STATUS_TRANSACTION_INVALID_TYPE = 0xc0000215, 4184 NT_STATUS_NOT_SERVER_SESSION = 0xc0000216, 4185 NT_STATUS_NOT_CLIENT_SESSION = 0xc0000217, 4186 NT_STATUS_CANNOT_LOAD_REGISTRY_FILE = 0xc0000218, 4187 NT_STATUS_DEBUG_ATTACH_FAILED = 0xc0000219, 4188 NT_STATUS_SYSTEM_PROCESS_TERMINATED = 0xc000021a, 4189 NT_STATUS_DATA_NOT_ACCEPTED = 0xc000021b, 4190 NT_STATUS_NO_BROWSER_SERVERS_FOUND = 0xc000021c, 4191 NT_STATUS_VDM_HARD_ERROR = 0xc000021d, 4192 NT_STATUS_DRIVER_CANCEL_TIMEOUT = 0xc000021e, 4193 NT_STATUS_REPLY_MESSAGE_MISMATCH = 0xc000021f, 4194 NT_STATUS_MAPPED_ALIGNMENT = 0xc0000220, 4195 NT_STATUS_IMAGE_CHECKSUM_MISMATCH = 0xc0000221, 4196 NT_STATUS_LOST_WRITEBEHIND_DATA = 0xc0000222, 4197 NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID = 0xc0000223, 4198 NT_STATUS_PASSWORD_MUST_CHANGE = 0xc0000224, 4199 NT_STATUS_NOT_FOUND = 0xc0000225, 4200 NT_STATUS_NOT_TINY_STREAM = 0xc0000226, 4201 NT_STATUS_RECOVERY_FAILURE = 0xc0000227, 4202 NT_STATUS_STACK_OVERFLOW_READ = 0xc0000228, 4203 NT_STATUS_FAIL_CHECK = 0xc0000229, 4204 NT_STATUS_DUPLICATE_OBJECTID = 0xc000022a, 4205 NT_STATUS_OBJECTID_EXISTS = 0xc000022b, 4206 NT_STATUS_CONVERT_TO_LARGE = 0xc000022c, 4207 NT_STATUS_RETRY = 0xc000022d, 4208 NT_STATUS_FOUND_OUT_OF_SCOPE = 0xc000022e, 4209 NT_STATUS_ALLOCATE_BUCKET = 0xc000022f, 4210 NT_STATUS_PROPSET_NOT_FOUND = 0xc0000230, 4211 NT_STATUS_MARSHALL_OVERFLOW = 0xc0000231, 4212 NT_STATUS_INVALID_VARIANT = 0xc0000232, 4213 NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND = 0xc0000233, 4214 NT_STATUS_ACCOUNT_LOCKED_OUT = 0xc0000234, 4215 NT_STATUS_HANDLE_NOT_CLOSABLE = 0xc0000235, 4216 NT_STATUS_CONNECTION_REFUSED = 0xc0000236, 4217 NT_STATUS_GRACEFUL_DISCONNECT = 0xc0000237, 4218 NT_STATUS_ADDRESS_ALREADY_ASSOCIATED = 0xc0000238, 4219 NT_STATUS_ADDRESS_NOT_ASSOCIATED = 0xc0000239, 4220 NT_STATUS_CONNECTION_INVALID = 0xc000023a, 4221 NT_STATUS_CONNECTION_ACTIVE = 0xc000023b, 4222 NT_STATUS_NETWORK_UNREACHABLE = 0xc000023c, 4223 NT_STATUS_HOST_UNREACHABLE = 0xc000023d, 4224 NT_STATUS_PROTOCOL_UNREACHABLE = 0xc000023e, 4225 NT_STATUS_PORT_UNREACHABLE = 0xc000023f, 4226 NT_STATUS_REQUEST_ABORTED = 0xc0000240, 4227 NT_STATUS_CONNECTION_ABORTED = 0xc0000241, 4228 NT_STATUS_BAD_COMPRESSION_BUFFER = 0xc0000242, 4229 NT_STATUS_USER_MAPPED_FILE = 0xc0000243, 4230 NT_STATUS_AUDIT_FAILED = 0xc0000244, 4231 NT_STATUS_TIMER_RESOLUTION_NOT_SET = 0xc0000245, 4232 NT_STATUS_CONNECTION_COUNT_LIMIT = 0xc0000246, 4233 NT_STATUS_LOGIN_TIME_RESTRICTION = 0xc0000247, 4234 NT_STATUS_LOGIN_WKSTA_RESTRICTION = 0xc0000248, 4235 NT_STATUS_IMAGE_MP_UP_MISMATCH = 0xc0000249, 4236 NT_STATUS_INSUFFICIENT_LOGON_INFO = 0xc0000250, 4237 NT_STATUS_BAD_DLL_ENTRYPOINT = 0xc0000251, 4238 NT_STATUS_BAD_SERVICE_ENTRYPOINT = 0xc0000252, 4239 NT_STATUS_LPC_REPLY_LOST = 0xc0000253, 4240 NT_STATUS_IP_ADDRESS_CONFLICT1 = 0xc0000254, 4241 NT_STATUS_IP_ADDRESS_CONFLICT2 = 0xc0000255, 4242 NT_STATUS_REGISTRY_QUOTA_LIMIT = 0xc0000256, 4243 NT_STATUS_PATH_NOT_COVERED = 0xc0000257, 4244 NT_STATUS_NO_CALLBACK_ACTIVE = 0xc0000258, 4245 NT_STATUS_LICENSE_QUOTA_EXCEEDED = 0xc0000259, 4246 NT_STATUS_PWD_TOO_SHORT = 0xc000025a, 4247 NT_STATUS_PWD_TOO_RECENT = 0xc000025b, 4248 NT_STATUS_PWD_HISTORY_CONFLICT = 0xc000025c, 4249 NT_STATUS_PLUGPLAY_NO_DEVICE = 0xc000025e, 4250 NT_STATUS_UNSUPPORTED_COMPRESSION = 0xc000025f, 4251 NT_STATUS_INVALID_HW_PROFILE = 0xc0000260, 4252 NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH = 0xc0000261, 4253 NT_STATUS_DRIVER_ORDINAL_NOT_FOUND = 0xc0000262, 4254 NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND = 0xc0000263, 4255 NT_STATUS_RESOURCE_NOT_OWNED = 0xc0000264, 4256 NT_STATUS_TOO_MANY_LINKS = 0xc0000265, 4257 NT_STATUS_QUOTA_LIST_INCONSISTENT = 0xc0000266, 4258 NT_STATUS_FILE_IS_OFFLINE = 0xc0000267, 4259 NT_STATUS_DS_NO_MORE_RIDS = 0xc00002a8, 4260 NT_STATUS_NOT_A_REPARSE_POINT = 0xc0000275, 4261 NT_STATUS_NO_SUCH_JOB = 0xc0000EDE 4262} 4263 4264for i, v in pairs(status_codes) do 4265 status_names[v] = i 4266end 4267 4268 4269local NP_LIBRARY_NAME = "PIPE" 4270 4271namedpipes = 4272{ 4273 get_pipe_subpath = function( pipeName, writeToDebugLog ) 4274 local status, pipeSubPath 4275 if not pipeName then return false end 4276 4277 local _, _, match = pipeName:match( "^(\\+)(.-)\\pipe(\\.-)$" ) 4278 if match then 4279 pipeSubPath = match 4280 status = true 4281 if writeToDebugLog then 4282 stdnse.debug2("%s: Converting %s to subpath %s", NP_LIBRARY_NAME, pipeName, match ) 4283 end 4284 else 4285 status = false 4286 pipeSubPath = pipeName 4287 end 4288 4289 return status, pipeSubPath 4290 end, 4291 4292 4293 make_pipe_name = function( hostnameOrIp, pipeSubPath ) 4294 if pipeSubPath:sub(1,1) ~= "\\" then 4295 pipeSubPath = "\\" .. pipeSubPath 4296 end 4297 4298 return string.format( "\\\\%s\\pipe%s", hostnameOrIp, pipeSubPath ) 4299 end, 4300 4301 4302 named_pipe = { 4303 4304 _smbstate = nil, 4305 _host = nil, 4306 _pipeSubPath = nil, 4307 _overrides = nil, 4308 name = nil, 4309 4310 new = function(self,o) 4311 o = o or {} 4312 setmetatable(o, self) 4313 self.__index = self 4314 return o 4315 end, 4316 4317 4318 connect = function( self, host, pipeSubPath, overrides ) 4319 4320 stdnse.debug2("%s: connect() called with %s", NP_LIBRARY_NAME, tostring( pipeSubPath ) ) 4321 self._overrides = overrides or {} 4322 self._host = host 4323 self._pipeSubPath = pipeSubPath 4324 if not host and not host.ip then return false, "host table is required" end 4325 if not pipeSubPath then return false, "pipeSubPath is required" end 4326 4327 -- If we got a full pipe name, not a sub-path, fix it 4328 if ( pipeSubPath:match( "^\\\\(.-)$" ) ) then 4329 local status 4330 status, self._pipeSubPath = namedpipes.get_pipe_subpath( self._pipeSubPath, true ) 4331 if ( not status ) then 4332 stdnse.debug1("%s: Attempt to connect to invalid pipe name: %s", NP_LIBRARY_NAME, tostring( pipeSubPath ) ) 4333 return false, "Invalid pipe name" 4334 end 4335 end 4336 self.name = namedpipes.make_pipe_name( self._host.ip, self._pipeSubPath ) 4337 4338 stdnse.debug2("%s: Connecting to named pipe: %s", NP_LIBRARY_NAME, self.name ) 4339 local errorMessage 4340 local bool_negotiate_protocol, bool_start_session, bool_disable_extended = true, true, false 4341 local _, fqpn_share = get_fqpn(host, "IPC$") 4342 local status, result = start_ex( self._host, bool_negotiate_protocol, bool_start_session, 4343 fqpn_share, self._pipeSubPath, bool_disable_extended, self._overrides ) 4344 4345 if status then 4346 self._smbstate = result 4347 else 4348 errorMessage = string.format( "Connection failed: %s", result ) 4349 stdnse.debug2("%s: Connection to named pipe (%s) failed: %s", 4350 NP_LIBRARY_NAME, self.name, errorMessage ) 4351 end 4352 4353 return status, errorMessage, result 4354 end, 4355 4356 4357 disconnect = function( self ) 4358 if ( self._smbstate ) then 4359 stdnse.debug2("%s: Disconnecting named pipe: %s", NP_LIBRARY_NAME, self.name ) 4360 return stop( self._smbstate ) 4361 else 4362 stdnse.debug2("%s: disconnect() called, but SMB connection is already closed: %s", NP_LIBRARY_NAME, self.name ) 4363 end 4364 end, 4365 4366 4367 send = function( self, messageData ) 4368 if not self._smbstate then 4369 stdnse.debug2("%s: send() called on closed pipe (%s)", NP_LIBRARY_NAME, self.name ) 4370 return false, "Failed to send message on named pipe" 4371 end 4372 4373 local offset = 0 -- offset is actually ignored for named pipes, but we'll define the argument for clarity 4374 local status, result, errorMessage 4375 4376 status, result = write_file( self._smbstate, messageData, offset, self._overrides ) 4377 4378 -- if status is true, result is data that we don't need to pay attention to 4379 if not status then 4380 stdnse.debug2("%s: Write to named pipe (%s) failed: %s", 4381 NP_LIBRARY_NAME, self.name, result ) 4382 errorMessage = "Failed to send message on named pipe", result 4383 end 4384 4385 return status, errorMessage 4386 end, 4387 4388 4389 receive = function( self ) 4390 if not self._smbstate then 4391 stdnse.debug2("%s: receive() called on closed pipe (%s)", NP_LIBRARY_NAME, self.name ) 4392 return false, "Failed to read from named pipe" 4393 end 4394 4395 local status, result, messageData 4396 -- Packet header values 4397 local offset = 0 -- offset is actually ignored for named pipes, but we'll define the argument for clarity 4398 local MAX_BYTES_PER_READ = 4096 4399 4400 status, result = read_file( self._smbstate, offset, MAX_BYTES_PER_READ, self._overrides ) 4401 4402 if status and result.data then 4403 messageData = result.data 4404 else 4405 stdnse.debug2("%s: Read from named pipe (%s) failed: %s", 4406 NP_LIBRARY_NAME, self.name, result ) 4407 return false, "Failed to read from named pipe", result 4408 end 4409 4410 while (result["status"] == status_codes.NT_STATUS_BUFFER_OVERFLOW) do 4411 status, result = read_file( self._smbstate, offset, MAX_BYTES_PER_READ, self._overrides ) 4412 4413 if status and result.data then 4414 messageData = messageData .. result.data 4415 else 4416 stdnse.debug2("%s: Read additional data from named pipe (%s) failed: %s", 4417 NP_LIBRARY_NAME, self.name, result ) 4418 return false, "Failed to read from named pipe", result 4419 end 4420 end 4421 4422 return status, messageData 4423 end, 4424 } 4425 4426} 4427 4428filetype_codes = 4429{ 4430 FILE_TYPE_DISK = 0x00, 4431 FILE_TYPE_BYTE_MODE_PIPE = 0x01, 4432 FILE_TYPE_MESSAGE_MODE_PIPE = 0x02, 4433 FILE_TYPE_PRINTER = 0x03, 4434 FILE_TYPE_UNKNOWN = 0xFF 4435} 4436 4437for i, v in pairs(filetype_codes) do 4438 filetype_names[v] = i 4439end 4440 4441return _ENV; 4442