Coverage for /root/GitHubProjects/impacket/impacket/examples/smbclient.py: 10%

# Coverage for /root/GitHubProjects/impacket/impacket/examples/smbclient.py : 10%

## 391 statements

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# Description: Mini shell using some of the SMB funcionality of the library

8#

9# Author:

10# Alberto Solino (@agsolino)

11#

12#

13# Reference for:

14# SMB DCE/RPC

15#

16 from __future__ import division

17 from __future__ import print_function

18 from io import BytesIO

19 import sys

20 import time

21 import cmd

22 import os

23 import ntpath

24

25 from six import PY2

26 from impacket.dcerpc.v5 import samr, transport, srvs

27 from impacket.dcerpc.v5.dtypes import NULL

28 from impacket import LOG

29 from impacket.smbconnection import SMBConnection, SMB2_DIALECT_002, SMB2_DIALECT_21, SMB_DIALECT, SessionError, \

30 FILE_READ_DATA, FILE_SHARE_READ, FILE_SHARE_WRITE

31 from impacket.smb3structs import FILE_DIRECTORY_FILE, FILE_LIST_DIRECTORY

32

33 import chardet

34

35

36# If you wanna have readline like functionality in Windows, install pyreadline

37 try:

38 import pyreadline as readline

39 except ImportError:

40 import readline

41

42 class MiniImpacketShell(cmd.Cmd):

43 def __init__(self, smbClient, tcpShell=None):

44 #If the tcpShell parameter is passed (used in ntlmrelayx),

45 # all input and output is redirected to a tcp socket

46 # instead of to stdin / stdout

47 if tcpShell is not None:

48 cmd.Cmd.__init__(self, stdin=tcpShell.stdin, stdout=tcpShell.stdout)

49 sys.stdout = tcpShell.stdout

50 sys.stdin = tcpShell.stdin

51 sys.stderr = tcpShell.stdout

52 self.use_rawinput = False

53 self.shell = tcpShell

54 else:

55 cmd.Cmd.__init__(self)

56 self.shell = None

57

58 self.prompt = '# '

59 self.smb = smbClient

60 self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, self.TGT, self.TGS = smbClient.getCredentials()

61 self.tid = None

62 self.intro = 'Type help for list of commands'

63 self.pwd = ''

64 self.share = None

65 self.loggedIn = True

66 self.last_output = None

67 self.completion = []

68

69 def emptyline(self):

70 pass

71

72 def precmd(self,line):

73 # switch to unicode

74 if PY2:

75 return line.decode('utf-8')

76 return line

77

78 def onecmd(self,s):

79 retVal = False

80 try:

81 retVal = cmd.Cmd.onecmd(self,s)

82 except Exception as e:

83 LOG.error(e)

84 LOG.debug('Exception info', exc_info=True)

85

86 return retVal

87

88 def do_exit(self,line):

89 if self.shell is not None:

90 self.shell.close()

91 return True

92

93 def do_shell(self, line):

94 output = os.popen(line).read()

95 print(output)

96 self.last_output = output

97

98 def do_help(self,line):

99 print("""

100 open {host,port=445} - opens a SMB connection against the target host/port

101 login {domain/username,passwd} - logs into the current SMB connection, no parameters for NULL connection. If no password specified, it'll be prompted

102 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

103 login_hash {domain/username,lmhash:nthash} - logs into the current SMB connection using the password hashes

104 logoff - logs off

105 shares - list available shares

106 use {sharename} - connect to an specific share

107 cd {path} - changes the current directory to {path}

108 lcd {path} - changes the current local directory to {path}

109 pwd - shows current remote directory

110 password - changes the user password, the new password will be prompted for input

111 ls {wildcard} - lists all the files in the current directory

112 rm {file} - removes the selected file

113 mkdir {dirname} - creates the directory under the current path

114 rmdir {dirname} - removes the directory under the current path

115 put {filename} - uploads the filename into the current path

116 get {filename} - downloads the filename from the current path

117 cat {filename} - reads the filename from the current path

118 mount {target,path} - creates a mount point from {path} to {target} (admin required)

119 umount {path} - removes the mount point at {path} without deleting the directory (admin required)

120 list_snapshots {path} - lists the vss snapshots for the specified path

121 info - returns NetrServerInfo main results

122 who - returns the sessions currently connected at the target host (admin required)

123 close - closes the current SMB Session

124 exit - terminates the server process (and this session)

125

126""")

