# DON'T USE THIS VERSION! # Try https://gist.github.com/wdormann/89ed779933fe205fb52ecf3eacf5ff40 instead import os import subprocess # See: https://blogs.msmvps.com/erikr/2007/09/26/set-permissions-on-a-specific-service-windows/ svcinfo = {} FNULL = open(os.devnull, 'w') win10builtin = ['AppVClient', 'ClickToRunSvc', 'COMSysApp', 'diagnosticshub.standardcollector.service', 'msiserver', 'ose', 'perceptionsimulation', 'SecurityHealthService', 'Sense', 'SensorDataService', 'SgrmBroker', 'Spooler', 'ssh-agent', 'TieringEngineService', 'TrustedInstaller', 'UevAgentService', 'vds', 'VSS', 'wbengine', 'WinDefend', 'wmiApSrv', 'WSearch'] def sliceperms(permstring): permparts = [] if permstring: parts = int(len(permstring)) # print('%s parts' % parts) for i in range(0, parts, 2): # print(permstring[i:i+2]) permparts.append(permstring[i:i + 2]) return permparts def getsvcacls(svcname): svcacl = None try: svcacl = subprocess.check_output(['sc', 'sdshow', svcname], stderr=FNULL).decode('utf-8', 'backslashreplace').strip() except subprocess.CalledProcessError: pass return svcacl def whichfile(file): if file: fullpath = '' try: fullpath = subprocess.check_output(['where', file, ], stderr=FNULL).decode('utf-8', 'backslashreplace').strip() except subprocess.CalledProcessError: pass return fullpath def svchosttarget(svcname): parsed = '' svctarget = '' try: parsed = subprocess.check_output(['reg', 'query', r'HKLM\SYSTEM\CurrentControlSet\Services\%s\Parameters' % svcname], stderr=FNULL).decode('utf-8', 'backslashreplace') except subprocess.CalledProcessError: pass for line in parsed.splitlines(): if ' servicedll ' in line.lower(): lineparts = line.split(' REG_EXPAND_SZ ') svctarget = os.path.expandvars((lineparts[-1])) if not os.path.exists(svctarget): svctarget = whichfile(svctarget) return svctarget def checkservices(): nameindex = None dispnameindex = None privindex = None stateindex = None pathindex = None startmodeindex = None parsed = subprocess.check_output(['wmic', 'service', 'get', 'name,startname,displayname,state,pathname,startmode,' 'DesktopInteract', '/format:csv'], stderr=FNULL).decode( 'utf-8', 'backslashreplace') for line in parsed.splitlines(): if line: columns = line.split(',') if line.startswith('Node,'): nameindex = columns.index('Name') dispnameindex = columns.index('DisplayName') privindex = columns.index('StartName') stateindex = columns.index('State') pathindex = columns.index('PathName') startmodeindex = columns.index('StartMode') desktopindex = columns.index('DesktopInteract') else: reasons = [] svcname = columns[nameindex] svcdict = {} svcdict['priv'] = columns[privindex] svcdict['dispname'] = columns[dispnameindex] svcdict['state'] = columns[stateindex] svcdict['path'] = columns[pathindex] svcdict['startmode'] = columns[startmodeindex] svcdict['desktop'] = columns[desktopindex] if svcdict['desktop'].lower() == 'true': svcdict['desktop'] = True else: svcdict['desktop'] = False if 'svchost.exe' in svcdict['path']: realtarget = svchosttarget(svcname) if realtarget: # print('%s uses svchost: %s' % (svcname,realtarget)) svcdict['path'] = realtarget elif '"' in svcdict['path']: # Quoted path splitpath = svcdict['path'].split('"') if len(splitpath) > 2 and splitpath[2]: # Quoted path with arguments svcdict['path'] = '"%s"' % splitpath[1] else: # Quoted path without arguments pass else: # Non-quoted path splitpath = svcdict['path'].split() if len(splitpath) > 1: # Non-quoted path with arguments svcdict['path'] = splitpath[0] svcinfo[svcname] = svcdict if (svcdict['priv'].lower() == 'localsystem') and not svcdict[ 'path'].endswith('lsass.exe') and svcdict['path'].lower().replace('"', '').endswith('.exe'): reasons.append('User-controlled and high-privileged') reasons = ', '.join(reasons) if reasons and svcname not in win10builtin: print('Service: %s' % svcname) print('Display name: %s' % svcinfo[svcname]['dispname']) print('Privilege: %s' % svcinfo[svcname]['priv']) print('Path: %s' % svcinfo[svcname]['path']) print('') if __name__ == "__main__": checkservices()