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# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

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

8# You provide an already established connection and an exefile 

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

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

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

12# 

13# Author: 

14# Alberto Solino (@agsolino) 

15# 

16 

17import random 

18import string 

19 

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

21from impacket import smb,smb3, LOG 

22from impacket.smbconnection import SMBConnection 

23from impacket.smb3structs import FILE_WRITE_DATA, FILE_DIRECTORY_FILE 

24 

25class ServiceInstall: 

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

27 self._rpctransport = 0 

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

29 

30 if binary_service_name is None: 

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

32 else: 

33 self.__binary_service_name = binary_service_name 

34 

35 self.__exeFile = exeFile 

36 

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

38 # with a SMBConnection one 

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

40 self.connection = SMBConnection(existingConnection = SMBObject) 

41 else: 

42 self.connection = SMBObject 

43 

44 self.share = '' 

45 

46 def getShare(self): 

47 return self.share 

48 

49 def getShares(self): 

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

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

52 try: 

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

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

55 smb_connection = self.connection) 

56 dce_srvs = self._rpctransport.get_dce_rpc() 

57 dce_srvs.connect() 

58 

59 dce_srvs.bind(srvs.MSRPC_UUID_SRVS) 

60 resp = srvs.hNetrShareEnum(dce_srvs, 1) 

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

62 except: 

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

64 raise 

65 

66 

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

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

69 

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

71 try: 

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

73 except Exception as e: 

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

75 # We're good, pass the exception 

76 pass 

77 else: 

78 raise e 

79 else: 

80 # It exists, remove it 

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

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

83 

84 # Create the service 

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

86 try: 

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

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

89 except: 

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

91 raise 

92 else: 

93 return resp['lpServiceHandle'] 

94 

95 def openSvcManager(self): 

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

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

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

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

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

101 self.rpcsvc.connect() 

102 self.rpcsvc.bind(scmr.MSRPC_UUID_SCMR) 

103 try: 

104 resp = scmr.hROpenSCManagerW(self.rpcsvc) 

105 except: 

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

107 raise Exception('Unable to open SVCManager') 

108 else: 

109 return resp['lpScHandle'] 

110 

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

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

113 if isinstance(src, str): 

114 # We have a filename 

115 fh = open(src, 'rb') 

116 else: 

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

118 fh = src 

119 f = dst 

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

121 try: 

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

123 except: 

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

125 raise 

126 fh.close() 

127 

128 def findWritableShare(self, shares): 

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

130 writeableShare = None 

131 for i in shares['Buffer']: 

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

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

134 tid = 0 

135 try: 

136 tid = self.connection.connectTree(share) 

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

138 except: 

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

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

141 pass 

142 else: 

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

144 writeableShare = str(share) 

145 break 

146 finally: 

147 if tid != 0: 

148 self.connection.disconnectTree(tid) 

149 return writeableShare 

150 

151 def install(self): 

152 if self.connection.isGuestSession(): 

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

154 self.connection.logoff() 

155 del self.connection 

156 else: 

157 fileCopied = False 

158 serviceCreated = False 

159 # Do the stuff here 

160 try: 

161 # Let's get the shares 

162 shares = self.getShares() 

163 self.share = self.findWritableShare(shares) 

164 if self.share is None: 

165 return False 

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

167 fileCopied = True 

168 svcManager = self.openSvcManager() 

169 if svcManager != 0: 

170 serverName = self.connection.getServerName() 

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

172 path = '%systemroot%' 

173 else: 

174 if serverName != '': 

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

176 else: 

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

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

179 serviceCreated = True 

180 if service != 0: 

181 # Start service 

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

183 try: 

184 scmr.hRStartServiceW(self.rpcsvc, service) 

185 except: 

186 pass 

187 scmr.hRCloseServiceHandle(self.rpcsvc, service) 

188 scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) 

189 return True 

190 except Exception as e: 

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

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

193 try: 

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

195 except: 

196 pass 

197 if fileCopied is True: 

198 try: 

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

200 except: 

201 pass 

202 if serviceCreated is True: 

203 try: 

204 scmr.hRDeleteService(self.rpcsvc, service) 

205 except: 

206 pass 

207 return False 

208 

209 def uninstall(self): 

210 fileCopied = True 

211 serviceCreated = True 

212 # Do the stuff here 

213 try: 

214 # Let's get the shares 

215 svcManager = self.openSvcManager() 

216 if svcManager != 0: 

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

218 service = resp['lpServiceHandle'] 

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

220 try: 

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

222 except: 

223 pass 

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

225 scmr.hRDeleteService(self.rpcsvc, service) 

226 scmr.hRCloseServiceHandle(self.rpcsvc, service) 

227 scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) 

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

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

230 except Exception: 

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

232 try: 

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

234 except: 

235 pass 

236 if fileCopied is True: 

237 try: 

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

239 except: 

240 try: 

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

242 except: 

243 pass 

244 pass 

245 if serviceCreated is True: 

246 try: 

247 scmr.hRDeleteService(self.rpcsvc, service) 

248 except: 

249 pass