413 lines
12 KiB
Python
413 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# All credit to @an0n_r0
|
|
# project : https://github.com/tothi/serviceDetector
|
|
|
|
from impacket.dcerpc.v5 import lsat, lsad
|
|
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
|
from impacket.dcerpc.v5.dtypes import NULL, MAXIMUM_ALLOWED, RPC_UNICODE_STRING
|
|
from impacket.dcerpc.v5 import transport, epm
|
|
|
|
import json
|
|
import pathlib
|
|
|
|
class CMEModule:
|
|
'''
|
|
Uses LsarLookupNames and NamedPipes to gather information on all endpoint protection solutions installed on the the remote host(s)
|
|
Module by @mpgn_x64
|
|
|
|
'''
|
|
|
|
name = 'enum_av'
|
|
description = 'Gathers information on all endpoint protection solutions installed on the the remote host(s) via LsarLookupNames (no privilege needed)'
|
|
supported_protocols = ['smb']
|
|
opsec_safe = True
|
|
multiple_hosts = True
|
|
|
|
def options(self, context, module_options):
|
|
pass
|
|
|
|
def on_login(self, context, connection):
|
|
|
|
success = 0
|
|
results = {}
|
|
context.log.debug("Detecting installed services on {} using LsarLookupNames()...".format(connection.host))
|
|
try:
|
|
lsa = LsaLookupNames(connection.domain, connection.username, connection.password, connection.hostname if connection.kerberos else connection.host, connection.kerberos, connection.domain, connection.lmhash, connection.nthash)
|
|
dce, rpctransport = lsa.connect()
|
|
policyHandle = lsa.open_policy(dce)
|
|
|
|
for i, product in enumerate(conf['products']):
|
|
for service in product['services']:
|
|
try:
|
|
lsa.LsarLookupNames(dce, policyHandle, service['name'])
|
|
context.log.debug("Detected installed service on {}: {} {}".format(connection.host, product['name'], service['description']))
|
|
if product['name'] not in results:
|
|
results[product['name']] = {"services": []}
|
|
results[product['name']]['services'].append(service)
|
|
except Exception as e:
|
|
pass
|
|
success += 1
|
|
except Exception as e:
|
|
context.log.error(str(e))
|
|
|
|
context.log.debug("Detecting running processes on {} by enumerating pipes...".format(connection.host))
|
|
try:
|
|
for f in connection.conn.listPath('IPC$', '\\*'):
|
|
fl = f.get_longname()
|
|
for i, product in enumerate(conf['products']):
|
|
for pipe in product['pipes']:
|
|
if pathlib.PurePath(fl).match(pipe['name']):
|
|
context.log.debug("{} running claim found on {} by existing pipe {} (likely processes: {})".format(product['name'], connection.host, fl, pipe['processes']))
|
|
if product['name'] not in results:
|
|
results[product['name']] = {}
|
|
if "pipes" not in results[product['name']]:
|
|
results[product['name']]['pipes'] = []
|
|
results[product['name']]['pipes'].append(pipe)
|
|
success += 1
|
|
except Exception as e:
|
|
context.log.error(str(e))
|
|
|
|
self.dump_results(results, connection.hostname, success, context)
|
|
|
|
def dump_results(self, results, remoteName, success, context):
|
|
# out1 = "On host {} found".format(remoteName)
|
|
out1 = ""
|
|
for item in results:
|
|
out = out1
|
|
if 'services' in results[item]:
|
|
out += "{} INSTALLED".format(item)
|
|
if 'pipes' in results[item]:
|
|
out += " and it seems to be RUNNING".format()
|
|
# else:
|
|
# for product in conf['products']:
|
|
# if (item == product['name']) and (len(product['pipes']) == 0):
|
|
# out += " (NamedPipe for this service was not provided in config)"
|
|
elif 'pipes' in results[item]:
|
|
out += " {} RUNNING".format(item)
|
|
context.log.highlight(out)
|
|
if (len(results) < 1) and (success > 1):
|
|
out = out1 + " NOTHING!".format()
|
|
context.log.highlight(out)
|
|
|
|
class LsaLookupNames():
|
|
timeout = None
|
|
authn_level = None
|
|
protocol = None
|
|
transfer_syntax = None
|
|
machine_account = False
|
|
|
|
iface_uuid = lsat.MSRPC_UUID_LSAT
|
|
authn = True
|
|
|
|
def __init__(self, domain="", username="", password="", remoteName="", k=False, kdcHost="", lmhash="", nthash=""):
|
|
self.domain = domain
|
|
self.username = username
|
|
self.password = password
|
|
self.remoteName = remoteName
|
|
self.string_binding = r"ncacn_np:{}[\PIPE\lsarpc]".format(remoteName)
|
|
self.doKerberos = k
|
|
self.lmhash = lmhash
|
|
self.nthash = nthash
|
|
self.dcHost = kdcHost
|
|
|
|
def connect(self, string_binding=None, iface_uuid=None):
|
|
"""Obtains a RPC Transport and a DCE interface according to the bindings and
|
|
transfer syntax specified.
|
|
:return: tuple of DCE/RPC and RPC Transport objects
|
|
:rtype: (DCERPC_v5, DCERPCTransport)
|
|
"""
|
|
string_binding = string_binding or self.string_binding
|
|
if not string_binding:
|
|
raise NotImplemented("String binding must be defined")
|
|
|
|
rpc_transport = transport.DCERPCTransportFactory(string_binding)
|
|
|
|
# Set timeout if defined
|
|
if self.timeout:
|
|
rpc_transport.set_connect_timeout(self.timeout)
|
|
|
|
# Authenticate if specified
|
|
if self.authn and hasattr(rpc_transport, 'set_credentials'):
|
|
# This method exists only for selected protocol sequences.
|
|
rpc_transport.set_credentials(self.username, self.password, self.domain, self.lmhash, self.nthash)
|
|
|
|
if self.doKerberos:
|
|
rpc_transport.set_kerberos(self.doKerberos, kdcHost=self.dcHost)
|
|
|
|
# Gets the DCE RPC object
|
|
dce = rpc_transport.get_dce_rpc()
|
|
|
|
# Set the authentication level
|
|
if self.authn_level:
|
|
dce.set_auth_level(self.authn_level)
|
|
|
|
# Connect
|
|
dce.connect()
|
|
|
|
# Bind if specified
|
|
iface_uuid = iface_uuid or self.iface_uuid
|
|
if iface_uuid and self.transfer_syntax:
|
|
dce.bind(iface_uuid, transfer_syntax=self.transfer_syntax)
|
|
elif iface_uuid:
|
|
dce.bind(iface_uuid)
|
|
|
|
return dce, rpc_transport
|
|
|
|
|
|
def open_policy(self, dce):
|
|
request = lsad.LsarOpenPolicy2()
|
|
request['SystemName'] = NULL
|
|
request['ObjectAttributes']['RootDirectory'] = NULL
|
|
request['ObjectAttributes']['ObjectName'] = NULL
|
|
request['ObjectAttributes']['SecurityDescriptor'] = NULL
|
|
request['ObjectAttributes']['SecurityQualityOfService'] = NULL
|
|
request['DesiredAccess'] = MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES
|
|
resp = dce.request(request)
|
|
return resp['PolicyHandle']
|
|
|
|
|
|
def LsarLookupNames(self, dce, policyHandle, service):
|
|
request = lsat.LsarLookupNames()
|
|
request['PolicyHandle'] = policyHandle
|
|
request['Count'] = 1
|
|
name1 = RPC_UNICODE_STRING()
|
|
name1['Data'] = 'NT Service\{}'.format(service)
|
|
request['Names'].append(name1)
|
|
request['TranslatedSids']['Sids'] = NULL
|
|
request['LookupLevel'] = lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta
|
|
resp = dce.request(request)
|
|
return resp
|
|
|
|
|
|
conf = {
|
|
"products": [
|
|
{
|
|
"name": "Bitdefender",
|
|
"services": [
|
|
{
|
|
"name": "bdredline_agent",
|
|
"description": "Bitdefender Agent RedLine Service"
|
|
},
|
|
{
|
|
"name": "BDAuxSrv",
|
|
"description": "Bitdefender Auxiliary Service"
|
|
},
|
|
{
|
|
"name": "UPDATESRV",
|
|
"description": "Bitdefender Desktop Update Service"
|
|
},
|
|
{
|
|
"name": "VSSERV",
|
|
"description": "Bitdefender Virus Shield"
|
|
},
|
|
{
|
|
"name": "bdredline",
|
|
"description": "Bitdefender RedLine Service"
|
|
}
|
|
],
|
|
"pipes": [
|
|
{
|
|
"name": "local\\msgbus\\antitracker.low\\*",
|
|
"processes": [
|
|
"bdagent.exe"
|
|
]
|
|
},
|
|
{
|
|
"name": "local\\msgbus\\aspam.actions.low\\*",
|
|
"processes": [
|
|
"bdagent.exe"
|
|
]
|
|
},
|
|
{
|
|
"name": "local\\msgbus\\bd.process.broker.pipe",
|
|
"processes": [
|
|
"bdagent.exe",
|
|
"bdservicehost.exe",
|
|
"updatesrv.exe"
|
|
]
|
|
},
|
|
{
|
|
"name": "local\\msgbus\\bdagent*",
|
|
"processes": [
|
|
"bdagent.exe"
|
|
]
|
|
},
|
|
{
|
|
"name": "local\\msgbus\\bdauxsrv",
|
|
"processes": [
|
|
"bdagent.exe",
|
|
"bdntwrk.exe"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Windows Defender",
|
|
"services": [
|
|
{
|
|
"name": "WinDefend",
|
|
"description": "Windows Defender Antivirus Service"
|
|
},
|
|
{
|
|
"name": "Sense",
|
|
"description": "Windows Defender Advanced Threat Protection Service"
|
|
},
|
|
{
|
|
"name": "WdNisSvc",
|
|
"description": "Windows Defender Antivirus Network Inspection Service"
|
|
}
|
|
],
|
|
"pipes": []
|
|
},
|
|
{
|
|
"name": "ESET",
|
|
"services": [
|
|
{
|
|
"name": "ekm",
|
|
"description": "ESET"
|
|
},
|
|
{
|
|
"name": "epfw",
|
|
"description": "ESET"
|
|
},
|
|
{
|
|
"name": "epfwlwf",
|
|
"description": "ESET"
|
|
},
|
|
{
|
|
"name": "epfwwfp",
|
|
"description": "ESET"
|
|
},
|
|
{
|
|
"name": "EraAgentSvc",
|
|
"description": "ESET"
|
|
}
|
|
],
|
|
"pipes": [
|
|
{
|
|
"name": "nod_scriptmon_pipe",
|
|
"processes": [
|
|
""
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "CrowdStrike",
|
|
"services": [
|
|
{
|
|
"name": "CSFalconService",
|
|
"description": "CrowdStrike Falcon Sensor Service"
|
|
}
|
|
],
|
|
"pipes": [
|
|
{
|
|
"name": "CrowdStrike\\{*",
|
|
"processes": [
|
|
"CSFalconContainer.exe",
|
|
"CSFalconService.exe"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "SentinelOne",
|
|
"services": [
|
|
{
|
|
"name": "SentinelAgent",
|
|
"description": "SentinelOne Endpoint Protection Agent"
|
|
},
|
|
{
|
|
"name": "SentinelStaticEngine",
|
|
"description": "Manage static engines for SentinelOne Endpoint Protection"
|
|
},
|
|
{
|
|
"name": "LogProcessorService",
|
|
"description": "Manage logs for SentinelOne Endpoint Protection"
|
|
}
|
|
],
|
|
"pipes": [
|
|
{
|
|
"name": "SentinelAgentWorkerCert.*",
|
|
"processes": [
|
|
""
|
|
]
|
|
},
|
|
{
|
|
"name": "DFIScanner.Etw.*",
|
|
"processes": [
|
|
"SentinelStaticEngine.exe"
|
|
]
|
|
},
|
|
{
|
|
"name": "DFIScanner.Inline.*",
|
|
"processes": [
|
|
"SentinelAgent.exe"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Carbon Black App Control",
|
|
"services": [
|
|
{
|
|
"name": "Parity",
|
|
"description": "Carbon Black App Control Agent"
|
|
}
|
|
],
|
|
"pipes": []
|
|
},
|
|
{
|
|
"name": "Cybereason",
|
|
"services": [
|
|
{
|
|
"name": "CybereasonActiveProbe",
|
|
"description": "Cybereason Active Probe"
|
|
},
|
|
{
|
|
"name": "CybereasonCRS",
|
|
"description": "Cybereason Anti-Ransomware"
|
|
},
|
|
{
|
|
"name": "CybereasonBlocki",
|
|
"description": "Cybereason Execution Prevention"
|
|
}
|
|
],
|
|
"pipes": [
|
|
{
|
|
"name": "CybereasonAPConsoleMinionHostIpc_*",
|
|
"processes": [
|
|
"minionhost.exe"
|
|
]
|
|
},
|
|
{
|
|
"name": "CybereasonAPServerProxyIpc_*",
|
|
"processes": [
|
|
"minionhost.exe"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Symantec Endpoint Protection",
|
|
"services": [
|
|
{
|
|
"name": "SepMasterService",
|
|
"description": "Symantec Endpoint Protection"
|
|
},
|
|
{
|
|
"name": "SepScanService",
|
|
"description": "Symantec Endpoint Protection Scan Services"
|
|
},
|
|
{
|
|
"name": "SNAC",
|
|
"description": "Symantec Network Access Control"
|
|
}
|
|
],
|
|
"pipes": []
|
|
}
|
|
]
|
|
}
|