Skip to content

Commit 1fee002

Browse files
authored
Merge branch 'fortra:master' into gmsamembership
2 parents d506870 + 2e87ade commit 1fee002

36 files changed

+2038
-232
lines changed

.github/workflows/build_and_test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ jobs:
4848
strategy:
4949
fail-fast: false
5050
matrix:
51-
python-version: ["3.8", "3.9", "3.10","3.11"]
51+
python-version: ["3.9", "3.10","3.11","3.12"]
5252
experimental: [false]
5353
os: [ubuntu-latest]
5454
include:
55-
- python-version: "3.12-dev"
55+
- python-version: "3.13-dev"
5656
experimental: true
5757
os: ubuntu-latest
5858
continue-on-error: ${{ matrix.experimental }}

examples/GetLAPSPassword.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def __init__(self, username, password, domain, cmdLineOptions):
7878
self.__kdcHost = cmdLineOptions.dc_host
7979
self.__targetComputer = cmdLineOptions.computer
8080
self.__outputFile = cmdLineOptions.outputfile
81+
self.__ldaps_flag = cmdLineOptions.ldaps_flag
8182
self.__KDSCache = {}
8283

8384
if cmdLineOptions.hashes is not None:
@@ -162,7 +163,7 @@ def getUnixTime(t):
162163

163164
def run(self):
164165
# Connect to LDAP
165-
ldapConnection = ldap_login(self.__target, self.baseDN, self.__kdcIP, self.__kdcHost, self.__doKerberos, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
166+
ldapConnection = ldap_login(self.__target, self.baseDN, self.__kdcIP, self.__kdcHost, self.__doKerberos, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__ldaps_flag)
166167
# updating "self.__target" as it may have changed in the ldap_login processing
167168
self.__target = ldapConnection._dstHost
168169

@@ -271,6 +272,10 @@ def run(self):
271272
group.add_argument('-dc-host', action='store', metavar='hostname', help='Hostname of the domain controller to use. '
272273
'If ommited, the domain part (FQDN) '
273274
'specified in the account parameter will be used')
275+
276+
group.add_argument('-ldaps', dest='ldaps_flag', action="store_true", help='Enable LDAPS (LDAP over SSL). '
277+
'Required when querying a Windows Server 2025'
278+
'domain controller with LDAPS enforced.')
274279

275280
if len(sys.argv)==1:
276281
parser.print_help()

examples/GetNPUsers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# you can send it for cracking.
1717
#
1818
# Original credit for this technique goes to @harmj0y:
19-
# https://www.harmj0y.net/blog/activedirectory/roasting-as-reps/
19+
# https://blog.harmj0y.net/activedirectory/roasting-as-reps/
2020
# Related work by Geoff Janjua:
2121
# https://www.exumbraops.com/layerone2016/party
2222
#

examples/dacledit.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,7 @@ def parse_args():
703703
auth_con.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line')
704704
auth_con.add_argument('-aesKey', action="store", metavar="hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)')
705705
auth_con.add_argument('-dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted it will use the domain part (FQDN) specified in the identity parameter')
706+
auth_con.add_argument('-dc-host', action='store', metavar="hostname", help='Hostname of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted, -dc-ip will be used')
706707

707708
principal_parser = parser.add_argument_group("principal", description="Object, controlled by the attacker, to reference in the ACE to create or to filter when printing a DACL")
708709
principal_parser.add_argument("-principal", dest="principal_sAMAccountName", metavar="NAME", type=str, required=False, help="sAMAccountName")
@@ -745,7 +746,7 @@ def main():
745746
domain, username, password, lmhash, nthash, args.k = parse_identity(args.identity, args.hashes, args.no_pass, args.aesKey, args.k)
746747

747748
try:
748-
ldap_server, ldap_session = init_ldap_session(domain, username, password, lmhash, nthash, args.k, args.dc_ip, args.aesKey, args.use_ldaps)
749+
ldap_server, ldap_session = init_ldap_session(domain, username, password, lmhash, nthash, args.k, args.dc_ip, args.dc_host, args.aesKey, args.use_ldaps)
749750
dacledit = DACLedit(ldap_server, ldap_session, args)
750751
if args.action == 'read':
751752
dacledit.read()

examples/ntlmrelayx.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
# Authors:
3535
# Alberto Solino (@agsolino)
3636
# Dirk-jan Mollema / Fox-IT (https://www.fox-it.com)
37+
# Sylvain Heiniger / Compass Security (https://www.compass-security.com)
3738
#
3839

3940
import argparse
@@ -52,7 +53,7 @@
5253

5354
from impacket import version
5455
from impacket.examples import logger
55-
from impacket.examples.ntlmrelayx.servers import SMBRelayServer, HTTPRelayServer, WCFRelayServer, RAWRelayServer
56+
from impacket.examples.ntlmrelayx.servers import SMBRelayServer, HTTPRelayServer, WCFRelayServer, RAWRelayServer, RPCRelayServer
5657
from impacket.examples.ntlmrelayx.utils.config import NTLMRelayxConfig, parse_listening_ports
5758
from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor, TargetsFileWatcher
5859
from impacket.examples.ntlmrelayx.servers.socksserver import SOCKS
@@ -194,14 +195,15 @@ def start_servers(options, threads):
194195
c.setOutputFile(options.output_file)
195196
c.setdumpHashes(options.dump_hashes)
196197
c.setLDAPOptions(options.no_dump, options.no_da, options.no_acl, options.no_validate_privs, options.escalate_user, options.add_computer, options.delegate_access, options.dump_laps, options.dump_gmsa, options.dump_adcs, options.sid, options.add_dns_record)
197-
c.setRPCOptions(options.rpc_mode, options.rpc_use_smb, options.auth_smb, options.hashes_smb, options.rpc_smb_port)
198+
c.setRPCOptions(options.rpc_mode, options.rpc_use_smb, options.auth_smb, options.hashes_smb, options.rpc_smb_port, options.icpr_ca_name)
198199
c.setMSSQLOptions(options.query)
199200
c.setInteractive(options.interactive)
200201
c.setIMAPOptions(options.keyword, options.mailbox, options.all, options.imap_max)
201202
c.setIPv6(options.ipv6)
202203
c.setWpadOptions(options.wpad_host, options.wpad_auth_num)
203204
c.setSMB2Support(options.smb2support)
204205
c.setSMBChallenge(options.ntlmchallenge)
206+
c.setSMBRPCAttack(options.rpc_attack)
205207
c.setInterfaceIp(options.interface_ip)
206208
c.setExploitOptions(options.remove_mic, options.remove_target)
207209
c.setWebDAVOptions(options.serve_image)
@@ -242,6 +244,8 @@ def start_servers(options, threads):
242244
c.setListeningPort(options.wcf_port)
243245
elif server is RAWRelayServer:
244246
c.setListeningPort(options.raw_port)
247+
elif server is RPCRelayServer:
248+
c.setListeningPort(options.rpc_port)
245249

246250
s = server(c)
247251
s.start()
@@ -293,11 +297,13 @@ def stop_servers(threads):
293297
serversoptions.add_argument('--no-http-server', action='store_true', help='Disables the HTTP server')
294298
serversoptions.add_argument('--no-wcf-server', action='store_true', help='Disables the WCF server')
295299
serversoptions.add_argument('--no-raw-server', action='store_true', help='Disables the RAW server')
300+
serversoptions.add_argument('--no-rpc-server', action='store_true', help='Disables the RPC server')
296301

297302
parser.add_argument('--smb-port', type=int, help='Port to listen on smb server', default=445)
298303
parser.add_argument('--http-port', help='Port(s) to listen on HTTP server. Can specify multiple ports by separating them with `,`, and ranges with `-`. Ex: `80,8000-8010`', default="80")
299304
parser.add_argument('--wcf-port', type=int, help='Port to listen on wcf server', default=9389) # ADWS
300305
parser.add_argument('--raw-port', type=int, help='Port to listen on raw server', default=6666)
306+
parser.add_argument('--rpc-port', type=int, help='Port to listen on rpc server', default=135)
301307

302308
parser.add_argument('--no-multirelay', action="store_true", required=False, help='If set, disable multi-host relay (SMB and HTTP servers)')
303309
parser.add_argument('--keep-relaying', action="store_true", required=False, help='If set, keeps relaying to a target even after a successful connection on it')
@@ -338,15 +344,17 @@ def stop_servers(threads):
338344
smboptions.add_argument('-e', action='store', required=False, metavar = 'FILE', help='File to execute on the target system. '
339345
'If not specified, hashes will be dumped (secretsdump.py must be in the same directory)')
340346
smboptions.add_argument('--enum-local-admins', action='store_true', required=False, help='If relayed user is not admin, attempt SAMR lookup to see who is (only works pre Win 10 Anniversary)')
347+
smboptions.add_argument('--rpc-attack', action='store', choices=[None, "TSCH", "ICPR"], required=False, default=None, help='Select the attack to perform over RPC over named pipes.')
341348

342349
#RPC arguments
343350
rpcoptions = parser.add_argument_group("RPC client options")
344-
rpcoptions.add_argument('-rpc-mode', choices=["TSCH"], default="TSCH", help='Protocol to attack, only TSCH supported')
351+
rpcoptions.add_argument('-rpc-mode', choices=["TSCH", "ICPR"], default="TSCH", help='Protocol to attack')
345352
rpcoptions.add_argument('-rpc-use-smb', action='store_true', required=False, help='Relay DCE/RPC to SMB pipes')
346353
rpcoptions.add_argument('-auth-smb', action='store', required=False, default='', metavar='[domain/]username[:password]',
347354
help='Use this credential to authenticate to SMB (low-privilege account)')
348355
rpcoptions.add_argument('-hashes-smb', action='store', required=False, metavar="LMHASH:NTHASH")
349356
rpcoptions.add_argument('-rpc-smb-port', type=int, choices=[139, 445], default=445, help='Destination port to connect to SMB')
357+
rpcoptions.add_argument('-icpr-ca-name', action='store', default="", help='Name of the CA for ICPR attack')
350358

351359
#MSSQL arguments
352360
mssqloptions = parser.add_argument_group("MSSQL client options")
@@ -502,6 +510,9 @@ def stop_servers(threads):
502510
if not options.no_raw_server:
503511
RELAY_SERVERS.append(RAWRelayServer)
504512

513+
if not options.no_rpc_server:
514+
RELAY_SERVERS.append(RPCRelayServer)
515+
505516
if targetSystem is not None and options.w:
506517
watchthread = TargetsFileWatcher(targetSystem)
507518
watchthread.start()

examples/owneredit.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# for more information.
1111
#
1212
# Description:
13-
# Python script for handling the msDS-AllowedToActOnBehalfOfOtherIdentity property of a target computer
13+
# Python script for reading and modifying the Owner attribute (OwnerSid) of an Active Directory object.
1414
#
1515
# Authors:
1616
# Charlie BROMBERG (@_nwodtuhs)
@@ -241,6 +241,7 @@ def parse_args():
241241
auth_con.add_argument('-aesKey', action="store", metavar="hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)')
242242
auth_con.add_argument('-dc-ip', action='store', metavar="ip address",
243243
help='IP Address of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted it will use the domain part (FQDN) specified in the identity parameter')
244+
auth_con.add_argument('-dc-host', action='store', metavar="hostname", help='Hostname of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted, -dc-ip will be used')
244245

245246
new_owner_parser = parser.add_argument_group("owner", description="Object, controlled by the attacker, to set as owner of the target object")
246247
new_owner_parser.add_argument("-new-owner", dest="new_owner_sAMAccountName", metavar="NAME", type=str, required=False, help="sAMAccountName")
@@ -277,7 +278,7 @@ def main():
277278
domain, username, password, lmhash, nthash, args.k = parse_identity(args.identity, args.hashes, args.no_pass, args.aesKey, args.k)
278279

279280
try:
280-
ldap_server, ldap_session = init_ldap_session(domain, username, password, lmhash, nthash, args.k, args.dc_ip, args.aesKey, args.use_ldaps)
281+
ldap_server, ldap_session = init_ldap_session(domain, username, password, lmhash, nthash, args.k, args.dc_ip, args.dc_host, args.aesKey, args.use_ldaps)
281282
owneredit = OwnerEdit(ldap_server, ldap_session, args)
282283
if args.action == 'read':
283284
owneredit.read()

examples/rbcd.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ def parse_args():
293293
help='IP Address of the domain controller or KDC (Key Distribution Center) for Kerberos. If '
294294
'omitted it will use the domain part (FQDN) specified in '
295295
'the identity parameter')
296+
group.add_argument('-dc-host', action='store', metavar="hostname", help='Hostname of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted, -dc-ip will be used')
296297

297298
if len(sys.argv) == 1:
298299
parser.print_help()
@@ -313,7 +314,7 @@ def main():
313314
domain, username, password, lmhash, nthash, args.k = parse_identity(args.identity, args.hashes, args.no_pass, args.aesKey, args.k)
314315

315316
try:
316-
ldap_server, ldap_session = init_ldap_session(domain, username, password, lmhash, nthash, args.k, args.dc_ip, args.aesKey, args.use_ldaps)
317+
ldap_server, ldap_session = init_ldap_session(domain, username, password, lmhash, nthash, args.k, args.dc_ip, args.dc_host, args.aesKey, args.use_ldaps)
317318
rbcd = RBCD(ldap_server, ldap_session, args.delegate_to)
318319
if args.action == 'read':
319320
rbcd.read()

examples/smbexec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
from impacket.dcerpc.v5 import transport, scmr
5757
from impacket.krb5.keytab import Keytab
5858

59-
OUTPUT_FILENAME = '__output'
59+
OUTPUT_FILENAME = '__output_' + ''.join([random.choice(string.ascii_letters) for i in range(8)])
6060
SMBSERVER_DIR = '__tmp'
6161
DUMMY_SHARE = 'TMP'
6262
CODEC = sys.stdout.encoding

examples/smbserver.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# Impacket - Collection of Python classes for working with network protocols.
33
#
4-
# Copyright Fortra, LLC and its affiliated companies
4+
# Copyright Fortra, LLC and its affiliated companies
55
#
66
# All rights reserved.
77
#
@@ -30,7 +30,7 @@
3030
print(version.BANNER)
3131

3232
parser = argparse.ArgumentParser(add_help = True, description = "This script will launch a SMB Server and add a "
33-
"share specified as an argument. You need to be root in order to bind to port 445. "
33+
"share specified as an argument. Usually, you need to be root in order to bind to port 445. "
3434
"For optional authentication, it is possible to specify username and password or the NTLM hash. "
3535
"Example: smbserver.py -comment 'My share' TMP /tmp")
3636

@@ -98,4 +98,8 @@
9898
server.setSMBChallenge('')
9999

100100
# Rock and roll
101-
server.start()
101+
try:
102+
server.start()
103+
except KeyboardInterrupt:
104+
print("\nInterrupted, exiting...")
105+
sys.exit(130)

impacket/dcerpc/v5/dcomrt.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@
7171
IID_IUnknown = uuidtup_to_bin(('00000000-0000-0000-C000-000000000046','0.0'))
7272
IID_IClassFactory = uuidtup_to_bin(('00000001-0000-0000-C000-000000000046','0.0'))
7373

74+
# Protocol Identifiers, from [c706] Annex I
75+
TOWERID_OSI_TP4 = 0x05
76+
TOWERID_OSI_CLNS = 0x06
77+
TOWERID_DOD_TCP = 0x0007
78+
TOWERID_DOD_UDP = 0x08
79+
TOWERID_DOD_IP = 0x09
80+
TOWERID_RPC_connectionless = 0x0a
81+
TOWERID_RPC_connectionoriented = 0x0b
82+
TOWERID_DNA_Session_Control = 0x02
83+
TOWERID_DNA_Session_Control_V3 = 0x03
84+
TOWERID_DNA_NSP_Transport = 0x04
85+
TOWERID_DNA_Routing = 0x06
86+
TOWERID_Named_Pipes = 0x10
87+
TOWERID_NetBIOS_11 = 0x11
88+
TOWERID_NetBEUI = 0x12
89+
TOWERID_Netware_SPX = 0x13
90+
TOWERID_Netware_IPX = 0x14
91+
TOWERID_Appletalk_Stream = 0x16
92+
TOWERID_Appletalk_Datagram = 0x17
93+
TOWERID_Appletalk = 0x18
94+
TOWERID_NetBIOS_19 = 0x19
95+
TOWERID_VINES_SPP = 0x1A
96+
TOWERID_VINES_IPC = 0x1B
97+
TOWERID_StreetTalk = 0x1C
98+
TOWERID_Unix_Domain_socket = 0x20
99+
TOWERID_null = 0x21
100+
TOWERID_NetBIOS_22 = 0x22
101+
74102
class DCERPCSessionError(DCERPCException):
75103
def __init__(self, error_string=None, error_code=None, packet=None):
76104
DCERPCException.__init__(self, error_string, error_code, packet)

0 commit comments

Comments
 (0)