127

128 def do_password(self, line):

129 if self.loggedIn is False:

130 LOG.error("Not logged in")

131 return

132 from getpass import getpass

133 newPassword = getpass("New Password:")

134 rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\samr', smb_connection = self.smb)

135 dce = rpctransport.get_dce_rpc()

136 dce.connect()

137 dce.bind(samr.MSRPC_UUID_SAMR)

138 samr.hSamrUnicodeChangePasswordUser2(dce, '\x00', self.username, self.password, newPassword, self.lmhash, self.nthash)

139 self.password = newPassword

140 self.lmhash = None

141 self.nthash = None

142

143 def do_open(self,line):

144 l = line.split(' ')

145 port = 445

146 if len(l) > 0:

147 host = l[0]

148 if len(l) > 1:

149 port = int(l[1])

150

151

152 if port == 139:

153 self.smb = SMBConnection('*SMBSERVER', host, sess_port=port)

154 else:

155 self.smb = SMBConnection(host, host, sess_port=port)

156

157 dialect = self.smb.getDialect()

158 if dialect == SMB_DIALECT:

159 LOG.info("SMBv1 dialect used")

160 elif dialect == SMB2_DIALECT_002:

161 LOG.info("SMBv2.0 dialect used")

162 elif dialect == SMB2_DIALECT_21:

163 LOG.info("SMBv2.1 dialect used")

164 else:

165 LOG.info("SMBv3.0 dialect used")

166

167 self.share = None

168 self.tid = None

169 self.pwd = ''

170 self.loggedIn = False

171 self.password = None

172 self.lmhash = None

173 self.nthash = None

174 self.username = None

175

176 def do_login(self,line):

177 if self.smb is None:

178 LOG.error("No connection open")

179 return

180 l = line.split(' ')

181 username = ''

182 password = ''

183 domain = ''

184 if len(l) > 0:

185 username = l[0]

186 if len(l) > 1:

187 password = l[1]

188

189 if username.find('/') > 0:

190 domain, username = username.split('/')

191

192 if password == '' and username != '':

193 from getpass import getpass

194 password = getpass("Password:")

195

196 self.smb.login(username, password, domain=domain)

197 self.password = password

198 self.username = username

199

200 if self.smb.isGuestSession() > 0:

201 LOG.info("GUEST Session Granted")

202 else:

203 LOG.info("USER Session Granted")

204 self.loggedIn = True

205

206 def do_kerberos_login(self,line):

207 if self.smb is None:

208 LOG.error("No connection open")

209 return

210 l = line.split(' ')

211 username = ''

212 password = ''

213 domain = ''

214 if len(l) > 0:

215 username = l[0]

216 if len(l) > 1:

217 password = l[1]

218

219 if username.find('/') > 0:

220 domain, username = username.split('/')

221

222 if domain == '':

223 LOG.error("Domain must be specified for Kerberos login")

224 return

225

226 if password == '' and username != '':

227 from getpass import getpass

228 password = getpass("Password:")

229

230 self.smb.kerberosLogin(username, password, domain=domain)

231 self.password = password

232 self.username = username

233

234 if self.smb.isGuestSession() > 0:

235 LOG.info("GUEST Session Granted")

236 else:

237 LOG.info("USER Session Granted")

238 self.loggedIn = True

239

240 def do_login_hash(self,line):

241 if self.smb is None:

242 LOG.error("No connection open")

243 return

244 l = line.split(' ')

245 domain = ''

246 if len(l) > 0:

247 username = l[0]

248 if len(l) > 1:

249 hashes = l[1]

250 else:

251 LOG.error("Hashes needed. Format is lmhash:nthash")

252 return

253

254 if username.find('/') > 0:

255 domain, username = username.split('/')

256

257 lmhash, nthash = hashes.split(':')

258

259 self.smb.login(username, '', domain,lmhash=lmhash, nthash=nthash)

260 self.username = username

261 self.lmhash = lmhash

262 self.nthash = nthash

263

264 if self.smb.isGuestSession() > 0:

265 LOG.info("GUEST Session Granted")

266 else:

267 LOG.info("USER Session Granted")

268 self.loggedIn = True

269

270 def do_logoff(self, line):

271 if self.smb is None:

272 LOG.error("No connection open")

273 return

