Soft Replacing the MAC address, of the interface with Python.

Hi to all! Today, let's write a small script using the C API.
And so what do we need?
  • Python2 + IDLE2
  • C headers and Linux man
Let's start:

1) The main structure: (man netdevice)
C:
struct ifreq {
    char ifr_name[16];
    union {
        struct sockaddr ifr_hwaddr;
        short           ifr_flags;
    };
};
But we need, not the whole structure!

2) Address structure (more bits/socket.h):
C:
struct sockaddr
{
    unsigned short sa_family;
    char sa_data[14];
};

3) Constants for ioctl:
  • more net/if.h
    • IFF_UP = 0x0001
    • IFF_LOOPBACK = 0x0008
    • IFF_POINTTOPOINT = 0x0010
  • more bits/ioctls.h
    • SIOCGIFFLAGS = 0x8913
    • SIOCSIFFLAGS = 0x8914
    • SIOCGIFHWADDR = 0x8927
    • SIOCSIFHWADDR = 0x8924

Now go to IDLE2:

Python:
import ctypes
import socket
import fcntl
import binascii
import random
import argparse
import pprint
#
digits = '0123456789ABCDEF'

We implement our C-structure:
Python:
class _sockaddr(ctypes.Structure):
    _fields_ = [
        ('sa_family', ctypes.c_ushort),
        ('sa_data', ctypes.c_char * 14)
    ]
#
#
class _ifunion(ctypes.Union):
    _anonymous_ = ('_sa',)
    _fields_ = [
        ('ifr_flags', ctypes.c_short),
        ('_sa', _sockaddr)
    ]
#
#
class ifreq(ctypes.Structure):
    _anonymous_ = ('_un',)
    _fields_ = [
        ('ifr_name', ctypes.c_char * 16),
        ('_un', _ifunion)
    ]

We implement the MAC class:
Python:
class MAC:
    def __init__(self, ifname):
        self._ifname = ifname
        self._socket = None
        #
        self._if_flags = ifreq()
        self._if_flags.ifr_name = ifname
        #
        self._if_hwaddr = ifreq()
        self._if_hwaddr.ifr_name = ifname
        #
        self._socket = socket.socket(
            socket.AF_PACKET,
            socket.SOCK_RAW,
            socket.ntohs(0x3)
        )
        self._socket.bind((self._ifname, 0))
        fcntl.ioctl(self._socket.fileno(), SIOCGIFFLAGS, self._if_flags)
    #
    def __del__(self):
        if self._socket: self._socket.close()
    #
    def if_isup(self):
        if bool(self._if_flags.ifr_flags & IFF_UP): return 'Up'
        else: return 'Down'
    #
    def if_up(self):
        self._if_flags.ifr_flags |= IFF_UP
        fcntl.ioctl(self._socket.fileno(), SIOCSIFFLAGS, self._if_flags)
    #
    def if_down(self):
        self._if_flags.ifr_flags ^= IFF_UP
        fcntl.ioctl(self._socket.fileno(), SIOCSIFFLAGS, self._if_flags)
    #
    def if_check(self):
        if (self._if_flags.ifr_flags & IFF_LOOPBACK): return False
        if (self._if_flags.ifr_flags & IFF_POINTTOPOINT): return False
        return True
    #
    def hwaddr_get(self):
        fcntl.ioctl(self._socket.fileno(), SIOCGIFHWADDR, self._if_hwaddr)
        MAC = self._if_hwaddr.sa_data
        MAC = binascii.hexlify(MAC)
        MAC = MAC.upper()
        #
        return '{}:{}:{}:{}:{}:{}'.format(
            MAC[:2], MAC[2:4],
            MAC[4:6], MAC[6:8],
            MAC[8:10], MAC[10:12]
        )
    #
    def hwaddr_rnd(self):
        MAC = '02{}{}{}{}{}{}{}{}{}{}'.format(
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits),
            random.choice(digits)
        )
        #
        self._if_hwaddr.sa_data = binascii.unhexlify(MAC)
        self.if_down()
        fcntl.ioctl(self._socket.fileno(), SIOCSIFHWADDR, self._if_hwaddr)
        self.if_up()
        return '{}:{}:{}:{}:{}:{}'.format(
            MAC[:2], MAC[2:4],
            MAC[4:6], MAC[6:8],
            MAC[8:10], MAC[10:12]
        )

Importantly! You can only replace the MAC address when the interface is off. Also, the MAC address must start at 02.

We handle the arguments:
Python:
args = argparse.ArgumentParser()
args.add_argument('iface')
args = args.parse_args()
#
try:
    mac = MAC(args.iface)
    pprint.pprint('Interface {} is {}'.format(args.iface, mac.if_isup()))
    #
    if mac.if_check():
        pprint.pprint('OLD: {}'.format(mac.hwaddr_get()))
        pprint.pprint('NEW: {}'.format(mac.hwaddr_rnd()))
        #
    else: raise TypeError('Interface loop or p-to-p')
    #
except Exception as msg:
    pprint.pprint('{}: {}'.format(msg.__class__.__name__, msg))

The final file can be downloaded here: GIT
 

f22

Codeby Academy
Gold Team
05.05.2019
1 940
228
BIT
1 773
Hi to all! Today, let's write a small script
Bash:
macchanger --help
Код:
GNU MAC Changer
Usage: macchanger [options] device

  -h,  --help                   Print this help
  -V,  --version                Print version and exit
  -s,  --show                   Print the MAC address and exit
  -e,  --ending                 Don't change the vendor bytes
  -a,  --another                Set random vendor MAC of the same kind
  -A                            Set random vendor MAC of any kind
  -p,  --permanent              Reset to original, permanent hardware MAC
  -r,  --random                 Set fully random MAC
  -l,  --list[=keyword]         Print known vendors
  -b,  --bia                    Pretend to be a burned-in-address
  -m,  --mac=XX:XX:XX:XX:XX:XX
       --mac XX:XX:XX:XX:XX:XX  Set the MAC XX:XX:XX:XX:XX:XX

Report bugs to https://github.com/alobbs/macchanger/issues
 
  • Нравится
Реакции: Vander
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!