108 lines
2.6 KiB
Ruby
108 lines
2.6 KiB
Ruby
require 'rex/text'
|
|
require 'rex/proto/smb/constants'
|
|
|
|
module Rex
|
|
module Proto
|
|
module SMB
|
|
class Utils
|
|
|
|
CONST = Rex::Proto::SMB::Constants
|
|
|
|
# Creates an access mask for use with the CLIENT.open() call based on a string
|
|
def self.open_mode_to_access(str)
|
|
access = CONST::OPEN_ACCESS_READ | CONST::OPEN_SHARE_DENY_NONE
|
|
str.each_byte { |c|
|
|
case [c].pack('C').downcase
|
|
when 'w'
|
|
access |= CONST::OPEN_ACCESS_READWRITE
|
|
end
|
|
}
|
|
return access
|
|
end
|
|
|
|
# Creates a mode mask for use with the CLIENT.open() call based on a string
|
|
def self.open_mode_to_mode(str)
|
|
mode = 0
|
|
|
|
str.each_byte { |c|
|
|
case [c].pack('C').downcase
|
|
when 'x' # Fail if the file already exists
|
|
mode |= CONST::OPEN_MODE_EXCL
|
|
when 't' # Truncate the file if it already exists
|
|
mode |= CONST::OPEN_MODE_TRUNC
|
|
when 'c' # Create the file if it does not exist
|
|
mode |= CONST::OPEN_MODE_CREAT
|
|
when 'o' # Just open the file, clashes with x
|
|
mode |= CONST::OPEN_MODE_OPEN
|
|
end
|
|
}
|
|
|
|
return mode
|
|
end
|
|
|
|
# Returns a disposition value for smb.create based on permission string
|
|
def self.create_mode_to_disposition(str)
|
|
str.each_byte { |c|
|
|
case [c].pack('C').downcase
|
|
when 'c' # Create the file if it does not exist
|
|
return CONST::CREATE_ACCESS_OPENCREATE
|
|
when 'o' # Just open the file and fail if it does not exist
|
|
return CONST::CREATE_ACCESS_EXIST
|
|
end
|
|
}
|
|
|
|
return CONST::CREATE_ACCESS_OPENCREATE
|
|
end
|
|
|
|
# NOTE: the difference below came from: Time.utc("1970-1-1") - Time.utc("1601-1-1")
|
|
|
|
# Convert a 64-bit signed SMB time to a unix timestamp
|
|
def self.time_smb_to_unix(thi, tlo)
|
|
(((thi << 32) + tlo) / 10000000) - 11644473600
|
|
end
|
|
|
|
# Convert a unix timestamp to a 64-bit signed server time
|
|
def self.time_unix_to_smb(unix_time)
|
|
t64 = (unix_time + 11644473600) * 10000000
|
|
thi = (t64 & 0xffffffff00000000) >> 32
|
|
tlo = (t64 & 0x00000000ffffffff)
|
|
return [thi, tlo]
|
|
end
|
|
|
|
# Convert a name to its NetBIOS equivalent
|
|
def self.nbname_encode(str)
|
|
encoded = ''
|
|
for x in (0..15)
|
|
if (x >= str.length)
|
|
encoded << 'CA'
|
|
else
|
|
c = str[x, 1].upcase[0,1].unpack('C*')[0]
|
|
encoded << [ (c / 16) + 0x41, (c % 16) + 0x41 ].pack('CC')
|
|
end
|
|
end
|
|
return encoded
|
|
end
|
|
|
|
# Convert a name from its NetBIOS equivalent
|
|
def self.nbname_decode(str)
|
|
decoded = ''
|
|
str << 'A' if str.length % 2 != 0
|
|
while (str.length > 0)
|
|
two = str.slice!(0, 2).unpack('C*')
|
|
if (two.length == 2)
|
|
decoded << [ ((two[0] - 0x41) * 16) + two[1] - 0x41 ].pack('C')
|
|
end
|
|
end
|
|
return decoded
|
|
end
|
|
|
|
# Determine whether the password is a known hash format
|
|
def self.is_pass_ntlm_hash?(str)
|
|
str.downcase =~ /^[0-9a-f]{32}:[0-9a-f]{32}$/
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|