def Run(self, unused_args): """Enumerate all MAC addresses.""" libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) ifa = Ifaddrs() p_ifa = ctypes.pointer(ifa) libc.getifaddrs(ctypes.pointer(p_ifa)) addresses = {} macs = {} ifs = set() m = p_ifa while m: ifname = ctypes.string_at(m.contents.ifa_name) ifs.add(ifname) try: iffamily = ord(m.contents.ifa_addr[1]) if iffamily == 0x2: # AF_INET data = ctypes.cast(m.contents.ifa_addr, ctypes.POINTER(Sockaddrin)) ip4 = "".join(map(chr, data.contents.sin_addr)) address_type = rdf_client.NetworkAddress.Family.INET address = rdf_client.NetworkAddress( address_type=address_type, packed_bytes=ip4) addresses.setdefault(ifname, []).append(address) if iffamily == 0x12: # AF_LINK data = ctypes.cast(m.contents.ifa_addr, ctypes.POINTER(Sockaddrdl)) iflen = data.contents.sdl_nlen addlen = data.contents.sdl_alen macs[ifname] = "".join( map(chr, data.contents.sdl_data[iflen:iflen + addlen])) if iffamily == 0x1E: # AF_INET6 data = ctypes.cast(m.contents.ifa_addr, ctypes.POINTER(Sockaddrin6)) ip6 = "".join(map(chr, data.contents.sin6_addr)) address_type = rdf_client.NetworkAddress.Family.INET6 address = rdf_client.NetworkAddress( address_type=address_type, packed_bytes=ip6) addresses.setdefault(ifname, []).append(address) except ValueError: # Some interfaces don't have a iffamily and will raise a null pointer # exception. We still want to send back the name. pass m = m.contents.ifa_next libc.freeifaddrs(p_ifa) for interface in ifs: mac = macs.setdefault(interface, "") address_list = addresses.setdefault(interface, "") args = {"ifname": interface} if mac: args["mac_address"] = mac if address_list: args["addresses"] = address_list self.SendReply(rdf_client.Interface(**args))
def _SetupClients(self, n): res = {} for i in range(1, n + 1): client_id = "C.100000000000000%d" % i client = objects.Client() client.system = "Windows" client.hostname = "host-%d" % i client.fqdn = "host-%d.example.com" % i client.interfaces = [ rdf_client.Interface(addresses=[ rdf_client.NetworkAddress( address_type=rdf_client.NetworkAddress.Family.INET, packed_bytes=ipv6_utils.InetPtoN( socket.AF_INET, "192.168.0.%d" % i)), rdf_client.NetworkAddress( address_type=rdf_client.NetworkAddress.Family.INET6, packed_bytes=ipv6_utils.InetPtoN( socket.AF_INET6, "2001:abcd::%d" % i)) ], mac_address=("aabbccddee0%d" % i).decode("hex")) ] res[client_id] = client return res
def testClientMetadataPing(self): d = self.db client_id_1 = "C.fc413187fefa1dcf" self._InitializeClient(client_id_1) # Typical update on client ping. d.WriteClientMetadata(client_id_1, last_ping=rdfvalue.RDFDatetime(200000000000), last_clock=rdfvalue.RDFDatetime(210000000000), last_ip=rdf_client.NetworkAddress( human_readable_address="8.8.8.8"), last_foreman=rdfvalue.RDFDatetime(220000000000)) res = d.ReadClientMetadatas([client_id_1]) self.assertEqual(len(res), 1) m1 = res[client_id_1] self.assertIsInstance(m1, objects.ClientMetadata) self.assertTrue(m1.fleetspeak_enabled) self.assertEqual(m1.ping, rdfvalue.RDFDatetime(200000000000)) self.assertEqual(m1.clock, rdfvalue.RDFDatetime(210000000000)) self.assertEqual( m1.ip, rdf_client.NetworkAddress(human_readable_address="8.8.8.8")) self.assertEqual(m1.last_foreman_time, rdfvalue.RDFDatetime(220000000000))
def _ConvertIPs(self, io_tuples, interface, output_dict): for inputkey, outputkey in io_tuples: addresses = [] if isinstance(interface[inputkey], list): for ip_address in interface[inputkey]: addresses.append(rdf_client.NetworkAddress( human_readable_address=ip_address)) else: addresses.append(rdf_client.NetworkAddress( human_readable_address=interface[inputkey])) output_dict[outputkey] = addresses return output_dict
def testClientListReport(self): """Check that we can create and run a ClientList Report.""" # Create some clients. client_ids = self.SetupClients(10) with aff4.FACTORY.Open(client_ids[0], token=self.token, mode="rw") as client: interfaces = client.Schema.INTERFACES() interfaces.Append(addresses=[ rdf_client.NetworkAddress(human_readable="1.1.1.1", address_type="INET") ], mac_address="11:11:11:11:11:11", ifname="eth0") client.Set(interfaces) client.Set(client.Schema.HOSTNAME("lawman")) # Also initialize a broken client with no hostname. with aff4.FACTORY.Open(client_ids[1], token=self.token, mode="rw") as client: client.Set(client.Schema.CLIENT_INFO()) # Create a report for all clients. report = reports.ClientListReport(token=self.token) report.Run() self.assertEqual(len(report.results), 10) hostnames = [x.get("Host") for x in report.results] self.assertTrue("lawman" in hostnames) report.SortResults("Host") self.assertEqual(len(report.AsDict()), 10) self.assertEqual(len(report.AsCsv().getvalue().splitlines()), 11) self.assertEqual(len(report.AsText().getvalue().splitlines()), 10) self.assertEqual(report.results[-1]["Interfaces"], "1.1.1.1") self.assertEqual(len(report.broken_clients), 1)
def _TestInterfaces(self, client_nr): ip1 = rdf_client.NetworkAddress() ip1.human_readable_address = "192.168.0.%d" % client_nr ip2 = rdf_client.NetworkAddress() ip2.human_readable_address = "2001:abcd::%x" % client_nr mac1 = rdf_client.MacAddress() mac1.human_readable_address = "aabbccddee%02x" % client_nr mac2 = rdf_client.MacAddress() mac2.human_readable_address = "bbccddeeff%02x" % client_nr return [ rdf_client.Interface(addresses=[ip1, ip2]), rdf_client.Interface(mac_address=mac1), rdf_client.Interface(mac_address=mac2), ]
def testIPv4(self): sample = rdf_client.NetworkAddress(human_readable_address="192.168.0.1") self.assertEqual(sample.address_type, rdf_client.NetworkAddress.Family.INET) self.assertEqual(sample.packed_bytes, socket.inet_pton(socket.AF_INET, "192.168.0.1")) self.assertEqual(sample.human_readable_address, "192.168.0.1") self.CheckRDFValue(self.rdfvalue_class(sample), sample)
def EnumerateInterfaces(self, _): self.response_count += 1 return [rdf_client.Interface( mac_address="123456", addresses=[ rdf_client.NetworkAddress( address_type=rdf_client.NetworkAddress.Family.INET, human_readable="100.100.100.1", packed_bytes=socket.inet_pton(socket.AF_INET, "100.100.100.1"),) ])]
def testIPv6(self): ipv6_addresses = ["fe80::202:b3ff:fe1e:8329", "::1"] for address in ipv6_addresses: sample = rdf_client.NetworkAddress(human_readable_address=address) self.assertEqual(sample.address_type, rdf_client.NetworkAddress.Family.INET6) self.assertEqual(sample.packed_bytes, socket.inet_pton(socket.AF_INET6, address)) self.assertEqual(sample.human_readable_address, address) self.CheckRDFValue(self.rdfvalue_class(sample), sample)
def RunNetAdapterWMIQuery(self): pythoncom.CoInitialize() for interface in wmi.WMI().Win32_NetworkAdapterConfiguration(IPEnabled=1): addresses = [] for ip_address in interface.IPAddress: addresses.append(rdf_client.NetworkAddress( human_readable_address=ip_address)) args = {"ifname": interface.Description} args["mac_address"] = binascii.unhexlify( interface.MACAddress.replace(":", "")) if addresses: args["addresses"] = addresses yield args
def Run(self, args): del args # Unused. pythoncom.CoInitialize() for interface in wmi.WMI().Win32_NetworkAdapterConfiguration(): addresses = [] for ip_address in interface.IPAddress: addresses.append( rdf_client.NetworkAddress(human_readable_address=ip_address)) response = rdf_client.Interface(ifname=interface.Description) if interface.MACAddress: response.mac_address = binascii.unhexlify( interface.MACAddress.replace(":", "")) if addresses: response.addresses = addresses self.SendReply(response)
def _WriteClientMetadata(client): """Store the AFF4 client metadata in the relational database.""" client_ip = client.Get(client.Schema.CLIENT_IP) if client_ip: last_ip = rdf_client.NetworkAddress( human_readable_address=utils.SmartStr(client_ip)) else: last_ip = None data_store.REL_DB.WriteClientMetadata( client.urn.Basename(), certificate=client.Get(client.Schema.CERT), fleetspeak_enabled=client.Get(client.Schema.FLEETSPEAK_ENABLED) or False, last_ping=client.Get(client.Schema.PING), last_clock=client.Get(client.Schema.CLOCK), last_ip=last_ip, last_foreman=client.Get(client.Schema.LAST_FOREMAN_TIME), first_seen=client.Get(client.Schema.FIRST_SEEN))
def Run(self): # Fix the time to avoid regressions. with test_lib.FakeTime(42): if data_store.RelationalDBReadEnabled(): client_obj = self.SetupTestClientObject(0) client_id = client_obj.client_id ip = rdf_client.NetworkAddress( human_readable_address="192.168.100.42", address_type=rdf_client.NetworkAddress.Family.INET) data_store.REL_DB.WriteClientMetadata(client_id, last_ip=ip) else: client_urn = self.SetupClient(0) client_id = client_urn.Basename() with aff4.FACTORY.Open( client_id, mode="rw", token=self.token) as grr_client: grr_client.Set(grr_client.Schema.CLIENT_IP("192.168.100.42")) self.Check( "GetLastClientIPAddress", args=client_plugin.ApiGetLastClientIPAddressArgs(client_id=client_id))
def testRdfFormatter(self): """Hints format RDF values with arbitrary values and attributes.""" # Create a complex RDF value rdf = rdf_client.ClientSummary() rdf.system_info.system = "Linux" rdf.system_info.node = "coreai.skynet.com" # Users (repeated) rdf.users = [rdf_client.User(username=u) for u in ("root", "jconnor")] # Interface (nested, repeated) addresses = [ rdf_client.NetworkAddress(human_readable=a) for a in ("1.1.1.1", "2.2.2.2", "3.3.3.3") ] eth0 = rdf_client.Interface(ifname="eth0", addresses=addresses[:2]) ppp0 = rdf_client.Interface(ifname="ppp0", addresses=addresses[2]) rdf.interfaces = [eth0, ppp0] template = ("{system_info.system} {users.username} {interfaces.ifname} " "{interfaces.addresses.human_readable}\n") hinter = hints.Hinter(template=template) expected = "Linux root,jconnor eth0,ppp0 1.1.1.1,2.2.2.2,3.3.3.3" result = hinter.Render(rdf) self.assertEqual(expected, result)
def GenerateSample(self, number=0): return rdf_client.NetworkAddress( human_readable_address="192.168.0.%s" % number)
def VerifyMessageSignature(self, response_comms, packed_message_list, cipher, cipher_verified, api_version, remote_public_key): """Verifies the message list signature. In the server we check that the timestamp is later than the ping timestamp stored with the client. This ensures that client responses can not be replayed. Args: response_comms: The raw response_comms rdfvalue. packed_message_list: The PackedMessageList rdfvalue from the server. cipher: The cipher object that should be used to verify the message. cipher_verified: If True, the cipher's signature is not verified again. api_version: The api version we should use. remote_public_key: The public key of the source. Returns: An rdf_flows.GrrMessage.AuthorizationState. """ if (not cipher_verified and not cipher.VerifyCipherSignature(remote_public_key)): stats.STATS.IncrementCounter("grr_unauthenticated_messages") return rdf_flows.GrrMessage.AuthorizationState.UNAUTHENTICATED try: client_id = cipher.cipher_metadata.source try: client = self.client_cache.Get(client_id) except KeyError: client = aff4.FACTORY.Create( client_id, aff4.AFF4Object.classes["VFSGRRClient"], mode="rw", token=self.token) self.client_cache.Put(client_id, client) stats.STATS.SetGaugeValue( "grr_frontendserver_client_cache_size", len(self.client_cache)) ip = response_comms.orig_request.source_ip client.Set(client.Schema.CLIENT_IP(ip)) # The very first packet we see from the client we do not have its clock remote_time = client.Get( client.Schema.CLOCK) or rdfvalue.RDFDatetime(0) client_time = packed_message_list.timestamp or rdfvalue.RDFDatetime( 0) # This used to be a strict check here so absolutely no out of # order messages would be accepted ever. Turns out that some # proxies can send your request with some delay even if the # client has already timed out (and sent another request in # the meantime, making the first one out of order). In that # case we would just kill the whole flow as a # precaution. Given the behavior of those proxies, this seems # now excessive and we have changed the replay protection to # only trigger on messages that are more than one hour old. if client_time < long(remote_time - rdfvalue.Duration("1h")): logging.warning("Message desynchronized for %s: %s >= %s", client_id, long(remote_time), int(client_time)) # This is likely an old message return rdf_flows.GrrMessage.AuthorizationState.DESYNCHRONIZED stats.STATS.IncrementCounter("grr_authenticated_messages") # Update the client and server timestamps only if the client # time moves forward. if client_time > long(remote_time): client.Set(client.Schema.CLOCK, rdfvalue.RDFDatetime(client_time)) client.Set(client.Schema.PING, rdfvalue.RDFDatetime.Now()) clock = client_time ping = rdfvalue.RDFDatetime.Now() for label in client.Get(client.Schema.LABELS, []): stats.STATS.IncrementCounter("client_pings_by_label", fields=[label.name]) else: clock = None ping = None logging.warning("Out of order message for %s: %s >= %s", client_id, long(remote_time), int(client_time)) client.Flush() if data_store.RelationalDBWriteEnabled(): source_ip = response_comms.orig_request.source_ip if source_ip: last_ip = rdf_client.NetworkAddress( human_readable_address=response_comms.orig_request. source_ip) else: last_ip = None if ping or clock or last_ip: data_store.REL_DB.WriteClientMetadata( client_id.Basename(), last_ip=last_ip, last_clock=clock, last_ping=ping, fleetspeak_enabled=False) except communicator.UnknownClientCert: pass return rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED
def VerifyMessageSignature(self, response_comms, packed_message_list, cipher, cipher_verified, api_version, remote_public_key): """Verifies the message list signature. In the server we check that the timestamp is later than the ping timestamp stored with the client. This ensures that client responses can not be replayed. Args: response_comms: The raw response_comms rdfvalue. packed_message_list: The PackedMessageList rdfvalue from the server. cipher: The cipher object that should be used to verify the message. cipher_verified: If True, the cipher's signature is not verified again. api_version: The api version we should use. remote_public_key: The public key of the source. Returns: An rdf_flows.GrrMessage.AuthorizationState. """ if (not cipher_verified and not cipher.VerifyCipherSignature(remote_public_key)): stats.STATS.IncrementCounter("grr_unauthenticated_messages") return rdf_flows.GrrMessage.AuthorizationState.UNAUTHENTICATED try: client_id = cipher.cipher_metadata.source.Basename() metadata = data_store.REL_DB.ReadClientMetadata(client_id) client_time = packed_message_list.timestamp or rdfvalue.RDFDatetime( 0) # This used to be a strict check here so absolutely no out of # order messages would be accepted ever. Turns out that some # proxies can send your request with some delay even if the # client has already timed out (and sent another request in # the meantime, making the first one out of order). In that # case we would just kill the whole flow as a # precaution. Given the behavior of those proxies, this seems # now excessive and we have changed the replay protection to # only trigger on messages that are more than one hour old. if metadata and metadata.clock: stored_client_time = metadata.clock if client_time < stored_client_time - rdfvalue.Duration("1h"): logging.warning("Message desynchronized for %s: %s >= %s", client_id, long(stored_client_time), long(client_time)) # This is likely an old message return rdf_flows.GrrMessage.AuthorizationState.DESYNCHRONIZED stats.STATS.IncrementCounter("grr_authenticated_messages") # Update the client and server timestamps only if the client # time moves forward. if client_time <= stored_client_time: logging.warning("Out of order message for %s: %s >= %s", client_id, long(stored_client_time), long(client_time)) return rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED stats.STATS.IncrementCounter("grr_authenticated_messages") for label in data_store.REL_DB.ReadClientLabels(client_id): stats.STATS.IncrementCounter("client_pings_by_label", fields=[label.name]) source_ip = response_comms.orig_request.source_ip if source_ip: last_ip = rdf_client.NetworkAddress( human_readable_address=response_comms.orig_request. source_ip) else: last_ip = None data_store.REL_DB.WriteClientMetadata( client_id, last_ip=last_ip, last_clock=client_time, last_ping=rdfvalue.RDFDatetime.Now(), fleetspeak_enabled=False) except communicator.UnknownClientCert: pass return rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED