mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-07-06 13:02:24 -07:00
directory structure has been simplified by grouping all the poisoners and servers in one folder impacket smb server has been replaced with responder's flask http server has beem replaced with responder's modified config file to support new changes
205 lines
No EOL
6.2 KiB
Python
205 lines
No EOL
6.2 KiB
Python
#!/usr/bin/env python
|
|
# This file is part of Responder
|
|
# Original work by Laurent Gaffie - Trustwave Holdings
|
|
#
|
|
# 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 socket
|
|
import struct
|
|
|
|
from core.configwatcher import ConfigWatcher
|
|
from core.packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData
|
|
from SocketServer import BaseRequestHandler
|
|
from core.utils import *
|
|
|
|
def WorkstationFingerPrint(data):
|
|
Role = {
|
|
"\x04\x00" :"Windows 95",
|
|
"\x04\x10" :"Windows 98",
|
|
"\x04\x90" :"Windows ME",
|
|
"\x05\x00" :"Windows 2000",
|
|
"\x05\x00" :"Windows XP",
|
|
"\x05\x02" :"Windows 2003",
|
|
"\x06\x00" :"Windows Vista/Server 2008",
|
|
"\x06\x01" :"Windows 7/Server 2008R2",
|
|
}
|
|
|
|
return Role[data] if data in Role else "Unknown"
|
|
|
|
def RequestType(data):
|
|
Type = {
|
|
"\x01": 'Host Announcement',
|
|
"\x02": 'Request Announcement',
|
|
"\x08": 'Browser Election',
|
|
"\x09": 'Get Backup List Request',
|
|
"\x0a": 'Get Backup List Response',
|
|
"\x0b": 'Become Backup Browser',
|
|
"\x0c": 'Domain/Workgroup Announcement',
|
|
"\x0d": 'Master Announcement',
|
|
"\x0e": 'Reset Browser State Announcement',
|
|
"\x0f": 'Local Master Announcement',
|
|
}
|
|
|
|
return Type[data] if data in Type else "Unknown"
|
|
|
|
def PrintServerName(data, entries):
|
|
if entries > 0:
|
|
|
|
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:
|
|
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]
|
|
StatusCode = Payload[PayloadOffset-4:PayloadOffset-2]
|
|
|
|
if StatusCode == "\x00\x00":
|
|
EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0]
|
|
return PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
|
|
|
|
else:
|
|
return None
|
|
|
|
def RAPThisDomain(Client,Domain):
|
|
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
|
|
if PDC is not None:
|
|
print text("[LANMAN] Detected Domains: %s" % ', '.join(PDC))
|
|
|
|
SQL = RapFinger(Client,Domain,"\x04\x00\x00\x00")
|
|
if SQL is not None:
|
|
print text("[LANMAN] Detected SQL Servers on domain %s: %s" % (Domain, ', '.join(SQL)))
|
|
|
|
WKST = RapFinger(Client,Domain,"\xff\xff\xff\xff")
|
|
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)
|
|
s.connect((Host,445))
|
|
s.settimeout(0.3)
|
|
|
|
Header = SMBHeader(cmd="\x72",mid="\x01\x00")
|
|
Body = SMBNegoData()
|
|
Body.calculate()
|
|
|
|
Packet = str(Header)+str(Body)
|
|
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
|
|
|
s.send(Buffer)
|
|
data = s.recv(1024)
|
|
|
|
# Session Setup AndX Request, Anonymous.
|
|
if data[8:10] == "\x72\x00":
|
|
Header = SMBHeader(cmd="\x73",mid="\x02\x00")
|
|
Body = SMBSessionData()
|
|
Body.calculate()
|
|
|
|
Packet = str(Header)+str(Body)
|
|
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
|
|
|
s.send(Buffer)
|
|
data = s.recv(1024)
|
|
|
|
# Tree Connect IPC$.
|
|
if data[8:10] == "\x73\x00":
|
|
Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00")
|
|
Body = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$")
|
|
Body.calculate()
|
|
|
|
Packet = str(Header)+str(Body)
|
|
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
|
|
|
s.send(Buffer)
|
|
data = s.recv(1024)
|
|
|
|
# Rap ServerEnum.
|
|
if data[8:10] == "\x75\x00":
|
|
Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00")
|
|
Body = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain))
|
|
Body.calculate()
|
|
|
|
Packet = str(Header)+str(Body)
|
|
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
|
|
|
s.send(Buffer)
|
|
data = s.recv(64736)
|
|
|
|
# Rap ServerEnum, Get answer and return what we're looking for.
|
|
if data[8:10] == "\x25\x00":
|
|
s.close()
|
|
return ParsePacket(data)
|
|
except:
|
|
pass
|
|
|
|
def BecomeBackup(data,Client):
|
|
try:
|
|
DataOffset = struct.unpack('<H',data[139:141])[0]
|
|
BrowserPacket = data[82+DataOffset:]
|
|
ReqType = RequestType(BrowserPacket[0])
|
|
|
|
if ReqType == "Become Backup Browser":
|
|
ServerName = BrowserPacket[1:]
|
|
Domain = Decode_Name(data[49:81])
|
|
Name = Decode_Name(data[15:47])
|
|
Role = NBT_NS_Role(data[45:48])
|
|
|
|
if settings.Config.AnalyzeMode:
|
|
print text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain))
|
|
print RAPThisDomain(Client, Domain)
|
|
|
|
except:
|
|
pass
|
|
|
|
def ParseDatagramNBTNames(data,Client):
|
|
try:
|
|
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])
|
|
|
|
|
|
if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode:
|
|
print text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2))
|
|
print RAPThisDomain(Client, Domain)
|
|
except:
|
|
pass
|
|
|
|
class Browser(BaseRequestHandler):
|
|
|
|
def handle(self):
|
|
try:
|
|
request, socket = self.request
|
|
|
|
if settings.Config.AnalyzeMode:
|
|
ParseDatagramNBTNames(request,self.client_address[0])
|
|
BecomeBackup(request,self.client_address[0])
|
|
|
|
BecomeBackup(request,self.client_address[0])
|
|
|
|
except Exception:
|
|
pass |