274 self.smb.logoff()

275 del self.smb

276 self.share = None

277 self.smb = None

278 self.tid = None

279 self.pwd = ''

280 self.loggedIn = False

281 self.password = None

282 self.lmhash = None

283 self.nthash = None

284 self.username = None

285

286 def do_info(self, line):

287 if self.loggedIn is False:

288 LOG.error("Not logged in")

289 return

290 rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb)

291 dce = rpctransport.get_dce_rpc()

292 dce.connect()

293 dce.bind(srvs.MSRPC_UUID_SRVS)

294 resp = srvs.hNetrServerGetInfo(dce, 102)

295

296 print("Version Major: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_major'])

297 print("Version Minor: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_minor'])

298 print("Server Name: %s" % resp['InfoStruct']['ServerInfo102']['sv102_name'])

299 print("Server Comment: %s" % resp['InfoStruct']['ServerInfo102']['sv102_comment'])

300 print("Server UserPath: %s" % resp['InfoStruct']['ServerInfo102']['sv102_userpath'])

301 print("Simultaneous Users: %d" % resp['InfoStruct']['ServerInfo102']['sv102_users'])

302

303 def do_who(self, line):

304 if self.loggedIn is False:

305 LOG.error("Not logged in")

306 return

307 rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb)

308 dce = rpctransport.get_dce_rpc()

309 dce.connect()

310 dce.bind(srvs.MSRPC_UUID_SRVS)

311 resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 10)

312

313 for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']:

314 print("host: %15s, user: %5s, active: %5d, idle: %5d" % (

315 session['sesi10_cname'][:-1], session['sesi10_username'][:-1], session['sesi10_time'],

316 session['sesi10_idle_time']))

317

318 def do_shares(self, line):

319 if self.loggedIn is False:

320 LOG.error("Not logged in")

321 return

322 resp = self.smb.listShares()

323 for i in range(len(resp)):

324 print(resp[i]['shi1_netname'][:-1])

325

326 def do_use(self,line):

327 if self.loggedIn is False:

328 LOG.error("Not logged in")

329 return

330 self.share = line

331 self.tid = self.smb.connectTree(line)

332 self.pwd = '\\'

333 self.do_ls('', False)

334

335 def complete_cd(self, text, line, begidx, endidx):

336 return self.complete_get(text, line, begidx, endidx, include = 2)

337

338 def do_cd(self, line):

339 if self.tid is None:

340 LOG.error("No share selected")

341 return

342 p = line.replace('/','\\')

343 oldpwd = self.pwd

344 if p[0] == '\\':

345 self.pwd = line

346 else:

347 self.pwd = ntpath.join(self.pwd, line)

348 self.pwd = ntpath.normpath(self.pwd)

349 # Let's try to open the directory to see if it's valid

350 try:

351 fid = self.smb.openFile(self.tid, self.pwd, creationOption = FILE_DIRECTORY_FILE, desiredAccess = FILE_READ_DATA |

352 FILE_LIST_DIRECTORY, shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE )

353 self.smb.closeFile(self.tid,fid)

354 except SessionError:

355 self.pwd = oldpwd

356 raise

357

358 def do_lcd(self, s):

359 print(s)

360 if s == '':

361 print(os.getcwd())

362 else:

363 os.chdir(s)

364

365 def do_pwd(self,line):

366 if self.loggedIn is False:

367 LOG.error("Not logged in")

368 return

369 print(self.pwd)

370

371 def do_ls(self, wildcard, display = True):

372 if self.loggedIn is False:

373 LOG.error("Not logged in")

374 return

375 if self.tid is None:

376 LOG.error("No share selected")

377 return

378 if wildcard == '':

379 pwd = ntpath.join(self.pwd,'*')

380 else:

381 pwd = ntpath.join(self.pwd, wildcard)

382 self.completion = []

383 pwd = pwd.replace('/','\\')

384 pwd = ntpath.normpath(pwd)

385 for f in self.smb.listPath(self.share, pwd):

386 if display is True:

387 print("%crw-rw-rw- %10d %s %s" % (

388 'd' if f.is_directory() > 0 else '-', f.get_filesize(), time.ctime(float(f.get_mtime_epoch())),

389 f.get_longname()))

390 self.completion.append((f.get_longname(), f.is_directory()))

391

392

393 def do_rm(self, filename):

