Skip to content

Commit

Permalink
mssqlclient: Add -target-ip (#1648)
Browse files Browse the repository at this point in the history
* mssqlclient: Enable Kerberos authentication without DNS lookup

* Group connection parameters under 'connection'
  • Loading branch information
Palkovsky authored Jan 16, 2024
1 parent 6c9a1aa commit 82267d8
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 11 deletions.
16 changes: 13 additions & 3 deletions examples/mssqlclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
parser = argparse.ArgumentParser(add_help = True, description = "TDS client implementation (SSL supported).")

parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
parser.add_argument('-port', action='store', default='1433', help='target MSSQL port (default 1433)')
parser.add_argument('-db', action='store', help='MSSQL database instance (default None)')
parser.add_argument('-windows-auth', action='store_true', default=False, help='whether or not to use Windows '
'Authentication (default False)')
Expand All @@ -52,8 +51,16 @@
'ones specified in the command line')
group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication '
'(128 or 256 bits)')

group = parser.add_argument_group('connection')

group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If '
'ommited it use the domain part (FQDN) specified in the target parameter')
group.add_argument('-target-ip', action='store', metavar = "ip address",
help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
'This is useful when target is the NetBIOS name and you cannot resolve it')
group.add_argument('-port', action='store', default='1433', help='target MSSQL port (default 1433)')


if len(sys.argv)==1:
parser.print_help()
Expand All @@ -68,7 +75,7 @@
else:
logging.getLogger().setLevel(logging.INFO)

domain, username, password, address = parse_target(options.target)
domain, username, password, remoteName = parse_target(options.target)

if domain is None:
domain = ''
Expand All @@ -77,10 +84,13 @@
from getpass import getpass
password = getpass("Password:")

if options.target_ip is None:
options.target_ip = remoteName

if options.aesKey is not None:
options.k = True

ms_sql = tds.MSSQL(address, int(options.port))
ms_sql = tds.MSSQL(options.target_ip, int(options.port), remoteName)
ms_sql.connect()
try:
if options.k is True:
Expand Down
15 changes: 7 additions & 8 deletions impacket/tds.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,11 @@ class TDS_COLMETADATA(Structure):
)

class MSSQL:
def __init__(self, address, port=1433, rowsPrinter=DummyPrint()):
def __init__(self, address, port=1433, remoteName = '', rowsPrinter=DummyPrint()):
#self.packetSize = 32764
self.packetSize = 32763
self.server = address
self.remoteName = remoteName
self.port = port
self.socket = 0
self.replies = {}
Expand Down Expand Up @@ -650,7 +651,6 @@ def recvTDS(self, packetSize = None):
return packet

def kerberosLogin(self, database, username, password='', domain='', hashes=None, aesKey='', kdcHost=None, TGT=None, TGS=None, useCache=True):

if hashes is not None:
lmhash, nthash = hashes.split(':')
lmhash = binascii.a2b_hex(lmhash)
Expand All @@ -663,7 +663,6 @@ def kerberosLogin(self, database, username, password='', domain='', hashes=None,
# Test this!
if resp['Encryption'] == TDS_ENCRYPT_REQ or resp['Encryption'] == TDS_ENCRYPT_OFF:
LOG.info("Encryption required, switching to TLS")

# Switching to TLS now
ctx = SSL.Context(SSL.TLS_METHOD)
ctx.set_cipher_list('ALL:@SECLEVEL=0'.encode('utf-8'))
Expand All @@ -690,7 +689,7 @@ def kerberosLogin(self, database, username, password='', domain='', hashes=None,

login['HostName'] = (''.join([random.choice(string.ascii_letters) for _ in range(8)])).encode('utf-16le')
login['AppName'] = (''.join([random.choice(string.ascii_letters) for _ in range(8)])).encode('utf-16le')
login['ServerName'] = self.server.encode('utf-16le')
login['ServerName'] = self.remoteName.encode('utf-16le')
login['CltIntName'] = login['AppName']
login['ClientPID'] = random.randint(0,1024)
login['PacketSize'] = self.packetSize
Expand All @@ -710,7 +709,7 @@ def kerberosLogin(self, database, username, password='', domain='', hashes=None,
import datetime

if useCache:
domain, username, TGT, TGS = CCache.parseFile(domain, username, 'MSSQLSvc/%s:%d' % (self.server, self.port))
domain, username, TGT, TGS = CCache.parseFile(domain, username, 'MSSQLSvc/%s:%d' % (self.remoteName, self.port))

if TGS is None:
# search for the port's instance name instead (instance name based SPN)
Expand All @@ -725,7 +724,7 @@ def kerberosLogin(self, database, username, password='', domain='', hashes=None,
pass

if instanceName:
domain, username, TGT, TGS = CCache.parseFile(domain, username, 'MSSQLSvc/%s.%s:%s' % (self.server.split('.')[0], domain, instanceName))
domain, username, TGT, TGS = CCache.parseFile(domain, username, 'MSSQLSvc/%s.%s:%s' % (self.remoteName.split('.')[0], domain, instanceName))

# First of all, we need to get a TGT for the user
userName = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
Expand Down Expand Up @@ -766,7 +765,7 @@ def kerberosLogin(self, database, username, password='', domain='', hashes=None,
# FQDN is the fully qualified domain name of the server.
# port is the TCP port number.
# instancename is the name of the SQL Server instance.
serverName = Principal('MSSQLSvc/%s.%s:%d' % (self.server.split('.')[0], domain, self.port), type=constants.PrincipalNameType.NT_SRV_INST.value)
serverName = Principal('MSSQLSvc/%s.%s:%d' % (self.remoteName.split('.')[0], domain, self.port), type=constants.PrincipalNameType.NT_SRV_INST.value)
try:
tgs, cipher, oldSessionKey, sessionKey = getKerberosTGS(serverName, domain, kdcHost, tgt, cipher, sessionKey)
except KerberosError as e:
Expand Down Expand Up @@ -899,7 +898,7 @@ def login(self, database, username, password='', domain='', hashes = None, useWi

login['HostName'] = (''.join([random.choice(string.ascii_letters) for i in range(8)])).encode('utf-16le')
login['AppName'] = (''.join([random.choice(string.ascii_letters) for i in range(8)])).encode('utf-16le')
login['ServerName'] = self.server.encode('utf-16le')
login['ServerName'] = self.remoteName.encode('utf-16le')
login['CltIntName'] = login['AppName']
login['ClientPID'] = random.randint(0,1024)
login['PacketSize'] = self.packetSize
Expand Down

0 comments on commit 82267d8

Please sign in to comment.