Hide keyboard shortcuts

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) 2019 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# Service Install Helper library used by psexec and smbrelayx 

11# You provide an already established connection and an exefile 

12# (or class that mimics a file class) and this will install and 

13# execute the service, and then uninstall (install(), uninstall(). 

14# It tries to take care as much as possible to leave everything clean. 

15# 

16# Author: 

17# Alberto Solino (@agsolino) 

18# 

19 

20import random 

21import string 

22 

23from impacket.dcerpc.v5 import transport, srvs, scmr 

24from impacket import smb,smb3, LOG 

25from impacket.smbconnection import SMBConnection 

26from impacket.smb3structs import FILE_WRITE_DATA, FILE_DIRECTORY_FILE 

27 

28class ServiceInstall: 

29 def __init__(self, SMBObject, exeFile, serviceName='', binary_service_name=None): 

30 self._rpctransport = 0 

31 self.__service_name = serviceName if len(serviceName) > 0 else ''.join([random.choice(string.ascii_letters) for i in range(4)]) 

32 

33 if binary_service_name is None: 

34 self.__binary_service_name = ''.join([random.choice(string.ascii_letters) for i in range(8)]) + '.exe' 

35 else: 

36 self.__binary_service_name = binary_service_name 

37 

38 self.__exeFile = exeFile 

39 

40 # We might receive two different types of objects, always end up 

41 # with a SMBConnection one 

42 if isinstance(SMBObject, smb.SMB) or isinstance(SMBObject, smb3.SMB3): 

43 self.connection = SMBConnection(existingConnection = SMBObject) 

44 else: 

45 self.connection = SMBObject 

46 

47 self.share = '' 

48 

49 def getShare(self): 

50 return self.share 

51 

52 def getShares(self): 

53 # Setup up a DCE SMBTransport with the connection already in place 

54 LOG.info("Requesting shares on %s....." % (self.connection.getRemoteHost())) 

55 try: 

56 self._rpctransport = transport.SMBTransport(self.connection.getRemoteHost(), 

57 self.connection.getRemoteHost(),filename = r'\srvsvc', 

58 smb_connection = self.connection) 

59 dce_srvs = self._rpctransport.get_dce_rpc() 

60 dce_srvs.connect() 

61 

62 dce_srvs.bind(srvs.MSRPC_UUID_SRVS) 

63 resp = srvs.hNetrShareEnum(dce_srvs, 1) 

64 return resp['InfoStruct']['ShareInfo']['Level1'] 

65 except: 

66 LOG.critical("Error requesting shares on %s, aborting....." % (self.connection.getRemoteHost())) 

67 raise 

68 

69 

70 def createService(self, handle, share, path): 

71 LOG.info("Creating service %s on %s....." % (self.__service_name, self.connection.getRemoteHost())) 

72 

73 # First we try to open the service in case it exists. If it does, we remove it. 

74 try: 

75 resp = scmr.hROpenServiceW(self.rpcsvc, handle, self.__service_name+'\x00') 

76 except Exception as e: 

77 if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') >= 0: 

78 # We're good, pass the exception 

79 pass 

80 else: 

81 raise e 

82 else: 

83 # It exists, remove it 

84 scmr.hRDeleteService(self.rpcsvc, resp['lpServiceHandle']) 

85 scmr.hRCloseServiceHandle(self.rpcsvc, resp['lpServiceHandle']) 

86 

87 # Create the service 

88 command = '%s\\%s' % (path, self.__binary_service_name) 

89 try: 

90 resp = scmr.hRCreateServiceW(self.rpcsvc, handle,self.__service_name + '\x00', self.__service_name + '\x00', 

91 lpBinaryPathName=command + '\x00', dwStartType=scmr.SERVICE_DEMAND_START) 

92 except: 

93 LOG.critical("Error creating service %s on %s" % (self.__service_name, self.connection.getRemoteHost())) 

94 raise 

95 else: 

96 return resp['lpServiceHandle'] 

97 

98 def openSvcManager(self): 

99 LOG.info("Opening SVCManager on %s....." % self.connection.getRemoteHost()) 

100 # Setup up a DCE SMBTransport with the connection already in place 

101 self._rpctransport = transport.SMBTransport(self.connection.getRemoteHost(), self.connection.getRemoteHost(), 

102 filename = r'\svcctl', smb_connection = self.connection) 

103 self.rpcsvc = self._rpctransport.get_dce_rpc() 

104 self.rpcsvc.connect() 

105 self.rpcsvc.bind(scmr.MSRPC_UUID_SCMR) 

106 try: 

107 resp = scmr.hROpenSCManagerW(self.rpcsvc) 

108 except: 

109 LOG.critical("Error opening SVCManager on %s....." % self.connection.getRemoteHost()) 

110 raise Exception('Unable to open SVCManager') 

111 else: 

112 return resp['lpScHandle'] 

113 

114 def copy_file(self, src, tree, dst): 