394 if self.tid is None:

395 LOG.error("No share selected")

396 return

397 f = ntpath.join(self.pwd, filename)

398 file = f.replace('/','\\')

399 self.smb.deleteFile(self.share, file)

400

401 def do_mkdir(self, path):

402 if self.tid is None:

403 LOG.error("No share selected")

404 return

405 p = ntpath.join(self.pwd, path)

406 pathname = p.replace('/','\\')

407 self.smb.createDirectory(self.share,pathname)

408

409 def do_rmdir(self, path):

410 if self.tid is None:

411 LOG.error("No share selected")

412 return

413 p = ntpath.join(self.pwd, path)

414 pathname = p.replace('/','\\')

415 self.smb.deleteDirectory(self.share, pathname)

416

417 def do_put(self, pathname):

418 if self.tid is None:

419 LOG.error("No share selected")

420 return

421 src_path = pathname

422 dst_name = os.path.basename(src_path)

423

424 fh = open(pathname, 'rb')

425 f = ntpath.join(self.pwd,dst_name)

426 finalpath = f.replace('/','\\')

427 self.smb.putFile(self.share, finalpath, fh.read)

428 fh.close()

429

430 def complete_get(self, text, line, begidx, endidx, include = 1):

431 # include means

432 # 1 just files

433 # 2 just directories

434 p = line.replace('/','\\')

435 if p.find('\\') < 0:

436 items = []

437 if include == 1:

438 mask = 0

439 else:

440 mask = 0x010

441 for i in self.completion:

442 if i[1] == mask:

443 items.append(i[0])

444 if text:

445 return [

446 item for item in items

447 if item.upper().startswith(text.upper())

448 ]

449 else:

450 return items

451

452 def do_get(self, filename):

453 if self.tid is None:

454 LOG.error("No share selected")

455 return

456 filename = filename.replace('/','\\')

457 fh = open(ntpath.basename(filename),'wb')

458 pathname = ntpath.join(self.pwd,filename)

459 try:

460 self.smb.getFile(self.share, pathname, fh.write)

461 except:

462 fh.close()

463 os.remove(filename)

464 raise

465 fh.close()

466

467 def do_cat(self, filename):

468 if self.tid is None:

469 LOG.error("No share selected")

470 return

471 filename = filename.replace('/','\\')

472 fh = BytesIO()

473 pathname = ntpath.join(self.pwd,filename)

474 try:

475 self.smb.getFile(self.share, pathname, fh.write)

476 except:

477 raise

478 output = fh.getvalue()

479 encoding = chardet.detect(output)["encoding"]

480 error_msg = "[-] Output cannot be correctly decoded, are you sure the text is readable ?"

481 if encoding:

482 try:

483 print(output.decode(encoding))

484 except:

485 print(error_msg)

486 finally:

487 fh.close()

488 else:

489 print(error_msg)

490 fh.close()

491

492 def do_close(self, line):

493 self.do_logoff(line)

494

495 def do_list_snapshots(self, line):

496 l = line.split(' ')

497 if len(l) > 0:

498 pathName= l[0].replace('/','\\')

499

500 # Relative or absolute path?

501 if pathName.startswith('\\') is not True:

502 pathName = ntpath.join(self.pwd, pathName)

503

504 snapshotList = self.smb.listSnapshots(self.tid, pathName)

505

506 if not snapshotList:

507 print("No snapshots found")

508 return

509

510 for timestamp in snapshotList:

511 print(timestamp)

512

513 def do_mount(self, line):

514 l = line.split(' ')

515 if len(l) > 1:

516 target = l[0].replace('/','\\')

517 pathName= l[1].replace('/','\\')

518

519 # Relative or absolute path?

520 if pathName.startswith('\\') is not True:

521 pathName = ntpath.join(self.pwd, pathName)

522

523 self.smb.createMountPoint(self.tid, pathName, target)

524

525 def do_umount(self, mountpoint):

526 mountpoint = mountpoint.replace('/','\\')

527

528 # Relative or absolute path?

529 if mountpoint.startswith('\\') is not True:

530 mountpoint = ntpath.join(self.pwd, mountpoint)

531

532 mountPath = ntpath.join(self.pwd, mountpoint)

533

534 self.smb.removeMountPoint(self.tid, mountPath)

535

536 def do_EOF(self, line):

537 print('Bye!\n')

538 return True