Coverage for /root/GitHubProjects/impacket/impacket/examples/ntlmrelayx/utils/targetsutils.py : 10%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Impacket - Collection of Python classes for working with network protocols.
2#
3# SECUREAUTH LABS. Copyright (C) 2021 SecureAuth Corporation. All rights reserved.
4#
5# This software is provided under a slightly modified version
6# of the Apache Software License. See the accompanying LICENSE file
7# for more information.
8#
9# Description:
10# Target utilities
11#
12# Classes for handling specified targets and keeping state of which targets have been processed
13# Format of targets are based in URI syntax
14# scheme://netloc/path
15# where:
16# scheme: the protocol to target (e.g. 'smb', 'mssql', 'all')
17# netloc: int the form of domain\username@host:port (domain\username and port are optional, and don't forget
18# to escape the '\')
19# path: only used by specific attacks (e.g. HTTP attack).
20#
21# Some examples:
22# smb://1.1.1.1: It will target host 1.1.1.1 (protocol SMB) with any user connecting
23# mssql://contoso.com\joe@10.1.1.1: It will target host 10.1.1.1 (protocol MSSQL) only when contoso.com\joe is
24# connecting.
25#
26# Author:
27# Alberto Solino (@agsolino)
28# Dirk-jan Mollema / Fox-IT (https://www.fox-it.com)
29#
30# ToDo:
31# [ ]: Expand the ALL:// to all the supported protocols
32#
33import os
34import random
35import time
36try:
37 from urllib.parse import urlparse
38except ImportError:
39 from urlparse import urlparse
40from impacket import LOG
41from threading import Thread
44class TargetsProcessor:
45 def __init__(self, targetListFile=None, singleTarget=None, protocolClients=None, randomize=False):
46 # Here we store the attacks that already finished, mostly the ones that have usernames, since the
47 # other ones will never finish.
48 self.finishedAttacks = []
49 self.protocolClients = protocolClients
50 if targetListFile is None:
51 self.filename = None
52 self.originalTargets = self.processTarget(singleTarget, protocolClients)
53 else:
54 self.filename = targetListFile
55 self.originalTargets = []
56 self.readTargets()
58 if randomize is True:
59 # Randomize the targets based
60 random.shuffle(self.originalTargets)
62 self.generalCandidates = [x for x in self.originalTargets if x.username is None]
63 self.namedCandidates = [x for x in self.originalTargets if x.username is not None]
65 @staticmethod
66 def processTarget(target, protocolClients):
67 # Check if we have a single target, with no URI form
68 if target.find('://') <= 0:
69 # Target is a single IP, assuming it's SMB.
70 return [urlparse('smb://%s' % target)]
72 # Checks if it needs to expand the list if there's a all://*
73 retVals = []
74 if target[:3].upper() == 'ALL':
75 strippedTarget = target[3:]
76 for protocol in protocolClients:
77 retVals.append(urlparse('%s%s' % (protocol, strippedTarget)))
78 return retVals
79 else:
80 return [urlparse(target)]
82 def readTargets(self):
83 try:
84 with open(self.filename,'r') as f:
85 self.originalTargets = []
86 for line in f:
87 target = line.strip()
88 if target != '' and target[0] != '#':
89 self.originalTargets.extend(self.processTarget(target, self.protocolClients))
90 except IOError as e:
91 LOG.error("Could not open file: %s - %s", self.filename, str(e))
93 if len(self.originalTargets) == 0:
94 LOG.critical("Warning: no valid targets specified!")
96 self.generalCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x.username is None]
97 self.namedCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x.username is not None]
99 def logTarget(self, target, gotRelay = False, gotUsername = None):
100 # If the target has a username, we can safely remove it from the list. Mission accomplished.
101 if gotRelay is True:
102 if target.username is not None:
103 self.finishedAttacks.append(target)
104 elif gotUsername is not None:
105 # We have data about the username we relayed the connection for,
106 # for a target that didn't have username specified.
107 # Let's log it
108 newTarget = urlparse('%s://%s@%s%s' % (target.scheme, gotUsername.replace('/','\\'), target.netloc, target.path))
109 self.finishedAttacks.append(newTarget)
111 def getTarget(self, identity=None):
112 # ToDo: We should have another list of failed attempts (with user) and check that inside this method so we do not
113 # retry those targets.
114 if identity is not None and len(self.namedCandidates) > 0:
115 # We've been asked to match a username that is connected to us
116 # Do we have an explicit request for it?
117 for target in self.namedCandidates:
118 if target.username is not None:
119 if target.username.upper() == identity.replace('/', '\\'):
120 self.namedCandidates.remove(target)
121 return target
122 if target.username.find('\\') < 0:
123 # Username with no domain, let's compare that way
124 if target.username.upper() == identity.split('/')[1]:
125 self.namedCandidates.remove(target)
126 return target
128 # No identity match, let's just grab something from the generalCandidates list
129 # Assuming it hasn't been relayed already
130 if len(self.generalCandidates) > 0:
131 if identity is not None:
132 for target in self.generalCandidates:
133 tmpTarget = '%s://%s@%s' % (target.scheme, identity.replace('/', '\\'), target.netloc)
134 match = [x for x in self.finishedAttacks if x.geturl().upper() == tmpTarget.upper()]
135 if len(match) == 0:
136 self.generalCandidates.remove(target)
137 return target
138 LOG.debug("No more targets for user %s" % identity)
139 return None
140 else:
141 return self.generalCandidates.pop()
142 else:
143 if len(self.originalTargets) > 0:
144 self.generalCandidates = [x for x in self.originalTargets if
145 x not in self.finishedAttacks and x.username is None]
147 if len(self.generalCandidates) == 0:
148 if len(self.namedCandidates) == 0:
149 # We are here, which means all the targets are already exhausted by the client
150 LOG.info("All targets processed!")
151 elif identity is not None:
152 # This user has no more targets
153 LOG.debug("No more targets for user %s" % identity)
154 return None
155 else:
156 return self.getTarget(identity)
158class TargetsFileWatcher(Thread):
159 def __init__(self,targetprocessor):
160 Thread.__init__(self)
161 self.targetprocessor = targetprocessor
162 self.lastmtime = os.stat(self.targetprocessor.filename).st_mtime
164 def run(self):
165 while True:
166 mtime = os.stat(self.targetprocessor.filename).st_mtime
167 if mtime > self.lastmtime:
168 LOG.info('Targets file modified - refreshing')
169 self.lastmtime = mtime
170 self.targetprocessor.readTargets()
171 time.sleep(1.0)