115 LOG.info("Uploading file %s" % dst) 

116 if isinstance(src, str): 

117 # We have a filename 

118 fh = open(src, 'rb') 

119 else: 

120 # We have a class instance, it must have a read method 

121 fh = src 

122 f = dst 

123 pathname = f.replace('/','\\') 

124 try: 

125 self.connection.putFile(tree, pathname, fh.read) 

126 except: 

127 LOG.critical("Error uploading file %s, aborting....." % dst) 

128 raise 

129 fh.close() 

130 

131 def findWritableShare(self, shares): 

132 # Check we can write a file on the shares, stop in the first one 

133 writeableShare = None 

134 for i in shares['Buffer']: 

135 if i['shi1_type'] == srvs.STYPE_DISKTREE or i['shi1_type'] == srvs.STYPE_SPECIAL: 

136 share = i['shi1_netname'][:-1] 

137 tid = 0 

138 try: 

139 tid = self.connection.connectTree(share) 

140 self.connection.openFile(tid, '\\', FILE_WRITE_DATA, creationOption=FILE_DIRECTORY_FILE) 

141 except: 

142 LOG.debug('Exception', exc_info=True) 

143 LOG.critical("share '%s' is not writable." % share) 

144 pass 

145 else: 

146 LOG.info('Found writable share %s' % share) 

147 writeableShare = str(share) 

148 break 

149 finally: 

150 if tid != 0: 

151 self.connection.disconnectTree(tid) 

152 return writeableShare 

153 

154 def install(self): 

155 if self.connection.isGuestSession(): 

156 LOG.critical("Authenticated as Guest. Aborting") 

157 self.connection.logoff() 

158 del self.connection 

159 else: 

160 fileCopied = False 

161 serviceCreated = False 

162 # Do the stuff here 

163 try: 

164 # Let's get the shares 

165 shares = self.getShares() 

166 self.share = self.findWritableShare(shares) 

167 if self.share is None: 

168 return False 

169 self.copy_file(self.__exeFile ,self.share,self.__binary_service_name) 

170 fileCopied = True 

171 svcManager = self.openSvcManager() 

172 if svcManager != 0: 

173 serverName = self.connection.getServerName() 

174 if self.share.lower() == 'admin$': 

175 path = '%systemroot%' 

176 else: 

177 if serverName != '': 

178 path = '\\\\%s\\%s' % (serverName, self.share) 

179 else: 

180 path = '\\\\127.0.0.1\\' + self.share 

181 service = self.createService(svcManager, self.share, path) 

182 serviceCreated = True 

183 if service != 0: 

184 # Start service 

185 LOG.info('Starting service %s.....' % self.__service_name) 

186 try: 

187 scmr.hRStartServiceW(self.rpcsvc, service) 

188 except: 

189 pass 

190 scmr.hRCloseServiceHandle(self.rpcsvc, service) 

191 scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) 

192 return True 

193 except Exception as e: 

194 LOG.critical("Error performing the installation, cleaning up: %s" %e) 

195 LOG.debug("Exception", exc_info=True) 

196 try: 

197 scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP) 

198 except: 

199 pass 

200 if fileCopied is True: 

201 try: 

202 self.connection.deleteFile(self.share, self.__binary_service_name) 

203 except: 

204 pass 

205 if serviceCreated is True: 

206 try: 

207 scmr.hRDeleteService(self.rpcsvc, service) 

208 except: 

209 pass 

210 return False 

211 

212 def uninstall(self): 

213 fileCopied = True 

214 serviceCreated = True 

215 # Do the stuff here 

216 try: 

217 # Let's get the shares 

218 svcManager = self.openSvcManager() 

219 if svcManager != 0: 

220 resp = scmr.hROpenServiceW(self.rpcsvc, svcManager, self.__service_name+'\x00') 

221 service = resp['lpServiceHandle'] 

222 LOG.info('Stopping service %s.....' % self.__service_name) 

223 try: 

224 scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP) 

225 except: 

226 pass 

227 LOG.info('Removing service %s.....' % self.__service_name) 

228 scmr.hRDeleteService(self.rpcsvc, service) 

229 scmr.hRCloseServiceHandle(self.rpcsvc, service) 

230 scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) 

231 LOG.info('Removing file %s.....' % self.__binary_service_name) 

232 self.connection.deleteFile(self.share, self.__binary_service_name) 

233 except Exception: 

234 LOG.critical("Error performing the uninstallation, cleaning up" ) 

235 try: 

236 scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP) 

237 except: 

238 pass 

239 if fileCopied is True: 

240 try: 

241 self.connection.deleteFile(self.share, self.__binary_service_name) 

242 except: 

243 try: 

244 self.connection.deleteFile(self.share, self.__binary_service_name) 

245 except: 

246 pass 

247 pass 

248 if serviceCreated is True: 

249 try: 

250 scmr.hRDeleteService(self.rpcsvc, service) 

251 except: 

252 pass