2013-09-02 20:24:54 +01:00
|
|
|
# -*- coding: binary -*-
|
|
|
|
|
module Msf
|
|
|
|
|
class Post
|
|
|
|
|
module Windows
|
|
|
|
|
|
|
|
|
|
module NetAPI
|
|
|
|
|
|
2013-09-05 14:30:08 -05:00
|
|
|
MAX_PREFERRED_LENGTH = -1
|
|
|
|
|
SV_TYPE_ALL = 0xFFFFFFFF
|
|
|
|
|
SV_TYPE_DOMAIN_ENUM = 0x80000000
|
2015-04-05 11:12:18 +01:00
|
|
|
SV_TYPE_DOMAIN_BAKCTRL = 0x00000010
|
|
|
|
|
SV_TYPE_DOMAIN_CTRL = 0x00000008
|
2013-09-05 14:30:08 -05:00
|
|
|
|
|
|
|
|
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']
|
2014-03-04 08:49:52 +02:00
|
|
|
when 0
|
2014-08-14 23:32:04 +01:00
|
|
|
# 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)
|
2014-03-04 08:49:52 +02:00
|
|
|
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
|
2013-09-05 14:30:08 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
netapi_buffer_free(result['bufptr'])
|
|
|
|
|
|
|
|
|
|
return hosts
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def read_server_structs(start_ptr, count, domain, server_type)
|
|
|
|
|
hosts = []
|
2014-08-14 23:32:04 +01:00
|
|
|
return hosts if count <= 0
|
2014-05-20 21:55:04 +01:00
|
|
|
|
2014-08-14 23:32:04 +01:00
|
|
|
ptr_size = client.railgun.util.pointer_size
|
|
|
|
|
ptr = (ptr_size == 8) ? 'Q<' : 'V'
|
|
|
|
|
|
|
|
|
|
base = 0
|
|
|
|
|
# Struct -> Ptr, Ptr
|
|
|
|
|
struct_size = ptr_size * 2
|
2014-05-20 21:55:04 +01:00
|
|
|
|
2013-09-05 14:30:08 -05:00
|
|
|
mem = client.railgun.memread(start_ptr, struct_size*count)
|
|
|
|
|
|
2014-03-04 08:49:52 +02:00
|
|
|
count.times do
|
2013-09-05 14:30:08 -05:00
|
|
|
x = {}
|
2014-08-14 23:32:04 +01:00
|
|
|
x[:version]= mem[(base + 0),ptr_size].unpack(ptr).first
|
|
|
|
|
nameptr = mem[(base + ptr_size),ptr_size].unpack(ptr).first
|
2013-09-05 14:30:08 -05:00
|
|
|
x[:name] = UnicodeByteStringToAscii(client.railgun.memread(nameptr, 255))
|
|
|
|
|
hosts << x
|
|
|
|
|
base += struct_size
|
|
|
|
|
end
|
|
|
|
|
|
2014-08-14 23:32:04 +01:00
|
|
|
hosts
|
2013-09-05 14:30:08 -05:00
|
|
|
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']
|
2014-03-04 08:49:52 +02:00
|
|
|
when 0
|
|
|
|
|
vprint_error("#{hostname} Session identified")
|
2014-08-14 23:32:04 +01:00
|
|
|
sessions = read_session_structs(result['bufptr'], (result['entriesread'] % 4294967296), hostname)
|
2014-03-04 08:49:52 +02:00
|
|
|
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
|
2013-09-05 14:30:08 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
netapi_buffer_free(result['bufptr'])
|
|
|
|
|
|
|
|
|
|
return sessions
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def read_session_structs(start_ptr, count, hostname)
|
|
|
|
|
sessions = []
|
2014-08-14 23:32:04 +01:00
|
|
|
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
|
2013-09-05 14:30:08 -05:00
|
|
|
mem = client.railgun.memread(start_ptr, struct_size*count)
|
2014-08-14 23:32:04 +01:00
|
|
|
|
2014-03-04 08:49:52 +02:00
|
|
|
count.times do
|
2013-09-05 14:30:08 -05:00
|
|
|
sess = {}
|
2014-08-14 23:32:04 +01:00
|
|
|
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
|
2013-09-05 14:30:08 -05:00
|
|
|
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
|
|
|
|
|
|
2014-08-14 23:32:04 +01:00
|
|
|
sessions
|
2013-09-05 14:30:08 -05:00
|
|
|
end
|
2013-09-02 20:24:54 +01:00
|
|
|
|
|
|
|
|
end # NetAPI
|
|
|
|
|
end # Windows
|
|
|
|
|
end # Post
|
|
|
|
|
end # Msf
|