b1a7e77fa9
The should be specified in hex as BAKCTRL is 16, not 10. CTRL should be 8. See documentation for NetServerEnum.
169 lines
4.6 KiB
Ruby
169 lines
4.6 KiB
Ruby
# -*- coding: binary -*-
|
|
module Msf
|
|
class Post
|
|
module Windows
|
|
|
|
module NetAPI
|
|
|
|
MAX_PREFERRED_LENGTH = -1
|
|
SV_TYPE_ALL = 0xFFFFFFFF
|
|
SV_TYPE_DOMAIN_ENUM = 0x80000000
|
|
SV_TYPE_DOMAIN_BAKCTRL = 0x00000010
|
|
SV_TYPE_DOMAIN_CTRL = 0x00000008
|
|
|
|
ERROR_ACCESS_DENIED = 5
|
|
ERROR_NOT_ENOUGH_MEMORY = 8
|
|
ERROR_INVALID_PARAMETER = 87
|
|
ERROR_INVALID_LEVEL = 124
|
|
ERROR_MORE_DATA = 234
|
|
ERROR_NO_BROWSER_SERVERS_FOUND = 6118
|
|
|
|
NERR_ClientNameNotFound = 2312
|
|
NERR_InvalidComputer = 2351
|
|
NERR_UserNotFound = 2221
|
|
|
|
def UnicodeByteStringToAscii(str)
|
|
length = (str.index "\0\0\0") + 1
|
|
Rex::Text.to_ascii(str[0..length])
|
|
end
|
|
|
|
def netapi_buffer_free(ptr)
|
|
# Free the buffer
|
|
ret = client.railgun.netapi32.NetApiBufferFree(ptr)
|
|
vprint_error("Unable to free buffer, Error Code: #{ret['return']}") unless ret['return'] == 0
|
|
end
|
|
|
|
def net_server_enum(server_type=SV_TYPE_ALL, domain=nil)
|
|
hosts = []
|
|
|
|
result = client.railgun.netapi32.NetServerEnum(
|
|
nil, # servername
|
|
100, # level (100/101)
|
|
4, # bufptr
|
|
MAX_PREFERRED_LENGTH, # prefmaxlen
|
|
4, # entries read
|
|
4, # total entries
|
|
server_type, # server_type
|
|
domain, # domain
|
|
nil # resume handle
|
|
)
|
|
|
|
case result['return']
|
|
when 0
|
|
# Railgun assumes PDWORDS are pointers and returns 8 bytes for x64 architectures.
|
|
# Therefore we need to truncate the result value to an actual
|
|
# DWORD for entriesread or totalentries.
|
|
hosts = read_server_structs(result['bufptr'], (result['entriesread'] % 4294967296), domain, server_type)
|
|
when ERROR_NO_BROWSER_SERVERS_FOUND
|
|
print_error("ERROR_NO_BROWSER_SERVERS_FOUND")
|
|
return nil
|
|
when ERROR_MORE_DATA
|
|
vprint_error("ERROR_MORE_DATA")
|
|
return nil
|
|
end
|
|
|
|
netapi_buffer_free(result['bufptr'])
|
|
|
|
return hosts
|
|
end
|
|
|
|
def read_server_structs(start_ptr, count, domain, server_type)
|
|
hosts = []
|
|
return hosts if count <= 0
|
|
|
|
ptr_size = client.railgun.util.pointer_size
|
|
ptr = (ptr_size == 8) ? 'Q<' : 'V'
|
|
|
|
base = 0
|
|
# Struct -> Ptr, Ptr
|
|
struct_size = ptr_size * 2
|
|
|
|
mem = client.railgun.memread(start_ptr, struct_size*count)
|
|
|
|
count.times do
|
|
x = {}
|
|
x[:version]= mem[(base + 0),ptr_size].unpack(ptr).first
|
|
nameptr = mem[(base + ptr_size),ptr_size].unpack(ptr).first
|
|
x[:name] = UnicodeByteStringToAscii(client.railgun.memread(nameptr, 255))
|
|
hosts << x
|
|
base += struct_size
|
|
end
|
|
|
|
hosts
|
|
end
|
|
|
|
def net_session_enum(hostname, username)
|
|
sessions = []
|
|
|
|
result = client.railgun.netapi32.NetSessionEnum(
|
|
hostname, # servername
|
|
nil, # UncClientName
|
|
username, # username
|
|
10, # level
|
|
4, # bufptr
|
|
MAX_PREFERRED_LENGTH, # prefmaxlen
|
|
4, # entriesread
|
|
4, # totalentries
|
|
nil # resume_handle
|
|
)
|
|
|
|
case result['return']
|
|
when 0
|
|
vprint_error("#{hostname} Session identified")
|
|
sessions = read_session_structs(result['bufptr'], (result['entriesread'] % 4294967296), hostname)
|
|
when ERROR_ACCESS_DENIED
|
|
vprint_error("#{hostname} Access denied...")
|
|
return nil
|
|
when 53
|
|
vprint_error("Host not found or did not respond: #{hostname}")
|
|
return nil
|
|
when 123
|
|
vprint_error("Invalid host: #{hostname}")
|
|
return nil
|
|
when NERR_UserNotFound
|
|
return nil
|
|
when ERROR_MORE_DATA
|
|
vprint_error("#{hostname} ERROR_MORE_DATA")
|
|
else
|
|
vprint_error("Unaccounted for error code: #{result['return']}")
|
|
return nil
|
|
end
|
|
|
|
netapi_buffer_free(result['bufptr'])
|
|
|
|
return sessions
|
|
end
|
|
|
|
def read_session_structs(start_ptr, count, hostname)
|
|
sessions = []
|
|
return sessions if count <= 0
|
|
|
|
ptr_size = client.railgun.util.pointer_size
|
|
ptr = (ptr_size == 8) ? 'Q<' : 'V'
|
|
|
|
base = 0
|
|
# Struct -> Ptr, Ptr, Dword Dword
|
|
struct_size = (ptr_size * 2) + 8
|
|
mem = client.railgun.memread(start_ptr, struct_size*count)
|
|
|
|
count.times do
|
|
sess = {}
|
|
cnameptr = mem[(base + 0),ptr_size].unpack(ptr).first
|
|
usernameptr = mem[(base + ptr_size),ptr_size].unpack(ptr).first
|
|
sess[:usetime] = mem[(base + (ptr_size * 2)),4].unpack('V').first
|
|
sess[:idletime] = mem[(base + (ptr_size * 2) + 4),4].unpack('V').first
|
|
sess[:cname] = UnicodeByteStringToAscii(client.railgun.memread(cnameptr,255))
|
|
sess[:username] = UnicodeByteStringToAscii(client.railgun.memread(usernameptr,255))
|
|
sess[:hostname] = hostname
|
|
sessions << sess
|
|
base = base + struct_size
|
|
end
|
|
|
|
sessions
|
|
end
|
|
|
|
end # NetAPI
|
|
end # Windows
|
|
end # Post
|
|
end # Msf
|