├── LICENSE ├── MANIFEST.in ├── README.md ├── doc └── known_macs.txt ├── macutil ├── modules ├── __init__.py ├── brute.py ├── general.py └── utility.py └── setup.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ignoto 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 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt 2 | include *.md 3 | recursive-include doc *.txt 4 | recursive-include modules *.py 5 | recursive-exclude *.DS_store 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # macutil 2 | MAC Address brute forcing tool, used to bypass MAC based filtering 3 | 4 | Network Access Control solutions are a simple idea, 802.1X cert based 5 | authentication, great! works like a charm. However, businesses are complex 6 | beasts and not all systems on that network support 802.1X and/or cert based 7 | authenticaiton. 8 | 9 | In this situation most look to simple MAC authentication to handle the 10 | exceptions. 11 | 12 | So if lets say your IP phones are on the same network, if we can find the 13 | correct MAC address we can essential spoof that address and access the network. 14 | 15 | This utility was designed for exactly this, MAC address manipulation and brute 16 | forcing. 17 | -------------------------------------------------------------------------------- /doc/known_macs.txt: -------------------------------------------------------------------------------- 1 | 00:08:5d, Mitel 2 | 08:00:0f, Mitel 3 | 00:05:86, Lucent-Technologies 4 | 00:07:72, Alcatel-lucent 5 | 00:08:9a, Alcatel-Microelectronics 6 | 00:0e:86, Alcatel-NorthAmerica 7 | 00:0f:62, Alcatel-Bell 8 | 00:11:3f, Alcatel-Di 9 | 00:11:8b, Alcatel-lucent 10 | 00:15:3f, Alcatel-Alenia 11 | 00:16:4d, Alcatel-lucent 12 | 00:17:cc, Alcatel-lucent 13 | 00:1a:10, Lucent-Trans 14 | 00:1a:f0, Alcatel-lucent 15 | 00:1c:8e, Alcatel-lucent 16 | 00:1d:4c, Alcatel-lucent 17 | 00:20:32, Alcatel-Taisel 18 | 00:20:60, Alcatel-Italia 19 | 00:20:da, Alcatel-lucent 20 | 00:21:05, Alcatel-lucent 21 | 00:21:35, Alcatel-lucent 22 | 00:21:ae, Alcatel-lucent 23 | 00:23:3e, Alcatel-lucent 24 | 00:25:ba, Alcatel-lucent 25 | 00:30:6d, Lucent-Technologies 26 | 00:60:1d, Lucent-Technologies 27 | 00:60:d2, Lucent-Technologies 28 | 00:80:21, Alcatel 29 | 00:80:39, Alcatel 30 | 00:a0:81, Alcatel 31 | 00:c0:be, Alcatel 32 | 00:d0:77, Lucent-Technologies 33 | 00:d0:95, Alcatel-lucent 34 | 00:e0:b1, Alcatel-lucent 35 | 00:e0:da, Alcatel-lucent 36 | 04:0a:83, Alcatel-lucent 37 | 0c:a4:02, Alcatel-lucent 38 | 0c:b5:de, Alcatel-Lucent 39 | 18:42:2f, Alcatel-Lucent 40 | 18:4a:6f, Alcatel-lucent 41 | 18:80:f5, Alcatel-lucent 42 | 24:af:4a, Alcatel-lucent 43 | 2c:fa:a2, Alcatel-lucent 44 | 3c:8b:cd, Alcatel-lucent 45 | 4c:5f:d2, Alcatel-lucent 46 | 4c:a7:4b, Alcatel-Lucent 47 | 54:05:5f, Alcatel-Lucent 48 | 54:a6:19, Alcatel-lucent 49 | 54:e3:f6, Alcatel-lucent 50 | 68:54:ed, Alcatel-lucent 51 | 68:59:7f, Alcatel-Lucent 52 | 6c:be:e9, Alcatel-lucent 53 | 7c:20:64, Alcatel-lucent 54 | 84:a7:83, Alcatel-Lucent 55 | 88:5c:47, Alcatel-Lucent 56 | 90:67:b5, Alcatel-lucent 57 | 90:67:f3, Alcatel-Lucent 58 | 94:24:e1, Alcatel-lucent 59 | 94:ae:61, Alcatel-Lucent 60 | a0:9d:86, Alcatel-lucent 61 | a0:f3:e4, Alcatel-lucent 62 | a8:ad:3d, Alcatel-lucent 63 | ac:9c:e4, Alcatel-lucent 64 | c8:f8:6d, Alcatel-lucent 65 | d0:99:d5, Alcatel-lucent 66 | d4:22:4e, Alcatel-Lucent 67 | dc:08:56, Alcatel-lucent 68 | e0:30:05, Alcatel-lucent 69 | e4:a1:e6, Alcatel-lucent 70 | e8:e7:32, Alcatel-lucent 71 | f4:c6:13, Alcatel-lucent 72 | f8:30:94, Alcatel-lucent 73 | 00:01:a3, Genesys 74 | 00:80:ac, Genesys 75 | 00:02:d6, Nice Systems 76 | 00:c0:da, Nice Systems 77 | 00:04:0d, Avaya 78 | 00:1b:4f, Avaya 79 | 00:54:9f, Avaya 80 | 00:e0:07, Avaya 81 | 04:8a:15, Avaya 82 | 10:cd:ae, Avaya 83 | 14:61:2f, Avaya 84 | 24:b2:09, Avaya 85 | 24:d9:21, Avaya 86 | 2c:f4:c5, Avaya 87 | 34:75:c7, Avaya 88 | 38:bb:3c, Avaya 89 | 3c:3a:73, Avaya 90 | 3c:b1:5b, Avaya 91 | 44:32:2a, Avaya 92 | 50:61:84, Avaya 93 | 50:cd:22, Avaya 94 | 58:16:26, Avaya 95 | 60:49:c1, Avaya 96 | 64:6a:52, Avaya 97 | 64:a7:dd, Avaya 98 | 64:c3:54, Avaya 99 | 6c:a8:49, Avaya 100 | 6c:fa:58, Avaya 101 | 70:30:18, Avaya 102 | 70:38:ee, Avaya 103 | 70:52:c5, Avaya 104 | 70:7c:69, Avaya 105 | 80:1d:aa, Avaya 106 | 84:83:71, Avaya 107 | 90:fb:5b, Avaya 108 | a0:09:ed, Avaya 109 | a0:12:90, Avaya 110 | a0:51:c6, Avaya 111 | a4:25:1b, Avaya 112 | a4:78:86, Avaya 113 | b0:ad:aa, Avaya 114 | b4:47:5e, Avaya 115 | b4:a9:5a, Avaya 116 | b4:b0:17, Avaya 117 | bc:ad:ab, Avaya 118 | c0:57:bc, Avaya 119 | c4:be:d4, Avaya 120 | c8:1f:ea, Avaya 121 | c8:f4:06, Avaya 122 | cc:f9:54, Avaya 123 | d4:78:56, Avaya 124 | d4:ea:0e, Avaya 125 | e4:5d:52, Avaya 126 | f8:15:47, Avaya 127 | f8:73:a2, Avaya 128 | fc:83:99, Avaya 129 | fc:a8:41, Avaya -------------------------------------------------------------------------------- /macutil: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | import argparse 5 | import traceback 6 | import sys 7 | 8 | from modules import general, utility, brute 9 | 10 | # Create parser and suppress help to utilise our own 11 | parser = argparse.ArgumentParser(prog='macutil', description='Address manipulation and brute forcing', add_help=False, 12 | formatter_class=lambda prog: argparse.RawDescriptionHelpFormatter(prog,max_help_position=100)) 13 | 14 | parser.add_argument('-set', help='set specific MAC address', required=False, action='store_true') 15 | parser.add_argument('-mac', help='address required for "-SET"', required=False) 16 | parser.add_argument('-v', help='print version', required=False, action='store_true') 17 | parser.add_argument('-h', '-help', help='help menu', required=False, action='store_true') 18 | parser.add_argument('-brute', help='brute force a MAC address, NAC bypassing', required=False, action='store_true') 19 | parser.add_argument('-random', help='set a random MAC address', required=False, action='store_true') 20 | parser.add_argument('-list', help='list current interfaces on the system', required=False, action='store_true') 21 | 22 | parser.add_argument('--VERSION_CONST', help=argparse.SUPPRESS, required=False) 23 | parser.add_argument('-reset', help='reset MAC address to default', required=False, action='store_true') 24 | parser.add_argument('-interface', help='interface to be manipulated', required=False) 25 | args = vars(parser.parse_args()) 26 | 27 | version = '0.1.21' 28 | args['VERSION_CONST'] = version 29 | 30 | try: 31 | 32 | # Check usage 33 | if not any((args['set'], args['reset'], args['random'], args['brute'], args['v'], args['list'], args['h'])): 34 | general.banner() 35 | general.description() 36 | else: 37 | general.banner() 38 | 39 | 40 | # Help menu full description 41 | if args['h']: 42 | general.full_description() 43 | 44 | 45 | # Set MAC addres 46 | if args['set']: 47 | live_interfaces = utility.get_live_interfaces_mac(args) 48 | if args['mac']: 49 | if general.validate_mac(args['mac']): 50 | utility.set_mac_address(args['mac'], live_interfaces['live'][0]['interface']) 51 | else: 52 | print('\nRequired: "-mac"\n') 53 | sys.exit() 54 | 55 | 56 | # Reset interface to default MAC address 57 | if args['reset']: 58 | if not args['interface']: 59 | general.banner() 60 | general.description() 61 | print('Required: "-interface"') 62 | else: 63 | utility.reset_default_mac(args['interface']) 64 | 65 | 66 | # Random: Set random MAC address 67 | if args['random']: 68 | if not args['interface']: 69 | live_interfaces = utility.get_live_interfaces_mac(args) 70 | args['interface'] = live_interfaces['live'][0]['interface'] 71 | 72 | utility.set_mac_address(utility.random_generator(), args['interface']) 73 | 74 | 75 | # List all interfaces 76 | if args['list']: 77 | utility.list_interfaces(args) 78 | 79 | 80 | # Start Spoofing MACs 81 | if args['brute']: 82 | live_interfaces = utility.get_live_interfaces_mac(args) 83 | if len(live_interfaces['live']) < 1: 84 | pass 85 | else: 86 | interface = live_interfaces['live'][0]['interface'] 87 | brute.start(interface) 88 | 89 | if not args['interface']: 90 | live_interfaces = utility.get_live_interfaces_mac(args) 91 | args['interface'] = live_interfaces['live'][0]['interface'] 92 | 93 | brute.start(args['interface']) 94 | 95 | print('') 96 | 97 | except KeyError as e: 98 | if not args['interface']: 99 | general.banner() 100 | general.description() 101 | print('No live interface found!\n\nRequired: "-interface"') 102 | else: 103 | print(e) 104 | except KeyboardInterrupt: 105 | print('\nRage quit!') 106 | except Exception: 107 | print(traceback.print_exc()) 108 | 109 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laneden-Labs/macutil/8399a5c18b4717f08a72103127abbc0213d5adc0/modules/__init__.py -------------------------------------------------------------------------------- /modules/brute.py: -------------------------------------------------------------------------------- 1 | #!/bin/bash/python3 2 | 3 | import random 4 | import subprocess 5 | import time 6 | import re 7 | import sys 8 | import os 9 | from .general import get_file_content 10 | from .utility import interface_down, interface_up, check_user 11 | 12 | 13 | def get_local_address(interface): 14 | # Check relevant interface for DHCP assigned address 15 | process = subprocess.Popen('ifconfig {interface}'.format(interface=interface), shell=True, stdout=subprocess.PIPE) 16 | output = process.communicate()[0] 17 | lines = output.splitlines() 18 | for line in lines: 19 | match = re.match(b'.*\s(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s.*', line) 20 | if match: 21 | # Return an identified IP address 22 | return(match.group(1)) 23 | 24 | # Return None if no address found 25 | return None 26 | 27 | 28 | def chunk_me(mac_address): 29 | # Randomly assign last 3 octets of MAC address and return a completed vendor address 30 | mac_2 = (":%02x:%02x:%02x" % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255),)) 31 | mac = mac_address + mac_2.upper() 32 | return mac 33 | 34 | 35 | def mac_search(mac_list, interface): 36 | 37 | if check_user(): 38 | random.shuffle(mac_list) 39 | # For each MAC address in our Vendor List 40 | print('\nSpoofing Mac Addresses\n') 41 | for mac in mac_list: 42 | 43 | # Create a valid random address from the vendor supplied MAC address 44 | mac_address = chunk_me(mac[0]) 45 | interface_down(interface) 46 | time.sleep(2) 47 | interface_up(interface) 48 | 49 | # Alter our system MAC address to that of the newly generated vendor mac address 50 | process = subprocess.Popen('ifconfig {interface} ether {mac_address}'.format(interface=interface, mac_address=mac_address), shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) 51 | output = process.communicate()[0] 52 | interface_up(interface) 53 | print('Set:\t{}\t{}'.format(mac_address, mac[1])) 54 | time.sleep(15) 55 | 56 | # Check if DHCP assigned us an ip address based on our spoofed MAC address 57 | result = get_local_address(interface) 58 | if result: 59 | if not result.startswith(b'169'): 60 | print('\nValid MAC Address Identified:\n') 61 | print('\tInterface:\t{}'.format(interface)) 62 | print('\tIp:\t\t{}'.format(result.decode())) 63 | print('\tVendor:\t\t{}'.format(mac[1])) 64 | print('\tMac:\t\t{}\n'.format(mac_address)) 65 | sys.exit() 66 | 67 | 68 | # MAIN 69 | # Start the MAC address search 70 | def start(interface): 71 | # A List of common Telephone Vendor Mac Addresses 72 | filename = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir) + '/doc/known_macs.txt') 73 | mac_list = get_file_content(filename) 74 | 75 | # Start Bruting 76 | mac_search(mac_list, interface) -------------------------------------------------------------------------------- /modules/general.py: -------------------------------------------------------------------------------- 1 | import os 2 | import csv 3 | import re 4 | import sys 5 | 6 | 7 | # Validate Mac address 8 | def validate_mac(mac): 9 | valid = re.match("[0-9A-F]{2}([-:]?)[0-9A-F]{2}(\\1[0-9A-F]{2}){4}$", mac.upper()) 10 | if valid: 11 | return True 12 | else: 13 | print('\nNot a valid MAC address: {}!\n'.format(mac)) 14 | sys.exit() 15 | 16 | 17 | # Read file into list of tuples 18 | def get_file_content(filename): 19 | 20 | known_macs = [tuple(row) for row in csv.reader(open(filename, 'r'))] 21 | return known_macs 22 | 23 | 24 | # Print banner and description 25 | def banner(): 26 | 27 | title = """ 28 | _ _ _ 29 | _ __ ___ __ _ ___ _ _| |_(_) | 30 | | '_ ` _ \ / _` |/ __| | | | __| | | 31 | | | | | | | (_| | (__| |_| | |_| | | 32 | |_| |_| |_|\__,_|\___|\__,_|\__|_|_| 33 | """ 34 | 35 | banner_desc = """{bypass} | {brute} | {random} 36 | 37 | {name} | {twit} 38 | 39 | {url}""" . format (name="Author: Darryl Lane", twit="Twitter: @darryllane101", bypass="NAC Bypass", brute="MAC Brute Force", random="MAC Random", url="https://github.com/Laneden-Labs/macutil") 40 | 41 | print(title) 42 | print(banner_desc) 43 | return 44 | 45 | 46 | # Print full description 47 | def full_description(): 48 | 49 | content = """ 50 | Network Access Control solutions are a simple idea, 802.1X cert based 51 | authentication, great! works like a charm. However, businesses are complex 52 | beasts and not all systems on that network support 802.1X and/or cert based 53 | authenticaiton. 54 | 55 | In this situation most look to simple MAC authentication to handle the 56 | exceptions. 57 | 58 | So if lets say your IP phones are on the same network, if we can find the 59 | correct MAC address we can essential spoof that address and access the network. 60 | 61 | This utility was designed for exactly this, MAC address manipulation and brute 62 | forcing. 63 | 64 | optional arguments: 65 | -h, --help Show this help message and exit 66 | -set Set specific MAC address "Required: -mac, -interface" 67 | -mac Address required for "Required: -set" 68 | -brute Brute force a MAC address, NAC bypassing 69 | -random Set a random MAC address 70 | -list List current interfaces on the system 71 | -reset Reset MAC address to default 72 | -interface Interface to be manipulated 73 | """ 74 | 75 | print(content) 76 | return 77 | 78 | 79 | # Print usage menu and examples 80 | def description(): 81 | 82 | content = """ 83 | optional arguments: 84 | -h, --help Show this help message and exit 85 | -set Set specific MAC address "Required: -mac, -interface" 86 | -mac Address required for "Required: -set" 87 | -brute Brute force a MAC address, NAC bypassing 88 | -random Set a random MAC address 89 | -list List current interfaces on the system 90 | -reset Reset MAC address to default 91 | -interface Interface to be manipulated 92 | 93 | examples: 94 | 95 | macutil -brute 96 | macutil -set -mac 00:11:22:33:44:55 -interface en0 97 | macutil -reset -interface en0 98 | """ 99 | 100 | print(content) 101 | return 102 | -------------------------------------------------------------------------------- /modules/utility.py: -------------------------------------------------------------------------------- 1 | import random 2 | import subprocess 3 | import time 4 | import re 5 | import sys 6 | import os 7 | import json 8 | 9 | 10 | # Check if user is running as root/sudo 11 | def check_user(): 12 | if os.getuid() == 0: 13 | return True 14 | else: 15 | print('\nroot required!...') 16 | sys.exit() 17 | 18 | 19 | #interface down 20 | def interface_down(interface): 21 | if check_user: 22 | subprocess.Popen('ifconfig {interface} down'.format(interface=interface), shell=True, stdout=subprocess.PIPE) 23 | return 24 | 25 | 26 | #interface up 27 | def interface_up(interface): 28 | if check_user: 29 | subprocess.Popen('ifconfig {interface} up'.format(interface=interface), shell=True, stdout=subprocess.PIPE) 30 | return 31 | 32 | 33 | # Randomly generate MAC address and return 34 | def random_generator(): 35 | mac = ("%02x:%02x:%02x:%02x:%02x:%02x" % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))) 36 | return mac.upper() 37 | 38 | 39 | # Request interface details 40 | def request_interfaces(args): 41 | live = [] 42 | results = re.findall(r'^(?:Hardware Port|Device|Ethernet Address): (.+)$', 43 | subprocess.check_output(('networksetup', '-listallhardwareports'), 44 | universal_newlines=True), re.MULTILINE) 45 | 46 | for i in range(0, len(results), 3): 47 | # Split results 48 | port, device, address = results[i:i + 3] 49 | if args['list']: 50 | print('\tPort:\t\t{}\n\tInterface:\t{}\n\tMac:\t\t{}\n'.format(port,device, address)) 51 | 52 | process = subprocess.Popen("ifconfig {}".format(device), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 53 | 54 | # Identify live ipv4 interfaces 55 | output = process.communicate()[0].decode() 56 | lines = output.splitlines() 57 | for line in lines: 58 | if re.match(r'.*inet\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\snetmask\s(.*)\sbroadcast\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.*', line): 59 | live_ip = re.match(r'.*inet\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\snetmask\s(.*)\sbroadcast\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.*', line).group(1) 60 | live.append('port: {port}'.format(port=port)) 61 | live.append('interface: {inter}'.format(inter=device)) 62 | live.append('mac: {mac}'.format(mac=address)) 63 | live.append('ip: {ipadd}'.format(ipadd=live_ip)) 64 | 65 | # Return dictionary of live results 66 | return {"live": [dict(item.split(": ") for item in live)]} 67 | 68 | 69 | # List all interfaces 70 | def list_interfaces(args): 71 | print('\nAll Interfaces\n') 72 | 73 | # Execute and parse interface output into list 74 | live_interfaces = request_interfaces(args) 75 | 76 | for k, v in live_interfaces.items(): 77 | for value in v: 78 | print('Live Interfaces:\n') 79 | print('\tPort:\t\t{port}'.format(port=value['port'])) 80 | print('\tInterface:\t{inter}'.format(inter=value['interface'])) 81 | print('\tMac:\t\t{mac}'.format(mac=value['mac'])) 82 | print('\tIP:\t\t{ipadd}\n'.format(ipadd=value['ip'])) 83 | return 84 | 85 | 86 | # Reset interface MAC address to default 87 | def reset_default_mac(interface): 88 | 89 | live = [] 90 | results = re.findall(r'^(?:Hardware Port|Device|Ethernet Address): (.+)$', 91 | subprocess.check_output(('networksetup', '-listallhardwareports'), 92 | universal_newlines=True), re.MULTILINE) 93 | 94 | for i in range(0, len(results), 3): 95 | port, interface, address = results[i:i + 3] 96 | if port == 'Bluetooth PAN': 97 | pass 98 | else: 99 | process = subprocess.Popen("ifconfig {}".format(interface), shell=True, stdout=subprocess.PIPE) 100 | output = process.communicate()[0].decode() 101 | lines = output.splitlines() 102 | for line in lines: 103 | if interface in line: 104 | set_mac_address(address, interface) 105 | return 106 | return 107 | 108 | 109 | # Set MAC address to interface 110 | def set_mac_address(mac_address, interface): 111 | subprocess.Popen("ifconfig {interface} ether {mac_address}".format(interface=interface, mac_address=mac_address), shell=True, stdout=subprocess.PIPE) 112 | print('\nSet Mac Address:\n') 113 | print('\tMac:\t\t{}'.format(mac_address)) 114 | print('\tInterface:\t{}'.format(interface)) 115 | return 116 | 117 | 118 | # Get live interfaces 119 | def get_live_interfaces_mac(args): 120 | return request_interfaces(args) 121 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import setuptools 3 | setup( 4 | name='macutil', 5 | version='0.1.21', 6 | author='Darryl lane', 7 | author_email='Darryllane101@gmail.com', 8 | url='https://github.com/Laneden-Labs/macutil', 9 | packages=[''], 10 | include_package_data=True, 11 | license='LICENSE.txt', 12 | description='''MAC Address brute forcing tool, used to bypass MAC based filtering''', 13 | long_description_content_type='text/markdown', 14 | long_description=open('README.md').read(), 15 | scripts=['macutil'] 16 | ) 17 | 18 | 19 | --------------------------------------------------------------------------------