Support retrieving interface information via netlink.
parent
284d99aa6c
commit
733a86ec74
|
@ -9,6 +9,7 @@ import socket
|
||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
has_windll = hasattr(ctypes, 'windll')
|
has_windll = hasattr(ctypes, 'windll')
|
||||||
|
|
||||||
|
@ -36,6 +37,9 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
has_winreg = False
|
has_winreg = False
|
||||||
|
|
||||||
|
#
|
||||||
|
# Windows Structures
|
||||||
|
#
|
||||||
class PROCESSENTRY32(ctypes.Structure):
|
class PROCESSENTRY32(ctypes.Structure):
|
||||||
_fields_ = [("dwSize", ctypes.c_uint32),
|
_fields_ = [("dwSize", ctypes.c_uint32),
|
||||||
("cntUsage", ctypes.c_uint32),
|
("cntUsage", ctypes.c_uint32),
|
||||||
|
@ -59,15 +63,40 @@ class SYSTEM_INFO(ctypes.Structure):
|
||||||
("dwProcessorType", ctypes.c_uint32),
|
("dwProcessorType", ctypes.c_uint32),
|
||||||
("dwAllocationGranularity", ctypes.c_uint32),
|
("dwAllocationGranularity", ctypes.c_uint32),
|
||||||
("wProcessorLevel", ctypes.c_uint16),
|
("wProcessorLevel", ctypes.c_uint16),
|
||||||
("wProcessorRevision", ctypes.c_uint16),]
|
("wProcessorRevision", ctypes.c_uint16)]
|
||||||
|
|
||||||
class SID_AND_ATTRIBUTES(ctypes.Structure):
|
class SID_AND_ATTRIBUTES(ctypes.Structure):
|
||||||
_fields_ = [("Sid", ctypes.c_void_p),
|
_fields_ = [("Sid", ctypes.c_void_p),
|
||||||
("Attributes", ctypes.c_uint32),]
|
("Attributes", ctypes.c_uint32)]
|
||||||
|
|
||||||
##
|
#
|
||||||
# STDAPI
|
# Linux Structures
|
||||||
##
|
#
|
||||||
|
class IFADDRMSG(ctypes.Structure):
|
||||||
|
_fields_ = [("family", ctypes.c_uint8),
|
||||||
|
("prefixlen", ctypes.c_uint8),
|
||||||
|
("flags", ctypes.c_uint8),
|
||||||
|
("scope", ctypes.c_uint8),
|
||||||
|
("index", ctypes.c_int32)]
|
||||||
|
|
||||||
|
class IFINFOMSG(ctypes.Structure):
|
||||||
|
_fields_ = [("family", ctypes.c_uint8),
|
||||||
|
("pad", ctypes.c_int8),
|
||||||
|
("type", ctypes.c_uint16),
|
||||||
|
("index", ctypes.c_int32),
|
||||||
|
("flags", ctypes.c_uint32),
|
||||||
|
("chagen", ctypes.c_uint32)]
|
||||||
|
|
||||||
|
class NLMSGHDR(ctypes.Structure):
|
||||||
|
_fields_ = [("len", ctypes.c_uint32),
|
||||||
|
("type", ctypes.c_uint16),
|
||||||
|
("flags", ctypes.c_uint16),
|
||||||
|
("seq", ctypes.c_uint32),
|
||||||
|
("pid", ctypes.c_uint32)]
|
||||||
|
|
||||||
|
class RTATTR(ctypes.Structure):
|
||||||
|
_fields_ = [("len", ctypes.c_uint16),
|
||||||
|
("type", ctypes.c_uint16)]
|
||||||
|
|
||||||
#
|
#
|
||||||
# TLV Meta Types
|
# TLV Meta Types
|
||||||
|
@ -293,9 +322,32 @@ ERROR_FAILURE = 1
|
||||||
# errors.
|
# errors.
|
||||||
ERROR_CONNECTION_ERROR = 10000
|
ERROR_CONNECTION_ERROR = 10000
|
||||||
|
|
||||||
|
# Windows Constants
|
||||||
WIN_AF_INET = 2
|
WIN_AF_INET = 2
|
||||||
WIN_AF_INET6 = 23
|
WIN_AF_INET6 = 23
|
||||||
|
|
||||||
|
# Linux Constants
|
||||||
|
RTM_GETLINK = 18
|
||||||
|
RTM_GETADDR = 22
|
||||||
|
RTM_GETROUTE = 26
|
||||||
|
|
||||||
|
IFLA_ADDRESS = 1
|
||||||
|
IFLA_BROADCAST = 2
|
||||||
|
IFLA_IFNAME = 3
|
||||||
|
IFLA_MTU = 4
|
||||||
|
|
||||||
|
IFA_ADDRESS = 1
|
||||||
|
IFA_LABEL = 3
|
||||||
|
|
||||||
|
def cstruct_pack(structure):
|
||||||
|
return ctypes.string_at(ctypes.byref(structure), ctypes.sizeof(structure))
|
||||||
|
|
||||||
|
def cstruct_unpack(structure, raw_data):
|
||||||
|
if not isinstance(structure, ctypes.Structure):
|
||||||
|
structure = structure()
|
||||||
|
ctypes.memmove(ctypes.byref(structure), raw_data, ctypes.sizeof(structure))
|
||||||
|
return structure
|
||||||
|
|
||||||
def get_stat_buffer(path):
|
def get_stat_buffer(path):
|
||||||
si = os.stat(path)
|
si = os.stat(path)
|
||||||
rdev = 0
|
rdev = 0
|
||||||
|
@ -328,6 +380,31 @@ def inet_pton(family, address):
|
||||||
return ''.join(map(chr, lpAddress[8:24]))
|
return ''.join(map(chr, lpAddress[8:24]))
|
||||||
raise Exception('no suitable inet_pton functionality is available')
|
raise Exception('no suitable inet_pton functionality is available')
|
||||||
|
|
||||||
|
def netlink_request(req_type):
|
||||||
|
# See RFC 3549
|
||||||
|
NLM_F_REQUEST = 0x0001
|
||||||
|
NLM_F_ROOT = 0x0100
|
||||||
|
NLMSG_ERROR = 0x0002
|
||||||
|
NLMSG_DONE = 0x0003
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE)
|
||||||
|
sock.bind((os.getpid(), 0))
|
||||||
|
seq = int(time.time())
|
||||||
|
nlmsg = struct.pack('IHHIIB15x', 32, req_type, (NLM_F_REQUEST | NLM_F_ROOT), seq, 0, socket.AF_UNSPEC)
|
||||||
|
sfd = os.fdopen(sock.fileno(), 'w+b')
|
||||||
|
sfd.write(nlmsg)
|
||||||
|
responses = []
|
||||||
|
response = cstruct_unpack(NLMSGHDR, sfd.read(ctypes.sizeof(NLMSGHDR)))
|
||||||
|
while response.type != NLMSG_DONE:
|
||||||
|
if response.type == NLMSG_ERROR:
|
||||||
|
break
|
||||||
|
response_data = sfd.read(response.len - 16)
|
||||||
|
responses.append(response_data)
|
||||||
|
response = cstruct_unpack(NLMSGHDR, sfd.read(ctypes.sizeof(NLMSGHDR)))
|
||||||
|
sfd.close()
|
||||||
|
sock.close()
|
||||||
|
return responses
|
||||||
|
|
||||||
def resolve_host(hostname, family):
|
def resolve_host(hostname, family):
|
||||||
address_info = socket.getaddrinfo(hostname, 0, family, socket.SOCK_DGRAM, socket.IPPROTO_UDP)[0]
|
address_info = socket.getaddrinfo(hostname, 0, family, socket.SOCK_DGRAM, socket.IPPROTO_UDP)[0]
|
||||||
family = address_info[0]
|
family = address_info[0]
|
||||||
|
@ -743,6 +820,100 @@ def stdapi_fs_stat(request, response):
|
||||||
response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
|
response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
|
||||||
return ERROR_SUCCESS, response
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_net_config_get_interfaces(request, response):
|
||||||
|
if hasattr(socket, 'AF_NETLINK'):
|
||||||
|
interfaces = stdapi_net_config_get_interfaces_via_netlink()
|
||||||
|
else:
|
||||||
|
ERROR_FAILURE, response
|
||||||
|
for iface_info in interfaces:
|
||||||
|
iface_tlv = ''
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_MAC_NAME, iface_info['name'])
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, iface_info['hw_addr'])
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_MTU, iface_info['mtu'])
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_FLAGS, iface_info['flags'])
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_INDEX, iface_info['index'])
|
||||||
|
for address in iface_info.get('addrs', []):
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_IP, address[1])
|
||||||
|
iface_tlv += tlv_pack(TLV_TYPE_NETMASK, address[2])
|
||||||
|
response += tlv_pack(TLV_TYPE_NETWORK_INTERFACE, iface_tlv)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
def stdapi_net_config_get_interfaces_via_netlink():
|
||||||
|
rta_align = lambda l: l+3 & ~3
|
||||||
|
iface_flags = {
|
||||||
|
0x0001: 'UP',
|
||||||
|
0x0002: 'BROADCAST',
|
||||||
|
0x0008: 'LOOPBACK',
|
||||||
|
0x0010: 'POINTTOPOINT',
|
||||||
|
0x0040: 'RUNNING',
|
||||||
|
0x0100: 'PROMISC',
|
||||||
|
0x1000: 'MULTICAST'
|
||||||
|
}
|
||||||
|
iface_flags_sorted = iface_flags.keys()
|
||||||
|
# Dictionaries don't maintain order
|
||||||
|
iface_flags_sorted.sort()
|
||||||
|
interfaces = {}
|
||||||
|
|
||||||
|
responses = netlink_request(RTM_GETLINK)
|
||||||
|
for res_data in responses:
|
||||||
|
iface = cstruct_unpack(IFINFOMSG, res_data)
|
||||||
|
iface_info = {'index':iface.index}
|
||||||
|
flags = []
|
||||||
|
for flag in iface_flags_sorted:
|
||||||
|
if (iface.flags & flag):
|
||||||
|
flags.append(iface_flags[flag])
|
||||||
|
iface_info['flags'] = ' '.join(flags)
|
||||||
|
cursor = ctypes.sizeof(IFINFOMSG)
|
||||||
|
while cursor < len(res_data):
|
||||||
|
attribute = cstruct_unpack(RTATTR, res_data[cursor:])
|
||||||
|
at_len = attribute.len
|
||||||
|
attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
|
||||||
|
cursor += rta_align(at_len)
|
||||||
|
|
||||||
|
if attribute.type == IFLA_ADDRESS:
|
||||||
|
iface_info['hw_addr'] = attr_data
|
||||||
|
elif attribute.type == IFLA_IFNAME:
|
||||||
|
iface_info['name'] = attr_data
|
||||||
|
elif attribute.type == IFLA_MTU:
|
||||||
|
iface_info['mtu'] = struct.unpack('<I', attr_data)[0]
|
||||||
|
interfaces[iface.index] = iface_info
|
||||||
|
|
||||||
|
calc_32bit_netmask = lambda b: 0xffffffff if b == 32 else ((0xffffffff << (32-(b%32))) & 0xffffffff)
|
||||||
|
responses = netlink_request(RTM_GETADDR)
|
||||||
|
for res_data in responses:
|
||||||
|
iface = cstruct_unpack(IFADDRMSG, res_data)
|
||||||
|
if not iface.family in (socket.AF_INET, socket.AF_INET6):
|
||||||
|
continue
|
||||||
|
iface_info = interfaces.get(iface.index, {})
|
||||||
|
cursor = ctypes.sizeof(IFADDRMSG)
|
||||||
|
while cursor < len(res_data):
|
||||||
|
attribute = cstruct_unpack(RTATTR, res_data[cursor:])
|
||||||
|
at_len = attribute.len
|
||||||
|
attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
|
||||||
|
cursor += rta_align(at_len)
|
||||||
|
|
||||||
|
if attribute.type == IFA_ADDRESS:
|
||||||
|
nm_bits = iface.prefixlen
|
||||||
|
if iface.family == socket.AF_INET:
|
||||||
|
netmask = struct.pack('!I', calc_32bit_netmask(nm_bits))
|
||||||
|
else:
|
||||||
|
if nm_bits >= 96:
|
||||||
|
netmask = struct.pack('!iiiI', -1, -1, -1, calc_32bit_netmask(nm_bits))
|
||||||
|
elif nm_bits >= 64:
|
||||||
|
netmask = struct.pack('!iiII', -1, -1, calc_32bit_netmask(nm_bits), 0)
|
||||||
|
elif nm_bits >= 32:
|
||||||
|
netmask = struct.pack('!iIII', -1, calc_32bit_netmask(nm_bits), 0, 0)
|
||||||
|
else:
|
||||||
|
netmask = struct.pack('!IIII', calc_32bit_netmask(nm_bits), 0, 0, 0)
|
||||||
|
addr_list = iface_info.get('addrs', [])
|
||||||
|
addr_list.append((iface.family, attr_data, netmask))
|
||||||
|
iface_info['addrs'] = addr_list
|
||||||
|
elif attribute.type == IFA_LABEL:
|
||||||
|
iface_info['name'] = attr_data
|
||||||
|
interfaces[iface.index] = iface_info
|
||||||
|
return interfaces.values()
|
||||||
|
|
||||||
@meterpreter.register_function
|
@meterpreter.register_function
|
||||||
def stdapi_net_resolve_host(request, response):
|
def stdapi_net_resolve_host(request, response):
|
||||||
hostname = packet_get_tlv(request, TLV_TYPE_HOST_NAME)['value']
|
hostname = packet_get_tlv(request, TLV_TYPE_HOST_NAME)['value']
|
||||||
|
|
Loading…
Reference in New Issue