Cheate MAC address

Table of Contents

背景

由于一些原因,很多软件会绑定网卡MAC地址,这样就导致换了网卡之后,软件就无法使用了。
一般的解决方案是通过命令修改MAC地址,但是这样不够优雅,并且还有导致mac地址重复的风险。

使用命令修改IP地址

ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx

使用HOOK来完成mac地址欺骗

找出受害者获取MAC地址的方法

受害人信息 1

OS Ubuntu 16.04 xenial
网卡 a8:83:3b:53:eb:35

找出受害人获取mac地址的方法

用strace抓一下log

strace ./lmhostid
execve("./lmhostid", ["./lmhostid"], [/* 30 vars */]) = 0
brk(NULL)                               = 0x828000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=138880, ...}) = 0
mmap(NULL, 138880, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f75775c6000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000b\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=144976, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f75775
# 省略......
close(3)                                = 0
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
openat(AT_FDCWD, "/proc/net/dev", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(4, "Inter-|   Receive               "..., 1024) = 718
read(4, "", 1024)                       = 0
close(4)                                = 0
stat("/sys/devices/virtual/net/eno1", 0x7ffd14cf1d40) = -1 ENOENT (No such file or directory)
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
ioctl(4, SIOCGIFHWADDR, {ifr_name="eno1", ifr_hwaddr=a8:83:3b:53:eb:35}) = 0
close(4)                                = 0
stat("/sys/devices/virtual/net/virbr0", {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
stat("/sys/devices/virtual/net/lo", {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
ioctl(3, SIOCGIFHWADDR, {ifr_name="eno1", ifr_hwaddr=a8:83:3b:53:eb:35}) = 0
socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
ioctl(4, SIOCGIFHWADDR, {ifr_name="eno1", ifr_hwaddr=a8:83:3b:53:eb:35}) = 0
close(4)                                = 0
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond0"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond1"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond2"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond3"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond4"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond5"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond6"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond7"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond8"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="bond9"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic0"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic1"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic2"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic3"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic4"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic5"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic6"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic7"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic8"}) = -1 ENODEV (No such device)
ioctl(3, SIOCGIFHWADDR, {ifr_name="vmnic9"}) = -1 ENODEV (No such device)
close(3)                                = 0
write(1, "The FlexNet host ID of this mach"..., 54The FlexNet host ID of this machine is "a8833b53eb35"
) = 54
exit_group(0)                           = ?
+++ exited with 0 +++

从上面的log可以很容易的看出,应用使用SIOCGIFHWADDR的ioctl来获取MAC地址,所以只要hook这个函数就可以完成我们想要的功能。

使用LD_PRELOAD来完成hook

  • 代码
/*
 * ifhwaddr hook - a hook SIOCGIFHWADDR ioctl to give a fake MAC address for apps
 * LD_PRELOAD="hook.so" command
 *
 */

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>

#ifndef RTLD_NEXT
#define RTLD_NEXT ((void *) -1l)
#endif

#define REAL_LIBC RTLD_NEXT

int ioctl (int __fd, unsigned long int __request, ...) {
    static int (*func_ioctl) (int, unsigned long int, void *) = NULL;
    va_list args;
    void *argp;
    int retval;

    if (! func_ioctl) {
        func_ioctl = (int (*) (int, unsigned long int, void *)) dlsym (REAL_LIBC, "ioctl");
    }
    va_start (args, __request);
    argp = va_arg (args, void *);
    va_end (args);
    struct ifreq *ifr = argp;

    retval = func_ioctl (__fd, __request, argp);

    if (SIOCGIFHWADDR == __request && retval == 0) {

        unsigned char* mac=(unsigned char*)ifr->ifr_hwaddr.sa_data;
        // set to b3:26:83:2c:73:ec
        mac[0] = 0xb3;
        mac[1] = 0x26;
        mac[2] = 0x83;
        mac[3] = 0x2c;
        mac[4] = 0x73;
        mac[5] = 0xec;
    }

    return retval;
}
  • 编译:

    gcc -shared -o hook.so hook.c
    

测试:

hook前:

./lmhostid
lmhostid - Copyright (c) 1989-2017 Flexera Software LLC. All Rights Reserved.
The FlexNet host ID of this machine is "a8833b53eb35"

hook后

LD_PRELOAD=./hook.so ./lmhostid
lmhostid - Copyright (c) 1989-2017 Flexera Software LLC. All Rights Reserved.
The FlexNet host ID of this machine is "b326832c73ec"

Footnotes:

1

本文中的MAC address都是随机数

Contact me via :)
虚怀乃若谷,水深则流缓。