1# Copyright (c) 2013-2017 CORE Security Technologies
2#
3# This software is provided under under a slightly modified version
4# of the Apache Software License. See the accompanying LICENSE file
5# for more information.
6#
7# Protocol Client Base Class definition
8#
9# Author:
10#  Alberto Solino (@agsolino)
11#
12# Description:
13#  Defines a base class for all clients + loads all available modules
14#
15# ToDo:
16#
17import os, sys, pkg_resources
18from impacket import LOG
19
20PROTOCOL_CLIENTS = {}
21
22# Base class for Protocol Clients for different protocols (SMB, MSSQL, etc)
23# Besides using this base class you need to define one global variable when
24# writing a plugin for protocol clients:
25# PROTOCOL_CLIENT_CLASS = "<name of the class for the plugin>"
26# PLUGIN_NAME must be the protocol name that will be matched later with the relay targets (e.g. SMB, LDAP, etc)
27class ProtocolClient:
28    PLUGIN_NAME = 'PROTOCOL'
29    def __init__(self, serverConfig, target, targetPort, extendedSecurity=True):
30        self.serverConfig = serverConfig
31        self.targetHost = target.hostname
32        # A default target port is specified by the subclass
33        if target.port is not None:
34            # We override it by the one specified in the target
35            self.targetPort = target.port
36        else:
37            self.targetPort = targetPort
38        self.target = target
39        self.extendedSecurity = extendedSecurity
40        self.session = None
41        self.sessionData = {}
42
43    def initConnection(self):
44        raise RuntimeError('Virtual Function')
45
46    def killConnection(self):
47        raise RuntimeError('Virtual Function')
48
49    def sendNegotiate(self, negotiateMessage):
50        # Charged of sending the type 1 NTLM Message
51        raise RuntimeError('Virtual Function')
52
53    def sendAuth(self, authenticateMessageBlob, serverChallenge=None):
54        # Charged of sending the type 3 NTLM Message to the Target
55        raise RuntimeError('Virtual Function')
56
57    def sendStandardSecurityAuth(self, sessionSetupData):
58        # Handle the situation When FLAGS2_EXTENDED_SECURITY is not set
59        raise RuntimeError('Virtual Function')
60
61    def getSession(self):
62        # Should return the active session for the relayed connection
63        raise RuntimeError('Virtual Function')
64
65    def getSessionData(self):
66        # Should return any extra data that could be useful for the SOCKS proxy to work (e.g. some of the
67        # answers from the original server)
68        return self.sessionData
69
70    def getStandardSecurityChallenge(self):
71        # Should return the Challenge returned by the server when Extended Security is not set
72        # This should only happen with against old Servers. By default we return None
73        return None
74
75    def keepAlive(self):
76        # Charged of keeping connection alive
77        raise RuntimeError('Virtual Function')
78
79for file in pkg_resources.resource_listdir('impacket.examples.ntlmrelayx', 'clients'):
80    if file.find('__') >=0 or os.path.splitext(file)[1] == '.pyc':
81        continue
82    __import__(__package__ + '.' + os.path.splitext(file)[0])
83    module = sys.modules[__package__ + '.' + os.path.splitext(file)[0]]
84    try:
85        pluginClasses = set()
86        try:
87            if hasattr(module,'PROTOCOL_CLIENT_CLASSES'):
88                for pluginClass in module.PROTOCOL_CLIENT_CLASSES:
89                    pluginClasses.add(getattr(module, pluginClass))
90            else:
91                pluginClasses.add(getattr(module, getattr(module, 'PROTOCOL_CLIENT_CLASS')))
92        except Exception, e:
93            LOG.debug(e)
94            pass
95
96        for pluginClass in pluginClasses:
97            LOG.info('Protocol Client %s loaded..' % pluginClass.PLUGIN_NAME)
98            PROTOCOL_CLIENTS[pluginClass.PLUGIN_NAME] = pluginClass
99    except Exception, e:
100        LOG.debug(str(e))
101
102